     unknown

   Generated by Sphinx 3.5.2.

SQLAlchemy
**********

     SQLAlchemy 1.4.2, Mar 20, 2021

     unknown

     Copyright © 2007-2021, the SQLAlchemy authors and contributors

Full table of contents.  For a high level overview of all documentation,
see index_toplevel.

 — The Detailed Node Listing —

Overview

Installation Guide

SQLAlchemy 1.4 / 2.0 Tutorial

Tutorial Overview

Working with Transactions and the DBAPI

Basics of Statement Execution

Working with Database Metadata

Defining Table Metadata with the ORM

Working with Data

Core Insert

Selecting Data

Explicit FROM clauses and JOINs

Using Aliases

Subqueries and CTEs

Working with SQL Functions

Core UPDATE and DELETE

The update() SQL Expression Construct

The delete() SQL Expression Construct

Data Manipulation with the ORM

Inserting Rows with the ORM

Updating ORM Objects

Deleting ORM Objects

Working with Related Objects

Persisting and Loading Relationships

Using Relationships in Queries

Loader Strategies

SQLAlchemy ORM

Object Relational Tutorial (1.x API)

Querying

Querying with Joins

Eager Loading

Deleting

Mapper Configuration

Mapping Python Classes

Declarative Mapping

Declarative Mapping with Dataclasses and Attrs

Example Two - Dataclasses with Declarative Table

Imperative (a.k.a. Classical) Mappings

Mapper Configuration Overview

Mapped Class Behavior

Mapping Classes with Declarative

Table Configuration with Declarative

Declarative Table

Mapping Declaratively with Reflected Tables

Mapper Configuration with Declarative

Other Declarative Mapping Directives

Composing Mapped Hierarchies with Mixins

Mixing in Relationships

Mapping Columns and Expressions

Mapping Table Columns

SQL Expressions as Mapped Attributes

Using column_property

Changing Attribute Behavior

Composite Column Types

Mapping Class Inheritance Hierarchies

Joined Table Inheritance

Single Table Inheritance

Concrete Table Inheritance

Non-Traditional Mappings

Configuring a Version Counter

Relationship Configuration

Basic Relationship Patterns

One To Many

Many To Many

Late-Evaluation of Relationship Arguments

Adjacency List Relationships

Linking Relationships with Backref

Configuring how Relationship Joins

Collection Configuration and Techniques

Working with Large Collections

Customizing Collection Access

Dictionary Collections

Custom Collection Implementations

Special Relationship Persistence Patterns

Mutable Primary Keys / Update Cascades

Querying Data, Loading Objects

ORM Querying Guide

SELECT statements

Selecting ORM Entities and Attributes

Joins

ORM Execution Options

Loading Columns

Deferred Column Loading

Load Only and Wildcard Options

Relationship Loading Techniques

Relationship Loading with Loader Options

Lazy Loading

Joined Eager Loading

Subquery Eager Loading

Wildcard Loading Strategies

Routing Explicit Joins/Statements into Eagerly Loaded Collections

Loading Inheritance Hierarchies

Using with_polymorphic

Polymorphic Selectin Loading

Referring to specific subtypes on relationships

Query API

Using the Session

Session Basics

Basics of Using a Session

UPDATE and DELETE with arbitrary WHERE clause

Session Frequently Asked Questions

State Management

Quickie Intro to Object States

Merging

Refreshing / Expiring

Cascades

delete

Transactions and Connection Management

Managing Transactions

Session-level vs. Engine level transaction control

Explicit Begin

Setting Transaction Isolation Levels / DBAPI AUTOCOMMIT

Additional Persistence Techniques

Fetching Server-Generated Defaults

Case 4: primary key, RETURNING or equivalent is not supported

Partitioning Strategies (e.g. multiple database backends per Session)

Bulk Operations

Contextual/Thread-local Sessions

Tracking queries, object and Session Changes with Events

Execute Events

Persistence Events

Object Lifecycle Events

Session API

Events and Internals

ORM Events

ORM Extensions

Asynchronous I/O (asyncio)

Synopsis - ORM

Association Proxy

Automap

Relationship Detection

Baked Queries

Special Query Techniques

Declarative Extensions

Declarative API

Basic Use

Configuring Relationships

Table Configuration

Mypy  / Pep-484 Support for ORM Mappings

Usage

Mutation Tracking

Establishing Mutability on Scalar Column Values

Establishing Mutability on Composites

Ordering List

Horizontal Sharding

Hybrid Attributes

Working with Relationships

Indexable

Alternate Class Instrumentation

ORM Examples

Mapping Recipes

Performance

Versioning Objects

Inheritance Mapping Recipes

Special APIs

Extending the ORM

SQLAlchemy Core

SQL Expression Language Tutorial (1.x API)

Operators

Using Textual SQL

Everything Else

Unions and Other Set Operations

Correlated Subqueries

Inserts, Updates and Deletes

SQL Statements and Expressions API

Column Elements and Expressions

Operator Reference

IN Comparisons

Selectables, Tables, FROM objects

Insert, Updates, Deletes

Custom SQL Constructs and Compilation Extension

Compiling sub-elements of a custom expression construct

Further Examples

Schema Definition Language

Describing Databases with MetaData

Specifying the Schema Name

Reflecting Database Objects

Column INSERT/UPDATE Defaults

Python-Executed Functions

Defining Sequences

Defining Constraints and Indexes

Defining Foreign Keys

Configuring Constraint Naming Conventions

Indexes

Customizing DDL

Column and Data Types

Column and Data Types

Custom Types

TypeDecorator Recipes

Marshal JSON Strings

Engine and Connection Use

Engine Configuration

Database Urls

Custom DBAPI connect() arguments / on-connect routines

Special Keyword Arguments Passed to dbapi.connect()

Controlling how parameters are passed to the DBAPI connect() function

Configuring Logging

Working with Engines and Connections

Using Transactions

Nesting of Transaction Blocks

SQL Compilation Caching

Using Lambdas to add significant speed gains to statement production

Working with Driver SQL and Raw DBAPI Connections

Registering New Dialects

Connection Pooling

Dealing with Disconnects

Disconnect Handling - Pessimistic

Disconnect Handling - Optimistic

Core Events

Core API Basics

Events

Runtime Inspection API

Dialects

Included Dialects

PostgreSQL

Sequences/SERIAL/IDENTITY

INSERT…ON CONFLICT (Upsert)

PostgreSQL-Specific Index Options

Table values, Table and Column valued functions, Row and Tuple objects

ENUM Types

PostgreSQL Data Types and Custom SQL Constructs

psycopg2

Unicode with Psycopg2

pg8000

asyncpg

psycopg2cffi

py-postgresql

pygresql

MySQL and MariaDB

Supported Versions and Features

Unicode

MySQL / MariaDB- Specific Index Options

MySQL / MariaDB Foreign Keys

TIMESTAMP / DATETIME issues

mysqlclient (fork of MySQL-Python)

PyMySQL

MySQL-Connector

aiomysql

cymysql

OurSQL

pyodbc

SQLite

Date and Time Types

SQLite Auto Incrementing Behavior

INSERT…ON CONFLICT (Upsert)

Pysqlite

Connect Strings

Threading/Pooling Behavior

Pysqlcipher

Oracle

Auto Increment Behavior

Oracle Specific Index Options

cx_Oracle

Unicode

Fine grained control over cx_Oracle data binding performance with setinputsizes

Microsoft SQL Server

Auto Increment Behavior / IDENTITY Columns

MSSQL-Specific Index Options

PyODBC

Connecting to PyODBC

mxODBC

pymssql

Deprecated, no longer supported dialects

Firebird

fdb

kinterbasdb

Sybase

python-sybase

pyodbc

mxodbc

Frequently Asked Questions

Connections / Engines

How Do I “Retry” a Statement Execution Automatically?

Why does SQLAlchemy issue so many ROLLBACKs?

MetaData / Schema

SQL Expressions

How do I render SQL expressions as strings, possibly with bound parameters inlined?

I’m using op() to generate a custom operator and my parenthesis are not coming out correctly

ORM Configuration

Performance

How can I profile a SQLAlchemy powered application?

Sessions / Queries

“This Session’s transaction has been rolled back due to a previous exception during flush.” (or similar)

Third Party Integration Issues

Error Messages

Legacy API Features

Connections and Transactions

DBAPI Errors

SQL Expression Language

Object Relational Mapping

AsyncIO Exceptions

Changes and Migration

Current Migration Guide

What’s New in SQLAlchemy 1.4?

Major API changes and features - General

API and Behavioral Changes - Core

The URL object is now immutable

RowProxy is no longer a “proxy”; is now called Row and behaves like an enhanced named tuple

New Features - ORM

Behavioral Changes - ORM

Dialect Changes

SQLAlchemy 2.0 Overview and Status

Migrating to SQLAlchemy 2.0

Overview

2.0 Migration - Core Connection / Transaction

Library-level (but not driver level) “Autocommit” removed from both Core and ORM

“Implicit” and “Connectionless” execution, “bound metadata” removed

2.0 Migration - Core Usage

2.0 Migration - ORM Configuration

2.0 Migration - ORM Usage

2.0 Migration - ORM Extension and Recipe Changes

Change logs

1.4 Changelog

1.4.2

1.4.1

1.4.0

1.4.0b3

1.4.0b2

1.4.0b1

1.3 Changelog

1.3.24

1.3.23

1.3.22

1.3.21

1.3.20

1.3.19

1.3.18

1.3.17

1.3.16

1.3.15

1.3.14

1.3.13

1.3.12

1.3.11

1.3.10

1.3.9

1.3.8

1.3.7

1.3.6

1.3.5

1.3.4

1.3.3

1.3.2

1.3.1

1.3.0

1.3.0b3

1.3.0b2

1.3.0b1

1.2 Changelog

1.2.19

1.2.18

1.2.17

1.2.16

1.2.15

1.2.14

1.2.13

1.2.12

1.2.11

1.2.10

1.2.9

1.2.8

1.2.7

1.2.6

1.2.5

1.2.4

1.2.3

1.2.2

1.2.1

1.2.0

1.2.0b3

1.2.0b2

1.2.0b1

1.1 Changelog

1.1.18

1.1.16

1.1.15

1.1.14

1.1.13

1.1.12

1.1.11

1.1.10

1.1.9

1.1.8

1.1.7

1.1.6

1.1.5

1.1.4

1.1.3

1.1.2

1.1.1

1.1.0

1.1.0b3

1.1.0b2

1.1.0b1

1.0 Changelog

1.0.19

1.0.18

1.0.17

1.0.16

1.0.15

1.0.14

1.0.13

1.0.12

1.0.11

1.0.10

1.0.9

1.0.8

1.0.7

1.0.6

1.0.5

1.0.4

1.0.3

1.0.2

1.0.1

1.0.0

1.0.0b5

1.0.0b4

1.0.0b3

1.0.0b2

1.0.0b1

0.9 Changelog

0.9.10

0.9.9

0.9.8

0.9.7

0.9.6

0.9.5

0.9.4

0.9.3

0.9.2

0.9.1

0.9.0

0.9.0b1

0.8 Changelog

0.8.7

0.8.6

0.8.5

0.8.4

0.8.3

0.8.2

0.8.1

0.8.0

0.8.0b2

0.8.0b1

0.7 Changelog

0.7.11

0.7.10

0.7.9

0.7.8

0.7.7

0.7.6

0.7.5

0.7.4

0.7.3

0.7.2

0.7.1

0.7.0

0.7.0b4

0.7.0b3

0.7.0b2

0.7.0b1

0.6 Changelog

0.6.9

0.6.8

0.6.7

0.6.6

0.6.5

0.6.4

0.6.3

0.6.2

0.6.1

0.6.0

0.6beta3

0.6beta2

0.6beta1

0.5 Changelog

0.5.9

0.5.8

0.5.7

0.5.6

0.5.5

0.5.4p2

0.5.4p1

0.5.4

0.5.3

0.5.2

0.5.1

0.5.0

0.5.0rc4

0.5.0rc3

0.5.0rc2

0.5.0rc1

0.5.0beta3

0.5.0beta2

0.5.0beta1

0.4 Changelog

0.4.8

0.4.7p1

0.4.7

0.4.6

0.4.5

0.4.4

0.4.3

0.4.2p3

0.4.2

0.4.1

0.4.0beta2

0.4.0beta1

0.3 Changelog

0.3.11

0.3.10

0.3.9

0.3.8

0.3.7

0.3.6

0.3.5

0.3.4

0.3.1

0.3.0

0.2 Changelog

0.1 Changelog

Older Migration Guides

What’s New in SQLAlchemy 1.3?

General

New Features and Improvements - ORM

Association Proxy Improvements

Key Behavioral Changes - ORM

New Features and Improvements - Core

Key Changes - Core

Dialect Improvements and Changes - PostgreSQL

Dialect Improvements and Changes - MySQL

Dialect Improvements and Changes - SQLite

Dialect Improvements and Changes - Oracle

Dialect Improvements and Changes - SQL Server

What’s New in SQLAlchemy 1.2?

Platform Support

New Features and Improvements - ORM

New Features and Improvements - Core

Key Behavioral Changes - ORM

Key Behavioral Changes - Core

Dialect Improvements and Changes - PostgreSQL

Dialect Improvements and Changes - MySQL

Dialect Improvements and Changes - Oracle

Dialect Improvements and Changes - SQL Server

What’s New in SQLAlchemy 1.1?

Platform / Installer Changes

New Features and Improvements - ORM

New Session lifecycle events

New Features and Improvements - Core

ResultSet column matching enhancements; positional column setup for textual SQL

Support for Python’s native enum type and compatible forms

JSON support added to Core

Key Behavioral Changes - ORM

Key Behavioral Changes - Core

Dialect Improvements and Changes - PostgreSQL

Dialect Improvements and Changes - MySQL

Dialect Improvements and Changes - SQLite

Dialect Improvements and Changes - SQL Server

Dialect Improvements and Changes - Oracle

What’s New in SQLAlchemy 1.0?

New Features and Improvements - ORM

New Features and Improvements - Core

UniqueConstraint is now part of the Table reflection process

Key Behavioral Changes - ORM

Key Behavioral Changes - Core

Warnings emitted when coercing full SQL fragments into text()

Dialect Improvements and Changes - PostgreSQL

Dialect Improvements and Changes - MySQL

Dialect Improvements and Changes - SQLite

Dialect Improvements and Changes - SQL Server

Dialect Improvements and Changes - Oracle

What’s New in SQLAlchemy 0.9?

Platform Support

Behavioral Changes - ORM

Behavioral Changes - Core

New Features

New Query Options API; load_only() option

Behavioral Improvements

Dialect Changes

What’s New in SQLAlchemy 0.8?

Platform Support

New ORM Features

New Core Features

Behavioral Changes

Removed

What’s New in SQLAlchemy 0.7?

New Features

Behavioral Changes (Backwards Compatible)

Query.count() simplified, should work virtually always

Behavioral Changes (Backwards Incompatible)

Deprecated API

Backwards Incompatible API Changes

Previously Deprecated, Now Removed

What’s New in SQLAlchemy 0.6?

New Dialect System

Expression Language Changes

New Schema Capabilities

Type System Changes

ORM Changes

Extensions

What’s new in SQLAlchemy 0.5?

What’s new in SQLAlchemy 0.4?

Object Relational Mapping

Querying

Relations

Sessions

Inheritance

Types

SQL Expressions

Schema and Reflection

SQL Execution

1 Overview
**********

The SQLAlchemy SQL Toolkit and Object Relational Mapper is a
comprehensive set of tools for working with databases and Python.  It
has several distinct areas of functionality which can be used
individually or combined together.  Its major components are illustrated
below, with component dependencies organized into layers:

Above, the two most significant front-facing portions of SQLAlchemy are
the `Object Relational Mapper (ORM)' and the `Core'.

Core contains the breadth of SQLAlchemy’s SQL and database integration
and description services, the most prominent part of this being the `SQL
Expression Language'.

The SQL Expression Language is a toolkit all its own, independent of the
ORM package, which provides a system of constructing SQL expressions
represented by composable objects, which can then be “executed” against
a target database within the scope of a specific transaction, returning
a result set.  Inserts, updates and deletes (i.e.  DML) are achieved by
passing SQL expression objects representing these statements along with
dictionaries that represent parameters to be used with each statement.

The ORM builds upon Core to provide a means of working with a domain
object model mapped to a database schema.  When using the ORM, SQL
statements are constructed in mostly the same way as when using Core,
however the task of DML, which here refers to the persistence of
business objects in a database, is automated using a pattern called unit
of work, which translates changes in state against mutable objects into
INSERT, UPDATE and DELETE constructs which are then invoked in terms of
those objects.  SELECT statements are also augmented by ORM-specific
automations and object-centric querying capabilities.

Whereas working with Core and the SQL Expression language presents a
schema-centric view of the database, along with a programming paradigm
that is oriented around immutability, the ORM builds on top of this a
domain-centric view of the database with a programming paradigm that is
more explcitly object-oriented and reliant upon mutability.  Since a
relational database is itself a mutable service, the difference is that
Core/SQL Expression language is command oriented whereas the ORM is
state oriented.

1.1 Documentation Overview
==========================

The documentation is separated into four sections:

   * SQLAlchemy 1.4 / 2.0 Tutorial. - this all-new tutorial
     for the 1.4/2.0 series of SQLAlchemy introduces the entire library
     holistically, starting from a description of Core and working more
     and more towards ORM-specific concepts.  New users, as well as
     users coming from 1.x style, who wish to work in 2.0 style should
     start here.

   * SQLAlchemy ORM. - In this section, reference
     documentation for the ORM is presented; this section also includes
     the now-legacy Object Relational Tutorial (1.x API).

   * SQLAlchemy Core. - Here, reference documentation for
     everything else within Core is presented; section also includes the
     legacy SQL Expression Language Tutorial (1.x API).
     SQLAlchemy engine, connection, and pooling services are also
     described here.

   * Dialects. - Provides reference documentation for all
     dialect implementations, including DBAPI specifics.

1.2 Code Examples
=================

Working code examples, mostly regarding the ORM, are included in the
SQLAlchemy distribution.  A description of all the included example
applications is at ORM Examples.

There is also a wide variety of examples involving both core SQLAlchemy
constructs as well as the ORM on the wiki.  See Theatrum Chemicum(1).

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/wiki/UsageRecipes

1.3 Installation Guide
======================

1.3.1 Supported Platforms
-------------------------

SQLAlchemy has been tested against the following platforms:

   * cPython 2.7

   * cPython 3.6 and higher

   * PyPy(1) 2.1 or greater

Changed in version 1.4: Within the Python 3 series, 3.6 is now the
minimum Python 3 version supported.

See also
........

See Python 3.6 is the minimum Python 3 version; Python 2.7 still supported.

   ---------- Footnotes ----------

   (1) http://pypy.org/

1.3.2 Supported Installation Methods
------------------------------------

SQLAlchemy installation is via standard Python methodologies that are
based on setuptools(1), either by referring to ‘setup.py’ directly or by
using pip(2) or other setuptools-compatible approaches.

Changed in version 1.1: setuptools is now required by the setup.py file;
plain distutils installs are no longer supported.

   ---------- Footnotes ----------

   (1) http://pypi.python.org/pypi/setuptools/

   (2) http://pypi.python.org/pypi/pip/

1.3.3 Install via pip
---------------------

When ‘pip’ is available, the distribution can be downloaded from PyPI
and installed in one step:

     pip install SQLAlchemy

This command will download the latest `released' version of SQLAlchemy
from the Python Cheese Shop(1) and install it to your system.

In order to install the latest `prerelease' version, such as ‘1.4.0b1’,
pip requires that the ‘--pre’ flag be used:

     pip install --pre SQLAlchemy

Where above, if the most recent version is a prerelease, it will be
installed instead of the latest released version.

   ---------- Footnotes ----------

   (1) http://pypi.python.org/pypi/SQLAlchemy

1.3.4 Installing using setup.py
-------------------------------

Otherwise, you can install from the distribution using the ‘setup.py’
script:

     python setup.py install

1.3.5 Installing the C Extensions
---------------------------------

SQLAlchemy includes C extensions which provide an extra speed boost for
dealing with result sets.  The extensions are supported on both the 2.xx
and 3.xx series of cPython.

‘setup.py’ will automatically build the extensions if an appropriate
platform is detected.  If the build of the C extensions fails due to a
missing compiler or other issue, the setup process will output a warning
message and re-run the build without the C extensions upon completion,
reporting final status.

To run the build/install without even attempting to compile the C
extensions, the ‘DISABLE_SQLALCHEMY_CEXT’ environment variable may be
specified.  The use case for this is either for special testing
circumstances, or in the rare case of compatibility/build issues not
overcome by the usual “rebuild” mechanism:

     export DISABLE_SQLALCHEMY_CEXT=1; python setup.py install

Changed in version 1.1: The legacy ‘--without-cextensions’ flag has been
removed from the installer as it relies on deprecated features of
setuptools.

1.3.6 Installing a Database API
-------------------------------

SQLAlchemy is designed to operate with a DBAPI implementation built for
a particular database, and includes support for the most popular
databases.  The individual database sections in Dialects
enumerate the available DBAPIs for each database, including external
links.

1.3.7 Checking the Installed SQLAlchemy Version
-----------------------------------------------

This documentation covers SQLAlchemy version 1.4.  If you’re working on
a system that already has SQLAlchemy installed, check the version from
your Python prompt like this:

     >>> import sqlalchemy
     >>> sqlalchemy.__version__ # doctest: +SKIP
     1.4.0

1.4 1.3 to 1.4 Migration
========================

Notes on what’s changed from 1.3 to 1.4 is available here at
What’s New in SQLAlchemy 1.4?.

2 SQLAlchemy 1.4 / 2.0 Tutorial
*******************************

     About this document: The new SQLAlchemy Tutorial is now integrated
     between Core and ORM and serves as a unified introduction to
     SQLAlchemy as a whole.  In the new 2.0 style of working, fully
     available in the 1.4 release, the ORM now uses Core-style
     querying with the select() construct, and transactional
     semantics between Core connections and ORM sessions are equivalent.
     Take note of the blue border styles for each section, that will
     tell you how “ORM-ish” a particular topic is!

     Users who are already familiar with SQLAlchemy, and especially
     those looking to migrate existing applications to work under
     SQLAlchemy 2.0 within the 1.4 transitional phase should check out
     the Migrating to SQLAlchemy 2.0 document as well.

     For the newcomer, this document has a `lot' of detail, however by
     the end they will be considered an `Alchemist'.

SQLAlchemy is presented as two distinct APIs, one building on top of the
other.  These APIs are known as `Core' and `ORM'.

`SQLAlchemy Core' is the foundational architecture for SQLAlchemy as a
“database toolkit”.  The library provides tools for managing
connectivity to a database, interacting with database queries and
results, and programmatic construction of SQL statements.

Sections that have a `dark blue border on the right' will discuss
concepts that are `primarily Core-only'; when using the ORM, these
concepts are still in play but are less often explicit in user code.

`SQLAlchemy ORM' builds upon the Core to provide optional `object
relational mapping' capabilities.  The ORM provides an additional
configuration layer allowing user-defined Python classes to be `mapped'
to database tables and other constructs, as well as an object
persistence mechanism known as the `Session'.  It then extends the
Core-level SQL Expression Language to allow SQL queries to be composed
and invoked in terms of user-defined objects.

Sections that have a `light blue border on the left' will discuss
concepts that are `primarily ORM-only'.  Core-only users can skip these.

A section that has `both light and dark borders on both sides' will
discuss a `Core concept that is also used explicitly with the ORM'.

2.1 Tutorial Overview
=====================

The tutorial will present both concepts in the natural order that they
should be learned, first with a mostly-Core-centric approach and then
spanning out into a more ORM-centric concepts.

The major sections of this tutorial are as follows:

SQLAlchemy 1.4 / 2.0 Tutorial
.............................

This page is part of the SQLAlchemy 1.4 / 2.0 Tutorial.

Previous: SQLAlchemy 1.4 / 2.0 Tutorial. | Next: Working with Transactions and the DBAPI.

2.1.1 Establishing Connectivity - the Engine
--------------------------------------------

The start of any SQLAlchemy application is an object called the
Engine.  This object acts as a central source of connections to a
particular database, providing both a factory as well as a holding space
called a connection pool for these database connections.  The
engine is typically a global object created just once for a particular
database server, and is configured using a URL string which will
describe how it should connect to the database host or backend.

For this tutorial we will use an in-memory-only SQLite database.  This
is an easy way to test things without needing to have an actual
pre-existing database set up.  The Engine is created by using
create_engine(), specifying the create_engine.future
flag set to ‘True’ so that we make full use of 2.0 style usage:

     >>> from sqlalchemy import create_engine
     >>> engine = create_engine("sqlite+pysqlite:///:memory:", echo=True, future=True)

The main argument to create_engine is a string URL, above
passed as the string ‘"sqlite+pysqlite:///:memory:"’.  This string
indicates to the Engine three important facts:

  1. What kind of database are we communicating with?  This is the
     ‘sqlite’ portion above, which links in SQLAlchemy to an object
     known as the dialect.

  2. What DBAPI are we using?  The Python DBAPI is a third party driver
     that SQLAlchemy uses to interact with a particular database.  In
     this case, we’re using the name ‘pysqlite’, which in modern Python
     use is the sqlite3(1) standard library interface for SQLite.  If
     omitted, SQLAlchemy will use a default DBAPI for the particular
     database selected.

  3. How do we locate the database?  In this case, our URL includes the
     phrase ‘/:memory:’, which is an indicator to the ‘sqlite3’ module
     that we will be using an `in-memory-only' database.  This kind of
     database is perfect for experimenting as it does not require any
     server nor does it need to create new files.

Lazy Connecting
...............

The Engine, when first returned by create_engine(),
has not actually tried to connect to the database yet; that happens only
the first time it is asked to perform a task against the database.  This
is a software design pattern known as lazy initialization.

We have also specified a parameter create_engine.echo, which
will instruct the Engine to log all of the SQL it emits to a
Python logger that will write to standard out.  This flag is a shorthand
way of setting up Python logging more formally and is useful
for experimentation in scripts.  Many of the SQL examples will include
this SQL logging output beneath a ‘[SQL]’ link that when clicked, will
reveal the full SQL interaction.

SQLAlchemy 1.4 / 2.0 Tutorial
.............................

Next Tutorial Section: Working with Transactions and the DBAPI.

SQLAlchemy 1.4 / 2.0 Tutorial
.............................

This page is part of the SQLAlchemy 1.4 / 2.0 Tutorial.

Previous: Establishing Connectivity - the Engine. | Next:
Working with Database Metadata.

   ---------- Footnotes ----------

   (1) http://docs.python.org/library/sqlite3.html

2.1.2 Working with Transactions and the DBAPI
---------------------------------------------

With the Engine object ready to go, we may now proceed to
dive into the basic operation of an Engine and its primary
interactive endpoints, the Connection and Result.
We will additionally introduce the ORM’s facade for these objects, known
as the Session.

`Note to ORM readers'

When using the ORM, the Engine is managed by another object
called the Session.  The Session in modern
SQLAlchemy emphasizes a transactional and SQL execution pattern that is
largely identical to that of the Connection discussed below,
so while this subsection is Core-centric, all of the concepts here are
essentially relevant to ORM use as well and is recommended for all ORM
learners.  The execution pattern used by the Connection will
be contrasted with that of the Session at the end of this
section.

As we have yet to introduce the SQLAlchemy Expression Language that is
the primary feature of SQLAlchemy, we will make use of one simple
construct within this package called the text() construct,
which allows us to write SQL statements as `textual SQL'. Rest assured
that textual SQL in day-to-day SQLAlchemy use is by far the exception
rather than the rule for most tasks, even though it always remains fully
available.

2.1.2.1 Getting a Connection
............................

The sole purpose of the Engine object from a user-facing
perspective is to provide a unit of connectivity to the database called
the Connection.  When working with the Core directly, the
Connection object is how all interaction with the database is
done.  As the Connection represents an open resource against
the database, we want to always limit the scope of our use of this
object to a specific context, and the best way to do that is by using
Python context manager form, also known as the with statement(1).  Below
we illustrate “Hello World”, using a textual SQL statement.  Textual SQL
is emitted using a construct called text() that will be
discussed in more detail later:

     >>> from sqlalchemy import text

     >>> with engine.connect() as conn:
     ...     result = conn.execute(text("select 'hello world'"))
     ...     print(result.all())
     {opensql}BEGIN (implicit)
     select 'hello world'
     [...] ()
     {stop}[('hello world',)]
     {opensql}ROLLBACK{stop}

In the above example, the context manager provided for a database
connection and also framed the operation inside of a transaction.  The
default behavior of the Python DBAPI includes that a transaction is
always in progress; when the scope of the connection is released, a
ROLLBACK is emitted to end the transaction.  The transaction is `not
committed automatically'; when we want to commit data we normally need
to call Connection.commit() as we’ll see in the next section.

     Tip: “autocommit” mode is available for special cases.  The section
     Setting Transaction Isolation Levels including DBAPI Autocommit
     discusses this.

The result of our SELECT was also returned in an object called
Result that will be discussed later, however for the moment we’ll
add that it’s best to ensure this object is consumed within the
“connect” block, and is not passed along outside of the scope of our
connection.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/reference/compound_stmts.html#with

2.1.2.2 Committing Changes
..........................

We just learned that the DBAPI connection is non-autocommitting.  What
if we want to commit some data?  We can alter our above example to
create a table and insert some data, and the transaction is then
committed using the Connection.commit() method, invoked
`inside' the block where we acquired the Connection object:

     # "commit as you go"
     >>> with engine.connect() as conn:
     ...     conn.execute(text("CREATE TABLE some_table (x int, y int)"))
     ...     conn.execute(
     ...         text("INSERT INTO some_table (x, y) VALUES (:x, :y)"),
     ...         [{"x": 1, "y": 1}, {"x": 2, "y": 4}]
     ...     )
     ...     conn.commit()
     {opensql}BEGIN (implicit)
     CREATE TABLE some_table (x int, y int)
     [...] ()
     <sqlalchemy.engine.cursor.CursorResult object at 0x...>
     INSERT INTO some_table (x, y) VALUES (?, ?)
     [...] ((1, 1), (2, 4))
     <sqlalchemy.engine.cursor.CursorResult object at 0x...>
     COMMIT

Above, we emitted two SQL statements that are generally transactional, a
“CREATE TABLE” statement (1) and an “INSERT” statement that’s
parameterized (the parameterization syntax above is discussed a few
sections below in Sending Multiple Parameters).  As we want
the work we’ve done to be committed within our block, we invoke the
Connection.commit() method which commits the transaction.
After we call this method inside the block, we can continue to run more
SQL statements and if we choose we may call Connection.commit()
again for subsequent statements.  SQLAlchemy refers to this style as
`commit as you go'.

There is also another style of committing data, which is that we can
declare our “connect” block to be a transaction block up front.  For
this mode of operation, we use the Engine.begin() method to
acquire the connection, rather than the Engine.connect()
method.  This method will both manage the scope of the Connection
and also enclose everything inside of a transaction with COMMIT at
the end, assuming a successful block, or ROLLBACK in case of exception
raise.  This style may be referred towards as `begin once':

     # "begin once"
     >>> with engine.begin() as conn:
     ...     conn.execute(
     ...         text("INSERT INTO some_table (x, y) VALUES (:x, :y)"),
     ...         [{"x": 6, "y": 8}, {"x": 9, "y": 10}]
     ...     )
     {opensql}BEGIN (implicit)
     INSERT INTO some_table (x, y) VALUES (?, ?)
     [...] ((6, 8), (9, 10))
     <sqlalchemy.engine.cursor.CursorResult object at 0x...>
     COMMIT

“Begin once” style is often preferred as it is more succinct and
indicates the intention of the entire block up front.  However, within
this tutorial we will normally use “commit as you go” style as it is
more flexible for demonstration purposes.

What’s “BEGIN (implicit)”?
..........................

You might have noticed the log line “BEGIN (implicit)” at the start of a
transaction block.  “implicit” here means that SQLAlchemy `did not
actually send any command' to the database; it just considers this to be
the start of the DBAPI’s implicit transaction.  You can register
event hooks to intercept this event, for example.

   ---------- Footnotes ----------

   (1) (1) DDL refers to the subset of SQL that instructs the database
to create, modify, or remove schema-level constructs such as tables.
DDL such as “CREATE TABLE” is recommended to be within a transaction
block that ends with COMMIT, as many databases uses transactional DDL
such that the schema changes don’t take place until the transaction is
committed.  However, as we’ll see later, we usually let SQLAlchemy run
DDL sequences for us as part of a higher level operation where we don’t
generally need to worry about the COMMIT.

2.1.2.3 Basics of Statement Execution
.....................................

We have seen a few examples that run SQL statements against a database,
making use of a method called Connection.execute(), in
conjunction with an object called text(), and returning an
object called Result.  In this section we’ll illustrate more
closely the mechanics and interactions of these components.

Most of the content in this section applies equally well to modern ORM
use when using the Session.execute() method, which works very
similarly to that of Connection.execute(), including that ORM
result rows are delivered using the same Result interface
used by Core.

2.1.2.4 Fetching Rows
.....................

We’ll first illustrate the Result object more closely by
making use of the rows we’ve inserted previously, running a textual
SELECT statement on the table we’ve created:

     >>> with engine.connect() as conn:
     ...     result = conn.execute(text("SELECT x, y FROM some_table"))
     ...     for row in result:
     ...         print(f"x: {row.x}  y: {row.y}")
     {opensql}BEGIN (implicit)
     SELECT x, y FROM some_table
     [...] ()
     {stop}x: 1  y: 1
     x: 2  y: 4
     x: 6  y: 8
     x: 9  y: 10
     {opensql}ROLLBACK{stop}

Above, the “SELECT” string we executed selected all rows from our table.
The object returned is called Result and represents an
iterable object of result rows.

Result has lots of methods for fetching and transforming
rows, such as the Result.all() method illustrated previously,
which returns a list of all Row objects.  It also implements
the Python iterator interface so that we can iterate over the collection
of Row objects directly.

The Row objects themselves are intended to act like Python
named tuples(1).  Below we illustrate a variety of ways to access rows.

   * `Tuple Assignment' - This is the most Python-idiomatic style, which
     is to assign variables to each row positionally as they are
     received:

          result = conn.execute(text("select x, y from some_table"))

          for x, y in result:
              # ...

   * `Integer Index' - Tuples are Python sequences, so regular integer
     access is available too:

          result = conn.execute(text("select x, y from some_table"))

            for row in result:
                x = row[0]

   * `Attribute Name' - As these are Python named tuples, the tuples
     have dynamic attribute names matching the names of each column.
     These names are normally the names that the SQL statement assigns
     to the columns in each row.  While they are usually fairly
     predictable and can also be controlled by labels, in less defined
     cases they may be subject to database-specific behaviors:

          result = conn.execute(text("select x, y from some_table"))

          for row in result:
              y = row.y

              # illustrate use with Python f-strings
              print(f"Row: {row.x} {row.y}")

   * `Mapping Access' - To receive rows as Python `mapping' objects,
     which is essentially a read-only version of Python’s interface to
     the common ‘dict’ object, the Result may be
     `transformed' into a MappingResult object using the
     Result.mappings() modifier; this is a result object that
     yields dictionary-like RowMapping objects rather than
     Row objects:

          result = conn.execute(text("select x, y from some_table"))

          for dict_row in result.mappings():
              x = dict_row['x']
              y = dict_row['y']

   ---------- Footnotes ----------

   (1)
https://docs.python.org/3/library/collections.html#collections.namedtuple

2.1.2.5 Sending Parameters
..........................

SQL statements are usually accompanied by data that is to be passed with
the statement itself, as we saw in the INSERT example previously.  The
Connection.execute() method therefore also accepts
parameters, which are referred towards as bound parameters.  A
rudimentary example might be if we wanted to limit our SELECT statement
only to rows that meet a certain criteria, such as rows where the “y”
value were greater than a certain value that is passed in to a function.

In order to achieve this such that the SQL statement can remain fixed
and that the driver can properly sanitize the value, we add a WHERE
criteria to our statement that names a new parameter called “y”; the
text() construct accepts these using a colon format “‘:y’”.
The actual value for “‘:y’” is then passed as the second argument to
Connection.execute() in the form of a dictionary:

     >>> with engine.connect() as conn:
     ...     result = conn.execute(
     ...         text("SELECT x, y FROM some_table WHERE y > :y"),
     ...         {"y": 2}
     ...     )
     ...     for row in result:
     ...        print(f"x: {row.x}  y: {row.y}")
     {opensql}BEGIN (implicit)
     SELECT x, y FROM some_table WHERE y > ?
     [...] (2,)
     {stop}x: 2  y: 4
     x: 6  y: 8
     x: 9  y: 10
     {opensql}ROLLBACK{stop}

In the logged SQL output, we can see that the bound parameter ‘:y’ was
converted into a question mark when it was sent to the SQLite database.
This is because the SQLite database driver uses a format called “qmark
parameter style”, which is one of six different formats allowed by the
DBAPI specification.  SQLAlchemy abstracts these formats into just one,
which is the “named” format using a colon.

Always use bound parameters
...........................

As mentioned at the beginning of this section, textual SQL is not the
usual way we work with SQLAlchemy.  However, when using textual SQL, a
Python literal value, even non-strings like integers or dates, should
`never be stringified into SQL string directly'; a parameter should
`always' be used.  This is most famously known as how to avoid SQL
injection attacks when the data is untrusted.  However it also allows
the SQLAlchemy dialects and/or DBAPI to correctly handle the incoming
input for the backend.  Outside of plain textual SQL use cases,
SQLAlchemy’s Core Expression API otherwise ensures that Python literal
values are passed as bound parameters where appropriate.

2.1.2.6 Sending Multiple Parameters
...................................

In the example at Committing Changes, we executed an INSERT
statement where it appeared that we were able to INSERT multiple rows
into the database at once.  For statements that `operate upon data, but
do not return result sets', namely DML statements such as “INSERT” which
don’t include a phrase like “RETURNING”, we can send `multi params' to
the Connection.execute() method by passing a list of
dictionaries instead of a single dictionary, thus allowing the single
SQL statement to be invoked against each parameter set individually:

     >>> with engine.connect() as conn:
     ...     conn.execute(
     ...         text("INSERT INTO some_table (x, y) VALUES (:x, :y)"),
     ...         [{"x": 11, "y": 12}, {"x": 13, "y": 14}]
     ...     )
     ...     conn.commit()
     {opensql}BEGIN (implicit)
     INSERT INTO some_table (x, y) VALUES (?, ?)
     [...] ((11, 12), (13, 14))
     <sqlalchemy.engine.cursor.CursorResult object at 0x...>
     COMMIT

Behind the scenes, the Connection objects uses a DBAPI
feature known as cursor.executemany()(1).  This method performs the
equivalent operation of invoking the given SQL statement against each
parameter set individually.  The DBAPI may optimize this operation in a
variety of ways, by using prepared statements, or by concatenating the
parameter sets into a single SQL statement in some cases.  Some
SQLAlchemy dialects may also use alternate APIs for this case, such as
the psycopg2 dialect for PostgreSQL which uses more
performant APIs for this use case.

     Tip: you may have noticed this section isn’t tagged as an ORM
     concept.  That’s because the “multiple parameters” use case is
     `usually' used for INSERT statements, which when using the ORM are
     invoked in a different way.  Multiple parameters also may be used
     with UPDATE and DELETE statements to emit distinct UPDATE/DELETE
     operations on a per-row basis, however again when using the ORM,
     there is a different technique generally used for updating or
     deleting many individual rows separately.

   ---------- Footnotes ----------

   (1) https://www.python.org/dev/peps/pep-0249/#id18

2.1.2.7 Bundling Parameters with a Statement
............................................

The two previous cases illustrate a series of parameters being passed to
accompany a SQL statement.  For single-parameter statement executions,
SQLAlchemy’s use of parameters is in fact more often than not done by
`bundling' the parameters with the statement itself, which is a primary
feature of the SQL Expression Language and makes for queries that can be
composed naturally while still making use of parameterization in all
cases.  This concept will be discussed in much more detail in the
sections that follow; for a brief preview, the text()
construct itself being part of the SQL Expression Language supports this
feature by using the TextClause.bindparams() method; this is
a generative method that returns a new copy of the SQL construct with
additional state added, in this case the parameter values we want to
pass along:

     >>> stmt = text("SELECT x, y FROM some_table WHERE y > :y ORDER BY x, y").bindparams(y=6)
     >>> with engine.connect() as conn:
     ...     result = conn.execute(stmt)
     ...     for row in result:
     ...        print(f"x: {row.x}  y: {row.y}")
     {opensql}BEGIN (implicit)
     SELECT x, y FROM some_table WHERE y > ? ORDER BY x, y
     [...] (6,)
     {stop}x: 6  y: 8
     x: 9  y: 10
     x: 11  y: 12
     x: 13  y: 14
     {opensql}ROLLBACK{stop}

The interesting thing to note above is that even though we passed only a
single argument, ‘stmt’, to the Connection.execute() method,
the execution of the statement illustrated both the SQL string as well
as the separate parameter tuple.

2.1.2.8 Executing with an ORM Session
.....................................

As mentioned previously, most of the patterns and examples above apply
to use with the ORM as well, so here we will introduce this usage so
that as the tutorial proceeds, we will be able to illustrate each
pattern in terms of Core and ORM use together.

The fundamental transactional / database interactive object when using
the ORM is called the Session.  In modern SQLAlchemy, this
object is used in a manner very similar to that of the Connection,
and in fact as the Session is used, it refers to a
Connection internally which it uses to emit SQL.

When the Session is used with non-ORM constructs, it passes
through the SQL statements we give it and does not generally do things
much differently from how the Connection does directly, so we
can illustrate it here in terms of the simple textual SQL operations
we’ve already learned.

The Session has a few different creational patterns, but here
we will illustrate the most basic one that tracks exactly with how the
Connection is used which is to construct it within a context
manager:

     >>> from sqlalchemy.orm import Session

     >>> stmt = text("SELECT x, y FROM some_table WHERE y > :y ORDER BY x, y").bindparams(y=6)
     >>> with Session(engine) as session:
     ...     result = session.execute(stmt)
     ...     for row in result:
     ...        print(f"x: {row.x}  y: {row.y}")
     {opensql}BEGIN (implicit)
     SELECT x, y FROM some_table WHERE y > ? ORDER BY x, y
     [...] (6,){stop}
     x: 6  y: 8
     x: 9  y: 10
     x: 11  y: 12
     x: 13  y: 14
     {opensql}ROLLBACK{stop}

The example above can be compared to the example in the preceding
section in Bundling Parameters with a Statement. - we directly
replace the call to ‘with engine.connect() as conn’ with ‘with
Session(engine) as session’, and then make use of the
Session.execute() method just like we do with the
Connection.execute() method.

Also, like the Connection, the Session features
“commit as you go” behavior using the Session.commit()
method, illustrated below using a textual UPDATE statement to alter some
of our data:

     >>> with Session(engine) as session:
     ...     result = session.execute(
     ...         text("UPDATE some_table SET y=:y WHERE x=:x"),
     ...         [{"x": 9, "y":11}, {"x": 13, "y": 15}]
     ...     )
     ...     session.commit()
     {opensql}BEGIN (implicit)
     UPDATE some_table SET y=? WHERE x=?
     [...] ((11, 9), (15, 13))
     COMMIT{stop}

Above, we invoked an UPDATE statement using the bound-parameter,
“executemany” style of execution introduced at Sending Multiple Parameters,
ending the block with a “commit as you go” commit.

     Tip: The Session doesn’t actually hold onto the
     Connection object after it ends the transaction.  It gets a
     new Connection from the Engine when executing
     SQL against the database is next needed.

The Session obviously has a lot more tricks up its sleeve
than that, however understanding that it has an Session.execute()
method that’s used the same way as Connection.execute()
will get us started with the examples that follow later.

SQLAlchemy 1.4 / 2.0 Tutorial
.............................

Next Tutorial Section: Working with Database Metadata.

SQLAlchemy 1.4 / 2.0 Tutorial
.............................

This page is part of the SQLAlchemy 1.4 / 2.0 Tutorial.

Previous: Working with Transactions and the DBAPI. | Next:
Working with Data.

2.1.3 Working with Database Metadata
------------------------------------

With engines and SQL execution down, we are ready to begin some Alchemy.
The central element of both SQLAlchemy Core and ORM is the SQL
Expression Language which allows for fluent, composable construction of
SQL queries.  The foundation for these queries are Python objects that
represent database concepts like tables and columns.  These objects are
known collectively as database metadata.

The most common foundational objects for database metadata in SQLAlchemy
are known as MetaData, Table, and Column.
The sections below will illustrate how these objects are used in both a
Core-oriented style as well as an ORM-oriented style.

`ORM readers, stay with us!'

As with other sections, Core users can skip the ORM sections, but ORM
users would best be familiar with these objects from both perspectives.

2.1.3.1 Setting up MetaData with Table objects
..............................................

When we work with a relational database, the basic structure that we
create and query from is known as a `table'.  In SQLAlchemy, the “table”
is represented by a Python object similarly named Table.

To start using the SQLAlchemy Expression Language, we will want to have
Table objects constructed that represent all of the database
tables we are interested in working with.  Each Table may be
`declared', meaning we explicitly spell out in source code what the
table looks like, or may be `reflected', which means we generate the
object based on what’s already present in a particular database.  The
two approaches can also be blended in many ways.

Whether we will declare or reflect our tables, we start out with a
collection that will be where we place our tables known as the
MetaData object.  This object is essentially a facade around a
Python dictionary that stores a series of Table objects keyed
to their string name.  Constructing this object looks like:

     >>> from sqlalchemy import MetaData
     >>> metadata = MetaData()

Having a single MetaData object for an entire application is
the most common case, represented as a module-level variable in a single
place in an application, often in a “models” or “dbschema” type of
package.  There can be multiple MetaData collections as well,
however it’s typically most helpful if a series Table objects
that are related to each other belong to a single MetaData
collection.

Once we have a MetaData object, we can declare some
Table objects.  This tutorial will start with the classic
SQLAlchemy tutorial model, that of the table ‘user’, which would for
example represent the users of a website, and the table ‘address’,
representing a list of email addresses associated with rows in the
‘user’ table.  We normally assign each Table object to a
variable that will be how we will refer to the table in application
code:

     >>> from sqlalchemy import Table, Column, Integer, String
     >>> user_table = Table(
     ...     "user_account",
     ...     metadata,
     ...     Column('id', Integer, primary_key=True),
     ...     Column('name', String(30)),
     ...     Column('fullname', String)
     ... )

We can observe that the above Table construct looks a lot
like a SQL CREATE TABLE statement; starting with the table name, then
listing out each column, where each column has a name and a datatype.
The objects we use above are:

   * Table. - represents a database table and assigns itself
     to a MetaData collection.

   * Column. - represents a column in a database table, and
     assigns itself to a Table object.  The Column
     usually includes a string name and a type object.  The collection
     of Column objects in terms of the parent Table
     are typically accessed via an associative array located at
     Table.c:

          >>> user_table.c.name
          Column('name', String(length=30), table=<user_account>)

          >>> user_table.c.keys()
          ['id', 'name', 'fullname']

   * Integer, String. - these classes represent SQL
     datatypes and can be passed to a Column with or without
     necessarily being instantiated.  Above, we want to give a length of
     “30” to the “name” column, so we instantiated ‘String(30)’.  But
     for “id” and “fullname” we did not specify these, so we can send
     the class itself.

See also
........

The reference and API documentation for MetaData, Table
and Column is at Describing Databases with MetaData.
The reference documentation for datatypes is at
Column and Data Types.

In an upcoming section, we will illustrate one of the fundamental
functions of Table which is to generate DDL on a particular
database connection.  But first we will declare a second Table.

2.1.3.2 Declaring Simple Constraints
....................................

The first Column in the above ‘user_table’ includes the
Column.primary_key parameter which is a shorthand technique of
indicating that this Column should be part of the primary key
for this table.  The primary key itself is normally declared implicitly
and is represented by the PrimaryKeyConstraint construct,
which we can see on the Table.primary_key attribute on the
Table object:

     >>> user_table.primary_key
     PrimaryKeyConstraint(Column('id', Integer(), table=<user_account>, primary_key=True, nullable=False))

The constraint that is most typically declared explicitly is the
ForeignKeyConstraint object that corresponds to a database foreign
key constraint.  When we declare tables that are related to each other,
SQLAlchemy uses the presence of these foreign key constraint
declarations not only so that they are emitted within CREATE statements
to the database, but also to assist in constructing SQL expressions.

A ForeignKeyConstraint that involves only a single column on
the target table is typically declared using a column-level shorthand
notation via the ForeignKey object.  Below we declare a
second table ‘address’ that will have a foreign key constraint referring
to the ‘user’ table:

     >>> from sqlalchemy import ForeignKey
     >>> address_table = Table(
     ...     "address",
     ...     metadata,
     ...     Column('id', Integer, primary_key=True),
     ...     Column('user_id', ForeignKey('user_account.id'), nullable=False),
     ...     Column('email_address', String, nullable=False)
     ... )

The table above also features a third kind of constraint, which in SQL
is the “NOT NULL” constraint, indicated above using the
Column.nullable parameter.

     Tip: When using the ForeignKey object within a
     Column definition, we can omit the datatype for that
     Column; it is automatically inferred from that of the related
     column, in the above example the Integer datatype of the
     ‘user_account.id’ column.

In the next section we will emit the completed DDL for the ‘user’ and
‘address’ table to see the completed result.

2.1.3.3 Emitting DDL to the Database
....................................

We’ve constructed a fairly elaborate object hierarchy to represent two
database tables, starting at the root MetaData object, then
into two Table objects, each of which hold onto a collection
of Column and Constraint objects.  This object
structure will be at the center of most operations we perform with both
Core and ORM going forward.

The first useful thing we can do with this structure will be to emit
CREATE TABLE statements, or DDL, to our SQLite database so that we can
insert and query data from them.  We have already all the tools needed
to do so, by invoking the MetaData.create_all() method on our
MetaData, sending it the Engine that refers to the
target database:

     >>> metadata.create_all(engine)
     {opensql}BEGIN (implicit)
     PRAGMA main.table_...info("user_account")
     ...
     PRAGMA main.table_...info("address")
     ...
     CREATE TABLE user_account (
         id INTEGER NOT NULL,
         name VARCHAR(30),
         fullname VARCHAR,
         PRIMARY KEY (id)
     )
     ...
     CREATE TABLE address (
         id INTEGER NOT NULL,
         user_id INTEGER NOT NULL,
         email_address VARCHAR NOT NULL,
         PRIMARY KEY (id),
         FOREIGN KEY(user_id) REFERENCES user_account (id)
     )
     ...
     COMMIT

The DDL create process by default includes some SQLite-specific PRAGMA
statements that test for the existence of each table before emitting a
CREATE. The full series of steps are also included within a BEGIN/COMMIT
pair to accommodate for transactional DDL (SQLite does actually support
transactional DDL, however the ‘sqlite3’ database driver historically
runs DDL in “autocommit” mode).

The create process also takes care of emitting CREATE statements in the
correct order; above, the FOREIGN KEY constraint is dependent on the
‘user’ table existing, so the ‘address’ table is created second.  In
more complicated dependency scenarios the FOREIGN KEY constraints may
also be applied to tables after the fact using ALTER.

The MetaData object also features a
MetaData.drop_all() method that will emit DROP statements in the
reverse order as it would emit CREATE in order to drop schema elements.

Migration tools are usually appropriate
.......................................

Overall, the CREATE / DROP feature of MetaData is useful for
test suites, small and/or new applications, and applications that use
short-lived databases.  For management of an application database schema
over the long term however, a schema management tool such as Alembic(1),
which builds upon SQLAlchemy, is likely a better choice, as it can
manage and orchestrate the process of incrementally altering a fixed
database schema over time as the design of the application changes.

   ---------- Footnotes ----------

   (1) https://alembic.sqlalchemy.org

2.1.3.4 Defining Table Metadata with the ORM
............................................

This ORM-only section will provide an example of the declaring the same
database structure illustrated in the previous section, using a more
ORM-centric configuration paradigm.  When using the ORM, the process by
which we declare Table metadata is usually combined with the
process of declaring mapped classes.  The mapped class is any Python
class we’d like to create, which will then have attributes on it that
will be linked to the columns in a database table.  While there are a
few varieties of how this is achieved, the most common style is known as
declarative, and allows us to declare our user-defined classes
and Table metadata at once.

2.1.3.5 Setting up the Registry
...............................

When using the ORM, the MetaData collection remains present,
however it itself is contained within an ORM-only object known as the
registry.  We create a registry by constructing it:

     >>> from sqlalchemy.orm import registry
     >>> mapper_registry = registry()

The above registry, when constructed, automatically includes a
MetaData object that will store a collection of Table
objects:

     >>> mapper_registry.metadata
     MetaData()

Instead of declaring Table objects directly, we will now
declare them indirectly through directives applied to our mapped
classes.  In the most common approach, each mapped class descends from a
common base class known as the `declarative base'.  We get a new
declarative base from the registry using the
registry.generate_base() method:

     >>> Base = mapper_registry.generate_base()

     Tip: The steps of creating the registry and “declarative
     base” classes can be combined into one step using the historically
     familiar declarative_base() function:

          from sqlalchemy.orm import declarative_base
          Base = declarative_base()

2.1.3.6 Declaring Mapped Classes
................................

The ‘Base’ object above is a Python class which will serve as the base
class for the ORM mapped classes we declare.  We can now define ORM
mapped classes for the ‘user’ and ‘address’ table in terms of new
classes ‘User’ and ‘Address’:

     >>> from sqlalchemy.orm import relationship
     >>> class User(Base):
     ...     __tablename__ = 'user_account'
     ...
     ...     id = Column(Integer, primary_key=True)
     ...     name = Column(String(30))
     ...     fullname = Column(String)
     ...
     ...     addresses = relationship("Address", back_populates="user")
     ...
     ...     def __repr__(self):
     ...        return f"User(id={self.id!r}, name={self.name!r}, fullname={self.fullname!r})"

     >>> class Address(Base):
     ...     __tablename__ = 'address'
     ...
     ...     id = Column(Integer, primary_key=True)
     ...     email_address = Column(String, nullable=False)
     ...     user_id = Column(Integer, ForeignKey('user_account.id'))
     ...
     ...     user = relationship("User", back_populates="addresses")
     ...
     ...     def __repr__(self):
     ...         return f"Address(id={self.id!r}, email_address={self.email_address!r})"

The above two classes are now our mapped classes, and are available for
use in ORM persistence and query operations, which will be described
later.  But they also include Table objects that were
generated as part of the declarative mapping process, and are equivalent
to the ones that we declared directly in the previous Core section.  We
can see these Table objects from a declarative mapped class
using the ‘.__table__’ attribute:

     >>> User.__table__
     Table('user_account', MetaData(),
         Column('id', Integer(), table=<user_account>, primary_key=True, nullable=False),
         Column('name', String(length=30), table=<user_account>),
         Column('fullname', String(), table=<user_account>), schema=None)

This Table object was generated from the declarative process
based on the ‘.__tablename__’ attribute defined on each of our classes,
as well as through the use of Column objects assigned to
class-level attributes within the classes.  These Column
objects can usually be declared without an explicit “name” field inside
the constructor, as the Declarative process will name them automatically
based on the attribute name that was used.

See also
........

See Declarative Mapping. - overview of Declarative class mapping

2.1.3.7 Other Mapped Class Details
..................................

For a few quick explanations for the classes above, note the following
attributes:

   * `the classes have an automatically generated __init__() method' -
     both classes by default receive an ‘__init__()’ method that allows
     for parameterized construction of the objects.  We are free to
     provide our own ‘__init__()’ method as well.  The ‘__init__()’
     allows us to create instances of ‘User’ and ‘Address’ passing
     attribute names, most of which above are linked directly to
     Column objects, as parameter names:

          >>> sandy = User(name="sandy", fullname="Sandy Cheeks")

     More detail on this method is at Default Constructor.

   * `we provided a __repr__() method' - this is `fully optional', and
     is strictly so that our custom classes have a descriptive string
     representation and is not otherwise required:

          >>> sandy
          User(id=None, name='sandy', fullname='Sandy Cheeks')

     An interesting thing to note above is that the ‘id’ attribute
     automatically returns ‘None’ when accessed, rather than raising
     ‘AttributeError’ as would be the usual Python behavior for missing
     attributes.

   * `we also included a bidirectional relationship' - this is another
     `fully optional' construct, where we made use of an ORM construct
     called relationship() on both classes, which indicates
     to the ORM that these ‘User’ and ‘Address’ classes refer to each
     other in a one to many / many to one relationship.  The use of
     relationship() above is so that we may demonstrate its
     behavior later in this tutorial; it is `not required' in order to
     define the Table structure.

2.1.3.8 Emitting DDL to the database
....................................

This section is named the same as the section Emitting DDL to the Database
discussed in terms of Core.  This is because emitting DDL
with our ORM mapped classes is not any different.  If we wanted to emit
DDL for the Table objects we’ve created as part of our
declaratively mapped classes, we still can use
MetaData.create_all() as before.

In our case, we have already generated the ‘user’ and ‘address’ tables
in our SQLite database.  If we had not done so already, we would be free
to make use of the MetaData associated with our
registry and ORM declarative base class in order to do so, using
MetaData.create_all():

     # emit CREATE statements given ORM registry
     mapper_registry.metadata.create_all(engine)

     # the identical MetaData object is also present on the
     # declarative base
     Base.metadata.create_all(engine)

2.1.3.9 Combining Core Table Declarations with ORM Declarative
..............................................................

As an alternative approach to the mapping process shown previously at
Declaring Mapped Classes, we may also make use of the
Table objects we created directly in the section Setting up MetaData with Table objects
in conjunction with declarative mapped
classes from a declarative_base() generated base class.

This form is called hybrid table, and it consists of assigning
to the ‘.__table__’ attribute directly, rather than having the
declarative process generate it:

     class User(Base):
         __table__ = user_table

          addresses = relationship("Address", back_populates="user")

          def __repr__(self):
             return f"User({self.name!r}, {self.fullname!r})"

     class Address(Base):
         __table__ = address_table

          user = relationship("User", back_populates="addresses")

          def __repr__(self):
              return f"Address({self.email_address!r})"

The above two classes are equivalent to those which we declared in the
previous mapping example.

The traditional “declarative base” approach using ‘__tablename__’ to
automatically generate Table objects remains the most popular
method to declare table metadata.  However, disregarding the ORM mapping
functionality it achieves, as far as table declaration it’s merely a
syntactical convenience on top of the Table constructor.

We will next refer to our ORM mapped classes above when we talk about
data manipulation in terms of the ORM, in the section Inserting Rows with the ORM.

2.1.3.10 Table Reflection
.........................

To round out the section on working with table metadata, we will
illustrate another operation that was mentioned at the beginning of the
section, that of `table reflection'.  Table reflection refers to the
process of generating Table and related objects by reading
the current state of a database.  Whereas in the previous sections we’ve
been declaring Table objects in Python and then emitting DDL
to the database, the reflection process does it in reverse.

As an example of reflection, we will create a new Table
object which represents the ‘some_table’ object we created manually in
the earler sections of this document.  There are again some varieties of
how this is performed, however the most basic is to construct a
Table object, given the name of the table and a MetaData
collection to which it will belong, then instead of indicating
individual Column and Constraint objects, pass it
the target Engine using the Table.autoload_with
parameter:

     >>> some_table = Table("some_table", metadata, autoload_with=engine)
     {opensql}BEGIN (implicit)
     PRAGMA main.table_...info("some_table")
     [raw sql] ()
     SELECT sql FROM  (SELECT * FROM sqlite_master UNION ALL   SELECT * FROM sqlite_temp_master) WHERE name = ? AND type = 'table'
     [raw sql] ('some_table',)
     PRAGMA main.foreign_key_list("some_table")
     ...
     PRAGMA main.index_list("some_table")
     ...
     ROLLBACK{stop}

At the end of the process, the ‘some_table’ object now contains the
information about the Column objects present in the table,
and the object is usable in exactly the same way as a Table
that we declared explicitly.:

     >>> some_table
     Table('some_table', MetaData(),
         Column('x', INTEGER(), table=<some_table>),
         Column('y', INTEGER(), table=<some_table>),
         schema=None)

See also
........

Read more about table and schema reflection at Reflecting Database Objects.

For ORM-related variants of table reflection, the section Mapping Declaratively with Reflected Tables
includes an overview of the
available options.

SQLAlchemy 1.4 / 2.0 Tutorial
.............................

Next Tutorial Section: Working with Data.

SQLAlchemy 1.4 / 2.0 Tutorial
.............................

This page is part of the SQLAlchemy 1.4 / 2.0 Tutorial.

Previous: Working with Database Metadata. | Next: Data Manipulation with the ORM.

2.1.4 Working with Data
-----------------------

In Working with Transactions and the DBAPI, we learned the
basics of how to interact with the Python DBAPI and its transactional
state.  Then, in Working with Database Metadata, we learned
how to represent database tables, columns, and constraints within
SQLAlchemy using the MetaData and related objects.  In this
section we will combine both concepts above to create, select and
manipulate data within a relational database.  Our interaction with the
database is `always' in terms of a transaction, even if we’ve set our
database driver to use autocommit behind the scenes.

The components of this section are as follows:

   * Core Insert. - to get some data into the database, we
     introduce and demonstrate the Core Insert construct.
     INSERTs from an ORM perspective are described in the next section
     Data Manipulation with the ORM.

   * Selecting Data. - this section will describe in detail
     the Select construct, which is the most commonly used
     object in SQLAlchemy.  The Select construct emits SELECT
     statements for both Core and ORM centric applications and both use
     cases will be described here.  Additional ORM use cases are also
     noted in the later section Using Relationships in Queries
     as well as the ORM Querying Guide.

   * Core UPDATE and DELETE. - Rounding out the INSERT and
     SELECtion of data, this section will describe from a Core
     perspective the use of the Update and Delete
     constructs.  ORM-specific UPDATE and DELETE is similarly described
     in the Data Manipulation with the ORM section.

2.1.4.1 Core Insert
...................

When using Core, a SQL INSERT statement is generated using the
insert() function - this function generates a new instance of
Insert which represents an INSERT statement in SQL, that adds new
data into a table.

`ORM Readers' - The way that rows are INSERTed into the database from an
ORM perspective makes use of object-centric APIs on the Session
object known as the unit of work process, and is fairly different
from the Core-only approach described here.  The more ORM-focused
sections later starting at Inserting Rows with the ORM
subsequent to the Expression Language sections introduce this.

2.1.4.2 The insert() SQL Expression Construct
.............................................

A simple example of Insert illustrating the target table and
the VALUES clause at once:

     >>> from sqlalchemy import insert
     >>> stmt = insert(user_table).values(name='spongebob', fullname="Spongebob Squarepants")

The above ‘stmt’ variable is an instance of Insert.  Most SQL
expressions can be stringified in place as a means to see the general
form of what’s being produced:

     >>> print(stmt)
     {opensql}INSERT INTO user_account (name, fullname) VALUES (:name, :fullname)

The stringified form is created by producing a Compiled form
of the object which includes a database-specific string SQL
representation of the statement; we can acquire this object directly
using the ClauseElement.compile() method:

     >>> compiled = stmt.compile()

Our Insert construct is an example of a “parameterized”
construct, illustrated previously at Sending Parameters; to
view the ‘name’ and ‘fullname’ bound parameters, these are available
from the Compiled construct as well:

     >>> compiled.params
     {'name': 'spongebob', 'fullname': 'Spongebob Squarepants'}

2.1.4.3 Executing the Statement
...............................

Invoking the statement we can INSERT a row into ‘user_table’.  The
INSERT SQL as well as the bundled parameters can be seen in the SQL
logging:

     >>> with engine.connect() as conn:
     ...     result = conn.execute(stmt)
     ...     conn.commit()
     {opensql}BEGIN (implicit)
     INSERT INTO user_account (name, fullname) VALUES (?, ?)
     [...] ('spongebob', 'Spongebob Squarepants')
     COMMIT

In its simple form above, the INSERT statement does not return any rows,
and if only a single row is inserted, it will usually include the
ability to return information about column-level default values that
were generated during the INSERT of that row, most commonly an integer
primary key value.  In the above case the first row in a SQLite database
will normally return ‘1’ for the first integer primary key value, which
we can acquire using the CursorResult.inserted_primary_key
accessor:

     >>> result.inserted_primary_key
     (1,)

     Tip: CursorResult.inserted_primary_key returns a tuple
     because a primary key may contain multiple columns.  This is known
     as a composite primary key.  The
     CursorResult.inserted_primary_key is intended to always
     contain the complete primary key of the record just inserted, not
     just a “cursor.lastrowid” kind of value, and is also intended to be
     populated regardless of whether or not “autoincrement” were used,
     hence to express a complete primary key it’s a tuple.

2.1.4.4 INSERT usually generates the “values” clause automatically
..................................................................

The example above made use of the Insert.values() method to
explicitly create the VALUES clause of the SQL INSERT statement.  This
method in fact has some variants that allow for special forms such as
multiple rows in one statement and insertion of SQL expressions.
However the usual way that Insert is used is such that the
VALUES clause is generated automatically from the parameters passed to
the Connection.execute() method; below we INSERT two more
rows to illustrate this:

     >>> with engine.connect() as conn:
     ...     result = conn.execute(
     ...         insert(user_table),
     ...         [
     ...             {"name": "sandy", "fullname": "Sandy Cheeks"},
     ...             {"name": "patrick", "fullname": "Patrick Star"}
     ...         ]
     ...     )
     ...     conn.commit()
     {opensql}BEGIN (implicit)
     INSERT INTO user_account (name, fullname) VALUES (?, ?)
     [...] (('sandy', 'Sandy Cheeks'), ('patrick', 'Patrick Star'))
     COMMIT{stop}

The execution above features “executemany” form first illustrated at
Sending Multiple Parameters, however unlike when using the
text() construct, we didn’t have to spell out any SQL. By
passing a dictionary or list of dictionaries to the
Connection.execute() method in conjunction with the Insert
construct, the Connection ensures that the column names
which are passed will be expressed in the VALUES clause of the
Insert construct automatically.

     deepalchemy: Hi, welcome to the first edition of `Deep Alchemy'.
     The person on the left is known as `The Alchemist', and you’ll note
     they are `not' a wizard, as the pointy hat is not sticking upwards.
     The Alchemist comes around to describe things that are generally
     `more advanced and/or tricky' and additionally `not usually
     needed', but for whatever reason they feel you should know about
     this thing that SQLAlchemy can do.

     In this edition, towards the goal of having some interesting data
     in the ‘address_table’ as well, below is a more advanced example
     illustrating how the Insert.values() method may be used
     explicitly while at the same time including for additional VALUES
     generated from the parameters.  A scalar subquery is constructed,
     making use of the select() construct introduced in the
     next section, and the parameters used in the subquery are set up
     using an explicit bound parameter name, established using the
     bindparam() construct.

     This is some slightly `deeper' alchemy just so that we can add
     related rows without fetching the primary key identifiers from the
     ‘user_table’ operation into the application.  Most Alchemists will
     simply use the ORM which takes care of things like this for us.

          >>> from sqlalchemy import select, bindparam
          >>> scalar_subquery = (
          ...     select(user_table.c.id).
          ...     where(user_table.c.name==bindparam('username')).
          ...     scalar_subquery()
          ... )

          >>> with engine.connect() as conn:
          ...     result = conn.execute(
          ...         insert(address_table).values(user_id=scalar_subquery),
          ...         [
          ...             {"username": 'spongebob', "email_address": "spongebob@sqlalchemy.org"},
          ...             {"username": 'sandy', "email_address": "sandy@sqlalchemy.org"},
          ...             {"username": 'sandy', "email_address": "sandy@squirrelpower.org"},
          ...         ]
          ...     )
          ...     conn.commit()
          {opensql}BEGIN (implicit)
          INSERT INTO address (user_id, email_address) VALUES ((SELECT user_account.id
          FROM user_account
          WHERE user_account.name = ?), ?)
          [...] (('spongebob', 'spongebob@sqlalchemy.org'), ('sandy', 'sandy@sqlalchemy.org'),
          ('sandy', 'sandy@squirrelpower.org'))
          COMMIT{stop}

2.1.4.5 INSERT…FROM SELECT
..........................

The Insert construct can compose an INSERT that gets rows
directly from a SELECT using the Insert.from_select() method:

     >>> select_stmt = select(user_table.c.id, user_table.c.name + "@aol.com")
     >>> insert_stmt = insert(address_table).from_select(
     ...     ["user_id", "email_address"], select_stmt
     ... )
     >>> print(insert_stmt)
     {opensql}INSERT INTO address (user_id, email_address)
     SELECT user_account.id, user_account.name || :name_1 AS anon_1
     FROM user_account

2.1.4.6 INSERT…RETURNING
........................

The RETURNING clause for supported backends is used automatically in
order to retrieve the last inserted primary key value as well as the
values for server defaults.  However the RETURNING clause may also be
specified explicitly using the Insert.returning() method; in
this case, the Result object that’s returned when the
statement is executed has rows which can be fetched:

     >>> insert_stmt = insert(address_table).returning(address_table.c.id, address_table.c.email_address)
     >>> print(insert_stmt)
     {opensql}INSERT INTO address (id, user_id, email_address)
     VALUES (:id, :user_id, :email_address)
     RETURNING address.id, address.email_address

It can also be combined with Insert.from_select(), as in the
example below that builds upon the example stated in INSERT…FROM SELECT:

     >>> select_stmt = select(user_table.c.id, user_table.c.name + "@aol.com")
     >>> insert_stmt = insert(address_table).from_select(
     ...     ["user_id", "email_address"], select_stmt
     ... )
     >>> print(insert_stmt.returning(address_table.c.id, address_table.c.email_address))
     {opensql}INSERT INTO address (user_id, email_address)
     SELECT user_account.id, user_account.name || :name_1 AS anon_1
     FROM user_account RETURNING address.id, address.email_address

     Tip: The RETURNING feature is also supported by UPDATE and DELETE
     statements, which will be introduced later in this tutorial.  The
     RETURNING feature is generally (1) only supported for statement
     executions that use a single set of bound parameters; that is, it
     wont work with the “executemany” form introduced at Sending Multiple Parameters.
     Additionally, some dialects such as the
     Oracle dialect only allow RETURNING to return a single row overall,
     meaning it won’t work with “INSERT..FROM SELECT” nor will it work
     with multiple row Update or Delete forms.

See also
........

See Insert. - in the SQL Expression API documentation

   ---------- Footnotes ----------

   (1) (1) There is internal support for the psycopg2 dialect
to INSERT many rows at once and also support RETURNING, which is
leveraged by the SQLAlchemy ORM. However this feature has not been
generalized to all dialects and is not yet part of SQLAlchemy’s regular
API.

2.1.4.7 Selecting Data
......................

For both Core and ORM, the select() function generates a
Select construct which is used for all SELECT queries.
Passed to methods like Connection.execute() in Core and
Session.execute() in ORM, a SELECT statement is emitted in the
current transaction and the result rows available via the returned
Result object.

`ORM Readers' - the content here applies equally well to both Core and
ORM use and basic ORM variant use cases are mentioned here.  However
there are a lot more ORM-specific features available as well; these are
documented at ORM Querying Guide.

2.1.4.8 The select() SQL Expression Construct
.............................................

The select() construct builds up a statement in the same way
as that of insert(), using a generative approach where each
method builds more state onto the object.  Like the other SQL
constructs, it can be stringified in place:

     >>> from sqlalchemy import select
     >>> stmt = select(user_table).where(user_table.c.name == 'spongebob')
     >>> print(stmt)
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     WHERE user_account.name = :name_1

Also in the same manner as all other statement-level SQL constructs, to
actually run the statement we pass it to an execution method.  Since a
SELECT statement returns rows we can always iterate the result object to
get Row objects back:

     >>> with engine.connect() as conn:
     ...     for row in conn.execute(stmt):
     ...         print(row)
     {opensql}BEGIN (implicit)
     SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     WHERE user_account.name = ?
     [...] ('spongebob',){stop}
     (1, 'spongebob', 'Spongebob Squarepants')
     {opensql}ROLLBACK{stop}

When using the ORM, particularly with a select() construct
that’s composed against ORM entities, we will want to execute it using
the Session.execute() method on the Session; using
this approach, we continue to get Row objects from the
result, however these rows are now capable of including complete
entities, such as instances of the ‘User’ class, as individual elements
within each row:

     >>> stmt = select(User).where(User.name == 'spongebob')
     >>> with Session(engine) as session:
     ...     for row in session.execute(stmt):
     ...         print(row)
     {opensql}BEGIN (implicit)
     SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     WHERE user_account.name = ?
     [...] ('spongebob',){stop}
     (User(id=1, name='spongebob', fullname='Spongebob Squarepants'),)
     {opensql}ROLLBACK{stop}

select() from a Table vs. ORM class
...................................

While the SQL generated in these examples looks the same whether we
invoke ‘select(user_table)’ or ‘select(User)’, in the more general case
they do not necessarily render the same thing, as an ORM-mapped class
may be mapped to other kinds of “selectables” besides tables.  The
‘select()’ that’s against an ORM entity also indicates that ORM-mapped
instances should be returned in a result, which is not the case when
SELECTing from a Table object.

The following sections will discuss the SELECT construct in more detail.

2.1.4.9 Setting the COLUMNS and FROM clause
...........................................

The select() function accepts positional elements
representing any number of Column and/or Table
expressions, as well as a wide range of compatible objects, which are
resolved into a list of SQL expressions to be SELECTed from that will be
returned as columns in the result set.  These elements also serve in
simpler cases to create the FROM clause, which is inferred from the
columns and table-like expressions passed:

     >>> print(select(user_table))
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account

To SELECT from individual columns using a Core approach, see Column
objects are accessed from the Table.c accessor and can be
sent directly; the FROM clause will be inferred as the set of all
Table and other FromClause objects that are represented
by those columns:

     >>> print(select(user_table.c.name, user_table.c.fullname))
     {opensql}SELECT user_account.name, user_account.fullname
     FROM user_account

2.1.4.10 Selecting ORM Entities and Columns
...........................................

ORM entities, such our ‘User’ class as well as the column-mapped
attributes upon it such as ‘User.name’, also participate in the SQL
Expression Language system representing tables and columns.  Below
illustrates an example of SELECTing from the ‘User’ entity, which
ultimately renders in the same way as if we had used ‘user_table’
directly:

     >>> print(select(User))
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account

When executing a statement like the above using the ORM
Session.execute() method, there is an important difference when we
select from a full entity such as ‘User’, as opposed to ‘user_table’,
which is that the `entity itself is returned as a single element within
each row'.  That is, when we fetch rows from the above statement, as
there is only the ‘User’ entity in the list of things to fetch, we get
back Row objects that have only one element, which contain
instances of the ‘User’ class:

     >>> row = session.execute(select(User)).first()
     {opensql}BEGIN...
     SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     [...] (){stop}
     >>> row
     (User(id=1, name='spongebob', fullname='Spongebob Squarepants'),)

The above Row has just one element, representing the ‘User’
entity:

     >>> row[0]
     User(id=1, name='spongebob', fullname='Spongebob Squarepants')

Alternatively, we can select individual columns of an ORM entity as
distinct elements within result rows, by using the class-bound
attributes; when these are passed to a construct such as select(),
they are resolved into the Column or other SQL expression
represented by each attribute:

     >>> print(select(User.name, User.fullname))
     {opensql}SELECT user_account.name, user_account.fullname
     FROM user_account

When we invoke `this' statement using Session.execute(), we
now receive rows that have individual elements per value, each
corresponding to a separate column or other SQL expression:

     >>> row = session.execute(select(User.name, User.fullname)).first()
     {opensql}SELECT user_account.name, user_account.fullname
     FROM user_account
     [...] (){stop}
     >>> row
     ('spongebob', 'Spongebob Squarepants')

The approaches can also be mixed, as below where we SELECT the ‘name’
attribute of the ‘User’ entity as the first element of the row, and
combine it with full ‘Address’ entities in the second element:

     >>> session.execute(
     ...     select(User.name, Address).
     ...     where(User.id==Address.user_id).
     ...     order_by(Address.id)
     ... ).all()
     {opensql}SELECT user_account.name, address.id, address.email_address, address.user_id
     FROM user_account, address
     WHERE user_account.id = address.user_id ORDER BY address.id
     [...] (){stop}
     [('spongebob', Address(id=1, email_address='spongebob@sqlalchemy.org')),
     ('sandy', Address(id=2, email_address='sandy@sqlalchemy.org')),
     ('sandy', Address(id=3, email_address='sandy@squirrelpower.org'))]

Approaches towards selecting ORM entities and columns as well as common
methods for converting rows are discussed further at Selecting ORM Entities and Attributes.

See also
........

See Selecting ORM Entities and Attributes. - in the ORM Querying Guide.

2.1.4.11 Selecting from Labeled SQL Expressions
...............................................

The ColumnElement.label() method as well as the same-named
method available on ORM attributes provides a SQL label of a column or
expression, allowing it to have a specific name in a result set.  This
can be helpful when referring to arbitrary SQL expressions in a result
row by name:

     >>> from sqlalchemy import func, cast
     >>> stmt = (
     ...     select(
     ...         ("Username: " + user_table.c.name).label("username"),
     ...     ).order_by(user_table.c.name)
     ... )
     >>> with engine.connect() as conn:
     ...     for row in conn.execute(stmt):
     ...         print(f"{row.username}")
     {opensql}BEGIN (implicit)
     SELECT ? || user_account.name AS username
     FROM user_account ORDER BY user_account.name
     [...] ('Username: ',){stop}
     Username: patrick
     Username: sandy
     Username: spongebob
     {opensql}ROLLBACK{stop}

2.1.4.12 The WHERE clause
.........................

SQLAlchemy allows us to compose SQL expressions, such as ‘name =
'squidward'’ or ‘user_id > 10’, by making use of standard Python
operators in conjunction with Column and similar objects.
For boolean expressions, most Python operators such as ‘==’, ‘!=’, ‘<’,
‘>=’ etc.  generate new SQL Expression objects, rather than plain
boolean ‘True’/‘False’ values:

     >>> print(user_table.c.name == 'squidward')
     user_account.name = :name_1

     >>> print(address_table.c.user_id > 10)
     address.user_id > :user_id_1

We can use expressions like these to generate the WHERE clause by
passing the resulting objects to the Select.where() method:

     >>> print(select(user_table).where(user_table.c.name == 'squidward'))
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     WHERE user_account.name = :name_1

To produce multiple expressions joined by AND, the Select.where()
method may be invoked any number of times:

     >>> print(
     ...     select(address_table.c.email_address).
     ...     where(user_table.c.name == 'squidward').
     ...     where(address_table.c.user_id == user_table.c.id)
     ... )
     {opensql}SELECT address.email_address
     FROM address, user_account
     WHERE user_account.name = :name_1 AND address.user_id = user_account.id

A single call to Select.where() also accepts multiple
expressions with the same effect:

     >>> print(
     ...     select(address_table.c.email_address).
     ...     where(
     ...          user_table.c.name == 'squidward',
     ...          address_table.c.user_id == user_table.c.id
     ...     )
     ... )
     {opensql}SELECT address.email_address
     FROM address, user_account
     WHERE user_account.name = :name_1 AND address.user_id = user_account.id

“AND” and “OR” conjunctions are both available directly using the
and_() and or_() functions, illustrated below in terms
of ORM entities:

     >>> from sqlalchemy import and_, or_
     >>> print(
     ...     select(Address.email_address).
     ...     where(
     ...         and_(
     ...             or_(User.name == 'squidward', User.name == 'sandy'),
     ...             Address.user_id == User.id
     ...         )
     ...     )
     ... )
     {opensql}SELECT address.email_address
     FROM address, user_account
     WHERE (user_account.name = :name_1 OR user_account.name = :name_2)
     AND address.user_id = user_account.id

For simple “equality” comparisons against a single entity, there’s also
a popular method known as Select.filter_by() which accepts
keyword arguments that match to column keys or ORM attribute names.  It
will filter against the leftmost FROM clause or the last entity joined:

     >>> print(
     ...     select(User).filter_by(name='spongebob', fullname='Spongebob Squarepants')
     ... )
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     WHERE user_account.name = :name_1 AND user_account.fullname = :fullname_1

See also
........

See Operator Reference. - descriptions of most SQL operator
functions in SQLAlchemy

2.1.4.13 Explicit FROM clauses and JOINs
........................................

As mentioned previously, the FROM clause is usually `inferred' based on
the expressions that we are setting in the columns clause as well as
other elements of the Select.

If we set a single column from a particular Table in the
COLUMNS clause, it puts that Table in the FROM clause as
well:

     >>> print(select(user_table.c.name))
     {opensql}SELECT user_account.name
     FROM user_account

If we were to put columns from two tables, then we get a comma-separated
FROM clause:

     >>> print(select(user_table.c.name, address_table.c.email_address))
     {opensql}SELECT user_account.name, address.email_address
     FROM user_account, address

In order to JOIN these two tables together, we typically use one of two
methods on Select.  The first is the Select.join_from()
method, which allows us to indicate the left and right side of the
JOIN explicitly:

     >>> print(
     ...     select(user_table.c.name, address_table.c.email_address).
     ...     join_from(user_table, address_table)
     ... )
     {opensql}SELECT user_account.name, address.email_address
     FROM user_account JOIN address ON user_account.id = address.user_id

The other is the the Select.join() method, which indicates
only the right side of the JOIN, the left hand-side is inferred:

     >>> print(
     ...     select(user_table.c.name, address_table.c.email_address).
     ...     join(address_table)
     ... )
     {opensql}SELECT user_account.name, address.email_address
     FROM user_account JOIN address ON user_account.id = address.user_id

The ON Clause is inferred
.........................

When using Select.join_from() or Select.join(),
we may observe that the ON clause of the join is also inferred for us in
simple foreign key cases.  More on that in the next section.

We also have the option add elements to the FROM clause explicitly, if
it is not inferred the way we want from the columns clause.  We use the
Select.select_from() method to achieve this, as below where
we establish ‘user_table’ as the first element in the FROM clause and
Select.join() to establish ‘address_table’ as the second:

     >>> print(
     ...     select(address_table.c.email_address).
     ...     select_from(user_table).join(address_table)
     ... )
     {opensql}SELECT address.email_address
     FROM user_account JOIN address ON user_account.id = address.user_id

Another example where we might want to use Select.select_from()
is if our columns clause doesn’t have enough information to provide
for a FROM clause.  For example, to SELECT from the common SQL
expression ‘count(*)’, we use a SQLAlchemy element known as
sqlalchemy.sql.expression.func to produce the SQL ‘count()’
function:

     >>> from sqlalchemy import func
     >>> print (
     ...     select(func.count('*')).select_from(user_table)
     ... )
     {opensql}SELECT count(:count_2) AS count_1
     FROM user_account

2.1.4.14 Setting the ON Clause
..............................

The previous examples of JOIN illustrated that the Select
construct can join between two tables and produce the ON clause
automatically.  This occurs in those examples because the ‘user_table’
and ‘address_table’ ‘Table’ objects include a single
ForeignKeyConstraint definition which is used to form this ON
clause.

If the left and right targets of the join do not have such a constraint,
or there are multiple constraints in place, we need to specify the ON
clause directly.  Both Select.join() and
Select.join_from() accept an additional argument for the ON
clause, which is stated using the same SQL Expression mechanics as we
saw about in The WHERE clause:

     >>> print(
     ...     select(address_table.c.email_address).
     ...     select_from(user_table).
     ...     join(address_table, user_table.c.id == address_table.c.user_id)
     ... )
     {opensql}SELECT address.email_address
     FROM user_account JOIN address ON user_account.id = address.user_id

`ORM Tip' - there’s another way to generate the ON clause when using ORM
entities that make use of the relationship() construct, like
the mapping set up in the previous section at Declaring Mapped Classes.
This is a whole subject onto itself, which is introduced
at length at Using Relationships to Join.

2.1.4.15 OUTER and FULL join
............................

Both the Select.join() and Select.join_from()
methods accept keyword arguments Select.join.isouter and
Select.join.full which will render LEFT OUTER JOIN and FULL
OUTER JOIN, respectively:

     >>> print(
     ...     select(user_table).join(address_table, isouter=True)
     ... )
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account LEFT OUTER JOIN address ON user_account.id = address.user_id{stop}

     >>> print(
     ...     select(user_table).join(address_table, full=True)
     ... )
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account FULL OUTER JOIN address ON user_account.id = address.user_id{stop}

There is also a method Select.outerjoin() that is equivalent
to using ‘.join(..., isouter=True)’.

     Tip: SQL also has a “RIGHT OUTER JOIN”.  SQLAlchemy doesn’t render
     this directly; instead, reverse the order of the tables and use
     “LEFT OUTER JOIN”.

2.1.4.16 ORDER BY
.................

The ORDER BY clause is constructed in terms of SQL Expression constructs
typically based on Column or similar objects.  The
Select.order_by() method accepts one or more of these expressions
positionally:

     >>> print(select(user_table).order_by(user_table.c.name))
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account ORDER BY user_account.name

Ascending / descending is available from the ColumnElement.asc()
and ColumnElement.desc() modifiers, which are present
from ORM-bound attributes as well:

     >>> print(select(User).order_by(User.name.asc(), User.fullname.desc()))
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account ORDER BY user_account.name ASC, user_account.fullname DESC

2.1.4.17 Aggregate functions with GROUP BY / HAVING
...................................................

In SQL, aggregate functions allow column expressions across multiple
rows to be aggregated together to produce a single result.  Examples
include counting, computing averages, as well as locating the maximum or
minimum value in a set of values.

SQLAlchemy provides for SQL functions in an open-ended way using a
namespace known as func.  This is a special constructor
object which will create new instances of Function when
given the name of a particular SQL function, which can have any name, as
well as zero or more arguments to pass to the function, which are, like
in all other cases, SQL Expression constructs.  For example, to render
the SQL COUNT() function against the ‘user_account.id’ column, we call
upon the name ‘count()’ name:

     >>> from sqlalchemy import func
     >>> count_fn = func.count(user_table.c.id)
     >>> print(count_fn)
     {opensql}count(user_account.id)

SQL functions are described in more detail later in this tutorial at
Working with SQL Functions.

When using aggregate functions in SQL, the GROUP BY clause is essential
in that it allows rows to be partitioned into groups where aggregate
functions will be applied to each group individually.  When requesting
non-aggregated columns in the COLUMNS clause of a SELECT statement, SQL
requires that these columns all be subject to a GROUP BY clause, either
directly or indirectly based on a primary key association.  The HAVING
clause is then used in a similar manner as the WHERE clause, except that
it filters out rows based on aggregated values rather than direct row
contents.

SQLAlchemy provides for these two clauses using the
Select.group_by() and Select.having() methods.  Below
we illustrate selecting user name fields as well as count of addresses,
for those users that have more than one address:

     >>> with engine.connect() as conn:
     ...     result = conn.execute(
     ...         select(User.name, func.count(Address.id).label("count")).
     ...         join(Address).
     ...         group_by(User.name).
     ...         having(func.count(Address.id) > 1)
     ...     )
     ...     print(result.all())
     {opensql}BEGIN (implicit)
     SELECT user_account.name, count(address.id) AS count
     FROM user_account JOIN address ON user_account.id = address.user_id GROUP BY user_account.name
     HAVING count(address.id) > ?
     [...] (1,){stop}
     [('sandy', 2)]
     {opensql}ROLLBACK{stop}

2.1.4.18 Ordering or Grouping by a Label
........................................

An important technique, in particular on some database backends, is the
ability to ORDER BY or GROUP BY an expression that is already stated in
the columns clause, without re-stating the expression in the ORDER BY or
GROUP BY clause and instead using the column name or labeled name from
the COLUMNS clause.  This form is available by passing the string text
of the name to the Select.order_by() or
Select.group_by() method.  The text passed is `not rendered
directly'; instead, the name given to an expression in the columns
clause and rendered as that expression name in context, raising an error
if no match is found.  The unary modifiers asc() and
desc() may also be used in this form:

     >>> from sqlalchemy import func, desc
     >>> stmt = select(
     ...         Address.user_id,
     ...         func.count(Address.id).label('num_addresses')).\
     ...         group_by("user_id").order_by("user_id", desc("num_addresses"))
     >>> print(stmt)
     {opensql}SELECT address.user_id, count(address.id) AS num_addresses
     FROM address GROUP BY address.user_id ORDER BY address.user_id, num_addresses DESC

2.1.4.19 Using Aliases
......................

Now that we are selecting from multiple tables and using joins, we
quickly run into the case where we need to refer to the same table
mutiple times in the FROM clause of a statement.  We accomplish this
using SQL `aliases', which are a syntax that supplies an alternative
name to a table or subquery from which it can be referred towards in the
statement.

In the SQLAlchemy Expression Language, these “names” are instead
represented by FromClause objects known as the Alias
construct, which is constructed in Core using the
FromClause.alias() method.  An Alias construct is just
like a ‘Table’ construct in that it also has a namespace of
Column objects within the ‘Alias.c’ collection.  The SELECT
statement below for example returns all unique pairs of user names:

     >>> user_alias_1 = user_table.alias()
     >>> user_alias_2 = user_table.alias()
     >>> print(
     ...     select(user_alias_1.c.name, user_alias_2.c.name).
     ...     join_from(user_alias_1, user_alias_2, user_alias_1.c.id > user_alias_2.c.id)
     ... )
     {opensql}SELECT user_account_1.name, user_account_2.name AS name_1
     FROM user_account AS user_account_1
     JOIN user_account AS user_account_2 ON user_account_1.id > user_account_2.id

2.1.4.20 ORM Entity Aliases
...........................

The ORM equivalent of the FromClause.alias() method is the
ORM aliased() function, which may be applied to an entity
such as ‘User’ and ‘Address’.  This produces a Alias object
internally that’s against the original mapped Table object,
while maintaining ORM functionality.  The SELECT below selects from the
‘User’ entity all objects that include two particular email addresses:

     >>> from sqlalchemy.orm import aliased
     >>> address_alias_1 = aliased(Address)
     >>> address_alias_2 = aliased(Address)
     >>> print(
     ...     select(User).
     ...     join_from(User, address_alias_1).
     ...     where(address_alias_1.email_address == 'patrick@aol.com').
     ...     join_from(User, address_alias_2).
     ...     where(address_alias_2.email_address == 'patrick@gmail.com')
     ... )
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     JOIN address AS address_1 ON user_account.id = address_1.user_id
     JOIN address AS address_2 ON user_account.id = address_2.user_id
     WHERE address_1.email_address = :email_address_1
     AND address_2.email_address = :email_address_2

     Tip: As mentioned in Setting the ON Clause, the ORM
     provides for another way to join using the relationship()
     construct.  The above example using aliases is demonstrated
     using relationship() at Joining between Aliased targets.

2.1.4.21 Subqueries and CTEs
............................

A subquery in SQL is a SELECT statement that is rendered within
parenthesis and placed within the context of an enclosing statement,
typically a SELECT statement but not necessarily.

This section will cover a so-called “non-scalar” subquery, which is
typically placed in the FROM clause of an enclosing SELECT. We will also
cover the Common Table Expression or CTE, which is used in a similar way
as a subquery, but includes additional features.

SQLAlchemy uses the Subquery object to represent a subquery
and the CTE to represent a CTE, usually obtained from the
Select.subquery() and Select.cte() methods,
respectively.  Either object can be used as a FROM element inside of a
larger select() construct.

We can construct a Subquery that will select an aggregate
count of rows from the ‘address’ table (aggregate functions and GROUP BY
were introduced previously at Aggregate functions with GROUP BY / HAVING):

     >>> subq = select(
     ...     func.count(address_table.c.id).label("count"),
     ...     address_table.c.user_id
     ... ).group_by(address_table.c.user_id).subquery()

Stringifying the subquery by itself without it being embedded inside of
another Select or other statement produces the plain SELECT
statement without any enclosing parenthesis:

     >>> print(subq)
     {opensql}SELECT count(address.id) AS count, address.user_id
     FROM address GROUP BY address.user_id

The Subquery object behaves like any other FROM object such
as a Table, notably that it includes a ‘Subquery.c’ namespace
of the columns which it selects.  We can use this namespace to refer to
both the ‘user_id’ column as well as our custom labeled ‘count’
expression:

     >>> print(select(subq.c.user_id, subq.c.count))
     {opensql}SELECT anon_1.user_id, anon_1.count
     FROM (SELECT count(address.id) AS count, address.user_id AS user_id
     FROM address GROUP BY address.user_id) AS anon_1

With a selection of rows contained within the ‘subq’ object, we can
apply the object to a larger Select that will join the data
to the ‘user_account’ table:

     >>> stmt = select(
     ...    user_table.c.name,
     ...    user_table.c.fullname,
     ...    subq.c.count
     ... ).join_from(user_table, subq)

     >>> print(stmt)
     {opensql}SELECT user_account.name, user_account.fullname, anon_1.count
     FROM user_account JOIN (SELECT count(address.id) AS count, address.user_id AS user_id
     FROM address GROUP BY address.user_id) AS anon_1 ON user_account.id = anon_1.user_id

In order to join from ‘user_account’ to ‘address’, we made use of the
Select.join_from() method.  As has been illustrated
previously, the ON clause of this join was again `inferred' based on
foreign key constraints.  Even though a SQL subquery does not itself
have any constraints, SQLAlchemy can act upon constraints represented on
the columns by determining that the ‘subq.c.user_id’ column is `derived'
from the ‘address_table.c.user_id’ column, which does express a foreign
key relationship back to the ‘user_table.c.id’ column which is then used
to generate the ON clause.

2.1.4.22 Common Table Expressions (CTEs)
........................................

Usage of the CTE construct in SQLAlchemy is virtually the
same as how the Subquery construct is used.  By changing the
invocation of the Select.subquery() method to use
Select.cte() instead, we can use the resulting object as a FROM
element in the same way, but the SQL rendered is the very different
common table expression syntax:

     >>> subq = select(
     ...     func.count(address_table.c.id).label("count"),
     ...     address_table.c.user_id
     ... ).group_by(address_table.c.user_id).cte()

     >>> stmt = select(
     ...    user_table.c.name,
     ...    user_table.c.fullname,
     ...    subq.c.count
     ... ).join_from(user_table, subq)

     >>> print(stmt)
     {opensql}WITH anon_1 AS
     (SELECT count(address.id) AS count, address.user_id AS user_id
     FROM address GROUP BY address.user_id)
      SELECT user_account.name, user_account.fullname, anon_1.count
     FROM user_account JOIN anon_1 ON user_account.id = anon_1.user_id

The CTE construct also features the ability to be used in a
“recursive” style, and may in more elaborate cases be composed from the
RETURNING clause of an INSERT, UPDATE or DELETE statement.  The
docstring for CTE includes details on these additional
patterns.

In both cases, the subquery and CTE were named at the SQL level using an
“anonymous” name.  In the Python code, we don’t need to provide these
names at all.  The object identity of the Subquery or
CTE instances serves as the syntactical identity of the object
when rendered.  A name that will be rendered in the SQL can be provided
by passing it as the first argument of the Select.subquery()
or Select.cte() methods.

See also
........

See Select.subquery(). - further detail on subqueries

See Select.cte(). - examples for CTE including how to use
RECURSIVE as well as DML-oriented CTEs

2.1.4.23 ORM Entity Subqueries/CTEs
...................................

In the ORM, the aliased() construct may be used to associate
an ORM entity, such as our ‘User’ or ‘Address’ class, with any
FromClause concept that represents a source of rows.  The preceding
section ORM Entity Aliases illustrates using
aliased() to associate the mapped class with an Alias
of its mapped Table.  Here we illustrate aliased()
doing the same thing against both a Subquery as well as a
CTE generated against a Select construct, that
ultimately derives from that same mapped Table.

Below is an example of applying aliased() to the
Subquery construct, so that ORM entities can be extracted from its
rows.  The result shows a series of ‘User’ and ‘Address’ objects, where
the data for each ‘Address’ object ultimately came from a subquery
against the ‘address’ table rather than that table directly:

     >>> subq = select(Address).where(~Address.email_address.like('%@aol.com')).subquery()
     >>> address_subq = aliased(Address, subq)
     >>> stmt = select(User, address_subq).join_from(User, address_subq).order_by(User.id, address_subq.id)
     >>> with Session(engine) as session:
     ...     for user, address in session.execute(stmt):
     ...         print(f"{user} {address}")
     {opensql}BEGIN (implicit)
     SELECT user_account.id, user_account.name, user_account.fullname,
     anon_1.id AS id_1, anon_1.email_address, anon_1.user_id
     FROM user_account JOIN
     (SELECT address.id AS id, address.email_address AS email_address, address.user_id AS user_id
     FROM address
     WHERE address.email_address NOT LIKE ?) AS anon_1 ON user_account.id = anon_1.user_id
     ORDER BY user_account.id, anon_1.id
     [...] ('%@aol.com',){stop}
     User(id=1, name='spongebob', fullname='Spongebob Squarepants') Address(id=1, email_address='spongebob@sqlalchemy.org')
     User(id=2, name='sandy', fullname='Sandy Cheeks') Address(id=2, email_address='sandy@sqlalchemy.org')
     User(id=2, name='sandy', fullname='Sandy Cheeks') Address(id=3, email_address='sandy@squirrelpower.org')
     {opensql}ROLLBACK{stop}

Another example follows, which is exactly the same except it makes use
of the CTE construct instead:

     >>> cte = select(Address).where(~Address.email_address.like('%@aol.com')).cte()
     >>> address_cte = aliased(Address, cte)
     >>> stmt = select(User, address_cte).join_from(User, address_cte).order_by(User.id, address_cte.id)
     >>> with Session(engine) as session:
     ...     for user, address in session.execute(stmt):
     ...         print(f"{user} {address}")
     {opensql}BEGIN (implicit)
     WITH anon_1 AS
     (SELECT address.id AS id, address.email_address AS email_address, address.user_id AS user_id
     FROM address
     WHERE address.email_address NOT LIKE ?)
     SELECT user_account.id, user_account.name, user_account.fullname,
     anon_1.id AS id_1, anon_1.email_address, anon_1.user_id
     FROM user_account
     JOIN anon_1 ON user_account.id = anon_1.user_id
     ORDER BY user_account.id, anon_1.id
     [...] ('%@aol.com',){stop}
     User(id=1, name='spongebob', fullname='Spongebob Squarepants') Address(id=1, email_address='spongebob@sqlalchemy.org')
     User(id=2, name='sandy', fullname='Sandy Cheeks') Address(id=2, email_address='sandy@sqlalchemy.org')
     User(id=2, name='sandy', fullname='Sandy Cheeks') Address(id=3, email_address='sandy@squirrelpower.org')
     {opensql}ROLLBACK{stop}

2.1.4.24 Scalar and Correlated Subqueries
.........................................

A scalar subquery is a subquery that returns exactly zero or one row and
exactly one column.  The subquery is then used in the COLUMNS or WHERE
clause of an enclosing SELECT statement and is different than a regular
subquery in that it is not used in the FROM clause.  A correlated
subquery is a scalar subquery that refers to a table in the enclosing
SELECT statement.

SQLAlchemy represents the scalar subquery using the ScalarSelect
construct, which is part of the ColumnElement
expression hierarchy, in contrast to the regular subquery which is
represented by the Subquery construct, which is in the
FromClause hierarchy.

Scalar subqueries are often, but not necessarily, used with aggregate
functions, introduced previously at Aggregate functions with GROUP BY / HAVING.
A scalar subquery is indicated explicitly by making
use of the Select.scalar_subquery() method as below.  It’s
default string form when stringified by itself renders as an ordinary
SELECT statement that is selecting from two tables:

     >>> subq = select(func.count(address_table.c.id)).\
     ...             where(user_table.c.id == address_table.c.user_id).\
     ...             scalar_subquery()
     >>> print(subq)
     {opensql}(SELECT count(address.id) AS count_1
     FROM address, user_account
     WHERE user_account.id = address.user_id)

The above ‘subq’ object now falls within the ColumnElement.
SQL expression hierarchy, in that it may be used like any other column
expression:

     >>> print(subq == 5)
     {opensql}(SELECT count(address.id) AS count_1
     FROM address, user_account
     WHERE user_account.id = address.user_id) = :param_1

Although the scalar subquery by itself renders both ‘user_account’ and
‘address’ in its FROM clause when stringified by itself, when embedding
it into an enclosing select() construct that deals with the
‘user_account’ table, the ‘user_account’ table is automatically
`correlated', meaning it does not render in the FROM clause of the
subquery:

     >>> stmt = select(user_table.c.name, subq.label("address_count"))
     >>> print(stmt)
     {opensql}SELECT user_account.name, (SELECT count(address.id) AS count_1
     FROM address
     WHERE user_account.id = address.user_id) AS address_count
     FROM user_account

Simple correlated subqueries will usually do the right thing that’s
desired.  However, in the case where the correlation is ambiguous,
SQLAlchemy will let us know that more clarity is needed:

     >>> stmt = select(
     ...     user_table.c.name,
     ...     address_table.c.email_address,
     ...     subq.label("address_count")
     ... ).\
     ... join_from(user_table, address_table).\
     ... order_by(user_table.c.id, address_table.c.id)
     >>> print(stmt)
     Traceback (most recent call last):
     ...
     InvalidRequestError: Select statement '<... Select object at ...>' returned
     no FROM clauses due to auto-correlation; specify correlate(<tables>) to
     control correlation manually.

To specify that the ‘user_table’ is the one we seek to correlate we
specify this using the ScalarSelect.correlate() or
ScalarSelect.correlate_except() methods:

     >>> subq = select(func.count(address_table.c.id)).\
     ...             where(user_table.c.id == address_table.c.user_id).\
     ...             scalar_subquery().correlate(user_table)

The statement then can return the data for this column like any other:

     >>> with engine.connect() as conn:
     ...     result = conn.execute(
     ...         select(
     ...             user_table.c.name,
     ...             address_table.c.email_address,
     ...             subq.label("address_count")
     ...         ).
     ...         join_from(user_table, address_table).
     ...         order_by(user_table.c.id, address_table.c.id)
     ...     )
     ...     print(result.all())
     {opensql}BEGIN (implicit)
     SELECT user_account.name, address.email_address, (SELECT count(address.id) AS count_1
     FROM address
     WHERE user_account.id = address.user_id) AS address_count
     FROM user_account JOIN address ON user_account.id = address.user_id ORDER BY user_account.id, address.id
     [...] (){stop}
     [('spongebob', 'spongebob@sqlalchemy.org', 1), ('sandy', 'sandy@sqlalchemy.org', 2),
      ('sandy', 'sandy@squirrelpower.org', 2)]
     {opensql}ROLLBACK{stop}

2.1.4.25 EXISTS subqueries
..........................

The SQL EXISTS keyword is an operator that is used with scalar subqueries
to return a boolean true or false depending on if the
SELECT statement would return a row.  SQLAlchemy includes a variant of
the ScalarSelect object called Exists, which will
generate an EXISTS subquery and is most conveniently generated using the
SelectBase.exists() method.  Below we produce an EXISTS so
that we can return ‘user_account’ rows that have more than one related
row in ‘address’:

     >>> subq = (
     ...     select(func.count(address_table.c.id)).
     ...     where(user_table.c.id == address_table.c.user_id).
     ...     group_by(address_table.c.user_id).
     ...     having(func.count(address_table.c.id) > 1)
     ... ).exists()
     >>> with engine.connect() as conn:
     ...     result = conn.execute(
     ...         select(user_table.c.name).where(subq)
     ...     )
     ...     print(result.all())
     {opensql}BEGIN (implicit)
     SELECT user_account.name
     FROM user_account
     WHERE EXISTS (SELECT count(address.id) AS count_1
     FROM address
     WHERE user_account.id = address.user_id GROUP BY address.user_id
     HAVING count(address.id) > ?)
     [...] (1,){stop}
     [('sandy',)]
     {opensql}ROLLBACK{stop}

The EXISTS construct is more often than not used as a negation, e.g.
NOT EXISTS, as it provides a SQL-efficient form of locating rows for
which a related table has no rows.  Below we select user names that have
no email addresses; note the binary negation operator (‘~’) used inside
the second WHERE clause:

     >>> subq = (
     ...     select(address_table.c.id).
     ...     where(user_table.c.id == address_table.c.user_id)
     ... ).exists()
     >>> with engine.connect() as conn:
     ...     result = conn.execute(
     ...         select(user_table.c.name).where(~subq)
     ...     )
     ...     print(result.all())
     {opensql}BEGIN (implicit)
     SELECT user_account.name
     FROM user_account
     WHERE NOT (EXISTS (SELECT address.id
     FROM address
     WHERE user_account.id = address.user_id))
     [...] (){stop}
     [('patrick',)]
     {opensql}ROLLBACK{stop}

2.1.4.26 Working with SQL Functions
...................................

First introduced earlier in this section at Aggregate functions with GROUP BY / HAVING,
the func object serves as a
factory for creating new Function objects, which when used
in a construct like select(), produce a SQL function display,
typically consisting of a name, some parenthesis (although not always),
and possibly some arguments.  Examples of typical SQL functions include:

   * the ‘count()’ function, an aggregate function which counts how many
     rows are returned:

          >>> print(select(func.count()).select_from(user_table))
          SELECT count(*) AS count_1
          FROM user_account

   * the ‘lower()’ function, a string function that converts a string to
     lower case:

          >>> print(select(func.lower("A String With Much UPPERCASE")))
          SELECT lower(:lower_2) AS lower_1

   * the ‘now()’ function, which provides for the current date and time;
     as this is a common function, SQLAlchemy knows how to render this
     differently for each backend, in the case of SQLite using the
     CURRENT_TIMESTAMP function:

          >>> stmt = select(func.now())
          >>> with engine.connect() as conn:
          ...     result = conn.execute(stmt)
          ...     print(result.all())
          {opensql}BEGIN (implicit)
          SELECT CURRENT_TIMESTAMP AS now_1
          [...] ()
          [(datetime.datetime(...),)]
          ROLLBACK

As most database backends feature dozens if not hundreds of different
SQL functions, see func tries to be as liberal as possible in
what it accepts.  Any name that is accessed from this namespace is
automatically considered to be a SQL function that will render in a
generic way:

     >>> print(select(func.some_crazy_function(user_table.c.name, 17)))
     SELECT some_crazy_function(user_account.name, :some_crazy_function_2) AS some_crazy_function_1
     FROM user_account

At the same time, a relatively small set of extremely common SQL
functions such as count, now, max,
concat include pre-packaged versions of themselves which
provide for proper typing information as well as backend-specific SQL
generation in some cases.  The example below contrasts the SQL
generation that occurs for the PostgreSQL dialect compared to the Oracle
dialect for the now function:

     >>> from sqlalchemy.dialects import postgresql
     >>> print(select(func.now()).compile(dialect=postgresql.dialect()))
     SELECT now() AS now_1

     >>> from sqlalchemy.dialects import oracle
     >>> print(select(func.now()).compile(dialect=oracle.dialect()))
     SELECT CURRENT_TIMESTAMP AS now_1 FROM DUAL

2.1.4.27 Functions Have Return Types
....................................

As functions are column expressions, they also have SQL datatypes
that describe the data type of a generated SQL expression.  We refer
to these types here as “SQL return types”, in reference to the type of
SQL value that is returned by the function in the context of a
database-side SQL expression, as opposed to the “return type” of a
Python function.

The SQL return type of any SQL function may be accessed, typically for
debugging purposes, by referring to the Function.type
attribute:

     >>> func.now().type
     DateTime()

These SQL return types are significant when making use of the function
expression in the context of a larger expression; that is, math
operators will work better when the datatype of the expression is
something like Integer or Numeric, JSON accessors
in order to work need to be using a type such as JSON.
Certain classes of functions return entire rows instead of column
values, where there is a need to refer to specific columns; such
functions are referred towards as table valued functions.

The SQL return type of the function may also be significant when
executing a statement and getting rows back, for those cases where
SQLAlchemy has to apply result-set processing.  A prime example of this
are date-related functions on SQLite, where SQLAlchemy’s DateTime
and related datatypes take on the role of converting from string
values to Python ‘datetime()’ objects as result rows are received.

To apply a specific type to a function we’re creating, we pass it using
the Function.type_ parameter; the type argument may be
either a TypeEngine class or an instance.  In the example
below we pass the JSON class to generate the PostgreSQL
‘json_object()’ function, noting that the SQL return type will be of
type JSON:

     >>> from sqlalchemy import JSON
     >>> function_expr = func.json_object('{a, 1, b, "def", c, 3.5}', type_=JSON)

By creating our JSON function with the JSON datatype, the
SQL expression object takes on JSON-related features, such as that of
accessing elements:

     >>> stmt = select(function_expr["def"])
     >>> print(stmt)
     SELECT json_object(:json_object_1)[:json_object_2] AS anon_1

2.1.4.28 Built-in Functions Have Pre-Configured Return Types
............................................................

For common aggregate functions like count, max,
min as well as a very small number of date functions like
now and string functions like concat, the SQL
return type is set up appropriately, sometimes based on usage.  The
max function and similar aggregate filtering functions will
set up the SQL return type based on the argument given:

     >>> m1 = func.max(Column("some_int", Integer))
     >>> m1.type
     Integer()

     >>> m2 = func.max(Column("some_str", String))
     >>> m2.type
     String()

Date and time functions typically correspond to SQL expressions
described by DateTime, Date or Time:

     >>> func.now().type
     DateTime()
     >>> func.current_date().type
     Date()

A known string function such as concat will know that a SQL
expression would be of type String:

     >>> func.concat("x", "y").type
     String()

However, for the vast majority of SQL functions, SQLAlchemy does not
have them explicitly present in its very small list of known functions.
For example, while there is typically no issue using SQL functions
‘func.lower()’ and ‘func.upper()’ to convert the casing of strings,
SQLAlchemy doesn’t actually know about these functions, so they have a
“null” SQL return type:

     >>> func.upper("lowercase").type
     NullType()

For simple functions like ‘upper’ and ‘lower’, the issue is not usually
significant, as string values may be received from the database without
any special type handling on the SQLAlchemy side, and SQLAlchemy’s type
coercion rules can often correctly guess intent as well; the Python ‘+’
operator for example will be correctly interpreted as the string
concatenation operator based on looking at both sides of the expression:

     >>> print(select(func.upper("lowercase") + " suffix"))
     SELECT upper(:upper_1) || :upper_2 AS anon_1

Overall, the scenario where the Function.type_ parameter is
likely necessary is:

  1. the function is not already a SQLAlchemy built-in function; this
     can be evidenced by creating the function and observing the
     Function.type attribute, that is:

          >>> func.count().type
          Integer()

     vs.:

          >>> func.json_object('{"a", "b"}').type
          NullType()

  2. Function-aware expression support is needed; this most typically
     refers to special operators related to datatypes such as
     JSON or ARRAY.

  3. Result value processing is needed, which may include types such as
     ‘DateTime’, see Boolean, Enum, or again special
     datatypes such as JSON, ARRAY.

2.1.4.29 Using Window Functions
...............................

A window function is a special use of a SQL aggregate function which
calculates the aggregate value over the rows being returned in a group
as the individual result rows are processed.  Whereas a function like
‘MAX()’ will give you the highest value of a column within a set of
rows, using the same function as a “window function” will given you the
highest value for each row, `as of that row'.

In SQL, window functions allow one to specify the rows over which the
function should be applied, a “partition” value which considers the
window over different sub-sets of rows, and an “order by” expression
which importantly indicates the order in which rows should be applied to
the aggregate function.

In SQLAlchemy, all SQL functions generated by the func
namespace include a method FunctionElement.over() which
grants the window function, or “OVER”, syntax; the construct produced is
the Over construct.

A common function used with window functions is the ‘row_number()’
function which simply counts rows.  We may partition this row count
against user name to number the email addresses of individual users:

     >>> stmt = select(
     ...     func.row_number().over(partition_by=user_table.c.name),
     ...     user_table.c.name,
     ...     address_table.c.email_address
     ... ).select_from(user_table).join(address_table)
     >>> with engine.connect() as conn:  # doctest:+SKIP
     ...     result = conn.execute(stmt)
     ...     print(result.all())
     {opensql}BEGIN (implicit)
     SELECT row_number() OVER (PARTITION BY user_account.name) AS anon_1,
     user_account.name, address.email_address
     FROM user_account JOIN address ON user_account.id = address.user_id
     [...] ()
     [(1, 'sandy', 'sandy@sqlalchemy.org'), (2, 'sandy', 'sandy@squirrelpower.org'), (1, 'spongebob', 'spongebob@sqlalchemy.org')]
     ROLLBACK

Above, the FunctionElement.over.partition_by parameter is
used so that the ‘PARTITION BY’ clause is rendered within the OVER
clause.  We also may make use of the ‘ORDER BY’ clause using
FunctionElement.over.order_by:

     >>> stmt = select(
     ...     func.count().over(order_by=user_table.c.name),
     ...     user_table.c.name,
     ...     address_table.c.email_address).select_from(user_table).join(address_table)
     >>> with engine.connect() as conn:  # doctest:+SKIP
     ...     result = conn.execute(stmt)
     ...     print(result.all())
     {opensql}BEGIN (implicit)
     SELECT count(*) OVER (ORDER BY user_account.name) AS anon_1,
     user_account.name, address.email_address
     FROM user_account JOIN address ON user_account.id = address.user_id
     [...] ()
     [(2, 'sandy', 'sandy@sqlalchemy.org'), (2, 'sandy', 'sandy@squirrelpower.org'), (3, 'spongebob', 'spongebob@sqlalchemy.org')]
     ROLLBACK

Further options for window functions include usage of ranges; see
over() for more examples.

     Tip: It’s important to note that the FunctionElement.over()
     method only applies to those SQL functions which are in fact
     aggregate functions; while the Over construct will
     happily render itself for any SQL function given, the database will
     reject the expression if the function itself is not a SQL aggregate
     function.

2.1.4.30 Special Modifiers WITHIN GROUP, FILTER
...............................................

The “WITHIN GROUP” SQL syntax is used in conjunction with an “ordered
set” or a “hypothetical set” aggregate function.  Common “ordered set”
functions include ‘percentile_cont()’ and ‘rank()’.  SQLAlchemy includes
built in implementations rank, dense_rank,
mode, percentile_cont and percentile_disc
which include a FunctionElement.within_group() method:

     >>> print(
     ...     func.unnest(
     ...         func.percentile_disc([0.25,0.5,0.75,1]).within_group(user_table.c.name)
     ...     )
     ... )
     unnest(percentile_disc(:percentile_disc_1) WITHIN GROUP (ORDER BY user_account.name))

“FILTER” is supported by some backends to limit the range of an
aggregate function to a particular subset of rows compared to the total
range of rows returned, available using the
FunctionElement.filter() method:

     >>> stmt = select(
     ...     func.count(address_table.c.email_address).filter(user_table.c.name == 'sandy'),
     ...     func.count(address_table.c.email_address).filter(user_table.c.name == 'spongebob')
     ... ).select_from(user_table).join(address_table)
     >>> with engine.connect() as conn:  # doctest:+SKIP
     ...     result = conn.execute(stmt)
     ...     print(result.all())
     {opensql}BEGIN (implicit)
     SELECT count(address.email_address) FILTER (WHERE user_account.name = ?) AS anon_1,
     count(address.email_address) FILTER (WHERE user_account.name = ?) AS anon_2
     FROM user_account JOIN address ON user_account.id = address.user_id
     [...] ('sandy', 'spongebob')
     [(2, 1)]
     ROLLBACK

2.1.4.31 Table-Valued Functions
...............................

Table-valued SQL functions support a scalar representation that contains
named sub-elements.  Often used for JSON and ARRAY-oriented functions as
well as functions like ‘generate_series()’, the table-valued function is
specified in the FROM clause, and is then referred towards as a table,
or sometimes even as a column.  Functions of this form are prominent
within the PostgreSQL database, however some forms of table valued
functions are also supported by SQLite, Oracle, and SQL Server.

See also
........

See Table values, Table and Column valued functions, Row and Tuple objects.
- in the PostgreSQL documentation.

While many databases support table valued and other special forms,
PostgreSQL tends to be where there is the most demand for these
features.  See this section for additional examples of PostgreSQL
syntaxes as well as additional features.

SQLAlchemy provides the FunctionElement.table_valued()
method as the basic “table valued function” construct, which will
convert a func object into a FROM clause containing a series
of named columns, based on string names passed positionally.  This
returns a TableValuedAlias object, which is a
function-enabled Alias construct that may be used as any
other FROM clause as introduced at Using Aliases.  Below we
illustrate the ‘json_each()’ function, which while common on PostgreSQL
is also supported by modern versions of SQLite:

     >>> onetwothree = func.json_each('["one", "two", "three"]').table_valued("value")
     >>> stmt = select(onetwothree).where(onetwothree.c.value.in_(["two", "three"]))
     >>> with engine.connect() as conn:  # doctest:+SKIP
     ...     result = conn.execute(stmt)
     ...     print(result.all())
     {opensql}BEGIN (implicit)
     SELECT anon_1.value
     FROM json_each(?) AS anon_1
     WHERE anon_1.value IN (?, ?)
     [...] ('["one", "two", "three"]', 'two', 'three')
     [('two',), ('three',)]
     ROLLBACK

Above, we used the ‘json_each()’ JSON function supported by SQLite and
PostgreSQL to generate a table valued expression with a single column
referred towards as ‘value’, and then selected two of its three rows.

See also
........

See Table-Valued Functions. - in the PostgreSQL
documentation - this section will detail additional syntaxes such as
special column derivations and “WITH ORDINALITY” that are known to work
with PostgreSQL.

2.1.4.32 Column Valued Functions - Table Valued Function as a Scalar Column
...........................................................................

A special syntax supported by PostgreSQL and Oracle is that of referring
towards a function in the FROM clause, which then delivers itself as a
single column in the columns clause of a SELECT statement or other
column expression context.  PostgreSQL makes great use of this syntax
for such functions as ‘json_array_elements()’, ‘json_object_keys()’,
‘json_each_text()’, ‘json_each()’, etc.

SQLAlchemy refers to this as a “column valued” function and is available
by applying the FunctionElement.column_valued() modifier to
a Function construct:

     >>> from sqlalchemy import select, func
     >>> stmt = select(func.json_array_elements('["one", "two"]').column_valued("x"))
     >>> print(stmt)
     SELECT x
     FROM json_array_elements(:json_array_elements_1) AS x

The “column valued” form is also supported by the Oracle dialect, where
it is usable for custom SQL functions:

     >>> from sqlalchemy.dialects import oracle
     >>> stmt = select(func.scalar_strings(5).column_valued("s"))
     >>> print(stmt.compile(dialect=oracle.dialect()))
     SELECT COLUMN_VALUE s
     FROM TABLE (scalar_strings(:scalar_strings_1)) s

See also
........

See Column Valued Functions. - in the PostgreSQL
documentation.

2.1.4.33 Core UPDATE and DELETE
...............................

So far we’ve covered Insert, so that we can get some data into
our database, and then spent a lot of time on Select which
handles the broad range of usage patterns used for retrieving data from
the database.  In this section we will cover the Update and
Delete constructs, which are used to modify existing rows as
well as delete existing rows.  This section will cover these constructs
from a Core-centric perspective.

`ORM Readers' - As was the case mentioned at Core Insert, the
Update and Delete operations when used with the
ORM are usually invoked internally from the Session object as
part of the unit of work process.

However, unlike Insert, the Update and
Delete constructs can also be used directly with the ORM, using a
pattern known as “ORM-enabled update and delete”; for this reason,
familiarity with these constructs is useful for ORM use.  Both styles of
use are discussed in the sections Updating ORM Objects and
Deleting ORM Objects.

2.1.4.34 The update() SQL Expression Construct
..............................................

The update() function generates a new instance of
Update which represents an UPDATE statement in SQL, that will
update existing data in a table.

Like the insert() construct, there is a “traditional” form of
update(), which emits UPDATE against a single table at a time
and does not return any rows.  However some backends support an UPDATE
statement that may modify multiple tables at once, and the UPDATE
statement also supports RETURNING such that columns contained in matched
rows may be returned in the result set.

A basic UPDATE looks like:

     >>> from sqlalchemy import update
     >>> stmt = (
     ...     update(user_table).where(user_table.c.name == 'patrick').
     ...     values(fullname='Patrick the Star')
     ... )
     >>> print(stmt)
     {opensql}UPDATE user_account SET fullname=:fullname WHERE user_account.name = :name_1

The Update.values() method controls the contents of the SET
elements of the UPDATE statement.  This is the same method shared by the
Insert construct.  Parameters can normally be passed using
the column names as keyword arguments.

UPDATE supports all the major SQL forms of UPDATE, including updates
against expressions, where we can make use of Column
expressions:

     >>> stmt = (
     ...     update(user_table).
     ...     values(fullname="Username: " + user_table.c.name)
     ... )
     >>> print(stmt)
     {opensql}UPDATE user_account SET fullname=(:name_1 || user_account.name)

To support UPDATE in an “executemany” context, where many parameter sets
will be invoked against the same statement, the bindparam()
construct may be used to set up bound parameters; these replace the
places that literal values would normally go:

     >>> from sqlalchemy import bindparam
     >>> stmt = (
     ...   update(user_table).
     ...   where(user_table.c.name == bindparam('oldname')).
     ...   values(name=bindparam('newname'))
     ... )
     >>> with engine.begin() as conn:
     ...   conn.execute(
     ...       stmt,
     ...       [
     ...          {'oldname':'jack', 'newname':'ed'},
     ...          {'oldname':'wendy', 'newname':'mary'},
     ...          {'oldname':'jim', 'newname':'jake'},
     ...       ]
     ...   )
     {opensql}BEGIN (implicit)
     UPDATE user_account SET name=? WHERE user_account.name = ?
     [...] (('ed', 'jack'), ('mary', 'wendy'), ('jake', 'jim'))
     <sqlalchemy.engine.cursor.CursorResult object at 0x...>
     COMMIT{stop}

Other techniques which may be applied to UPDATE include:

2.1.4.35 Correlated Updates
...........................

An UPDATE statement can make use of rows in other tables by using a
correlated subquery.  A subquery may be used anywhere a
column expression might be placed:

     >>> scalar_subq = (
     ...   select(address_table.c.email_address).
     ...   where(address_table.c.user_id == user_table.c.id).
     ...   order_by(address_table.c.id).
     ...   limit(1).
     ...   scalar_subquery()
     ... )
     >>> update_stmt = update(user_table).values(fullname=scalar_subq)
     >>> print(update_stmt)
     {opensql}UPDATE user_account SET fullname=(SELECT address.email_address
     FROM address
     WHERE address.user_id = user_account.id ORDER BY address.id
     LIMIT :param_1)

2.1.4.36 UPDATE..FROM
.....................

Some databases such as PostgreSQL and MySQL support a syntax “UPDATE
FROM” where additional tables may be stated directly in a special FROM
clause.  This syntax will be generated implicitly when additional tables
are located in the WHERE clause of the statement:

     >>> update_stmt = (
     ...    update(user_table).
     ...    where(user_table.c.id == address_table.c.user_id).
     ...    where(address_table.c.email_address == 'patrick@aol.com').
     ...    values(fullname='Pat')
     ...  )
     >>> print(update_stmt)
     {opensql}UPDATE user_account SET fullname=:fullname FROM address
     WHERE user_account.id = address.user_id AND address.email_address = :email_address_1

There is also a MySQL specific syntax that can UPDATE multiple tables.
This requires we refer to Table objects in the VALUES clause
in order to refer to additional tables:

     >>> update_stmt = (
     ...    update(user_table).
     ...    where(user_table.c.id == address_table.c.user_id).
     ...    where(address_table.c.email_address == 'patrick@aol.com').
     ...    values(
     ...        {
     ...            user_table.c.fullname: "Pat",
     ...            address_table.c.email_address: "pat@aol.com"
     ...        }
     ...    )
     ...  )
     >>> from sqlalchemy.dialects import mysql
     >>> print(update_stmt.compile(dialect=mysql.dialect()))
     {opensql}UPDATE user_account, address
     SET address.email_address=%s, user_account.fullname=%s
     WHERE user_account.id = address.user_id AND address.email_address = %s

2.1.4.37 Parameter Ordered Updates
..................................

Another MySQL-only behavior is that the order of parameters in the SET
clause of an UPDATE actually impacts the evaluation of each expression.
For this use case, the Update.ordered_values() method
accepts a sequence of tuples so that this order may be controlled (1):

     >>> update_stmt = (
     ...     update(some_table).
     ...     ordered_values(
     ...         (some_table.c.y, 20),
     ...         (some_table.c.x, some_table.c.y + 10)
     ...     )
     ... )
     >>> print(update_stmt)
     {opensql}UPDATE some_table SET y=:y, x=(some_table.y + :y_1)

   ---------- Footnotes ----------

   (1) (2) While Python dictionaries are guaranteed to be insert ordered
(https://mail.python.org/pipermail/python-dev/2017-December/151283.html)
as of Python 3.7, the Update.ordered_values() method still
provides an additional measure of clarity of intent when it is essential
that the SET clause of a MySQL UPDATE statement proceed in a specific
way.

2.1.4.38 The delete() SQL Expression Construct
..............................................

The delete() function generates a new instance of
Delete which represents an DELETE statement in SQL, that will
delete rows from a table.

The delete() statement from an API perspective is very
similar to that of the update() construct, traditionally
returning no rows but allowing for a RETURNING variant on some database
backends.

     >>> from sqlalchemy import delete
     >>> stmt = delete(user_table).where(user_table.c.name == 'patrick')
     >>> print(stmt)
     {opensql}DELETE FROM user_account WHERE user_account.name = :name_1

2.1.4.39 Multiple Table Deletes
...............................

Like Update, Delete supports the use of correlated
subqueries in the WHERE clause as well as backend-specific multiple
table syntaxes, such as ‘DELETE FROM..USING’ on MySQL:

     >>> delete_stmt = (
     ...    delete(user_table).
     ...    where(user_table.c.id == address_table.c.user_id).
     ...    where(address_table.c.email_address == 'patrick@aol.com')
     ...  )
     >>> from sqlalchemy.dialects import mysql
     >>> print(delete_stmt.compile(dialect=mysql.dialect()))
     {opensql}DELETE FROM user_account USING user_account, address
     WHERE user_account.id = address.user_id AND address.email_address = %s

2.1.4.40 Getting Affected Row Count from UPDATE, DELETE
.......................................................

Both Update and Delete support the ability to
return the number of rows matched after the statement proceeds, for
statements that are invoked using Core Connection, i.e.
see Connection.execute().  Per the caveats mentioned below, this
value is available from the CursorResult.rowcount attribute:

     >>> with engine.begin() as conn:
     ...     result = conn.execute(
     ...         update(user_table).
     ...         values(fullname="Patrick McStar").
     ...         where(user_table.c.name == 'patrick')
     ...     )
     ...     print(result.rowcount)
     {opensql}BEGIN (implicit)
     UPDATE user_account SET fullname=? WHERE user_account.name = ?
     [...] ('Patrick McStar', 'patrick'){stop}
     1
     {opensql}COMMIT{stop}

     Tip: The CursorResult class is a subclass of
     Result which contains additional attributes that are specific
     to the DBAPI ‘cursor’ object.  An instance of this subclass is
     returned when a statement is invoked via the
     Connection.execute() method.  When using the ORM, the
     Session.execute() method returns an object of this type for
     all INSERT, UPDATE, and DELETE statements.

Facts about CursorResult.rowcount:

   * The value returned is the number of rows `matched' by the WHERE
     clause of the statement.  It does not matter if the row were
     actually modified or not.

   * CursorResult.rowcount is not necessarily available for
     an UPDATE or DELETE statement that uses RETURNING.

   * For an executemany execution, see
     CursorResult.rowcount may not be available either, which
     depends highly on the DBAPI module in use as well as configured
     options.  The attribute
     CursorResult.supports_sane_multi_rowcount indicates if this
     value will be available for the current backend in use.

   * Some drivers, particularly third party dialects for non-relational
     databases, may not support CursorResult.rowcount at
     all.  The CursorResult.supports_sane_rowcount will
     indicate this.

   * “rowcount” is used by the ORM unit of work process to validate that
     an UPDATE or DELETE statement matched the expected number of rows,
     and is also essential for the ORM versioning feature documented at
     Configuring a Version Counter.

2.1.4.41 Using RETURNING with UPDATE, DELETE
............................................

Like the Insert construct, see Update and
Delete also support the RETURNING clause which is added by using
the Update.returning() and Delete.returning()
methods.  When these methods are used on a backend that supports
RETURNING, selected columns from all rows that match the WHERE criteria
of the statement will be returned in the Result object as
rows that can be iterated:

     >>> update_stmt = (
     ...     update(user_table).where(user_table.c.name == 'patrick').
     ...     values(fullname='Patrick the Star').
     ...     returning(user_table.c.id, user_table.c.name)
     ... )
     >>> print(update_stmt)
     {opensql}UPDATE user_account SET fullname=:fullname
     WHERE user_account.name = :name_1
     RETURNING user_account.id, user_account.name{stop}

     >>> delete_stmt = (
     ...     delete(user_table).where(user_table.c.name == 'patrick').
     ...     returning(user_table.c.id, user_table.c.name)
     ... )
     >>> print(delete_stmt)
     {opensql}DELETE FROM user_account
     WHERE user_account.name = :name_1
     RETURNING user_account.id, user_account.name{stop}

2.1.4.42 Further Reading for UPDATE, DELETE
...........................................

See also
........

API documentation for UPDATE / DELETE:

   * Update.

   * Delete.

ORM-enabled UPDATE and DELETE:

   * ORM-enabled UPDATE statements.

   * ORM-enabled DELETE Statements.

SQLAlchemy 1.4 / 2.0 Tutorial
.............................

Next Tutorial Section: Data Manipulation with the ORM.

SQLAlchemy 1.4 / 2.0 Tutorial
.............................

This page is part of the SQLAlchemy 1.4 / 2.0 Tutorial.

Previous: Working with Data. | Next: Working with Related Objects.

2.1.5 Data Manipulation with the ORM
------------------------------------

The previous section Working with Data remained focused on
the SQL Expression Language from a Core perspective, in order to provide
continuity across the major SQL statement constructs.  This section will
then build out the lifecycle of the Session and how it
interacts with these constructs.

`Prerequisite Sections' - the ORM focused part of the tutorial builds
upon two previous ORM-centric sections in this document:

   * Executing with an ORM Session. - introduces how to make
     an ORM Session object

   * Defining Table Metadata with the ORM. - where we set up
     our ORM mappings of the ‘User’ and ‘Address’ entities

   * Selecting ORM Entities and Columns. - a few examples on
     how to run SELECT statements for entities like ‘User’

2.1.5.1 Inserting Rows with the ORM
...................................

When using the ORM, the Session object is responsible for
constructing Insert constructs and emitting them for us in a
transaction.  The way we instruct the Session to do so is by
`adding' object entries to it; the Session then makes sure
these new entries will be emitted to the database when they are needed,
using a process known as a `flush'.

2.1.5.2 Instances of Classes represent Rows
...........................................

Whereas in the previous example we emitted an INSERT using Python
dictionaries to indicate the data we wanted to add, with the ORM we make
direct use of the custom Python classes we defined, back at
Defining Table Metadata with the ORM.  At the class level, the
‘User’ and ‘Address’ classes served as a place to define what the
corresponding database tables should look like.  These classes also
serve as extensible data objects that we use to create and manipulate
rows within a transaction as well.  Below we will create two ‘User’
objects each representing a potential database row to be INSERTed:

     >>> squidward = User(name="squidward", fullname="Squidward Tentacles")
     >>> krabs = User(name="ehkrabs", fullname="Eugene H. Krabs")

We are able to construct these objects using the names of the mapped
columns as keyword arguments in the constructor.  This is possible as
the ‘User’ class includes an automatically generated ‘__init__()’
constructor that was provided by the ORM mapping so that we could create
each object using column names as keys in the constructor.

In a similar manner as in our Core examples of Insert, we did
not include a primary key (i.e.  an entry for the ‘id’ column), since we
would like to make use of the auto-incrementing primary key feature of
the database, SQLite in this case, which the ORM also integrates with.
The value of the ‘id’ attribute on the above objects, if we were to view
it, displays itself as ‘None’:

     >>> squidward
     User(id=None, name='squidward', fullname='Squidward Tentacles')

The ‘None’ value is provided by SQLAlchemy to indicate that the
attribute has no value as of yet.  SQLAlchemy-mapped attributes always
return a value in Python and don’t raise ‘AttributeError’ if they’re
missing, when dealing with a new object that has not had a value
assigned.

At the moment, our two objects above are said to be in a state called
transient - they are not associated with any database state and are yet
to be associated with a Session object that can generate
INSERT statements for them.

2.1.5.3 Adding objects to a Session
...................................

To illustrate the addition process step by step, we will create a
Session without using a context manager (and hence we must make
sure we close it later!):

     >>> session = Session(engine)

The objects are then added to the Session using the
Session.add() method.  When this is called, the objects are in a
state known as pending and have not been inserted yet:

     >>> session.add(squidward)
     >>> session.add(krabs)

When we have pending objects, we can see this state by looking at a
collection on the Session called Session.new:

     >>> session.new
     IdentitySet([User(id=None, name='squidward', fullname='Squidward Tentacles'), User(id=None, name='ehkrabs', fullname='Eugene H. Krabs')])

The above view is using a collection called ‘IdentitySet’ that is
essentially a Python set that hashes on object identity in all cases
(i.e., using Python built-in ‘id()’ function, rather than the Python
‘hash()’ function).

2.1.5.4 Flushing
................

The Session makes use of a pattern known as unit of work.
This generally means it accumulates changes one at a time, but does not
actually communicate them to the database until needed.  This allows it
to make better decisions about how SQL DML should be emitted in the
transaction based on a given set of pending changes.  When it does emit
SQL to the database to push out the current set of changes, the process
is known as a `flush'.

We can illustrate the flush process manually by calling the
Session.flush() method:

     >>> session.flush()
     {opensql}BEGIN (implicit)
     INSERT INTO user_account (name, fullname) VALUES (?, ?)
     [...] ('squidward', 'Squidward Tentacles')
     INSERT INTO user_account (name, fullname) VALUES (?, ?)
     [...] ('ehkrabs', 'Eugene H. Krabs')

Above we observe the Session was first called upon to emit
SQL, so it created a new transaction and emitted the appropriate INSERT
statements for the two objects.  The transaction now `remains open'
until we call any of the Session.commit(),
Session.rollback(), or Session.close() methods of
Session.

While Session.flush() may be used to manually push out
pending changes to the current transaction, it is usually unnecessary as
the Session features a behavior known as `autoflush', which
we will illustrate later.  It also flushes out changes whenever
Session.commit() is called.

2.1.5.5 Autogenerated primary key attributes
............................................

Once the rows are inserted, the two Python objects we’ve created are in
a state known as persistent, where they are associated with the
Session object in which they were added or loaded, and feature lots
of other behaviors that will be covered later.

Another effect of the INSERT that occurred was that the ORM has
retrieved the new primary key identifiers for each new object;
internally it normally uses the same
CursorResult.inserted_primary_key accessor we introduced
previously.  The ‘squidward’ and ‘krabs’ objects now have these new
primary key identifiers associated with them and we can view them by
acesssing the ‘id’ attribute:

     >>> squidward.id
     4
     >>> krabs.id
     5

     Tip: Why did the ORM emit two separate INSERT statements when it
     could have used executemany.?  As we’ll see in the next
     section, the Session when flushing objects always needs
     to know the primary key of newly inserted objects.  If a feature
     such as SQLite’s autoincrement is used (other examples include
     PostgreSQL IDENTITY or SERIAL, using sequences, etc.), the
     CursorResult.inserted_primary_key feature usually requires
     that each INSERT is emitted one row at a time.  If we had provided
     values for the primary keys ahead of time, the ORM would have been
     able to optimize the operation better.  Some database backends such
     as psycopg2 can also INSERT many rows at once while
     still being able to retrieve the primary key values.

2.1.5.6 Identity Map
....................

The primary key identity of the objects are significant to the
Session, as the objects are now linked to this identity in memory
using a feature known as the identity map.  The identity map is an
in-memory store that links all objects currently loaded in memory to
their primary key identity.  We can observe this by retrieving one of
the above objects using the Session.get() method, which will
return an entry from the identity map if locally present, otherwise
emitting a SELECT:

     >>> some_squidward = session.get(User, 4)
     >>> some_squidward
     User(id=4, name='squidward', fullname='Squidward Tentacles')

The important thing to note about the identity map is that it maintains
a `unique instance' of a particular Python object per a particular
database identity, within the scope of a particular Session
object.  We may observe that the ‘some_squidward’ refers to the `same
object' as that of ‘squidward’ previously:

     >>> some_squidward is squidward
     True

The identity map is a critical feature that allows complex sets of
objects to be manipulated within a transaction without things getting
out of sync.

2.1.5.7 Committing
..................

There’s much more to say about how the Session works which
will be discussed further.  For now we will commit the transaction so
that we can build up knowledge on how to SELECT rows before examining
more ORM behaviors and features:

     >>> session.commit()
     COMMIT

2.1.5.8 Updating ORM Objects
............................

In the preceding section Core UPDATE and DELETE, we introduced
the Update construct that represents a SQL UPDATE statement.
When using the ORM, there are two ways in which this construct is used.
The primary way is that it is emitted automatically as part of the unit
of work process used by the Session, where an UPDATE statement
is emitted on a per-primary key basis corresponding to individual
objects that have changes on them.  A second form of UPDATE is called an
“ORM enabled UPDATE” and allows us to use the Update
construct with the Session explicitly; this is described in
the next section.

Supposing we loaded the ‘User’ object for the username ‘sandy’ into a
transaction (also showing off the Select.filter_by() method
as well as the Result.scalar_one() method):

     {sql}>>> sandy = session.execute(select(User).filter_by(name="sandy")).scalar_one()
     BEGIN (implicit)
     SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     WHERE user_account.name = ?
     [...] ('sandy',)

The Python object ‘sandy’ as mentioned before acts as a `proxy' for the
row in the database, more specifically the database row `in terms of the
current transaction', that has the primary key identity of ‘2’:

     >>> sandy
     User(id=2, name='sandy', fullname='Sandy Cheeks')

If we alter the attributes of this object, the Session tracks
this change:

     >>> sandy.fullname = "Sandy Squirrel"

The object appears in a collection called Session.dirty,
indicating the object is “dirty”:

     >>> sandy in session.dirty
     True

When the Session next emits a flush, an UPDATE will be
emitted that updates this value in the database.  As mentioned
previously, a flush occurs automatically before we emit any SELECT,
using a behavior known as `autoflush'.  We can query directly for the
‘User.fullname’ column from this row and we will get our updated value
back:

     >>> sandy_fullname = session.execute(
     ...     select(User.fullname).where(User.id == 2)
     ... ).scalar_one()
     {opensql}UPDATE user_account SET fullname=? WHERE user_account.id = ?
     [...] ('Sandy Squirrel', 2)
     SELECT user_account.fullname
     FROM user_account
     WHERE user_account.id = ?
     [...] (2,){stop}
     >>> print(sandy_fullname)
     Sandy Squirrel

We can see above that we requested that the Session execute a
single select() statement.  However the SQL emitted shows
that an UPDATE were emitted as well, which was the flush process pushing
out pending changes.  The ‘sandy’ Python object is now no longer
considered dirty:

     >>> sandy in session.dirty
     False

However note we are `still in a transaction' and our changes have not
been pushed to the database’s permanent storage.  Since Sandy’s last
name is in fact “Cheeks” not “Squirrel”, we will repair this mistake
later when we roll back the transction.  But first we’ll make some more
data changes.

See also
........

See Flushing.- details the flush process as well as information
about the Session.autoflush setting.

2.1.5.9 ORM-enabled UPDATE statements
.....................................

As previously mentioned, there’s a second way to emit UPDATE statements
in terms of the ORM, which is known as an `ORM enabled UPDATE
statement'.  This allows the use of a generic SQL UPDATE statement that
can affect many rows at once.  For example to emit an UPDATE that will
change the ‘User.fullname’ column based on a value in the ‘User.name’
column:

     >>> session.execute(
     ...     update(User).
     ...     where(User.name == "sandy").
     ...     values(fullname="Sandy Squirrel Extraodinaire")
     ... )
     {opensql}UPDATE user_account SET fullname=? WHERE user_account.name = ?
     [...] ('Sandy Squirrel Extraodinaire', 'sandy'){stop}
     <sqlalchemy.engine.cursor.CursorResult object ...>

When invoking the ORM-enabled UPDATE statement, special logic is used to
locate objects in the current session that match the given criteria, so
that they are refreshed with the new data.  Above, the ‘sandy’ object
identity was located in memory and refreshed:

     >>> sandy.fullname
     'Sandy Squirrel Extraodinaire'

The refresh logic is known as the ‘synchronize_session’ option, and is
described in detail in the section UPDATE and DELETE with arbitrary WHERE clause.

See also
........

See UPDATE and DELETE with arbitrary WHERE clause. - describes
ORM use of update() and delete() as well as ORM
synchronization options.

2.1.5.10 Deleting ORM Objects
.............................

To round out the basic persistence operations, an individual ORM object
may be marked for deletion by using the Session.delete()
method.  Let’s load up ‘patrick’ from the database:

     {sql}>>> patrick = session.get(User, 3)
     SELECT user_account.id AS user_account_id, user_account.name AS user_account_name,
     user_account.fullname AS user_account_fullname
     FROM user_account
     WHERE user_account.id = ?
     [...] (3,)

If we mark ‘patrick’ for deletion, as is the case with other operations,
nothing actually happens yet until a flush proceeds:

     >>> session.delete(patrick)

Current ORM behavior is that ‘patrick’ stays in the Session
until the flush proceeds, which as mentioned before occurs if we emit a
query:

     >>> session.execute(select(User).where(User.name == "patrick")).first()
     {opensql}SELECT address.id AS address_id, address.email_address AS address_email_address,
     address.user_id AS address_user_id
     FROM address
     WHERE ? = address.user_id
     [...] (3,)
     DELETE FROM user_account WHERE user_account.id = ?
     [...] (3,)
     SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     WHERE user_account.name = ?
     [...] ('patrick',)

Above, the SELECT we asked to emit was preceded by a DELETE, which
indicated the pending deletion for ‘patrick’ proceeded.  There was also
a ‘SELECT’ against the ‘address’ table, which was prompted by the ORM
looking for rows in this table which may be related to the target row;
this behavior is part of a behavior known as cascade, and can be
tailored to work more efficiently by allowing the database to handle
related rows in ‘address’ automatically; the section delete
has all the detail on this.

See also
........

See delete. - describes how to tune the behavior of
Session.delete() in terms of how related rows in other tables
should be handled.

Beyond that, the ‘patrick’ object instance now being deleted is no
longer considered to be persistent within the Session, as is
shown by the containment check:

     >>> patrick in session
     False

However just like the UPDATEs we made to the ‘sandy’ object, every
change we’ve made here is local to an ongoing transaction, which won’t
become permanent if we don’t commit it.  As rolling the transaction back
is actually more interesting at the moment, we will do that in the next
section.

2.1.5.11 ORM-enabled DELETE Statements
......................................

Like UPDATE operations, there is also an ORM-enabled version of DELETE
which we can illustrate by using the delete() construct with
Session.execute().  It also has a feature by which `non
expired' objects (see expired) that match the given deletion criteria
will be automatically marked as “deleted” in the Session:

     >>> # refresh the target object for demonstration purposes
     >>> # only, not needed for the DELETE
     {sql}>>> squidward = session.get(User, 4)
     SELECT user_account.id AS user_account_id, user_account.name AS user_account_name,
     user_account.fullname AS user_account_fullname
     FROM user_account
     WHERE user_account.id = ?
     [...] (4,){stop}

     >>> session.execute(delete(User).where(User.name == "squidward"))
     {opensql}DELETE FROM user_account WHERE user_account.name = ?
     [...] ('squidward',){stop}
     <sqlalchemy.engine.cursor.CursorResult object at 0x...>

The ‘squidward’ identity, like that of ‘patrick’, is now also in a
deleted state.  Note that we had to re-load ‘squidward’ above in order
to demonstrate this; if the object were expired, the DELETE operation
would not take the time to refresh expired objects just to see that they
had been deleted:

     >>> squidward in session
     False

2.1.5.12 Rolling Back
.....................

The Session has a Session.rollback() method that
as expected emits a ROLLBACK on the SQL connection in progress.
However, it also has an effect on the objects that are currently
associated with the Session, in our previous example the
Python object ‘sandy’.  While we changed the ‘.fullname’ of the ‘sandy’
object to read ‘"Sandy Squirrel"’, we want to roll back this change.
Calling Session.rollback() will not only roll back the
transaction but also `expire' all objects currently associated with this
Session, which will have the effect that they will refresh
themselves when next accessed using a process known as lazy loading:

     >>> session.rollback()
     ROLLBACK

To view the “expiration” process more closely, we may observe that the
Python object ‘sandy’ has no state left within its Python ‘__dict__’,
with the exception of a special SQLAlchemy internal state object:

     >>> sandy.__dict__
     {'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x...>}

This is the “expired” state; accessing the attribute again will
autobegin a new transaction and refresh ‘sandy’ with the current
database row:

     >>> sandy.fullname
     {opensql}BEGIN (implicit)
     SELECT user_account.id AS user_account_id, user_account.name AS user_account_name,
     user_account.fullname AS user_account_fullname
     FROM user_account
     WHERE user_account.id = ?
     [...] (2,){stop}
     'Sandy Cheeks'

We may now observe that the full database row was also populated into
the ‘__dict__’ of the ‘sandy’ object:

     >>> sandy.__dict__
     {'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x...>,
      'id': 2, 'name': 'sandy', 'fullname': 'Sandy Cheeks'}

For deleted objects, when we earlier noted that ‘patrick’ was no longer
in the session, that object’s identity is also restored:

     >>> patrick in session
     True

and of course the database data is present again as well:

     {sql}>>> session.execute(select(User).where(User.name == 'patrick')).scalar_one() is patrick
     SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     WHERE user_account.name = ?
     [...] ('patrick',){stop}
     True

2.1.5.13 Closing a Session
..........................

Within the above sections we used a Session object outside of
a Python context manager, that is, we didn’t use the ‘with’ statement.
That’s fine, however if we are doing things this way, it’s best that we
explicitly close out the Session when we are done with it:

     >>> session.close()
     {opensql}ROLLBACK

Closing the Session, which is what happens when we use it in a
context manager as well, accomplishes the following things:

   * It releases all connection resources to the connection pool,
     cancelling out (e.g.  rolling back) any transactions that were in
     progress.

     This means that when we make use of a session to perform some
     read-only tasks and then close it, we don’t need to explicitly call
     upon Session.rollback() to make sure the transaction is
     rolled back; the connection pool handles this.

   * It `expunges' all objects from the Session.

     This means that all the Python objects we had loaded for this
     Session, like ‘sandy’, ‘patrick’ and ‘squidward’, are now in a
     state known as detached.  In particular, we will note that objects
     that were still in an expired state, for example due to the call to
     Session.commit(), are now non-functional, as they don’t
     contain the state of a current row and are no longer associated
     with any database transaction in which to be refreshed:

          >>> squidward.name
          Traceback (most recent call last):
            ...
          sqlalchemy.orm.exc.DetachedInstanceError: Instance <User at 0x...> is not bound to a Session; attribute refresh operation cannot proceed

     The detached objects can be re-associated with the same, or a new
     Session using the Session.add() method,
     which will re-establish their relationship with their particular
     database row:

          >>> session.add(squidward)
          >>> squidward.name
          {opensql}BEGIN (implicit)
          SELECT user_account.id AS user_account_id, user_account.name AS user_account_name, user_account.fullname AS user_account_fullname
          FROM user_account
          WHERE user_account.id = ?
          [...] (4,){stop}
          'squidward'

          Tip: Try to avoid using objects in their detached state, if
          possible.  When the Session is closed, clean up
          references to all the previously attached objects as well.
          For cases where detached objects are necessary, typically the
          immediate display of just-committed objects for a web
          application where the Session is closed before the
          view is rendered, set the Session.expire_on_commit
          flag to ‘False’.

SQLAlchemy 1.4 / 2.0 Tutorial
.............................

Next Tutorial Section: Working with Related Objects.

SQLAlchemy 1.4 / 2.0 Tutorial
.............................

This page is part of the SQLAlchemy 1.4 / 2.0 Tutorial.

Previous: Data Manipulation with the ORM. | Next:
Further Reading.

2.1.6 Working with Related Objects
----------------------------------

In this section, we will cover one more essential ORM concept, which is
how the ORM interacts with mapped classes that refer to other objects.
In the section Declaring Mapped Classes, the mapped class
examples made use of a construct called relationship().  This
construct defines a linkage between two different mapped classes, or
from a mapped class to itself, the latter of which is called a
`self-referential' relationship.

To describe the basic idea of relationship(), first we’ll
review the mapping in short form, omitting the Column
mappings and other directives:

     from sqlalchemy.orm import relationship
     class User(Base):
         __tablename__ = 'user_account'

         # ... Column mappings

         addresses = relationship("Address", back_populates="user")

     class Address(Base):
         __tablename__ = 'address'

         # ... Column mappings

         user = relationship("User", back_populates="addresses")

Above, the ‘User’ class now has an attribute ‘User.addresses’ and the
‘Address’ class has an attribute ‘Address.user’.  The
relationship() construct will be used to inspect the table
relationships between the Table objects that are mapped to
the ‘User’ and ‘Address’ classes.  As the Table object
representing the ‘address’ table has a ForeignKeyConstraint
which refers to the ‘user_account’ table, the relationship()
can determine unambiguously that there is as one to many relationship
from ‘User.addresses’ to ‘User’; one particular row in the
‘user_account’ table may be referred towards by many rows in the
‘address’ table.

All one-to-many relationships naturally correspond to a many to one
relationship in the other direction, in this case the one noted by
‘Address.user’.  The relationship.back_populates parameter,
seen above configured on both relationship() objects
referring to the other name, establishes that each of these two
relationship() constructs should be considered to be complimentary
to each other; we will see how this plays out in the next section.

2.1.6.1 Persisting and Loading Relationships
............................................

We can start by illustrating what relationship() does to
instances of objects.  If we make a new ‘User’ object, we can note that
there is a Python list when we access the ‘.addresses’ element:

     >>> u1 = User(name='pkrabs', fullname='Pearl Krabs')
     >>> u1.addresses
     []

This object is a SQLAlchemy-specific version of Python ‘list’ which has
the ability to track and respond to changes made to it.  The collection
also appeared automatically when we accessed the attribute, even though
we never assigned it to the object.  This is similar to the behavior
noted at Inserting Rows with the ORM where it was observed
that column-based attributes to which we don’t explicitly assign a value
also display as ‘None’ automatically, rather than raising an
‘AttributeError’ as would be Python’s usual behavior.

As the ‘u1’ object is still transient and the ‘list’ that we got from
‘u1.addresses’ has not been mutated (i.e.  appended or extended), it’s
not actually associated with the object yet, but as we make changes to
it, it will become part of the state of the ‘User’ object.

The collection is specific to the ‘Address’ class which is the only type
of Python object that may be persisted within it.  Using the
‘list.append()’ method we may add an ‘Address’ object:

     >>> a1 = Address(email_address="pearl.krabs@gmail.com")
     >>> u1.addresses.append(a1)

At this point, the ‘u1.addresses’ collection as expected contains the
new ‘Address’ object:

     >>> u1.addresses
     [Address(id=None, email_address='pearl.krabs@gmail.com')]

As we associated the ‘Address’ object with the ‘User.addresses’
collection of the ‘u1’ instance, another behavior also occurred, which
is that the ‘User.addresses’ relationship synchronized itself with the
‘Address.user’ relationship, such that we can navigate not only from the
‘User’ object to the ‘Address’ object, we can also navigate from the
‘Address’ object back to the “parent” ‘User’ object:

     >>> a1.user
     User(id=None, name='pkrabs', fullname='Pearl Krabs')

This synchronization occurred as a result of our use of the
relationship.back_populates parameter between the two
relationship() objects.  This parameter names another
relationship() for which complementary attribute assignment / list
mutation should occur.  It will work equally well in the other
direction, which is that if we create another ‘Address’ object and
assign to its ‘Address.user’ attribute, that ‘Address’ becomes part of
the ‘User.addresses’ collection on that ‘User’ object:

     >>> a2 = Address(email_address="pearl@aol.com", user=u1)
     >>> u1.addresses
     [Address(id=None, email_address='pearl.krabs@gmail.com'), Address(id=None, email_address='pearl@aol.com')]

We actually made use of the ‘user’ parameter as a keyword argument in
the ‘Address’ consructor, which is accepted just like any other mapped
attribute that was declared on the ‘Address’ class.  It is equivalent to
assignment of the ‘Address.user’ attribute after the fact:

     # equivalent effect as a2 = Address(user=u1)
     >>> a2.user = u1

2.1.6.2 Cascading Objects into the Session
..........................................

We now have a ‘User’ and two ‘Address’ objects that are associated in a
bidirectional structure in memory, but as noted previously in
Inserting Rows with the ORM. , these objects are said to be in the
transient state until they are associated with a Session
object.

We make use of the Session that’s still ongoing, and note
that when we apply the Session.add() method to the lead
‘User’ object, the related ‘Address’ object also gets added to that same
Session:

     >>> session.add(u1)
     >>> u1 in session
     True
     >>> a1 in session
     True
     >>> a2 in session
     True

The above behavior, where the Session received a ‘User’
object, and followed along the ‘User.addresses’ relationship to locate a
related ‘Address’ object, is known as the `save-update cascade' and is
discussed in detail in the ORM reference documentation at
Cascades.

The three objects are now in the pending state; this means they are
ready to be the subject of an INSERT operation but this has not yet
proceeded; all three objects have no primary key assigned yet, and in
addition, the ‘a1’ and ‘a2’ objects have an attribute called ‘user_id’
which refers to the Column that has a ‘ForeignKeyConsraint’
referring to the ‘user_account.id’ column; these are also ‘None’ as the
objects are not yet associated with a real database row:

     >>> print(u1.id)
     None
     >>> print(a1.user_id)
     None

It’s at this stage that we can see the very great utility that the unit
of work process provides; recall in the section INSERT usually generates the “values” clause automatically,
rows were inserted into
the ‘user_account’ and ‘address’ tables using some elaborate syntaxes in
order to automatically associate the ‘address.user_id’ columns with
those of the ‘user_account’ rows.  Additionally, it was necessary that
we emit INSERT for ‘user_account’ rows first, before those of ‘address’,
since rows in ‘address’ are `dependent' on their parent row in
‘user_account’ for a value in their ‘user_id’ column.

When using the Session, all this tedium is handled for us and
even the most die-hard SQL purist can benefit from automation of INSERT,
UPDATE and DELETE statements.  When we Session.commit() the
transaction all steps invoke in the correct order, and furthermore the
newly generated primary key of the ‘user_account’ row is applied to the
‘address.user_id’ column appropriately:

     >>> session.commit()
     {opensql}INSERT INTO user_account (name, fullname) VALUES (?, ?)
     [...] ('pkrabs', 'Pearl Krabs')
     INSERT INTO address (email_address, user_id) VALUES (?, ?)
     [...] ('pearl.krabs@gmail.com', 6)
     INSERT INTO address (email_address, user_id) VALUES (?, ?)
     [...] ('pearl@aol.com', 6)
     COMMIT

2.1.6.3 Loading Relationships
.............................

In the last step, we called Session.commit() which emitted a
COMMIT for the transaction, and then per
Session.commit.expire_on_commit expired all objects so that they
refresh for the next transaction.

When we next access an attribute on these objects, we’ll see the SELECT
emitted for the primary attributes of the row, such as when we view the
newly generated primary key for the ‘u1’ object:

     >>> u1.id
     {opensql}BEGIN (implicit)
     SELECT user_account.id AS user_account_id, user_account.name AS user_account_name,
     user_account.fullname AS user_account_fullname
     FROM user_account
     WHERE user_account.id = ?
     [...] (6,){stop}
     6

The ‘u1’ ‘User’ object now has a persistent collection ‘User.addresses’
that we may also access.  As this collection consists of an additional
set of rows from the ‘address’ table, when we access this collection as
well we again see a lazy load emitted in order to retrieve the objects:

     >>> u1.addresses
     {opensql}SELECT address.id AS address_id, address.email_address AS address_email_address,
     address.user_id AS address_user_id
     FROM address
     WHERE ? = address.user_id
     [...] (6,){stop}
     [Address(id=4, email_address='pearl.krabs@gmail.com'), Address(id=5, email_address='pearl@aol.com')]

Collections and related attributes in the SQLAlchemy ORM are persistent
in memory; once the collection or attribute is populated, SQL is no
longer emitted until that collection or attribute is expired.  We may
access ‘u1.addresses’ again as well as add or remove items and this will
not incur any new SQL calls:

     >>> u1.addresses
     [Address(id=4, email_address='pearl.krabs@gmail.com'), Address(id=5, email_address='pearl@aol.com')]

While the loading emitted by lazy loading can quickly become expensive
if we don’t take explicit steps to optimize it, the network of lazy
loading at least is fairly well optimized to not perform redundant work;
as the ‘u1.addresses’ collection was refreshed, per the identity map
these are in fact the same ‘Address’ instances as the ‘a1’ and ‘a2’
objects we’ve been dealing with already, so we’re done loading all
attributes in this particular object graph:

     >>> a1
     Address(id=4, email_address='pearl.krabs@gmail.com')
     >>> a2
     Address(id=5, email_address='pearl@aol.com')

The issue of how relationships load, or not, is an entire subject onto
itself.  Some additional introduction to these concepts is later in this
section at Loader Strategies.

2.1.6.4 Using Relationships in Queries
......................................

The previous section introduced the behavior of the
relationship() construct when working with `instances of a mapped
class', above, the ‘u1’, ‘a1’ and ‘a2’ instances of the ‘User’ and
‘Address’ classes.  In this section, we introduce the behavior of
relationship() as it applies to `class level behavior of a mapped
class', where it serves in several ways to help automate the
construction of SQL queries.

2.1.6.5 Using Relationships to Join
...................................

The sections Explicit FROM clauses and JOINs and
Setting the ON Clause introduced the usage of the
Select.join() and Select.join_from() methods to
compose SQL JOIN clauses.  In order to describe how to join between
tables, these methods either `infer' the ON clause based on the presence
of a single unambiguous ForeignKeyConstraint object within
the table metadata structure that links the two tables, or otherwise we
may provide an explicit SQL Expression construct that indicates a
specific ON clause.

When using ORM entities, an additional mechanism is available to help us
set up the ON clause of a join, which is to make use of the
relationship() objects that we set up in our user mapping, as was
demonstrated at Declaring Mapped Classes.  The class-bound
attribute corresponding to the relationship() may be passed
as the `single argument' to Select.join(), where it serves to
indicate both the right side of the join as well as the ON clause at
once:

     >>> print(
     ...     select(Address.email_address).
     ...     select_from(User).
     ...     join(User.addresses)
     ... )
     {opensql}SELECT address.email_address
     FROM user_account JOIN address ON user_account.id = address.user_id

The presence of an ORM relationship() on a mapping is not
used by Select.join() or Select.join_from() if
we don’t specify it; it is `not used for ON clause inference'.  This
means, if we join from ‘User’ to ‘Address’ without an ON clause, it
works because of the ForeignKeyConstraint between the two
mapped Table objects, not because of the
relationship() objects on the ‘User’ and ‘Address’ classes:

     >>> print(
     ...    select(Address.email_address).
     ...    join_from(User, Address)
     ... )
     {opensql}SELECT address.email_address
     FROM user_account JOIN address ON user_account.id = address.user_id

2.1.6.6 Joining between Aliased targets
.......................................

In the section ORM Entity Aliases we introduced the
aliased() construct, which is used to apply a SQL alias to an ORM
entity.  When using a relationship() to help construct SQL
JOIN, the use case where the target of the join is to be an
aliased() is suited by making use of the
PropComparator.of_type() modifier.  To demonstrate we will
construct the same join illustrated at ORM Entity Aliases
using the relationship() attributes to join instead:

     >>> print(
     ...        select(User).
     ...        join(User.addresses.of_type(address_alias_1)).
     ...        where(address_alias_1.email_address == 'patrick@aol.com').
     ...        join(User.addresses.of_type(address_alias_2)).
     ...        where(address_alias_2.email_address == 'patrick@gmail.com')
     ...    )
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     JOIN address AS address_1 ON user_account.id = address_1.user_id
     JOIN address AS address_2 ON user_account.id = address_2.user_id
     WHERE address_1.email_address = :email_address_1
     AND address_2.email_address = :email_address_2

To make use of a relationship() to construct a join `from' an
aliased entity, the attribute is available from the aliased()
construct directly:

     >>> user_alias_1 = aliased(User)
     >>> print(
     ...     select(user_alias_1.name).
     ...     join(user_alias_1.addresses)
     ... )
     {opensql}SELECT user_account_1.name
     FROM user_account AS user_account_1
     JOIN address ON user_account_1.id = address.user_id

2.1.6.7 Augmenting the ON Criteria
..................................

The ON clause generated by the relationship() construct may
also be augmented with additional criteria.  This is useful both for
quick ways to limit the scope of a particular join over a relationship
path, and also for use cases like configuring loader strategies,
introduced below at Loader Strategies.  The
PropComparator.and_() method accepts a series of SQL expressions
positionally that will be joined to the ON clause of the JOIN via AND.
For example if we wanted to JOIN from ‘User’ to ‘Address’ but also limit
the ON criteria to only certain email addresses:

     >>> stmt = (
     ...   select(User.fullname).
     ...   join(User.addresses.and_(Address.email_address == 'pearl.krabs@gmail.com'))
     ... )
     >>> session.execute(stmt).all()
     {opensql}SELECT user_account.fullname
     FROM user_account
     JOIN address ON user_account.id = address.user_id AND address.email_address = ?
     [...] ('pearl.krabs@gmail.com',){stop}
     [('Pearl Krabs',)]

2.1.6.8 EXISTS forms: has() / any()
...................................

In the section EXISTS subqueries, we introduced the
Exists object that provides for the SQL EXISTS keyword in
conjunction with a scalar subquery.  The relationship()
construct provides for some helper methods that may be used to generate
some common EXISTS styles of queries in terms of the relationship.

For a one-to-many relationship such as ‘User.addresses’, an EXISTS
against the ‘address’ table that correlates back to the ‘user_account’
table can be produced using PropComparator.any().  This
method accepts an optional WHERE criteria to limit the rows matched by
the subquery:

     >>> stmt = (
     ...   select(User.fullname).
     ...   where(User.addresses.any(Address.email_address == 'pearl.krabs@gmail.com'))
     ... )
     >>> session.execute(stmt).all()
     {opensql}SELECT user_account.fullname
     FROM user_account
     WHERE EXISTS (SELECT 1
     FROM address
     WHERE user_account.id = address.user_id AND address.email_address = ?)
     [...] ('pearl.krabs@gmail.com',){stop}
     [('Pearl Krabs',)]

As EXISTS tends to be more efficient for negative lookups, a common
query is to locate entities where there are no related entities present.
This is succinct using a phrase such as ‘~User.addresses.any()’, to
select for ‘User’ entities that have no related ‘Address’ rows:

     >>> stmt = (
     ...   select(User.fullname).
     ...   where(~User.addresses.any())
     ... )
     >>> session.execute(stmt).all()
     {opensql}SELECT user_account.fullname
     FROM user_account
     WHERE NOT (EXISTS (SELECT 1
     FROM address
     WHERE user_account.id = address.user_id))
     [...] (){stop}
     [('Patrick McStar',), ('Squidward Tentacles',), ('Eugene H. Krabs',)]

The PropComparator.has() method works in mostly the same way
as PropComparator.any(), except that it’s used for
many-to-one relationships, such as if we wanted to locate all ‘Address’
objects which belonged to “pearl”:

     >>> stmt = (
     ...   select(Address.email_address).
     ...   where(Address.user.has(User.name=="pkrabs"))
     ... )
     >>> session.execute(stmt).all()
     {opensql}SELECT address.email_address
     FROM address
     WHERE EXISTS (SELECT 1
     FROM user_account
     WHERE user_account.id = address.user_id AND user_account.name = ?)
     [...] ('pkrabs',){stop}
     [('pearl.krabs@gmail.com',), ('pearl@aol.com',)]

2.1.6.9 Common Relationship Operators
.....................................

There are some additional varieties of SQL generation helpers that come
with relationship(), including:

   * `many to one equals comparison' - a specific object instance can be
     compared to many-to-one relationship, to select rows where the
     foreign key of the target entity matches the primary key value of
     the object given:

          >>> print(select(Address).where(Address.user == u1))
          {opensql}SELECT address.id, address.email_address, address.user_id
          FROM address
          WHERE :param_1 = address.user_id

   * `many to one not equals comparison' - the not equals operator may
     also be used:

          >>> print(select(Address).where(Address.user != u1))
          {opensql}SELECT address.id, address.email_address, address.user_id
          FROM address
          WHERE address.user_id != :user_id_1 OR address.user_id IS NULL

   * `object is contained in a one-to-many collection' - this is
     essentially the one-to-many version of the “equals” comparison,
     select rows where the primary key equals the value of the foreign
     key in a related object:

          >>> print(select(User).where(User.addresses.contains(a1)))
          {opensql}SELECT user_account.id, user_account.name, user_account.fullname
          FROM user_account
          WHERE user_account.id = :param_1

   * `An object has a particular parent from a one-to-many perspective'
     - the with_parent() function produces a comparison that
     returns rows which are referred towards by a given parent, this is
     essentially the same as using the ‘==’ operator with the
     many-to-one side:

          >>> from sqlalchemy.orm import with_parent
          >>> print(select(Address).where(with_parent(u1, User.addresses)))
          {opensql}SELECT address.id, address.email_address, address.user_id
          FROM address
          WHERE :param_1 = address.user_id

2.1.6.10 Loader Strategies
..........................

In the section Loading Relationships we introduced the
concept that when we work with instances of mapped objects, accessing
the attributes that are mapped using relationship() in the
default case will emit a lazy load when the collection is not populated
in order to load the objects that should be present in this collection.

Lazy loading is one of the most famous ORM patterns, and is also the one
that is most controversial.  When several dozen ORM objects in memory
each refer to a handful of unloaded attributes, routine manipulation of
these objects can spin off many additional queries that can add up
(otherwise known as the N plus one problem), and to make matters worse
they are emitted implicitly.  These implicit queries may not be noticed,
may cause errors when they are attempted after there’s no longer a
database tranasction available, or when using alternative concurrency
patterns such as asyncio, they actually won’t work at all.

At the same time, lazy loading is a vastly popular and useful pattern
when it is compatible with the concurrency approach in use and isn’t
otherwise causing problems.  For these reasons, SQLAlchemy’s ORM places
a lot of emphasis on being able to control and optimize this loading
behavior.

Above all, the first step in using ORM lazy loading effectively is to
`test the application, turn on SQL echoing, and watch the SQL that is
emitted'.  If there seem to be lots of redundant SELECT statements that
look very much like they could be rolled into one much more efficiently,
if there are loads occurring inappropriately for objects that have been
detached from their Session, that’s when to look into using
`loader strategies'.

Loader strategies are represented as objects that may be associated with
a SELECT statement using the Select.options() method, e.g.:

     for user_obj in session.execute(
         select(User).options(selectinload(User.addresses))
     ).scalars():
         user_obj.addresses  # access addresses collection already loaded

They may be also configured as defaults for a relationship()
using the relationship.lazy option, e.g.:

     from sqlalchemy.orm import relationship
     class User(Base):
         __tablename__ = 'user_account'

         addresses = relationship("Address", back_populates="user", lazy="selectin")

Each loader strategy object adds some kind of information to the
statement that will be used later by the Session when it is
deciding how various attributes should be loaded and/or behave when they
are accessed.

The sections below will introduce a few of the most prominently used
loader strategies.

See also
........

Two sections in Relationship Loading Techniques:

   * Configuring Loader Strategies at Mapping Time. - details
     on configuring the strategy on relationship().

   * Relationship Loading with Loader Options. - details on
     using query-time loader strategies

2.1.6.11 Selectin Load
......................

The most useful loader in modern SQLAlchemy is the selectinload()
loader option.  This option solves the most common form of the “N
plus one” problem which is that of a set of objects that refer to
related collections.  selectinload() will ensure that a
particular collection for a full series of objects are loaded up front
using a single query.  It does this using a SELECT form that in most
cases can be emitted against the related table alone, without the
introduction of JOINs or subqueries, and only queries for those parent
objects for which the collection isn’t already loaded.  Below we
illustrate selectinload() by loading all of the ‘User’
objects and all of their related ‘Address’ objects; while we invoke
Session.execute() only once, given a select()
construct, when the database is accessed, there are in fact two SELECT
statements emitted, the second one being to fetch the related ‘Address’
objects:

     >>> from sqlalchemy.orm import selectinload
     >>> stmt = (
     ...   select(User).options(selectinload(User.addresses)).order_by(User.id)
     ... )
     >>> for row in session.execute(stmt):
     ...     print(f"{row.User.name}  ({', '.join(a.email_address for a in row.User.addresses)})")
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account ORDER BY user_account.id
     [...] ()
     SELECT address.user_id AS address_user_id, address.id AS address_id,
     address.email_address AS address_email_address
     FROM address
     WHERE address.user_id IN (?, ?, ?, ?, ?, ?)
     [...] (1, 2, 3, 4, 5, 6){stop}
     spongebob  (spongebob@sqlalchemy.org)
     sandy  (sandy@sqlalchemy.org, sandy@squirrelpower.org)
     patrick  ()
     squidward  ()
     ehkrabs  ()
     pkrabs  (pearl.krabs@gmail.com, pearl@aol.com)

See also
........

See Select IN loading. - in Relationship Loading Techniques.

2.1.6.12 Joined Load
....................

The joinedload() eager load strategy is the oldest eager
loader in SQLAlchemy, which augments the SELECT statement that’s being
passed to the database with a JOIN (which may an outer or an inner join
depending on options), which can then load in related objects.

The joinedload() strategy is best suited towards loading
related many-to-one objects, as this only requires that additional
columns are added to a primary entity row that would be fetched in any
case.  For greater effiency, it also accepts an option
joinedload.innerjoin so that an inner join instead of an outer
join may be used for a case such as below where we know that all
‘Address’ objects have an associated ‘User’:

     >>> from sqlalchemy.orm import joinedload
     >>> stmt = (
     ...   select(Address).options(joinedload(Address.user, innerjoin=True)).order_by(Address.id)
     ... )
     >>> for row in session.execute(stmt):
     ...     print(f"{row.Address.email_address} {row.Address.user.name}")
     {opensql}SELECT address.id, address.email_address, address.user_id, user_account_1.id AS id_1,
     user_account_1.name, user_account_1.fullname
     FROM address
     JOIN user_account AS user_account_1 ON user_account_1.id = address.user_id
     ORDER BY address.id
     [...] (){stop}
     spongebob@sqlalchemy.org spongebob
     sandy@sqlalchemy.org sandy
     sandy@squirrelpower.org sandy
     pearl.krabs@gmail.com pkrabs
     pearl@aol.com pkrabs

joinedload() also works for collections, meaning one-to-many
relationships, however it has the effect of multiplying out primary rows
per related item in a recursive way that grows the amount of data sent
for a result set by orders of magnitude for nested collections and/or
larger collections, so its use vs.  another option such as
selectinload() should be evaluated on a per-case basis.

It’s important to note that the WHERE and ORDER BY criteria of the
enclosing Select statement `do not target the table rendered
by joinedload()'.  Above, it can be seen in the SQL that an `anonymous
alias' is applied to the ‘user_account’ table such that is not directly
addressible in the query.  This concept is discussed in more detail in
the section The Zen of Joined Eager Loading.

The ON clause rendered by joinedload() may be affected
directly by using the PropComparator.and_() method described
previously at Augmenting the ON Criteria; examples of this
technique with loader strategies are further below at Augmenting Loader Strategy Paths.
However, more generally, “joined eager
loading” may be applied to a Select that uses
Select.join() using the approach described in the next section,
see Explicit Join + Eager load.

     Tip: It’s important to note that many-to-one eager loads are often
     not necessary, as the “N plus one” problem is much less prevalent
     in the common case.  When many objects all refer to the same
     related object, such as many ‘Address’ objects that each refer ot
     the same ‘User’, SQL will be emitted only once for that ‘User’
     object using normal lazy loading.  The lazy load routine will look
     up the related object by primary key in the current Session
     without emitting any SQL when possible.

See also
........

See Joined Eager Loading. - in Relationship Loading Techniques.

2.1.6.13 Explicit Join + Eager load
...................................

If we were to load ‘Address’ rows while joining to the ‘user_account’
table using a method such as Select.join() to render the
JOIN, we could also leverage that JOIN in order to eagerly load the
contents of the ‘Address.user’ attribute on each ‘Address’ object
returned.  This is essentially that we are using “joined eager loading”
but rendering the JOIN ourselves.  This common use case is acheived by
using the contains_eager() option.  this option is very
similar to joinedload(), except that it assumes we have set
up the JOIN ourselves, and it instead only indicates that additional
columns in the COLUMNS clause should be loaded into related attributes
on each returned object, for example:

     >>> from sqlalchemy.orm import contains_eager
     >>> stmt = (
     ...   select(Address).
     ...   join(Address.user).
     ...   where(User.name == 'pkrabs').
     ...   options(contains_eager(Address.user)).order_by(Address.id)
     ... )
     >>> for row in session.execute(stmt):
     ...     print(f"{row.Address.email_address} {row.Address.user.name}")
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname,
     address.id AS id_1, address.email_address, address.user_id
     FROM address JOIN user_account ON user_account.id = address.user_id
     WHERE user_account.name = ? ORDER BY address.id
     [...] ('pkrabs',){stop}
     pearl.krabs@gmail.com pkrabs
     pearl@aol.com pkrabs

Above, we both filtered the rows on ‘user_account.name’ and also loaded
rows from ‘user_account’ into the ‘Address.user’ attribute of the
returned rows.  If we had applied joinedload() separately,
we would get a SQL query that unnecessarily joins twice:

     >>> stmt = (
     ...   select(Address).
     ...   join(Address.user).
     ...   where(User.name == 'pkrabs').
     ...   options(joinedload(Address.user)).order_by(Address.id)
     ... )
     >>> print(stmt)  # SELECT has a JOIN and LEFT OUTER JOIN unnecessarily
     {opensql}SELECT address.id, address.email_address, address.user_id,
     user_account_1.id AS id_1, user_account_1.name, user_account_1.fullname
     FROM address JOIN user_account ON user_account.id = address.user_id
     LEFT OUTER JOIN user_account AS user_account_1 ON user_account_1.id = address.user_id
     WHERE user_account.name = :name_1 ORDER BY address.id

See also
........

Two sections in Relationship Loading Techniques:

   * The Zen of Joined Eager Loading. - describes the above
     problem in detail

   * Routing Explicit Joins/Statements into Eagerly Loaded Collections.
     - using contains_eager().

2.1.6.14 Augmenting Loader Strategy Paths
.........................................

In Augmenting the ON Criteria we illustrated how to add
arbitrary criteria to a JOIN rendered with relationship() to
also include additional criteria in the ON clause.  The
PropComparator.and_() method is in fact generally available for
most loader options.  For example, if we wanted to re-load the names of
users and their email addresses, but omitting the email addresses with
the ‘sqlalchemy.org’ domain, we can apply PropComparator.and_()
to the argument passed to selectinload() to limit this
criteria:

     >>> from sqlalchemy.orm import selectinload
     >>> stmt = (
     ...   select(User).
     ...   options(
     ...       selectinload(
     ...           User.addresses.and_(
     ...             ~Address.email_address.endswith("sqlalchemy.org")
     ...           )
     ...       )
     ...   ).
     ...   order_by(User.id).
     ...   execution_options(populate_existing=True)
     ... )
     >>> for row in session.execute(stmt):
     ...     print(f"{row.User.name}  ({', '.join(a.email_address for a in row.User.addresses)})")
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account ORDER BY user_account.id
     [...] ()
     SELECT address.user_id AS address_user_id, address.id AS address_id,
     address.email_address AS address_email_address
     FROM address
     WHERE address.user_id IN (?, ?, ?, ?, ?, ?)
     AND (address.email_address NOT LIKE '%' || ?)
     [...] (1, 2, 3, 4, 5, 6, 'sqlalchemy.org'){stop}
     spongebob  ()
     sandy  (sandy@squirrelpower.org)
     patrick  ()
     squidward  ()
     ehkrabs  ()
     pkrabs  (pearl.krabs@gmail.com, pearl@aol.com)

A very important thing to note above is that a special option is added
with ‘.execution_options(populate_existing=True)’.  This option which
takes effect when rows are being fetched indicates that the loader
option we are using should `replace' the existing contents of
collections on the objects, if they are already loaded.  As we are
working with a single Session repeatedly, the objects we see
being loaded above are the same Python instances as those that were
first persisted at the start of the ORM section of this tutorial.

See also
........

See Adding Criteria to loader options. - in Relationship Loading Techniques.

See Populate Existing. - in ORM Querying Guide.

2.1.6.15 Raiseload
..................

One additional loader strategy worth mentioning is raiseload().
This option is used to completely block an application from having
the N plus one problem at all by causing what would normally be a lazy
load to raise an error instead.  It has two variants that are controlled
via the raiseload.sql_only option to block either lazy loads
that require SQL, versus all “load” operations including those which
only need to consult the current Session.

One way to use raiseload() is to configure it on
relationship() itself, by setting relationship.lazy to
the value ‘"raise_on_sql"’, so that for a particular mapping, a certain
relationship will never try to emit SQL:

     class User(Base):
         __tablename__ = 'user_account'

         # ... Column mappings

         addresses = relationship("Address", back_populates="user", lazy="raise_on_sql")

     class Address(Base):
         __tablename__ = 'address'

         # ... Column mappings

         user = relationship("User", back_populates="addresses", lazy="raise_on_sql")

Using such a mapping, the application is blocked from lazy loading,
indicating that a particular query would need to specify a loader
strategy:

     u1 = s.execute(select(User)).scalars().first()
     u1.addresses
     sqlalchemy.exc.InvalidRequestError: 'User.addresses' is not available due to lazy='raise_on_sql'

The exception would indicate that this collection should be loaded up
front instead:

     u1 = s.execute(select(User).options(selectinload(User.addresses))).scalars().first()

The ‘lazy="raise_on_sql"’ option tries to be smart about many-to-one
relationships as well; above, if the ‘Address.user’ attribute of an
‘Address’ object were not loaded, but that ‘User’ object were locally
present in the same Session, the “raiseload” strategy would
not raise an error.

See also
........

See Preventing unwanted lazy loads using raiseload. - in
Relationship Loading Techniques.

SQLAlchemy 1.4 / 2.0 Tutorial
.............................

Next Tutorial Section: Further Reading.

SQLAlchemy 1.4 / 2.0 Tutorial
.............................

This page is part of the SQLAlchemy 1.4 / 2.0 Tutorial.

Previous: Working with Related Objects.

2.1.7 Further Reading
---------------------

The sections below are the major top-level sections that discuss the
concepts in this tutorial in much more detail, as well as describe many
more features of each subsystem.

Core Essential Reference

   * Working with Engines and Connections.

   * Schema Definition Language.

   * SQL Statements and Expressions API.

   * Column and Data Types.

ORM Essential Reference

   * Mapper Configuration.

   * Relationship Configuration.

   * Using the Session.

   * Querying Data, Loading Objects.

   * Establishing Connectivity - the Engine. - all SQLAlchemy
     applications start with an Engine object; here’s how to
     create one.

   * Working with Transactions and the DBAPI. - the usage API
     of the Engine and it’s related objects
     Connection and Result are presented here.  This
     content is Core-centric however ORM users will want to be familiar
     with at least the Result object.

   * Working with Database Metadata. - SQLAlchemy’s SQL
     abstractions as well as the ORM rely upon a system of defining
     database schema constructs as Python objects.  This section
     introduces how to do that from both a Core and an ORM perspective.

   * Working with Data. - here we learn how to create, select,
     update and delete data in the database.  The so-called CRUD
     operations here are given in terms of SQLAlchemy Core with links
     out towards their ORM counterparts.  The SELECT operation that is
     introduced in detail at Selecting Data applies equally
     well to Core and ORM.

   * Data Manipulation with the ORM covers the persistence
     framework of the ORM; basically the ORM-centric ways to insert,
     update and delete, as well as how to handle transactions.

   * Working with Related Objects introduces the concept of
     the relationship() construct and provides a brief
     overview of how it’s used, with links to deeper documentation.

   * Further Reading lists a series of major top-level
     documentation sections which fully documents the concepts
     introduced in this tutorial.

2.1.8 Version Check
-------------------

This tutorial is written using a system called doctest(1).  All of the
code excerpts written with a ‘>>>’ are actually run as part of
SQLAlchemy’s test suite, and the reader is invited to work with the code
examples given in real time with their own Python interpreter.

If running the examples, it is advised that the reader perform quick
check to verify that we are on `version 1.4' of SQLAlchemy:

     >>> import sqlalchemy
     >>> sqlalchemy.__version__  # doctest: +SKIP
     1.4.0

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/doctest.html

2.1.9 A Note on the Future
--------------------------

This tutorial describes a new API that’s released in SQLAlchemy 1.4
known as 2.0 style.  The purpose of the 2.0-style API is to provide
forwards compatibility with SQLAlchemy 2.0, which is planned
as the next generation of SQLAlchemy.

In order to provide the full 2.0 API, a new flag called ‘future’ will be
used, which will be seen as the tutorial describes the Engine
and Session objects.  These flags fully enable
2.0-compatibility mode and allow the code in the tutorial to proceed
fully.  When using the ‘future’ flag with the create_engine()
function, the object returned is a sublass of
sqlalchemy.engine.Engine described as
sqlalchemy.future.Engine.  This tutorial will be referring to
sqlalchemy.future.Engine.

SQLAlchemy 1.4 / 2.0 Tutorial
=============================

Next Section: Establishing Connectivity - the Engine.

3 SQLAlchemy ORM
****************

Here, the Object Relational Mapper is introduced and fully described.
If you want to work with higher-level SQL which is constructed
automatically for you, as well as automated persistence of Python
objects, proceed first to the tutorial.

3.1 Object Relational Tutorial (1.x API)
========================================

     About this document: This tutorial covers the well known SQLAlchemy
     ORM API that has been in use for many years.  As of SQLAlchemy 1.4,
     there are two distinct styles of ORM use known as 1.x style and 2.0
     style, the latter of which makes a wide range of changes most
     prominently around how ORM queries are constructed and executed.

     The plan is that in SQLAlchemy 2.0, the 1.x style of ORM use will
     be considered legacy and no longer featured in documentation and
     many aspects of it will be removed.  However, the most central
     element of 1.x style ORM use, the Query object, will
     still remain available for long-term legacy use cases.

     This tutorial is applicable to users who want to learn how
     SQLAlchemy has been used for many years, particularly those users
     working with existing applications or related learning material
     that is in 1.x style.

     For an introduction to SQLAlchemy from the new 1.4/2.0 perspective,
     see SQLAlchemy 1.4 / 2.0 Tutorial.

     See also
     ........

     See ORM Query is internally unified with select, update, delete; 2.0 style execution available.

     See Migrating to SQLAlchemy 2.0.

     See SQLAlchemy 1.4 / 2.0 Tutorial.

The SQLAlchemy Object Relational Mapper presents a method of associating
user-defined Python classes with database tables, and instances of those
classes (objects) with rows in their corresponding tables.  It includes
a system that transparently synchronizes all changes in state between
objects and their related rows, called a unit of work, as well as a
system for expressing database queries in terms of the user defined
classes and their defined relationships between each other.

The ORM is in contrast to the SQLAlchemy Expression Language, upon which
the ORM is constructed.  Whereas the SQL Expression Language, introduced
in SQL Expression Language Tutorial (1.x API), presents a
system of representing the primitive constructs of the relational
database directly without opinion, the ORM presents a high level and
abstracted pattern of usage, which itself is an example of applied usage
of the Expression Language.

While there is overlap among the usage patterns of the ORM and the
Expression Language, the similarities are more superficial than they may
at first appear.  One approaches the structure and content of data from
the perspective of a user-defined domain model which is transparently
persisted and refreshed from its underlying storage model.  The other
approaches it from the perspective of literal schema and SQL expression
representations which are explicitly composed into messages consumed
individually by the database.

A successful application may be constructed using the Object Relational
Mapper exclusively.  In advanced situations, an application constructed
with the ORM may make occasional usage of the Expression Language
directly in certain areas where specific database interactions are
required.

The following tutorial is in doctest format, meaning each ‘>>>’ line
represents something you can type at a Python command prompt, and the
following text represents the expected return value.

3.1.1 Version Check
-------------------

A quick check to verify that we are on at least `version 1.4' of
SQLAlchemy:

     >>> import sqlalchemy
     >>> sqlalchemy.__version__
     1.4.0

3.1.2 Connecting
----------------

For this tutorial we will use an in-memory-only SQLite database.  To
connect we use create_engine():

     >>> from sqlalchemy import create_engine
     >>> engine = create_engine('sqlite:///:memory:', echo=True)

The ‘echo’ flag is a shortcut to setting up SQLAlchemy logging, which is
accomplished via Python’s standard ‘logging’ module.  With it enabled,
we’ll see all the generated SQL produced.  If you are working through
this tutorial and want less output generated, set it to ‘False’.  This
tutorial will format the SQL behind a popup window so it doesn’t get in
our way; just click the “SQL” links to see what’s being generated.

The return value of create_engine() is an instance of
Engine, and it represents the core interface to the database,
adapted through a dialect that handles the details of the database and
DBAPI in use.  In this case the SQLite dialect will interpret
instructions to the Python built-in ‘sqlite3’ module.

Lazy Connecting
...............

The Engine, when first returned by create_engine(),
has not actually tried to connect to the database yet; that happens only
the first time it is asked to perform a task against the database.

The first time a method like Engine.execute() or
Engine.connect() is called, the Engine establishes a
real DBAPI connection to the database, which is then used to emit the
SQL. When using the ORM, we typically don’t use the Engine
directly once created; instead, it’s used behind the scenes by the ORM
as we’ll see shortly.

See also
........

See Database Urls. - includes examples of create_engine()
connecting to several kinds of databases with links to more
information.

3.1.3 Declare a Mapping
-----------------------

When using the ORM, the configurational process starts by describing the
database tables we’ll be dealing with, and then by defining our own
classes which will be mapped to those tables.  In modern SQLAlchemy,
these two tasks are usually performed together, using a system known as
Declarative Extensions, which allows us to create classes
that include directives to describe the actual database table they will
be mapped to.

Classes mapped using the Declarative system are defined in terms of a
base class which maintains a catalog of classes and tables relative to
that base - this is known as the `declarative base class'.  Our
application will usually have just one instance of this base in a
commonly imported module.  We create the base class using the
declarative_base() function, as follows:

     >>> from sqlalchemy.orm import declarative_base

     >>> Base = declarative_base()

Now that we have a “base”, we can define any number of mapped classes in
terms of it.  We will start with just a single table called ‘users’,
which will store records for the end-users using our application.  A new
class called ‘User’ will be the class to which we map this table.
Within the class, we define details about the table to which we’ll be
mapping, primarily the table name, and names and datatypes of columns:

     >>> from sqlalchemy import Column, Integer, String
     >>> class User(Base):
     ...     __tablename__ = 'users'
     ...
     ...     id = Column(Integer, primary_key=True)
     ...     name = Column(String)
     ...     fullname = Column(String)
     ...     nickname = Column(String)
     ...
     ...     def __repr__(self):
     ...        return "<User(name='%s', fullname='%s', nickname='%s')>" % (
     ...                             self.name, self.fullname, self.nickname)

Tip
...

The ‘User’ class defines a ‘__repr__()’ method, but note that is
`optional'; we only implement it in this tutorial so that our examples
show nicely formatted ‘User’ objects.

A class using Declarative at a minimum needs a ‘__tablename__’
attribute, and at least one Column which is part of a primary
key (1).  SQLAlchemy never makes any assumptions by itself about the
table to which a class refers, including that it has no built-in
conventions for names, datatypes, or constraints.  But this doesn’t mean
boilerplate is required; instead, you’re encouraged to create your own
automated conventions using helper functions and mixin classes, which is
described in detail at Mixin and Custom Base Classes.

When our class is constructed, Declarative replaces all the
Column objects with special Python accessors known as descriptors;
this is a process known as instrumentation.  The “instrumented” mapped
class will provide us with the means to refer to our table in a SQL
context as well as to persist and load the values of columns from the
database.

Outside of what the mapping process does to our class, the class remains
otherwise mostly a normal Python class, to which we can define any
number of ordinary attributes and methods needed by our application.

   ---------- Footnotes ----------

   (1) (1) For information on why a primary key is required, see
How do I map a table that has no primary key?.

3.1.4 Create a Schema
---------------------

With our ‘User’ class constructed via the Declarative system, we have
defined information about our table, known as table metadata.  The
object used by SQLAlchemy to represent this information for a specific
table is called the Table object, and here Declarative has
made one for us.  We can see this object by inspecting the ‘__table__’
attribute:

     >>> User.__table__
     Table('users', MetaData(),
                 Column('id', Integer(), table=<users>, primary_key=True, nullable=False),
                 Column('name', String(), table=<users>),
                 Column('fullname', String(), table=<users>),
                 Column('nickname', String(), table=<users>), schema=None)

Classical Mappings
..................

The Declarative system, though highly recommended, is not required in
order to use SQLAlchemy’s ORM. Outside of Declarative, any plain Python
class can be mapped to any Table using the mapper()
function directly; this less common usage is described at
Imperative (a.k.a. Classical) Mappings.

When we declared our class, Declarative used a Python metaclass in order
to perform additional activities once the class declaration was
complete; within this phase, it then created a Table object
according to our specifications, and associated it with the class by
constructing a Mapper object.  This object is a
behind-the-scenes object we normally don’t need to deal with directly
(though it can provide plenty of information about our mapping when we
need it).

The Table object is a member of a larger collection known as
MetaData.  When using Declarative, this object is available
using the ‘.metadata’ attribute of our declarative base class.

The MetaData is a registry which includes the ability to emit
a limited set of schema generation commands to the database.  As our
SQLite database does not actually have a ‘users’ table present, we can
use MetaData to issue CREATE TABLE statements to the database
for all tables that don’t yet exist.  Below, we call the
MetaData.create_all() method, passing in our Engine as
a source of database connectivity.  We will see that special commands
are first emitted to check for the presence of the ‘users’ table, and
following that the actual ‘CREATE TABLE’ statement:

     >>> Base.metadata.create_all(engine)
     BEGIN...
     CREATE TABLE users (
         id INTEGER NOT NULL,
         name VARCHAR,
         fullname VARCHAR,
         nickname VARCHAR,
         PRIMARY KEY (id)
     )
     [...] ()
     COMMIT

Minimal Table Descriptions vs. Full Descriptions
................................................

Users familiar with the syntax of CREATE TABLE may notice that the
VARCHAR columns were generated without a length; on SQLite and
PostgreSQL, this is a valid datatype, but on others, it’s not allowed.
So if running this tutorial on one of those databases, and you wish to
use SQLAlchemy to issue CREATE TABLE, a “length” may be provided to the
String type as below:

     Column(String(50))

The length field on String, as well as similar precision/scale
fields available on Integer, Numeric, etc.  are not
referenced by SQLAlchemy other than when creating tables.

Additionally, Firebird and Oracle require sequences to generate new
primary key identifiers, and SQLAlchemy doesn’t generate or assume these
without being instructed.  For that, you use the Sequence
construct:

     from sqlalchemy import Sequence
     Column(Integer, Sequence('user_id_seq'), primary_key=True)

A full, foolproof Table generated via our declarative mapping
is therefore:

     class User(Base):
         __tablename__ = 'users'
         id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
         name = Column(String(50))
         fullname = Column(String(50))
         nickname = Column(String(50))

         def __repr__(self):
             return "<User(name='%s', fullname='%s', nickname='%s')>" % (
                                     self.name, self.fullname, self.nickname)

We include this more verbose table definition separately to highlight
the difference between a minimal construct geared primarily towards
in-Python usage only, versus one that will be used to emit CREATE TABLE
statements on a particular set of backends with more stringent
requirements.

3.1.5 Create an Instance of the Mapped Class
--------------------------------------------

With mappings complete, let’s now create and inspect a ‘User’ object:

     >>> ed_user = User(name='ed', fullname='Ed Jones', nickname='edsnickname')
     >>> ed_user.name
     'ed'
     >>> ed_user.nickname
     'edsnickname'
     >>> str(ed_user.id)
     'None'

the __init__() method
.....................

Our ‘User’ class, as defined using the Declarative system, has been
provided with a constructor (e.g.  ‘__init__()’ method) which
automatically accepts keyword names that match the columns we’ve mapped.
We are free to define any explicit ‘__init__()’ method we prefer on our
class, which will override the default method provided by Declarative.

Even though we didn’t specify it in the constructor, the ‘id’ attribute
still produces a value of ‘None’ when we access it (as opposed to
Python’s usual behavior of raising ‘AttributeError’ for an undefined
attribute).  SQLAlchemy’s instrumentation normally produces this default
value for column-mapped attributes when first accessed.  For those
attributes where we’ve actually assigned a value, the instrumentation
system is tracking those assignments for use within an eventual INSERT
statement to be emitted to the database.

3.1.6 Creating a Session
------------------------

We’re now ready to start talking to the database.  The ORM’s “handle” to
the database is the ‘Session’.  When we first set up the application, at
the same level as our create_engine() statement, we define a
‘Session’ class which will serve as a factory for new ‘Session’ objects:

     >>> from sqlalchemy.orm import sessionmaker
     >>> Session = sessionmaker(bind=engine)

In the case where your application does not yet have an Engine
when you define your module-level objects, just set it up like
this:

     >>> Session = sessionmaker()

Later, when you create your engine with create_engine(),
connect it to the ‘Session’ using sessionmaker.configure():

     >>> Session.configure(bind=engine)  # once engine is available

Session Lifecycle Patterns
..........................

The question of when to make a Session depends a lot on what
kind of application is being built.  Keep in mind, the Session
is just a workspace for your objects, local to a particular database
connection - if you think of an application thread as a guest at a
dinner party, the Session is the guest’s plate and the
objects it holds are the food (and the database…the kitchen?)!  More on
this topic available at When do I construct a Session, when do I commit it, and when do I close it?.

This custom-made ‘Session’ class will create new ‘Session’ objects which
are bound to our database.  Other transactional characteristics may be
defined when calling sessionmaker as well; these are
described in a later chapter.  Then, whenever you need to have a
conversation with the database, you instantiate a ‘Session’:

     >>> session = Session()

The above ‘Session’ is associated with our SQLite-enabled Engine,
but it hasn’t opened any connections yet.  When it’s first used, it
retrieves a connection from a pool of connections maintained by the
Engine, and holds onto it until we commit all changes and/or
close the session object.

3.1.7 Adding and Updating Objects
---------------------------------

To persist our ‘User’ object, we Session.add() it to our
‘Session’:

     >>> ed_user = User(name='ed', fullname='Ed Jones', nickname='edsnickname')
     >>> session.add(ed_user)

At this point, we say that the instance is `pending'; no SQL has yet
been issued and the object is not yet represented by a row in the
database.  The ‘Session’ will issue the SQL to persist ‘Ed Jones’ as
soon as is needed, using a process known as a `flush'.  If we query the
database for ‘Ed Jones’, all pending information will first be flushed,
and the query is issued immediately thereafter.

For example, below we create a new ‘Query’ object which loads instances
of ‘User’.  We “filter by” the ‘name’ attribute of ‘ed’, and indicate
that we’d like only the first result in the full list of rows.  A ‘User’
instance is returned which is equivalent to that which we’ve added:

     {sql}>>> our_user = session.query(User).filter_by(name='ed').first() # doctest:+NORMALIZE_WHITESPACE
     BEGIN (implicit)
     INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
     [...] ('ed', 'Ed Jones', 'edsnickname')
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname
     FROM users
     WHERE users.name = ?
      LIMIT ? OFFSET ?
     [...] ('ed', 1, 0)
     {stop}>>> our_user
     <User(name='ed', fullname='Ed Jones', nickname='edsnickname')>

In fact, the ‘Session’ has identified that the row returned is the
`same' row as one already represented within its internal map of
objects, so we actually got back the identical instance as that which we
just added:

     >>> ed_user is our_user
     True

The ORM concept at work here is known as an identity map and ensures
that all operations upon a particular row within a ‘Session’ operate
upon the same set of data.  Once an object with a particular primary key
is present in the ‘Session’, all SQL queries on that ‘Session’ will
always return the same Python object for that particular primary key; it
also will raise an error if an attempt is made to place a second,
already-persisted object with the same primary key within the session.

We can add more ‘User’ objects at once using ‘add_all()’:

     >>> session.add_all([
     ...     User(name='wendy', fullname='Wendy Williams', nickname='windy'),
     ...     User(name='mary', fullname='Mary Contrary', nickname='mary'),
     ...     User(name='fred', fullname='Fred Flintstone', nickname='freddy')])

Also, we’ve decided Ed’s nickname isn’t that great, so lets change it:

     >>> ed_user.nickname = 'eddie'

The ‘Session’ is paying attention.  It knows, for example, that ‘Ed
Jones’ has been modified:

     >>> session.dirty
     IdentitySet([<User(name='ed', fullname='Ed Jones', nickname='eddie')>])

and that three new ‘User’ objects are pending:

     >>> session.new  # doctest: +SKIP
     IdentitySet([<User(name='wendy', fullname='Wendy Williams', nickname='windy')>,
     <User(name='mary', fullname='Mary Contrary', nickname='mary')>,
     <User(name='fred', fullname='Fred Flintstone', nickname='freddy')>])

We tell the ‘Session’ that we’d like to issue all remaining changes to
the database and commit the transaction, which has been in progress
throughout.  We do this via Session.commit().  The ‘Session’
emits the ‘UPDATE’ statement for the nickname change on “ed”, as well as
‘INSERT’ statements for the three new ‘User’ objects we’ve added:

     {sql}>>> session.commit()
     UPDATE users SET nickname=? WHERE users.id = ?
     [...] ('eddie', 1)
     INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
     [...] ('wendy', 'Wendy Williams', 'windy')
     INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
     [...] ('mary', 'Mary Contrary', 'mary')
     INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
     [...] ('fred', 'Fred Flintstone', 'freddy')
     COMMIT

Session.commit() flushes the remaining changes to the
database, and commits the transaction.  The connection resources
referenced by the session are now returned to the connection pool.
Subsequent operations with this session will occur in a `new'
transaction, which will again re-acquire connection resources when first
needed.

If we look at Ed’s ‘id’ attribute, which earlier was ‘None’, it now has
a value:

     {sql}>>> ed_user.id # doctest: +NORMALIZE_WHITESPACE
     BEGIN (implicit)
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname
     FROM users
     WHERE users.id = ?
     [...] (1,)
     {stop}1

After the ‘Session’ inserts new rows in the database, all newly
generated identifiers and database-generated defaults become available
on the instance, either immediately or via load-on-first-access.  In
this case, the entire row was re-loaded on access because a new
transaction was begun after we issued Session.commit().
SQLAlchemy by default refreshes data from a previous transaction the
first time it’s accessed within a new transaction, so that the most
recent state is available.  The level of reloading is configurable as is
described in Using the Session.

Session Object States
.....................

As our ‘User’ object moved from being outside the Session, to
inside the Session without a primary key, to actually being
inserted, it moved between three out of five available “object states” -
`transient', `pending', and `persistent'.  Being aware of these states
and what they mean is always a good idea - be sure to read Quickie Intro to Object States
for a quick overview.

3.1.8 Rolling Back
------------------

Since the ‘Session’ works within a transaction, we can roll back changes
made too.  Let’s make two changes that we’ll revert; ‘ed_user’’s user
name gets set to ‘Edwardo’:

     >>> ed_user.name = 'Edwardo'

and we’ll add another erroneous user, ‘fake_user’:

     >>> fake_user = User(name='fakeuser', fullname='Invalid', nickname='12345')
     >>> session.add(fake_user)

Querying the session, we can see that they’re flushed into the current
transaction:

     {sql}>>> session.query(User).filter(User.name.in_(['Edwardo', 'fakeuser'])).all()
     UPDATE users SET name=? WHERE users.id = ?
     [...] ('Edwardo', 1)
     INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
     [...] ('fakeuser', 'Invalid', '12345')
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname
     FROM users
     WHERE users.name IN (?, ?)
     [...] ('Edwardo', 'fakeuser')
     {stop}[<User(name='Edwardo', fullname='Ed Jones', nickname='eddie')>, <User(name='fakeuser', fullname='Invalid', nickname='12345')>]

Rolling back, we can see that ‘ed_user’’s name is back to ‘ed’, and
‘fake_user’ has been kicked out of the session:

     {sql}>>> session.rollback()
     ROLLBACK
     {stop}

     {sql}>>> ed_user.name
     BEGIN (implicit)
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname
     FROM users
     WHERE users.id = ?
     [...] (1,)
     {stop}u'ed'
     >>> fake_user in session
     False

issuing a SELECT illustrates the changes made to the database:

     {sql}>>> session.query(User).filter(User.name.in_(['ed', 'fakeuser'])).all()
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname
     FROM users
     WHERE users.name IN (?, ?)
     [...] ('ed', 'fakeuser')
     {stop}[<User(name='ed', fullname='Ed Jones', nickname='eddie')>]

3.1.9 Querying
--------------

A ‘Query’ object is created using the ‘query()’ method on ‘Session’.
This function takes a variable number of arguments, which can be any
combination of classes and class-instrumented descriptors.  Below, we
indicate a ‘Query’ which loads ‘User’ instances.  When evaluated in an
iterative context, the list of ‘User’ objects present is returned:

     {sql}>>> for instance in session.query(User).order_by(User.id):
     ...     print(instance.name, instance.fullname)
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname
     FROM users ORDER BY users.id
     [...] ()
     {stop}ed Ed Jones
     wendy Wendy Williams
     mary Mary Contrary
     fred Fred Flintstone

The ‘Query’ also accepts ORM-instrumented descriptors as arguments.  Any
time multiple class entities or column-based entities are expressed as
arguments to the ‘query()’ function, the return result is expressed as
tuples:

     {sql}>>> for name, fullname in session.query(User.name, User.fullname):
     ...     print(name, fullname)
     SELECT users.name AS users_name,
             users.fullname AS users_fullname
     FROM users
     [...] ()
     {stop}ed Ed Jones
     wendy Wendy Williams
     mary Mary Contrary
     fred Fred Flintstone

The tuples returned by ‘Query’ are `named' tuples, supplied by the
Row class, and can be treated much like an ordinary Python object.
The names are the same as the attribute’s name for an attribute, and the
class name for a class:

     {sql}>>> for row in session.query(User, User.name).all():
     ...    print(row.User, row.name)
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname
     FROM users
     [...] ()
     {stop}<User(name='ed', fullname='Ed Jones', nickname='eddie')> ed
     <User(name='wendy', fullname='Wendy Williams', nickname='windy')> wendy
     <User(name='mary', fullname='Mary Contrary', nickname='mary')> mary
     <User(name='fred', fullname='Fred Flintstone', nickname='freddy')> fred

You can control the names of individual column expressions using the
ColumnElement.label() construct, which is available from any
ColumnElement.-derived object, as well as any class attribute
which is mapped to one (such as ‘User.name’):

     {sql}>>> for row in session.query(User.name.label('name_label')).all():
     ...    print(row.name_label)
     SELECT users.name AS name_label
     FROM users
     [...] (){stop}
     ed
     wendy
     mary
     fred

The name given to a full entity such as ‘User’, assuming that multiple
entities are present in the call to Session.query(), can be
controlled using aliased(). :

     >>> from sqlalchemy.orm import aliased
     >>> user_alias = aliased(User, name='user_alias')

     {sql}>>> for row in session.query(user_alias, user_alias.name).all():
     ...    print(row.user_alias)
     SELECT user_alias.id AS user_alias_id,
             user_alias.name AS user_alias_name,
             user_alias.fullname AS user_alias_fullname,
             user_alias.nickname AS user_alias_nickname
     FROM users AS user_alias
     [...] (){stop}
     <User(name='ed', fullname='Ed Jones', nickname='eddie')>
     <User(name='wendy', fullname='Wendy Williams', nickname='windy')>
     <User(name='mary', fullname='Mary Contrary', nickname='mary')>
     <User(name='fred', fullname='Fred Flintstone', nickname='freddy')>

Basic operations with ‘Query’ include issuing LIMIT and OFFSET, most
conveniently using Python array slices and typically in conjunction with
ORDER BY:

     {sql}>>> for u in session.query(User).order_by(User.id)[1:3]:
     ...    print(u)
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname
     FROM users ORDER BY users.id
     LIMIT ? OFFSET ?
     [...] (2, 1){stop}
     <User(name='wendy', fullname='Wendy Williams', nickname='windy')>
     <User(name='mary', fullname='Mary Contrary', nickname='mary')>

and filtering results, which is accomplished either with ‘filter_by()’,
which uses keyword arguments:

     {sql}>>> for name, in session.query(User.name).\
     ...             filter_by(fullname='Ed Jones'):
     ...    print(name)
     SELECT users.name AS users_name FROM users
     WHERE users.fullname = ?
     [...] ('Ed Jones',)
     {stop}ed

…or ‘filter()’, which uses more flexible SQL expression language
constructs.  These allow you to use regular Python operators with the
class-level attributes on your mapped class:

     {sql}>>> for name, in session.query(User.name).\
     ...             filter(User.fullname=='Ed Jones'):
     ...    print(name)
     SELECT users.name AS users_name FROM users
     WHERE users.fullname = ?
     [...] ('Ed Jones',)
     {stop}ed

The ‘Query’ object is fully `generative', meaning that most method calls
return a new ‘Query’ object upon which further criteria may be added.
For example, to query for users named “ed” with a full name of “Ed
Jones”, you can call ‘filter()’ twice, which joins criteria using ‘AND’:

     {sql}>>> for user in session.query(User).\
     ...          filter(User.name=='ed').\
     ...          filter(User.fullname=='Ed Jones'):
     ...    print(user)
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname
     FROM users
     WHERE users.name = ? AND users.fullname = ?
     [...] ('ed', 'Ed Jones')
     {stop}<User(name='ed', fullname='Ed Jones', nickname='eddie')>

3.1.9.1 Common Filter Operators
...............................

Here’s a rundown of some of the most common operators used in
‘filter()’:

   * ColumnOperators.__eq__():

          query.filter(User.name == 'ed')

   * ColumnOperators.__ne__():

          query.filter(User.name != 'ed')

   * ColumnOperators.like():

          query.filter(User.name.like('%ed%'))

          Note: ColumnOperators.like() renders the LIKE
          operator, which is case insensitive on some backends, and case
          sensitive on others.  For guaranteed case-insensitive
          comparisons, use ColumnOperators.ilike().

   * ColumnOperators.ilike(). (case-insensitive LIKE):

          query.filter(User.name.ilike('%ed%'))

          Note: most backends don’t support ILIKE directly.  For those,
          the ColumnOperators.ilike() operator renders an
          expression combining LIKE with the LOWER SQL function applied
          to each operand.

   * ColumnOperators.in_():

          query.filter(User.name.in_(['ed', 'wendy', 'jack']))

          # works with query objects too:
          query.filter(User.name.in_(
              session.query(User.name).filter(User.name.like('%ed%'))
          ))

          # use tuple_() for composite (multi-column) queries
          from sqlalchemy import tuple_
          query.filter(
              tuple_(User.name, User.nickname).\
              in_([('ed', 'edsnickname'), ('wendy', 'windy')])
          )

   * ColumnOperators.not_in():

          query.filter(~User.name.in_(['ed', 'wendy', 'jack']))

   * ColumnOperators.is_():

          query.filter(User.name == None)

          # alternatively, if pep8/linters are a concern
          query.filter(User.name.is_(None))

   * ColumnOperators.is_not():

          query.filter(User.name != None)

          # alternatively, if pep8/linters are a concern
          query.filter(User.name.is_not(None))

   * AND:

          # use and_()
          from sqlalchemy import and_
          query.filter(and_(User.name == 'ed', User.fullname == 'Ed Jones'))

          # or send multiple expressions to .filter()
          query.filter(User.name == 'ed', User.fullname == 'Ed Jones')

          # or chain multiple filter()/filter_by() calls
          query.filter(User.name == 'ed').filter(User.fullname == 'Ed Jones')

          Note: Make sure you use and_() and `not' the Python
          ‘and’ operator!

   * OR:

          from sqlalchemy import or_
          query.filter(or_(User.name == 'ed', User.name == 'wendy'))

          Note: Make sure you use or_() and `not' the Python
          ‘or’ operator!

   * ColumnOperators.match():

          query.filter(User.name.match('wendy'))

          Note: ColumnOperators.match() uses a
          database-specific ‘MATCH’ or ‘CONTAINS’ function; its behavior
          will vary by backend and is not available on some backends
          such as SQLite.

3.1.9.2 Returning Lists and Scalars
...................................

A number of methods on Query immediately issue SQL and
return a value containing loaded database results.  Here’s a brief tour:

   * Query.all() returns a list:

          >>> query = session.query(User).filter(User.name.like('%ed')).order_by(User.id)
          {sql}>>> query.all()
          SELECT users.id AS users_id,
                  users.name AS users_name,
                  users.fullname AS users_fullname,
                  users.nickname AS users_nickname
          FROM users
          WHERE users.name LIKE ? ORDER BY users.id
          [...] ('%ed',)
          {stop}[<User(name='ed', fullname='Ed Jones', nickname='eddie')>,
                <User(name='fred', fullname='Fred Flintstone', nickname='freddy')>]

          Warning: When the Query object returns lists of
          ORM-mapped objects such as the ‘User’ object above, the
          entries are `deduplicated' based on primary key, as the
          results are interpreted from the SQL result set.  That is, if
          SQL query returns a row with ‘id=7’ twice, you would only get
          a single ‘User(id=7)’ object back in the result list.  This
          does not apply to the case when individual columns are
          queried.

          See also
          ........

          See My Query does not return the same number of objects as query.count() tells me - why?.

   * Query.first() applies a limit of one and returns the
     first result as a scalar:

          {sql}>>> query.first()
          SELECT users.id AS users_id,
                  users.name AS users_name,
                  users.fullname AS users_fullname,
                  users.nickname AS users_nickname
          FROM users
          WHERE users.name LIKE ? ORDER BY users.id
           LIMIT ? OFFSET ?
          [...] ('%ed', 1, 0)
          {stop}<User(name='ed', fullname='Ed Jones', nickname='eddie')>

   * Query.one() fully fetches all rows, and if not exactly
     one object identity or composite row is present in the result,
     raises an error.  With multiple rows found:

          >>> user = query.one()
          Traceback (most recent call last):
          ...
          MultipleResultsFound: Multiple rows were found for one()

     With no rows found:

          >>> user = query.filter(User.id == 99).one()
          Traceback (most recent call last):
          ...
          NoResultFound: No row was found for one()

     The Query.one() method is great for systems that expect
     to handle “no items found” versus “multiple items found”
     differently; such as a RESTful web service, which may want to raise
     a “404 not found” when no results are found, but raise an
     application error when multiple results are found.

   * Query.one_or_none() is like Query.one(),
     except that if no results are found, it doesn’t raise an error; it
     just returns ‘None’.  Like Query.one(), however, it does
     raise an error if multiple results are found.

   * Query.scalar() invokes the Query.one().
     method, and upon success returns the first column of the row:

          >>> query = session.query(User.id).filter(User.name == 'ed').\
          ...    order_by(User.id)
          {sql}>>> query.scalar()
          SELECT users.id AS users_id
          FROM users
          WHERE users.name = ? ORDER BY users.id
          [...] ('ed',)
          {stop}1

3.1.9.3 Using Textual SQL
.........................

Literal strings can be used flexibly with ‘Query’, by specifying their
use with the text() construct, which is accepted by most
applicable methods.  For example, see Query.filter() and
Query.order_by():

     >>> from sqlalchemy import text
     {sql}>>> for user in session.query(User).\
     ...             filter(text("id<224")).\
     ...             order_by(text("id")).all():
     ...     print(user.name)
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname
     FROM users
     WHERE id<224 ORDER BY id
     [...] ()
     {stop}ed
     wendy
     mary
     fred

Bind parameters can be specified with string-based SQL, using a colon.
To specify the values, use the Query.params() method:

     {sql}>>> session.query(User).filter(text("id<:value and name=:name")).\
     ...     params(value=224, name='fred').order_by(User.id).one()
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname
     FROM users
     WHERE id<? and name=? ORDER BY users.id
     [...] (224, 'fred')
     {stop}<User(name='fred', fullname='Fred Flintstone', nickname='freddy')>

To use an entirely string-based statement, a text() construct
representing a complete statement can be passed to
Query.from_statement().  Without further specification, the ORM
will match columns in the ORM mapping to the result returned by the SQL
statement based on column name:

     {sql}>>> session.query(User).from_statement(
     ...  text("SELECT * FROM users where name=:name")).params(name='ed').all()
     SELECT * FROM users where name=?
     [...] ('ed',)
     {stop}[<User(name='ed', fullname='Ed Jones', nickname='eddie')>]

For better targeting of mapped columns to a textual SELECT, as well as
to match on a specific subset of columns in arbitrary order, individual
mapped columns are passed in the desired order to
TextClause.columns():

     >>> stmt = text("SELECT name, id, fullname, nickname "
     ...             "FROM users where name=:name")
     >>> stmt = stmt.columns(User.name, User.id, User.fullname, User.nickname)
     {sql}>>> session.query(User).from_statement(stmt).params(name='ed').all()
     SELECT name, id, fullname, nickname FROM users where name=?
     [...] ('ed',)
     {stop}[<User(name='ed', fullname='Ed Jones', nickname='eddie')>]

When selecting from a text() construct, the Query
may still specify what columns and entities are to be returned; instead
of ‘query(User)’ we can also ask for the columns individually, as in any
other case:

     >>> stmt = text("SELECT name, id FROM users where name=:name")
     >>> stmt = stmt.columns(User.name, User.id)
     {sql}>>> session.query(User.id, User.name).\
     ...          from_statement(stmt).params(name='ed').all()
     SELECT name, id FROM users where name=?
     [...] ('ed',)
     {stop}[(1, u'ed')]

See also
........

See Using Textual SQL. - The text() construct
explained from the perspective of Core-only queries.

3.1.9.4 Counting
................

‘Query’ includes a convenience method for counting called
Query.count():

     {sql}>>> session.query(User).filter(User.name.like('%ed')).count()
     SELECT count(*) AS count_1
     FROM (SELECT users.id AS users_id,
                     users.name AS users_name,
                     users.fullname AS users_fullname,
                     users.nickname AS users_nickname
     FROM users
     WHERE users.name LIKE ?) AS anon_1
     [...] ('%ed',)
     {stop}2

Counting on count()
...................

Query.count() used to be a very complicated method when it
would try to guess whether or not a subquery was needed around the
existing query, and in some exotic cases it wouldn’t do the right thing.
Now that it uses a simple subquery every time, it’s only two lines long
and always returns the right answer.  Use ‘func.count()’ if a particular
statement absolutely cannot tolerate the subquery being present.

The Query.count() method is used to determine how many rows
the SQL statement would return.  Looking at the generated SQL above,
SQLAlchemy always places whatever it is we are querying into a subquery,
then counts the rows from that.  In some cases this can be reduced to a
simpler ‘SELECT count(*) FROM table’, however modern versions of
SQLAlchemy don’t try to guess when this is appropriate, as the exact SQL
can be emitted using more explicit means.

For situations where the “thing to be counted” needs to be indicated
specifically, we can specify the “count” function directly using the
expression ‘func.count()’, available from the expression.func
construct.  Below we use it to return the count of each distinct
user name:

     >>> from sqlalchemy import func
     {sql}>>> session.query(func.count(User.name), User.name).group_by(User.name).all()
     SELECT count(users.name) AS count_1, users.name AS users_name
     FROM users GROUP BY users.name
     [...] ()
     {stop}[(1, u'ed'), (1, u'fred'), (1, u'mary'), (1, u'wendy')]

To achieve our simple ‘SELECT count(*) FROM table’, we can apply it as:

     {sql}>>> session.query(func.count('*')).select_from(User).scalar()
     SELECT count(?) AS count_1
     FROM users
     [...] ('*',)
     {stop}4

The usage of Query.select_from() can be removed if we
express the count in terms of the ‘User’ primary key directly:

     {sql}>>> session.query(func.count(User.id)).scalar()
     SELECT count(users.id) AS count_1
     FROM users
     [...] ()
     {stop}4

3.1.10 Building a Relationship
------------------------------

Let’s consider how a second table, related to ‘User’, can be mapped and
queried.  Users in our system can store any number of email addresses
associated with their username.  This implies a basic one to many
association from the ‘users’ to a new table which stores email
addresses, which we will call ‘addresses’.  Using declarative, we define
this table along with its mapped class, ‘Address’:

     >>> from sqlalchemy import ForeignKey
     >>> from sqlalchemy.orm import relationship

     >>> class Address(Base):
     ...     __tablename__ = 'addresses'
     ...     id = Column(Integer, primary_key=True)
     ...     email_address = Column(String, nullable=False)
     ...     user_id = Column(Integer, ForeignKey('users.id'))
     ...
     ...     user = relationship("User", back_populates="addresses")
     ...
     ...     def __repr__(self):
     ...         return "<Address(email_address='%s')>" % self.email_address

     >>> User.addresses = relationship(
     ...     "Address", order_by=Address.id, back_populates="user")

The above class introduces the ForeignKey construct, which is
a directive applied to Column that indicates that values in
this column should be constrained to be values present in the named
remote column.  This is a core feature of relational databases, and is
the “glue” that transforms an otherwise unconnected collection of tables
to have rich overlapping relationships.  The ForeignKey above
expresses that values in the ‘addresses.user_id’ column should be
constrained to those values in the ‘users.id’ column, i.e.  its primary
key.

A second directive, known as relationship(), tells the ORM
that the ‘Address’ class itself should be linked to the ‘User’ class,
using the attribute ‘Address.user’.  relationship() uses the
foreign key relationships between the two tables to determine the nature
of this linkage, determining that ‘Address.user’ will be many to one.
An additional relationship() directive is placed on the
‘User’ mapped class under the attribute ‘User.addresses’.  In both
relationship() directives, the parameter
relationship.back_populates is assigned to refer to the
complementary attribute names; by doing so, each relationship()
can make intelligent decision about the same relationship as
expressed in reverse; on one side, ‘Address.user’ refers to a ‘User’
instance, and on the other side, ‘User.addresses’ refers to a list of
‘Address’ instances.

     Note: The relationship.back_populates parameter is a
     newer version of a very common SQLAlchemy feature called
     relationship.backref.  The relationship.backref
     parameter hasn’t gone anywhere and will always remain available!
     The relationship.back_populates is the same thing,
     except a little more verbose and easier to manipulate.  For an
     overview of the entire topic, see the section Linking Relationships with Backref.

The reverse side of a many-to-one relationship is always one to many.  A
full catalog of available relationship() configurations is at
Basic Relationship Patterns.

The two complementing relationships ‘Address.user’ and ‘User.addresses’
are referred to as a bidirectional relationship, and is a key feature of
the SQLAlchemy ORM. The section Linking Relationships with Backref
discusses the “backref” feature in detail.

Arguments to relationship() which concern the remote class
can be specified using strings, assuming the Declarative system is in
use.  Once all mappings are complete, these strings are evaluated as
Python expressions in order to produce the actual argument, in the above
case the ‘User’ class.  The names which are allowed during this
evaluation include, among other things, the names of all classes which
have been created in terms of the declared base.

See the docstring for relationship() for more detail on
argument style.

Did you know ?
..............

   * a FOREIGN KEY constraint in most (though not all) relational
     databases can only link to a primary key column, or a column that
     has a UNIQUE constraint.

   * a FOREIGN KEY constraint that refers to a multiple column primary
     key, and itself has multiple columns, is known as a “composite
     foreign key”.  It can also reference a subset of those columns.

   * FOREIGN KEY columns can automatically update themselves, in
     response to a change in the referenced column or row.  This is
     known as the CASCADE `referential action', and is a built in
     function of the relational database.

   * FOREIGN KEY can refer to its own table.  This is referred to as a
     “self-referential” foreign key.

   * Read more about foreign keys at Foreign Key - Wikipedia(1).

We’ll need to create the ‘addresses’ table in the database, so we will
issue another CREATE from our metadata, which will skip over tables
which have already been created:

     {sql}>>> Base.metadata.create_all(engine)
     BEGIN...
     CREATE TABLE addresses (
         id INTEGER NOT NULL,
         email_address VARCHAR NOT NULL,
         user_id INTEGER,
         PRIMARY KEY (id),
         FOREIGN KEY(user_id) REFERENCES users (id)
     )
     [...] ()
     COMMIT

   ---------- Footnotes ----------

   (1) http://en.wikipedia.org/wiki/Foreign_key

3.1.11 Working with Related Objects
-----------------------------------

Now when we create a ‘User’, a blank ‘addresses’ collection will be
present.  Various collection types, such as sets and dictionaries, are
possible here (see Customizing Collection Access for
details), but by default, the collection is a Python list.

     >>> jack = User(name='jack', fullname='Jack Bean', nickname='gjffdd')
     >>> jack.addresses
     []

We are free to add ‘Address’ objects on our ‘User’ object.  In this case
we just assign a full list directly:

     >>> jack.addresses = [
     ...                 Address(email_address='jack@google.com'),
     ...                 Address(email_address='j25@yahoo.com')]

When using a bidirectional relationship, elements added in one direction
automatically become visible in the other direction.  This behavior
occurs based on attribute on-change events and is evaluated in Python,
without using any SQL:

     >>> jack.addresses[1]
     <Address(email_address='j25@yahoo.com')>

     >>> jack.addresses[1].user
     <User(name='jack', fullname='Jack Bean', nickname='gjffdd')>

Let’s add and commit ‘Jack Bean’ to the database.  ‘jack’ as well as the
two ‘Address’ members in the corresponding ‘addresses’ collection are
both added to the session at once, using a process known as `cascading':

     >>> session.add(jack)
     {sql}>>> session.commit()
     INSERT INTO users (name, fullname, nickname) VALUES (?, ?, ?)
     [...] ('jack', 'Jack Bean', 'gjffdd')
     INSERT INTO addresses (email_address, user_id) VALUES (?, ?)
     [...] ('jack@google.com', 5)
     INSERT INTO addresses (email_address, user_id) VALUES (?, ?)
     [...] ('j25@yahoo.com', 5)
     COMMIT

Querying for Jack, we get just Jack back.  No SQL is yet issued for
Jack’s addresses:

     {sql}>>> jack = session.query(User).\
     ... filter_by(name='jack').one()
     BEGIN (implicit)
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname
     FROM users
     WHERE users.name = ?
     [...] ('jack',)

     {stop}>>> jack
     <User(name='jack', fullname='Jack Bean', nickname='gjffdd')>

Let’s look at the ‘addresses’ collection.  Watch the SQL:

     {sql}>>> jack.addresses
     SELECT addresses.id AS addresses_id,
             addresses.email_address AS
             addresses_email_address,
             addresses.user_id AS addresses_user_id
     FROM addresses
     WHERE ? = addresses.user_id ORDER BY addresses.id
     [...] (5,)
     {stop}[<Address(email_address='jack@google.com')>, <Address(email_address='j25@yahoo.com')>]

When we accessed the ‘addresses’ collection, SQL was suddenly issued.
This is an example of a lazy loading relationship.  The ‘addresses’
collection is now loaded and behaves just like an ordinary list.  We’ll
cover ways to optimize the loading of this collection in a bit.

3.1.12 Querying with Joins
--------------------------

Now that we have two tables, we can show some more features of
Query, specifically how to create queries that deal with both
tables at the same time.  The Wikipedia page on SQL JOIN(1) offers a
good introduction to join techniques, several of which we’ll illustrate
here.

To construct a simple implicit join between ‘User’ and ‘Address’, we can
use Query.filter() to equate their related columns together.
Below we load the ‘User’ and ‘Address’ entities at once using this
method:

     {sql}>>> for u, a in session.query(User, Address).\
     ...                     filter(User.id==Address.user_id).\
     ...                     filter(Address.email_address=='jack@google.com').\
     ...                     all():
     ...     print(u)
     ...     print(a)
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname,
             addresses.id AS addresses_id,
             addresses.email_address AS addresses_email_address,
             addresses.user_id AS addresses_user_id
     FROM users, addresses
     WHERE users.id = addresses.user_id
             AND addresses.email_address = ?
     [...] ('jack@google.com',)
     {stop}<User(name='jack', fullname='Jack Bean', nickname='gjffdd')>
     <Address(email_address='jack@google.com')>

The actual SQL JOIN syntax, on the other hand, is most easily achieved
using the Query.join() method:

     {sql}>>> session.query(User).join(Address).\
     ...         filter(Address.email_address=='jack@google.com').\
     ...         all()
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname
     FROM users JOIN addresses ON users.id = addresses.user_id
     WHERE addresses.email_address = ?
     [...] ('jack@google.com',)
     {stop}[<User(name='jack', fullname='Jack Bean', nickname='gjffdd')>]

Query.join() knows how to join between ‘User’ and ‘Address’
because there’s only one foreign key between them.  If there were no
foreign keys, or several, see Query.join() works better when one
of the following forms are used:

     query.join(Address, User.id==Address.user_id)          # explicit condition
     query.join(User.addresses)                             # specify relationship from left to right
     query.join(Address, User.addresses)                    # same, with explicit target
     query.join(User.addresses.and_(Address.name != 'foo')) # use relationship + additional ON criteria

As you would expect, the same idea is used for “outer” joins, using the
Query.outerjoin() function:

     query.outerjoin(User.addresses)   # LEFT OUTER JOIN

The reference documentation for Query.join() contains
detailed information and examples of the calling styles accepted by this
method; see Query.join() is an important method at the center of
usage for any SQL-fluent application.

What does Query select from if there’s multiple entities?
.........................................................

The Query.join() method will `typically join from the
leftmost item' in the list of entities, when the ON clause is omitted,
or if the ON clause is a plain SQL expression.  To control the first
entity in the list of JOINs, use the Query.select_from()
method:

     query = session.query(User, Address).select_from(Address).join(User)

   ---------- Footnotes ----------

   (1) http://en.wikipedia.org/wiki/Join_%28SQL%29

3.1.12.1 Using Aliases
......................

When querying across multiple tables, if the same table needs to be
referenced more than once, SQL typically requires that the table be
`aliased' with another name, so that it can be distinguished against
other occurrences of that table.  This is supported using the
aliased() construct.  When joining to relationships using using
aliased(), the special attribute method
PropComparator.of_type() may be used to alter the target of a
relationship join to refer to a given aliased() object.
Below we join to the ‘Address’ entity twice, to locate a user who has
two distinct email addresses at the same time:

     >>> from sqlalchemy.orm import aliased
     >>> adalias1 = aliased(Address)
     >>> adalias2 = aliased(Address)
     {sql}>>> for username, email1, email2 in \
     ...     session.query(User.name, adalias1.email_address, adalias2.email_address).\
     ...     join(User.addresses.of_type(adalias1)).\
     ...     join(User.addresses.of_type(adalias2)).\
     ...     filter(adalias1.email_address=='jack@google.com').\
     ...     filter(adalias2.email_address=='j25@yahoo.com'):
     ...     print(username, email1, email2)
     SELECT users.name AS users_name,
             addresses_1.email_address AS addresses_1_email_address,
             addresses_2.email_address AS addresses_2_email_address
     FROM users JOIN addresses AS addresses_1
             ON users.id = addresses_1.user_id
     JOIN addresses AS addresses_2
             ON users.id = addresses_2.user_id
     WHERE addresses_1.email_address = ?
             AND addresses_2.email_address = ?
     [...] ('jack@google.com', 'j25@yahoo.com')
     {stop}jack jack@google.com j25@yahoo.com

In addition to using the PropComparator.of_type() method, it
is common to see the Query.join() method joining to a
specific target by indicating it separately:

     # equivalent to query.join(User.addresses.of_type(adalias1))
     q = query.join(adalias1, User.addresses)

3.1.12.2 Using Subqueries
.........................

The ‘Query’ is suitable for generating statements which can be used as
subqueries.  Suppose we wanted to load ‘User’ objects along with a count
of how many ‘Address’ records each user has.  The best way to generate
SQL like this is to get the count of addresses grouped by user ids, and
JOIN to the parent.  In this case we use a LEFT OUTER JOIN so that we
get rows back for those users who don’t have any addresses, e.g.:

     SELECT users.*, adr_count.address_count FROM users LEFT OUTER JOIN
         (SELECT user_id, count(*) AS address_count
             FROM addresses GROUP BY user_id) AS adr_count
         ON users.id=adr_count.user_id

Using the ‘Query’, we build a statement like this from the inside out.
The ‘statement’ accessor returns a SQL expression representing the
statement generated by a particular ‘Query’ - this is an instance of a
select() construct, which are described in SQL Expression Language Tutorial (1.x API):

     >>> from sqlalchemy.sql import func
     >>> stmt = session.query(Address.user_id, func.count('*').\
     ...         label('address_count')).\
     ...         group_by(Address.user_id).subquery()

The ‘func’ keyword generates SQL functions, and the ‘subquery()’ method
on ‘Query’ produces a SQL expression construct representing a SELECT
statement embedded within an alias (it’s actually shorthand for
‘query.statement.alias()’).

Once we have our statement, it behaves like a Table
construct, such as the one we created for ‘users’ at the start of this
tutorial.  The columns on the statement are accessible through an
attribute called ‘c’:

     {sql}>>> for u, count in session.query(User, stmt.c.address_count).\
     ...     outerjoin(stmt, User.id==stmt.c.user_id).order_by(User.id):
     ...     print(u, count)
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname,
             anon_1.address_count AS anon_1_address_count
     FROM users LEFT OUTER JOIN
         (SELECT addresses.user_id AS user_id, count(?) AS address_count
         FROM addresses GROUP BY addresses.user_id) AS anon_1
         ON users.id = anon_1.user_id
     ORDER BY users.id
     [...] ('*',)
     {stop}<User(name='ed', fullname='Ed Jones', nickname='eddie')> None
     <User(name='wendy', fullname='Wendy Williams', nickname='windy')> None
     <User(name='mary', fullname='Mary Contrary', nickname='mary')> None
     <User(name='fred', fullname='Fred Flintstone', nickname='freddy')> None
     <User(name='jack', fullname='Jack Bean', nickname='gjffdd')> 2

3.1.12.3 Selecting Entities from Subqueries
...........................................

Above, we just selected a result that included a column from a subquery.
What if we wanted our subquery to map to an entity ?  For this we use
‘aliased()’ to associate an “alias” of a mapped class to a subquery:

     {sql}>>> stmt = session.query(Address).\
     ...                 filter(Address.email_address != 'j25@yahoo.com').\
     ...                 subquery()
     >>> adalias = aliased(Address, stmt)
     >>> for user, address in session.query(User, adalias).\
     ...         join(adalias, User.addresses):
     ...     print(user)
     ...     print(address)
     SELECT users.id AS users_id,
                 users.name AS users_name,
                 users.fullname AS users_fullname,
                 users.nickname AS users_nickname,
                 anon_1.id AS anon_1_id,
                 anon_1.email_address AS anon_1_email_address,
                 anon_1.user_id AS anon_1_user_id
     FROM users JOIN
         (SELECT addresses.id AS id,
                 addresses.email_address AS email_address,
                 addresses.user_id AS user_id
         FROM addresses
         WHERE addresses.email_address != ?) AS anon_1
         ON users.id = anon_1.user_id
     [...] ('j25@yahoo.com',)
     {stop}<User(name='jack', fullname='Jack Bean', nickname='gjffdd')>
     <Address(email_address='jack@google.com')>

3.1.12.4 Using EXISTS
.....................

The EXISTS keyword in SQL is a boolean operator which returns True if
the given expression contains any rows.  It may be used in many
scenarios in place of joins, and is also useful for locating rows which
do not have a corresponding row in a related table.

There is an explicit EXISTS construct, which looks like this:

     >>> from sqlalchemy.sql import exists
     >>> stmt = exists().where(Address.user_id==User.id)
     {sql}>>> for name, in session.query(User.name).filter(stmt):
     ...     print(name)
     SELECT users.name AS users_name
     FROM users
     WHERE EXISTS (SELECT *
     FROM addresses
     WHERE addresses.user_id = users.id)
     [...] ()
     {stop}jack

The ‘Query’ features several operators which make usage of EXISTS
automatically.  Above, the statement can be expressed along the
‘User.addresses’ relationship using Comparator.any():

     {sql}>>> for name, in session.query(User.name).\
     ...         filter(User.addresses.any()):
     ...     print(name)
     SELECT users.name AS users_name
     FROM users
     WHERE EXISTS (SELECT 1
     FROM addresses
     WHERE users.id = addresses.user_id)
     [...] ()
     {stop}jack

Comparator.any() takes criterion as well, to limit the rows
matched:

     {sql}>>> for name, in session.query(User.name).\
     ...     filter(User.addresses.any(Address.email_address.like('%google%'))):
     ...     print(name)
     SELECT users.name AS users_name
     FROM users
     WHERE EXISTS (SELECT 1
     FROM addresses
     WHERE users.id = addresses.user_id AND addresses.email_address LIKE ?)
     [...] ('%google%',)
     {stop}jack

Comparator.has() is the same operator as
Comparator.any() for many-to-one relationships (note the ‘~’
operator here too, which means “NOT”):

     {sql}>>> session.query(Address).\
     ...         filter(~Address.user.has(User.name=='jack')).all()
     SELECT addresses.id AS addresses_id,
             addresses.email_address AS addresses_email_address,
             addresses.user_id AS addresses_user_id
     FROM addresses
     WHERE NOT (EXISTS (SELECT 1
     FROM users
     WHERE users.id = addresses.user_id AND users.name = ?))
     [...] ('jack',)
     {stop}[]

3.1.12.5 Common Relationship Operators
......................................

Here’s all the operators which build on relationships - each one is
linked to its API documentation which includes full details on usage and
behavior:

   * Comparator.__eq__(). (many-to-one “equals” comparison):

          query.filter(Address.user == someuser)

   * Comparator.__ne__(). (many-to-one “not equals”
     comparison):

          query.filter(Address.user != someuser)

   * IS NULL (many-to-one comparison, also uses
     Comparator.__eq__()):

          query.filter(Address.user == None)

   * Comparator.contains(). (used for one-to-many
     collections):

          query.filter(User.addresses.contains(someaddress))

   * Comparator.any(). (used for collections):

          query.filter(User.addresses.any(Address.email_address == 'bar'))

          # also takes keyword arguments:
          query.filter(User.addresses.any(email_address='bar'))

   * Comparator.has(). (used for scalar references):

          query.filter(Address.user.has(name='ed'))

   * Query.with_parent(). (used for any relationship):

          session.query(Address).with_parent(someuser, 'addresses')

3.1.13 Eager Loading
--------------------

Recall earlier that we illustrated a lazy loading operation, when we
accessed the ‘User.addresses’ collection of a ‘User’ and SQL was
emitted.  If you want to reduce the number of queries (dramatically, in
many cases), we can apply an eager load to the query operation.
SQLAlchemy offers three types of eager loading, two of which are
automatic, and a third which involves custom criterion.  All three are
usually invoked via functions known as query options which give
additional instructions to the Query on how we would like
various attributes to be loaded, via the Query.options()
method.

3.1.13.1 Selectin Load
......................

In this case we’d like to indicate that ‘User.addresses’ should load
eagerly.  A good choice for loading a set of objects as well as their
related collections is the selectinload() option, which
emits a second SELECT statement that fully loads the collections
associated with the results just loaded.  The name “selectin” originates
from the fact that the SELECT statement uses an IN clause in order to
locate related rows for multiple objects at once:

     >>> from sqlalchemy.orm import selectinload
     {sql}>>> jack = session.query(User).\
     ...                 options(selectinload(User.addresses)).\
     ...                 filter_by(name='jack').one()
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname
     FROM users
     WHERE users.name = ?
     [...] ('jack',)
     SELECT addresses.user_id AS addresses_user_id,
             addresses.id AS addresses_id,
             addresses.email_address AS addresses_email_address
     FROM addresses
     WHERE addresses.user_id IN (?)
     ORDER BY addresses.id
     [...] (5,)
     {stop}>>> jack
     <User(name='jack', fullname='Jack Bean', nickname='gjffdd')>

     >>> jack.addresses
     [<Address(email_address='jack@google.com')>, <Address(email_address='j25@yahoo.com')>]

3.1.13.2 Joined Load
....................

The other automatic eager loading function is more well known and is
called joinedload().  This style of loading emits a JOIN, by
default a LEFT OUTER JOIN, so that the lead object as well as the
related object or collection is loaded in one step.  We illustrate
loading the same ‘addresses’ collection in this way - note that even
though the ‘User.addresses’ collection on ‘jack’ is actually populated
right now, the query will emit the extra join regardless:

     >>> from sqlalchemy.orm import joinedload

     {sql}>>> jack = session.query(User).\
     ...                        options(joinedload(User.addresses)).\
     ...                        filter_by(name='jack').one()
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname,
             addresses_1.id AS addresses_1_id,
             addresses_1.email_address AS addresses_1_email_address,
             addresses_1.user_id AS addresses_1_user_id
     FROM users
         LEFT OUTER JOIN addresses AS addresses_1 ON users.id = addresses_1.user_id
     WHERE users.name = ? ORDER BY addresses_1.id
     [...] ('jack',)

     {stop}>>> jack
     <User(name='jack', fullname='Jack Bean', nickname='gjffdd')>

     >>> jack.addresses
     [<Address(email_address='jack@google.com')>, <Address(email_address='j25@yahoo.com')>]

Note that even though the OUTER JOIN resulted in two rows, we still only
got one instance of ‘User’ back.  This is because Query
applies a “uniquing” strategy, based on object identity, to the returned
entities.  This is specifically so that joined eager loading can be
applied without affecting the query results.

While joinedload() has been around for a long time, see
selectinload() is a newer form of eager loading.
selectinload() tends to be more appropriate for loading related
collections while joinedload() tends to be better suited for
many-to-one relationships, due to the fact that only one row is loaded
for both the lead and the related object.  Another form of loading,
see subqueryload(), also exists, which can be used in place of
selectinload() when making use of composite primary keys on
certain backends.

joinedload() is not a replacement for join()
............................................

The join created by joinedload() is anonymously aliased such
that it `does not affect the query results'.  An Query.order_by()
or Query.filter() call `cannot' reference these aliased
tables - so-called “user space” joins are constructed using
Query.join().  The rationale for this is that joinedload()
is only applied in order to affect how related objects or
collections are loaded as an optimizing detail - it can be added or
removed with no impact on actual results.  See the section The Zen of Joined Eager Loading
for a detailed description of how this is
used.

3.1.13.3 Explicit Join + Eagerload
..................................

A third style of eager loading is when we are constructing a JOIN
explicitly in order to locate the primary rows, and would like to
additionally apply the extra table to a related object or collection on
the primary object.  This feature is supplied via the
contains_eager() function, and is most typically useful for
pre-loading the many-to-one object on a query that needs to filter on
that same object.  Below we illustrate loading an ‘Address’ row as well
as the related ‘User’ object, filtering on the ‘User’ named “jack” and
using contains_eager() to apply the “user” columns to the
‘Address.user’ attribute:

     >>> from sqlalchemy.orm import contains_eager
     {sql}>>> jacks_addresses = session.query(Address).\
     ...                             join(Address.user).\
     ...                             filter(User.name=='jack').\
     ...                             options(contains_eager(Address.user)).\
     ...                             all()
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname,
             addresses.id AS addresses_id,
             addresses.email_address AS addresses_email_address,
             addresses.user_id AS addresses_user_id
     FROM addresses JOIN users ON users.id = addresses.user_id
     WHERE users.name = ?
     [...] ('jack',)

     {stop}>>> jacks_addresses
     [<Address(email_address='jack@google.com')>, <Address(email_address='j25@yahoo.com')>]

     >>> jacks_addresses[0].user
     <User(name='jack', fullname='Jack Bean', nickname='gjffdd')>

For more information on eager loading, including how to configure
various forms of loading by default, see the section Relationship Loading Techniques.

3.1.14 Deleting
---------------

Let’s try to delete ‘jack’ and see how that goes.  We’ll mark the object
as deleted in the session, then we’ll issue a ‘count’ query to see that
no rows remain:

     >>> session.delete(jack)
     {sql}>>> session.query(User).filter_by(name='jack').count()
     UPDATE addresses SET user_id=? WHERE addresses.id = ?
     [...] ((None, 1), (None, 2))
     DELETE FROM users WHERE users.id = ?
     [...] (5,)
     SELECT count(*) AS count_1
     FROM (SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname
     FROM users
     WHERE users.name = ?) AS anon_1
     [...] ('jack',)
     {stop}0

So far, so good.  How about Jack’s ‘Address’ objects ?

     {sql}>>> session.query(Address).filter(
     ...     Address.email_address.in_(['jack@google.com', 'j25@yahoo.com'])
     ...  ).count()
     SELECT count(*) AS count_1
     FROM (SELECT addresses.id AS addresses_id,
                     addresses.email_address AS addresses_email_address,
                     addresses.user_id AS addresses_user_id
     FROM addresses
     WHERE addresses.email_address IN (?, ?)) AS anon_1
     [...] ('jack@google.com', 'j25@yahoo.com')
     {stop}2

Uh oh, they’re still there !  Analyzing the flush SQL, we can see that
the ‘user_id’ column of each address was set to NULL, but the rows
weren’t deleted.  SQLAlchemy doesn’t assume that deletes cascade, you
have to tell it to do so.

3.1.14.1 Configuring delete/delete-orphan Cascade
.................................................

We will configure `cascade' options on the ‘User.addresses’ relationship
to change the behavior.  While SQLAlchemy allows you to add new
attributes and relationships to mappings at any point in time, in this
case the existing relationship needs to be removed, so we need to tear
down the mappings completely and start again - we’ll close the
Session:

     >>> session.close()
     ROLLBACK

and use a new declarative_base():

     >>> Base = declarative_base()

Next we’ll declare the ‘User’ class, adding in the ‘addresses’
relationship including the cascade configuration (we’ll leave the
constructor out too):

     >>> class User(Base):
     ...     __tablename__ = 'users'
     ...
     ...     id = Column(Integer, primary_key=True)
     ...     name = Column(String)
     ...     fullname = Column(String)
     ...     nickname = Column(String)
     ...
     ...     addresses = relationship("Address", back_populates='user',
     ...                     cascade="all, delete, delete-orphan")
     ...
     ...     def __repr__(self):
     ...        return "<User(name='%s', fullname='%s', nickname='%s')>" % (
     ...                                self.name, self.fullname, self.nickname)

Then we recreate ‘Address’, noting that in this case we’ve created the
‘Address.user’ relationship via the ‘User’ class already:

     >>> class Address(Base):
     ...     __tablename__ = 'addresses'
     ...     id = Column(Integer, primary_key=True)
     ...     email_address = Column(String, nullable=False)
     ...     user_id = Column(Integer, ForeignKey('users.id'))
     ...     user = relationship("User", back_populates="addresses")
     ...
     ...     def __repr__(self):
     ...         return "<Address(email_address='%s')>" % self.email_address

Now when we load the user ‘jack’ (below using Query.get(),
which loads by primary key), removing an address from the corresponding
‘addresses’ collection will result in that ‘Address’ being deleted:

     # load Jack by primary key
     {sql}>>> jack = session.query(User).get(5)
     BEGIN (implicit)
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname
     FROM users
     WHERE users.id = ?
     [...] (5,)
     {stop}

     # remove one Address (lazy load fires off)
     {sql}>>> del jack.addresses[1]
     SELECT addresses.id AS addresses_id,
             addresses.email_address AS addresses_email_address,
             addresses.user_id AS addresses_user_id
     FROM addresses
     WHERE ? = addresses.user_id
     [...] (5,)
     {stop}

     # only one address remains
     {sql}>>> session.query(Address).filter(
     ...     Address.email_address.in_(['jack@google.com', 'j25@yahoo.com'])
     ... ).count()
     DELETE FROM addresses WHERE addresses.id = ?
     [...] (2,)
     SELECT count(*) AS count_1
     FROM (SELECT addresses.id AS addresses_id,
                     addresses.email_address AS addresses_email_address,
                     addresses.user_id AS addresses_user_id
     FROM addresses
     WHERE addresses.email_address IN (?, ?)) AS anon_1
     [...] ('jack@google.com', 'j25@yahoo.com')
     {stop}1

Deleting Jack will delete both Jack and the remaining ‘Address’
associated with the user:

     >>> session.delete(jack)

     {sql}>>> session.query(User).filter_by(name='jack').count()
     DELETE FROM addresses WHERE addresses.id = ?
     [...] (1,)
     DELETE FROM users WHERE users.id = ?
     [...] (5,)
     SELECT count(*) AS count_1
     FROM (SELECT users.id AS users_id,
                     users.name AS users_name,
                     users.fullname AS users_fullname,
                     users.nickname AS users_nickname
     FROM users
     WHERE users.name = ?) AS anon_1
     [...] ('jack',)
     {stop}0

     {sql}>>> session.query(Address).filter(
     ...    Address.email_address.in_(['jack@google.com', 'j25@yahoo.com'])
     ... ).count()
     SELECT count(*) AS count_1
     FROM (SELECT addresses.id AS addresses_id,
                     addresses.email_address AS addresses_email_address,
                     addresses.user_id AS addresses_user_id
     FROM addresses
     WHERE addresses.email_address IN (?, ?)) AS anon_1
     [...] ('jack@google.com', 'j25@yahoo.com')
     {stop}0

More on Cascades
................

Further detail on configuration of cascades is at Cascades.
The cascade functionality can also integrate smoothly with the ‘ON
DELETE CASCADE’ functionality of the relational database.  See
Using foreign key ON DELETE cascade with ORM relationships for
details.

3.1.15 Building a Many To Many Relationship
-------------------------------------------

We’re moving into the bonus round here, but lets show off a many-to-many
relationship.  We’ll sneak in some other features too, just to take a
tour.  We’ll make our application a blog application, where users can
write ‘BlogPost’ items, which have ‘Keyword’ items associated with them.

For a plain many-to-many, we need to create an un-mapped Table
construct to serve as the association table.  This looks like the
following:

     >>> from sqlalchemy import Table, Text
     >>> # association table
     >>> post_keywords = Table('post_keywords', Base.metadata,
     ...     Column('post_id', ForeignKey('posts.id'), primary_key=True),
     ...     Column('keyword_id', ForeignKey('keywords.id'), primary_key=True)
     ... )

Above, we can see declaring a Table directly is a little
different than declaring a mapped class.  Table is a
constructor function, so each individual Column argument is
separated by a comma.  The Column object is also given its
name explicitly, rather than it being taken from an assigned attribute
name.

Next we define ‘BlogPost’ and ‘Keyword’, using complementary
relationship() constructs, each referring to the ‘post_keywords’
table as an association table:

     >>> class BlogPost(Base):
     ...     __tablename__ = 'posts'
     ...
     ...     id = Column(Integer, primary_key=True)
     ...     user_id = Column(Integer, ForeignKey('users.id'))
     ...     headline = Column(String(255), nullable=False)
     ...     body = Column(Text)
     ...
     ...     # many to many BlogPost<->Keyword
     ...     keywords = relationship('Keyword',
     ...                             secondary=post_keywords,
     ...                             back_populates='posts')
     ...
     ...     def __init__(self, headline, body, author):
     ...         self.author = author
     ...         self.headline = headline
     ...         self.body = body
     ...
     ...     def __repr__(self):
     ...         return "BlogPost(%r, %r, %r)" % (self.headline, self.body, self.author)

     >>> class Keyword(Base):
     ...     __tablename__ = 'keywords'
     ...
     ...     id = Column(Integer, primary_key=True)
     ...     keyword = Column(String(50), nullable=False, unique=True)
     ...     posts = relationship('BlogPost',
     ...                          secondary=post_keywords,
     ...                          back_populates='keywords')
     ...
     ...     def __init__(self, keyword):
     ...         self.keyword = keyword

     Note: The above class declarations illustrate explicit ‘__init__()’
     methods.  Remember, when using Declarative, it’s optional!

Above, the many-to-many relationship is ‘BlogPost.keywords’.  The
defining feature of a many-to-many relationship is the ‘secondary’
keyword argument which references a Table object representing
the association table.  This table only contains columns which reference
the two sides of the relationship; if it has `any' other columns, such
as its own primary key, or foreign keys to other tables, SQLAlchemy
requires a different usage pattern called the “association object”,
described at Association Object.

We would also like our ‘BlogPost’ class to have an ‘author’ field.  We
will add this as another bidirectional relationship, except one issue
we’ll have is that a single user might have lots of blog posts.  When we
access ‘User.posts’, we’d like to be able to filter results further so
as not to load the entire collection.  For this we use a setting
accepted by relationship() called ‘lazy='dynamic'’, which
configures an alternate `loader strategy' on the attribute:

     >>> BlogPost.author = relationship(User, back_populates="posts")
     >>> User.posts = relationship(BlogPost, back_populates="author", lazy="dynamic")

Create new tables:

     {sql}>>> Base.metadata.create_all(engine)
     BEGIN...
     CREATE TABLE keywords (
         id INTEGER NOT NULL,
         keyword VARCHAR(50) NOT NULL,
         PRIMARY KEY (id),
         UNIQUE (keyword)
     )
     [...] ()
     CREATE TABLE posts (
         id INTEGER NOT NULL,
         user_id INTEGER,
         headline VARCHAR(255) NOT NULL,
         body TEXT,
         PRIMARY KEY (id),
         FOREIGN KEY(user_id) REFERENCES users (id)
     )
     [...] ()
     CREATE TABLE post_keywords (
         post_id INTEGER NOT NULL,
         keyword_id INTEGER NOT NULL,
         PRIMARY KEY (post_id, keyword_id),
         FOREIGN KEY(post_id) REFERENCES posts (id),
         FOREIGN KEY(keyword_id) REFERENCES keywords (id)
     )
     [...] ()
     COMMIT

Usage is not too different from what we’ve been doing.  Let’s give Wendy
some blog posts:

     {sql}>>> wendy = session.query(User).\
     ...                 filter_by(name='wendy').\
     ...                 one()
     SELECT users.id AS users_id,
             users.name AS users_name,
             users.fullname AS users_fullname,
             users.nickname AS users_nickname
     FROM users
     WHERE users.name = ?
     [...] ('wendy',)
     {stop}
     >>> post = BlogPost("Wendy's Blog Post", "This is a test", wendy)
     >>> session.add(post)

We’re storing keywords uniquely in the database, but we know that we
don’t have any yet, so we can just create them:

     >>> post.keywords.append(Keyword('wendy'))
     >>> post.keywords.append(Keyword('firstpost'))

We can now look up all blog posts with the keyword ‘firstpost’.  We’ll
use the ‘any’ operator to locate “blog posts where any of its keywords
has the keyword string ‘firstpost’”:

     {sql}>>> session.query(BlogPost).\
     ...             filter(BlogPost.keywords.any(keyword='firstpost')).\
     ...             all()
     INSERT INTO keywords (keyword) VALUES (?)
     [...] ('wendy',)
     INSERT INTO keywords (keyword) VALUES (?)
     [...] ('firstpost',)
     INSERT INTO posts (user_id, headline, body) VALUES (?, ?, ?)
     [...] (2, "Wendy's Blog Post", 'This is a test')
     INSERT INTO post_keywords (post_id, keyword_id) VALUES (?, ?)
     [...] (...)
     SELECT posts.id AS posts_id,
             posts.user_id AS posts_user_id,
             posts.headline AS posts_headline,
             posts.body AS posts_body
     FROM posts
     WHERE EXISTS (SELECT 1
         FROM post_keywords, keywords
         WHERE posts.id = post_keywords.post_id
             AND keywords.id = post_keywords.keyword_id
             AND keywords.keyword = ?)
     [...] ('firstpost',)
     {stop}[BlogPost("Wendy's Blog Post", 'This is a test', <User(name='wendy', fullname='Wendy Williams', nickname='windy')>)]

If we want to look up posts owned by the user ‘wendy’, we can tell the
query to narrow down to that ‘User’ object as a parent:

     {sql}>>> session.query(BlogPost).\
     ...             filter(BlogPost.author==wendy).\
     ...             filter(BlogPost.keywords.any(keyword='firstpost')).\
     ...             all()
     SELECT posts.id AS posts_id,
             posts.user_id AS posts_user_id,
             posts.headline AS posts_headline,
             posts.body AS posts_body
     FROM posts
     WHERE ? = posts.user_id AND (EXISTS (SELECT 1
         FROM post_keywords, keywords
         WHERE posts.id = post_keywords.post_id
             AND keywords.id = post_keywords.keyword_id
             AND keywords.keyword = ?))
     [...] (2, 'firstpost')
     {stop}[BlogPost("Wendy's Blog Post", 'This is a test', <User(name='wendy', fullname='Wendy Williams', nickname='windy')>)]

Or we can use Wendy’s own ‘posts’ relationship, which is a “dynamic”
relationship, to query straight from there:

     {sql}>>> wendy.posts.\
     ...         filter(BlogPost.keywords.any(keyword='firstpost')).\
     ...         all()
     SELECT posts.id AS posts_id,
             posts.user_id AS posts_user_id,
             posts.headline AS posts_headline,
             posts.body AS posts_body
     FROM posts
     WHERE ? = posts.user_id AND (EXISTS (SELECT 1
         FROM post_keywords, keywords
         WHERE posts.id = post_keywords.post_id
             AND keywords.id = post_keywords.keyword_id
             AND keywords.keyword = ?))
     [...] (2, 'firstpost')
     {stop}[BlogPost("Wendy's Blog Post", 'This is a test', <User(name='wendy', fullname='Wendy Williams', nickname='windy')>)]

3.1.16 Further Reference
------------------------

Query Reference: Query API.

Mapper Reference: Mapper Configuration.

Relationship Reference: Relationship Configuration.

Session Reference: Using the Session.

3.2 Mapper Configuration
========================

This section describes a variety of configurational patterns that are
usable with mappers.  It assumes you’ve worked through Object Relational Tutorial (1.x API)
and know how to construct and use
rudimentary mappers and relationships.

3.2.1 Mapping Python Classes
----------------------------

SQLAlchemy historically features two distinct styles of mapper
configuration.  The original mapping API is commonly referred to as
“classical” style, whereas the more automated style of mapping is known
as “declarative” style.  SQLAlchemy now refers to these two mapping
styles as `imperative mapping' and `declarative mapping'.

Both styles may be used interchangeably, as the end result of each is
exactly the same - a user-defined class that has a Mapper
configured against a selectable unit, typically represented by a
Table object.

Both imperative and declarative mapping begin with an ORM
registry object, which maintains a set of classes that are mapped.
This registry is present for all mappings.

Changed in version 1.4: Declarative and classical mapping are now
referred to as “declarative” and “imperative” mapping, and are unified
internally, all originating from the registry construct that
represents a collection of related mappings.

The full suite of styles can be hierarchically organized as follows:

   *
     Declarative Mapping.

             *
               Using declarative_base(). Base class w/ metaclass

                       * Declarative Table.

                       * Imperative Table (a.k.a. “hybrid table”).

             *
               Using registry.mapped(). Declarative Decorator

                       * Declarative Table. - combine
                         registry.mapped() with ‘__tablename__’

                       * Imperative Table (Hybrid) - combine
                         registry.mapped() with ‘__table__’

                       *
                         Declarative Mapping with Dataclasses and Attrs.

                                 * Example One - Dataclasses with Imperative Table.

                                 * Example Two - Dataclasses with Declarative Table.

                                 * Example Three - attrs with Imperative Table.

   *
     Imperative (a.k.a. “classical” mapping).

             *
               Using registry.map_imperatively().

                       * Imperative Mapping with Dataclasses and Attrs.

3.2.1.1 Declarative Mapping
...........................

The `Declarative Mapping' is the typical way that mappings are
constructed in modern SQLAlchemy.  The most common pattern is to first
construct a base class using the declarative_base() function,
which will apply the declarative mapping process to all subclasses that
derive from it.  Below features a declarative base which is then used in
a declarative table mapping:

     from sqlalchemy import Column, Integer, String, ForeignKey
     from sqlalchemy.orm import declarative_base

     # declarative base class
     Base = declarative_base()

     # an example mapping using the base
     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         name = Column(String)
         fullname = Column(String)
         nickname = Column(String)

Above, the declarative_base() callable returns a new base
class from which new classes to be mapped may inherit from, as above a
new mapped class ‘User’ is constructed.

The base class refers to a registry object that maintains a
collection of related mapped classes.  The declarative_base()
function is in fact shorthand for first creating the registry with the
registry constructor, and then generating a base class using
the registry.generate_base() method:

     from sqlalchemy.orm import registry

     # equivalent to Base = declarative_base()

     mapper_registry = registry()
     Base = mapper_registry.generate_base()

The registry is used directly in order to access a variety of
mapping styles to suit different use cases:

   * Declarative Mapping using a Decorator (no declarative base).
     - declarative mapping using a decorator, rather than a base
     class.

   * Imperative (a.k.a. Classical) Mappings. - imperative
     mapping, specifying all mapping arguments directly rather than
     scanning a class.

Documentation for Declarative mapping continues at Mapping Classes with Declarative.

See also
........

See Mapping Classes with Declarative.

3.2.1.2 Creating an Explicit Base Non-Dynamically (for use with mypy, similar)
..............................................................................

SQLAlchemy includes a Mypy plugin that automatically
accommodates for the dynamically generated ‘Base’ class delivered by
SQLAlchemy functions like declarative_base().  This plugin
works along with a new set of typing stubs published at
sqlalchemy2-stubs(1).

When this plugin is not in use, or when using other PEP 484(2) tools
which may not know how to interpret this class, the declarative base
class may be produced in a fully explicit fashion using the
‘DeclarativeMeta’ directly as follows:

     from sqlalchemy.orm import registry
     from sqlalchemy.orm.decl_api import DeclarativeMeta

     mapper_registry = registry()

     class Base(metaclass=DeclarativeMeta):
         __abstract__ = True

         # these are supplied by the sqlalchemy2-stubs, so may be omitted
         # when they are installed
         registry = mapper_registry
         metadata = mapper_registry.metadata

The above ‘Base’ is equivalent to one created using the
registry.generate_base() method and will be fully understood by
type analysis tools without the use of plugins.

See also
........

See Mypy / Pep-484 Support for ORM Mappings. - background on the
Mypy plugin which applies the above structure automatically when running
Mypy.

   ---------- Footnotes ----------

   (1) https://pypi.org/project/sqlalchemy2-stubs

   (2) https://www.python.org/dev/peps/pep-0484

3.2.1.3 Declarative Mapping using a Decorator (no declarative base)
...................................................................

As an alternative to using the “declarative base” class is to apply
declarative mapping to a class explicitly, using either an imperative
technique similar to that of a “classical” mapping, or more succinctly
by using a decorator.  The registry.mapped() function is a
class decorator that can be applied to any Python class with no
hierarchy in place.  The Python class otherwise is configured in
declarative style normally:

     from sqlalchemy import Column, Integer, String, Text, ForeignKey

     from sqlalchemy.orm import registry
     from sqlalchemy.orm import relationship

     mapper_registry = registry()

     @mapper_registry.mapped
     class User:
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         name = Column(String)

         addresses = relationship("Address", back_populates="user")

     @mapper_registry.mapped
     class Address:
         __tablename__ = 'address'

         id = Column(Integer, primary_key=True)
         user_id = Column(ForeignKey("user.id"))
         email_address = Column(String)

         user = relationship("User", back_populates="addresses")

Above, the same registry that we’d use to generate a
declarative base class via its registry.generate_base()
method may also apply a declarative-style mapping to a class without
using a base.  When using the above style, the mapping of a particular
class will `only' proceed if the decorator is applied to that class
directly.  For inheritance mappings, the decorator should be applied to
each subclass:

     from sqlalchemy.orm import registry
     mapper_registry = registry()

     @mapper_registry.mapped
     class Person:
         __tablename__ = "person"

         person_id = Column(Integer, primary_key=True)
         type = Column(String, nullable=False)

         __mapper_args__ = {

             "polymorphic_on": type,
             "polymorphic_identity": "person"
         }

     @mapper_registry.mapped
     class Employee(Person):
         __tablename__ = "employee"

         person_id = Column(ForeignKey("person.person_id"), primary_key=True)

         __mapper_args__ = {
             "polymorphic_identity": "employee"
         }

Both the “declarative table” and “imperative table” styles of
declarative mapping may be used with the above mapping style.

The decorator form of mapping is particularly useful when combining a
SQLAlchemy declarative mapping with other forms of class declaration,
notably the Python ‘dataclasses’ module.  See the next section.

3.2.1.4 Declarative Mapping with Dataclasses and Attrs
......................................................

The dataclasses(1) module, added in Python 3.7, provides a ‘@dataclass’
class decorator to automatically generate boilerplate definitions of
‘__init__()’, ‘__eq__()’, ‘__repr()__’, etc.  methods.  Another very
popular library that does the same, and much more, is attrs(2).  Both
libraries make use of class decorators in order to scan a class for
attributes that define the class’ behavior, which are then used to
generate methods, documentation, and annotations.

The registry.mapped() class decorator allows the declarative
mapping of a class to occur after the class has been fully constructed,
allowing the class to be processed by other class decorators first.  The
‘@dataclass’ and ‘@attr.s’ decorators may therefore be applied first
before the ORM mapping process proceeds via the registry.mapped()
decorator or via the registry.map_imperatively() method
discussed in a later section.

Mapping with ‘@dataclass’ or ‘@attr.s’ may be used in a straightforward
way with Declarative with Imperative Table (a.k.a. Hybrid Declarative)
style, where the the Table, which means that
it is defined separately and associated with the class via the
‘__table__’.  For dataclasses specifically, see Declarative Table
is also supported.

New in version 1.4.0b2: Added support for full declarative mapping when
using dataclasses.

When attributes are defined using ‘dataclasses’, the ‘@dataclass’
decorator consumes them but leaves them in place on the class.
SQLAlchemy’s mapping process, when it encounters an attribute that
normally is to be mapped to a Column, checks explicitly if the
attribute is part of a Dataclasses setup, and if so will `replace' the
class-bound dataclass attribute with its usual mapped properties.  The
‘__init__’ method created by ‘@dataclass’ is left intact.  In contrast,
the ‘@attr.s’ decorator actually removes its own class-bound attributes
after the decorator runs, so that SQLAlchemy’s mapping process takes
over these attributes without any issue.

New in version 1.4: Added support for direct mapping of Python
dataclasses, where the Mapper will now detect attributes
that are specific to the ‘@dataclasses’ module and replace them at
mapping time, rather than skipping them as is the default behavior for
any class attribute that’s not part of the mapping.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/dataclasses.html

   (2) https://pypi.org/project/attrs/

3.2.1.5 Example One - Dataclasses with Imperative Table
.......................................................

An example of a mapping using ‘@dataclass’ using Declarative with Imperative Table (a.k.a. Hybrid Declarative)
is as follows:

     from __future__ import annotations

     from dataclasses import dataclass
     from dataclasses import field
     from typing import List
     from typing import Optional

     from sqlalchemy import Column
     from sqlalchemy import ForeignKey
     from sqlalchemy import Integer
     from sqlalchemy import String
     from sqlalchemy import Table
     from sqlalchemy.orm import registry
     from sqlalchemy.orm import relationship

     mapper_registry = registry()

     @mapper_registry.mapped
     @dataclass
     class User:
         __table__ = Table(
             "user",
             mapper_registry.metadata,
             Column("id", Integer, primary_key=True),
             Column("name", String(50)),
             Column("fullname", String(50)),
             Column("nickname", String(12)),
         )
         id: int = field(init=False)
         name: Optional[str] = None
         fullname: Optional[str] = None
         nickname: Optional[str] = None
         addresses: List[Address] = field(default_factory=list)

         __mapper_args__ = {   # type: ignore
             "properties" : {
                 "addresses": relationship("Address")
             }
         }

     @mapper_registry.mapped
     @dataclass
     class Address:
         __table__ = Table(
             "address",
             mapper_registry.metadata,
             Column("id", Integer, primary_key=True),
             Column("user_id", Integer, ForeignKey("user.id")),
             Column("email_address", String(50)),
         )
         id: int = field(init=False)
         user_id: int = field(init=False)
         email_address: Optional[str] = None

In the above example, the ‘User.id’, ‘Address.id’, and ‘Address.user_id’
attributes are defined as ‘field(init=False)’.  This means that
parameters for these won’t be added to ‘__init__()’ methods, but
Session will still be able to set them after getting their values
during flush from autoincrement or other default value generator.  To
allow them to be specified in the constructor explicitly, they would
instead be given a default value of ‘None’.

For a relationship() to be declared separately, it needs to
be specified directly within the mapper.properties
dictionary passed to the mapper().  An alternative to this
approach is in the next example.

3.2.1.6 Example Two - Dataclasses with Declarative Table
........................................................

The fully declarative approach requires that Column objects
are declared as class attributes, which when using dataclasses would
conflict with the dataclass-level attributes.  An approach to combine
these together is to make use of the ‘metadata’ attribute on the
‘dataclass.field’ object, where SQLAlchemy-specific mapping information
may be supplied.  Declarative supports extraction of these parameters
when the class specifies the attribute ‘__sa_dataclass_metadata_key__’.
This also provides a more succinct method of indicating the
relationship() association:

     from __future__ import annotations

     from dataclasses import dataclass
     from dataclasses import field
     from typing import List

     from sqlalchemy import Column
     from sqlalchemy import ForeignKey
     from sqlalchemy import Integer
     from sqlalchemy import String
     from sqlalchemy.orm import registry
     from sqlalchemy.orm import relationship

     mapper_registry = registry()

     @mapper_registry.mapped
     @dataclass
     class User:
         __tablename__ = "user"

         __sa_dataclass_metadata_key__ = "sa"
         id: int = field(
             init=False, metadata={"sa": Column(Integer, primary_key=True)}
         )
         name: str = field(default=None, metadata={"sa": Column(String(50))})
         fullname: str = field(default=None, metadata={"sa": Column(String(50))})
         nickname: str = field(default=None, metadata={"sa": Column(String(12))})
         addresses: List[Address] = field(
             default_factory=list, metadata={"sa": relationship("Address")}
         )

     @mapper_registry.mapped
     @dataclass
     class Address:
         __tablename__ = "address"
         __sa_dataclass_metadata_key__ = "sa"
         id: int = field(
             init=False, metadata={"sa": Column(Integer, primary_key=True)}
         )
         user_id: int = field(
             init=False, metadata={"sa": Column(ForeignKey("user.id"))}
         )
         email_address: str = field(
             default=None, metadata={"sa": Column(String(50))}
         )

3.2.1.7 Using Declarative Mixins with Dataclasses
.................................................

In the section Composing Mapped Hierarchies with Mixins,
Declarative Mixin classes are introduced.  One requirement of
declarative mixins is that certain constructs that can’t be easily
duplicated must be given as callables, using the declared_attr
decorator, such as in the example at Mixing in Relationships:

     class RefTargetMixin(object):
         @declared_attr
         def target_id(cls):
             return Column('target_id', ForeignKey('target.id'))

         @declared_attr
         def target(cls):
             return relationship("Target")

This form is supported within the Dataclasses ‘field()’ object by using
a lambda to indicate the SQLAlchemy construct inside the ‘field()’.
Using declared_attr() to surround the lambda is optional.
If we wanted to produce our ‘User’ class above where the ORM fields came
from a mixin that is itself a dataclass, the form would be:

     @dataclass
     class UserMixin:
         __tablename__ = "user"

         __sa_dataclass_metadata_key__ = "sa"

         id: int = field(
             init=False, metadata={"sa": Column(Integer, primary_key=True)}
         )

         addresses: List[Address] = field(
             default_factory=list, metadata={"sa": lambda: relationship("Address")}
         )

     @dataclass
     class AddressMixin:
         __tablename__ = "address"
         __sa_dataclass_metadata_key__ = "sa"
         id: int = field(
             init=False, metadata={"sa": Column(Integer, primary_key=True)}
         )
         user_id: int = field(
             init=False, metadata={"sa": lambda: Column(ForeignKey("user.id"))}
         )
         email_address: str = field(
             default=None, metadata={"sa": Column(String(50))}
         )

     @mapper_registry.mapped
     class User(UserMixin):
         pass

     @mapper_registry.mapped
     class Address(AddressMixin):
       pass

New in version 1.4.2: Added support for “declared attr” style mixin
attributes, namely relationship() constructs as well as
Column objects with foreign key declarations, to be used within
“Dataclasses with Declarative Table” style mappings.

3.2.1.8 Example Three - attrs with Imperative Table
...................................................

A mapping using ‘@attr.s’, in conjunction with imperative table:

     import attr

     # other imports

     from sqlalchemy.orm import registry

     mapper_registry = registry()

     @mapper_registry.mapped
     @attr.s
     class User:
         __table__ = Table(
             "user",
             mapper_registry.metadata,
             Column("id", Integer, primary_key=True),
             Column("name", String(50)),
             Column("fullname", String(50)),
             Column("nickname", String(12)),
         )
         id = attr.ib()
         name = attr.ib()
         fullname = attr.ib()
         nickname = attr.ib()
         addresses = attr.ib()

     # other classes...

‘@dataclass’ and attrs(1) mappings may also be used with classical
mappings, i.e.  with the registry.map_imperatively()
function.  See the section Imperative Mapping with Dataclasses and Attrs
for a similar example.

   ---------- Footnotes ----------

   (1) https://pypi.org/project/attrs/

3.2.1.9 Imperative (a.k.a. Classical) Mappings
..............................................

An `imperative' or `classical' mapping refers to the configuration of a
mapped class using the registry.map_imperatively() method,
where the target class does not include any declarative class
attributes.  The “map imperative” style has historically been achieved
using the mapper() function directly, however this function
now expects that a sqlalchemy.orm.registry() is present.

Deprecated since version 1.4: Using the mapper() function
directly to achieve a classical mapping directly is deprecated.  The
registry.map_imperatively() method retains the identical
functionality while also allowing for string-based resolution of other
mapped classes from within the registry.

In “classical” form, the table metadata is created separately with the
Table construct, then associated with the ‘User’ class via
the registry.map_imperatively() method:

     from sqlalchemy import Table, Column, Integer, String, ForeignKey
     from sqlalchemy.orm import registry

     mapper_registry = registry()

     user_table = Table(
         'user',
         mapper_registry.metadata,
         Column('id', Integer, primary_key=True),
         Column('name', String(50)),
         Column('fullname', String(50)),
         Column('nickname', String(12))
     )

     class User:
         pass

     mapper_registry.map_imperatively(User, user_table)

Information about mapped attributes, such as relationships to other
classes, are provided via the ‘properties’ dictionary.  The example
below illustrates a second Table object, mapped to a class
called ‘Address’, then linked to ‘User’ via relationship():

     address = Table('address', metadata,
                 Column('id', Integer, primary_key=True),
                 Column('user_id', Integer, ForeignKey('user.id')),
                 Column('email_address', String(50))
                 )

     mapper(User, user, properties={
         'addresses' : relationship(Address, backref='user', order_by=address.c.id)
     })

     mapper(Address, address)

When using classical mappings, classes must be provided directly without
the benefit of the “string lookup” system provided by Declarative.  SQL
expressions are typically specified in terms of the Table
objects, i.e.  ‘address.c.id’ above for the ‘Address’ relationship, and
not ‘Address.id’, as ‘Address’ may not yet be linked to table metadata,
nor can we specify a string here.

Some examples in the documentation still use the classical approach, but
note that the classical as well as Declarative approaches are `fully
interchangeable'.  Both systems ultimately create the same
configuration, consisting of a Table, user-defined class,
linked together with a mapper().  When we talk about “the
behavior of mapper().”, this includes when using the
Declarative system as well - it’s still used, just behind the scenes.

3.2.1.10 Imperative Mapping with Dataclasses and Attrs
......................................................

As described in the section Declarative Mapping with Dataclasses and Attrs,
the ‘@dataclass’ decorator and the attrs(1) library both
work as class decorators that are applied to a class first, before it is
passed to SQLAlchemy for mapping.  Just like we can use the
registry.mapped() decorator in order to apply declarative-style
mapping to the class, we can also pass it to the
registry.map_imperatively() method so that we may pass all
Table and Mapper configuration imperatively to the
function rather than having them defined on the class itself as
declarative class variables:

     from __future__ import annotations

     from dataclasses import dataclass
     from dataclasses import field
     from typing import List

     from sqlalchemy import Column
     from sqlalchemy import ForeignKey
     from sqlalchemy import Integer
     from sqlalchemy import MetaData
     from sqlalchemy import String
     from sqlalchemy import Table
     from sqlalchemy.orm import registry
     from sqlalchemy.orm import relationship

     mapper_registry = registry()

     @dataclass
     class User:
         id: int = field(init=False)
         name: str = None
         fullname: str = None
         nickname: str = None
         addresses: List[Address] = field(default_factory=list)

     @dataclass
     class Address:
         id: int = field(init=False)
         user_id: int = field(init=False)
         email_address: str = None

     metadata = MetaData()

     user = Table(
         'user',
         metadata,
         Column('id', Integer, primary_key=True),
         Column('name', String(50)),
         Column('fullname', String(50)),
         Column('nickname', String(12)),
     )

     address = Table(
         'address',
         metadata,
         Column('id', Integer, primary_key=True),
         Column('user_id', Integer, ForeignKey('user.id')),
         Column('email_address', String(50)),
     )

     mapper_registry.map_imperatively(User, user, properties={
         'addresses': relationship(Address, backref='user', order_by=address.c.id),
     })

     mapper_registry.map_imperatively(Address, address)

   ---------- Footnotes ----------

   (1) https://pypi.org/project/attrs/

3.2.1.11 Mapper Configuration Overview
......................................

With all mapping forms, the mapping of the class can be configured in
many ways by passing construction arguments that become part of the
Mapper object.  The function which ultimately receives these
arguments is the mapper() function, which are delivered to
it originating from one of the front-facing mapping functions defined on
the registry object.

There are four general classes of configuration information that the
mapper() function looks for:

3.2.1.12 The class to be mapped
...............................

This is a class that we construct in our application.  There are
generally no restrictions on the structure of this class.  (1) When a
Python class is mapped, there can only be `one' Mapper
object for the class.  (2)

When mapping with the declarative mapping style, the class to
be mapped is either a subclass of the declarative base class, or is
handled by a decorator or function such as registry.mapped().

When mapping with the imperative style, the class is passed
directly as the map_imperatively.class_ argument.

   ---------- Footnotes ----------

   (1) (1) When running under Python 2, a Python 2 “old style” class is
the only kind of class that isn’t compatible.  When running code on
Python 2, all classes must extend from the Python ‘object’ class.  Under
Python 3 this is always the case.

   (2) (2) There is a legacy feature known as a “non primary mapper”,
where additional Mapper objects may be associated with a
class that’s already mapped, however they don’t apply instrumentation to
the class.  This feature is deprecated as of SQLAlchemy 1.3.

3.2.1.13 The table, or other from clause object
...............................................

In the vast majority of common cases this is an instance of Table.
For more advanced use cases, it may also refer to any kind of
FromClause object, the most common alternative objects being the
Subquery and Join object.

When mapping with the declarative mapping style, the subject
table is either generated by the declarative system based on the
‘__tablename__’ attribute and the Column objects presented,
or it is established via the ‘__table__’ attribute.  These two styles of
configuration are presented at Declarative Table and
Declarative with Imperative Table (a.k.a. Hybrid Declarative).

When mapping with the imperative style, the subject table is
passed positionally as the map_imperatively.local_table
argument.

In contrast to the “one mapper per class” requirement of a mapped class,
the Table or other FromClause object that is the
subject of the mapping may be associated with any number of mappings.
The Mapper applies modifications directly to the
user-defined class, but does not modify the given Table or
other FromClause in any way.

3.2.1.14 The properties dictionary
..................................

This is a dictionary of all of the attributes that will be associated
with the mapped class.  By default, the Mapper generates
entries for this dictionary derived from the given Table, in
the form of ColumnProperty objects which each refer to an
individual Column of the mapped table.  The properties
dictionary will also contain all the other kinds of
MapperProperty objects to be configured, most commonly instances
generated by the relationship() construct.

When mapping with the declarative mapping style, the
properties dictionary is generated by the declarative system by scanning
the class to be mapped for appropriate attributes.  See the section
Defining Mapped Properties with Declarative for notes on
this process.

When mapping with the imperative style, the properties
dictionary is passed directly as the ‘properties’ argument to
registry.map_imperatively(), which will pass it along to the
mapper.properties parameter.

3.2.1.15 Other mapper configuration parameters
..............................................

These flags are documented at mapper().

When mapping with the declarative mapping style, additional
mapper configuration arguments are configured via the ‘__mapper_args__’
class attribute, documented at Mapper Configuration Options with Declarative.

When mapping with the imperative style, keyword arguments
are passed to the to registry.map_imperatively() method
which passes them along to the mapper() function.

3.2.1.16 Mapped Class Behavior
..............................

Across all styles of mapping using the registry object, the
following behaviors are common:

3.2.1.17 Default Constructor
............................

The registry applies a default constructor, i.e.  ‘__init__’
method, to all mapped classes that don’t explicitly have their own
‘__init__’ method.  The behavior of this method is such that it provides
a convenient keyword constructor that will accept as optional keyword
arguments all the attributes that are named.  E.g.:

     from sqlalchemy.orm import declarative_base

     Base = declarative_base()

     class User(Base):
         __tablename__ = 'user'

         id = Column(...)
         name = Column(...)
         fullname = Column(...)

An object of type ‘User’ above will have a constructor which allows
‘User’ objects to be created as:

     u1 = User(name='some name', fullname='some fullname')

The above constructor may be customized by passing a Python callable to
the registry.constructor parameter which provides the
desired default ‘__init__()’ behavior.

The constructor also applies to imperative mappings:

     from sqlalchemy.orm import registry

     mapper_registry = registry()

     user_table = Table(
         'user',
         mapper_registry.metadata,
         Column('id', Integer, primary_key=True),
         Column('name', String(50))
     )

     class User:
         pass

     mapper_registry.map_imperatively(User, user_table)

The above class, mapped imperatively as described at Imperative (a.k.a. Classical) Mappings,
will also feature the default
constructor associated with the registry.

New in version 1.4: classical mappings now support a standard
configuration-level constructor when they are mapped via the
registry.map_imperatively() method.

3.2.1.18 Runtime Introspection of Mapped classes and Mappers
............................................................

A class that is mapped using registry will also feature a few
attributes that are common to all mappings:

   * The ‘__mapper__’ attribute will refer to the Mapper.
     that is associated with the class:

          mapper = User.__mapper__

     This Mapper is also what’s returned when using the
     inspect() function against the mapped class:

          from sqlalchemy import inspect

          mapper = inspect(User)

   * The ‘__table__’ attribute will refer to the Table, or
     more generically to the ‘FromClause’ object, to which the class is
     mapped:

          table = User.__table__

     This ‘FromClause’ is also what’s returned when using the
     Mapper.local_table attribute of the Mapper:

          table = inspect(User).local_table

     For a single-table inheritance mapping, where the class is a
     subclass that does not have a table of its own, the
     Mapper.local_table attribute as well as the ‘.__table__’
     attribute will be ‘None’.  To retrieve the “selectable” that is
     actually selected from during a query for this class, this is
     available via the Mapper.selectable attribute:

          table = inspect(User).selectable

3.2.1.19 Mapper Inspection Features
...................................

As illustrated in the previous section, the Mapper object is
available from any mapped class, regardless of method, using the
Runtime Inspection API system.  Using the inspect()
function, one can acquire the Mapper from a mapped class:

     >>> from sqlalchemy import inspect
     >>> insp = inspect(User)

Detailed information is available including Mapper.columns:

     >>> insp.columns
     <sqlalchemy.util._collections.OrderedProperties object at 0x102f407f8>

This is a namespace that can be viewed in a list format or via
individual names:

     >>> list(insp.columns)
     [Column('id', Integer(), table=<user>, primary_key=True, nullable=False), Column('name', String(length=50), table=<user>), Column('fullname', String(length=50), table=<user>), Column('nickname', String(length=50), table=<user>)]
     >>> insp.columns.name
     Column('name', String(length=50), table=<user>)

Other namespaces include Mapper.all_orm_descriptors, which
includes all mapped attributes as well as hybrids, association proxies:

     >>> insp.all_orm_descriptors
     <sqlalchemy.util._collections.ImmutableProperties object at 0x1040e2c68>
     >>> insp.all_orm_descriptors.keys()
     ['fullname', 'nickname', 'name', 'id']

As well as Mapper.column_attrs:

     >>> list(insp.column_attrs)
     [<ColumnProperty at 0x10403fde0; id>, <ColumnProperty at 0x10403fce8; name>, <ColumnProperty at 0x1040e9050; fullname>, <ColumnProperty at 0x1040e9148; nickname>]
     >>> insp.column_attrs.name
     <ColumnProperty at 0x10403fce8; name>
     >>> insp.column_attrs.name.expression
     Column('name', String(length=50), table=<user>)

See also
........

See Runtime Inspection API.

See Mapper.

See InstanceState.

3.2.2 Mapping Classes with Declarative
--------------------------------------

The Declarative mapping style is the primary style of mapping that is
used with SQLAlchemy.  See the section Declarative Mapping
for the top level introduction.

3.2.2.1 Table Configuration with Declarative
............................................

As introduced at Declarative Mapping, the Declarative style
includes the ability to generate a mapped Table object at the
same time, or to accommodate a Table or other
FromClause object directly.

The following examples assume a declarative base class as:

     from sqlalchemy.orm import declarative_base

     Base = declarative_base()

All of the examples that follow illustrate a class inheriting from the
above ‘Base’.  The decorator style introduced at Declarative Mapping using a Decorator (no declarative base)
is fully supported
with all the following examples as well.

3.2.2.2 Declarative Table
.........................

With the declarative base class, the typical form of mapping includes an
attribute ‘__tablename__’ that indicates the name of a Table
that should be generated along with the mapping:

     from sqlalchemy import Column, Integer, String, ForeignKey
     from sqlalchemy.orm import declarative_base

     Base = declarative_base()

     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         name = Column(String)
         fullname = Column(String)
         nickname = Column(String)

Above, see Column objects are placed inline with the class
definition.  The declarative mapping process will generate a new
Table object against the MetaData collection associated
with the declarative base, and each specified Column object
will become part of the Table.columns collection of this
Table object.  The Column objects can omit their
“name” field, which is usually the first positional argument to the
Column constructor; the declarative system will assign the
key associated with each Column as the name, to produce a
Table that is equivalent to:

     # equivalent Table object produced
     user_table = Table(
         "user",
         Base.metadata,
         Column("id", Integer, primary_key=True),
         Column("name", String),
         Column("fullname", String),
         Column("nickname", String),
     )

3.2.2.3 Accessing Table and Metadata
....................................

A declaratively mapped class will always include an attribute called
‘__table__’; when the above configuration using ‘__tablename__’ is
complete, the declarative process makes the Table available
via the ‘__table__’ attribute:

     # access the Table
     user_table = User.__table__

The above table is ultimately the same one that corresponds to the
Mapper.local_table attribute, which we can see through the
runtime inspection system:

     from sqlalchemy import inspect

     user_table = inspect(User).local_table

The MetaData collection associated with both the declarative
registry as well as the base class is frequently necessary in
order to run DDL operations such as CREATE, as well as in use with
migration tools such as Alembic.  This object is available via the
‘.metadata’ attribute of registry as well as the declarative
base class.  Below, for a small script we may wish to emit a CREATE for
all tables against a SQLite database:

     engine = create_engine("sqlite://")

     Base.metadata.create_all(engine)

3.2.2.4 Declarative Table Configuration
.......................................

When using Declarative Table configuration with the ‘__tablename__’
declarative class attribute, additional arguments to be supplied to the
Table constructor should be provided using the
‘__table_args__’ declarative class attribute.

This attribute accommodates both positional as well as keyword arguments
that are normally sent to the Table constructor.  The
attribute can be specified in one of two forms.  One is as a dictionary:

     class MyClass(Base):
         __tablename__ = 'sometable'
         __table_args__ = {'mysql_engine':'InnoDB'}

The other, a tuple, where each argument is positional (usually
constraints):

     class MyClass(Base):
         __tablename__ = 'sometable'
         __table_args__ = (
                 ForeignKeyConstraint(['id'], ['remote_table.id']),
                 UniqueConstraint('foo'),
                 )

Keyword arguments can be specified with the above form by specifying the
last argument as a dictionary:

     class MyClass(Base):
         __tablename__ = 'sometable'
         __table_args__ = (
                 ForeignKeyConstraint(['id'], ['remote_table.id']),
                 UniqueConstraint('foo'),
                 {'autoload':True}
                 )

A class may also specify the ‘__table_args__’ declarative attribute, as
well as the ‘__tablename__’ attribute, in a dynamic style using the
declared_attr() method decorator.  See the section
Mixin and Custom Base Classes for examples on how this is often
used.

3.2.2.5 Explicit Schema Name with Declarative Table
...................................................

The schema name for a Table as documented at Specifying the Schema Name
is applied to an individual Table using
the Table.schema argument.  When using Declarative tables,
this option is passed like any other to the ‘__table_args__’ dictionary:

     class MyClass(Base):
         __tablename__ = 'sometable'
         __table_args__ = {'schema': 'some_schema'}

The schema name can also be applied to all Table objects
globally by using the MetaData.schema parameter documented
at Specifying a Default Schema Name with MetaData.  The
MetaData object may be constructed separately and passed either to
registry() or declarative_base():

     from sqlalchemy import metadata
     metadata = MetaData(schema="some_schema")

     Base = declarative_base(metadata = metadata)

     class MyClass(Base):
         # will use "some_schema" by default
         __tablename__ = 'sometable'

See also
........

See Specifying the Schema Name. - in the Describing Databases with MetaData
documentation.

3.2.2.6 Adding New Columns
..........................

The declarative table configuration allows the addition of new
Column objects under two scenarios.  The most basic is that of
simply assigning new Column objects to the class:

     MyClass.some_new_column = Column('data', Unicode)

The above operation performed against a declarative class that has been
mapped using the declarative base (note, not the decorator form of
declarative) will add the above Column to the Table
using the Table.append_column() method and will also add
the column to the Mapper to be fully mapped.

     Note: assignment of new columns to an existing declaratively mapped
     class will only function correctly if the “declarative base” class
     is used, which also provides for a metaclass-driven ‘__setattr__()’
     method which will intercept these operations.  It will `not' work
     if the declarative decorator provided by registry.mapped()
     is used, nor will it work for an imperatively mapped class
     mapped by registry.map_imperatively().

The other scenario where a Column is added on the fly is when
an inheriting subclass that has no table of its own indicates additional
columns; these columns will be added to the superclass table.  The
section Single Table Inheritance discusses single table
inheritance.

3.2.2.7 Declarative with Imperative Table (a.k.a. Hybrid Declarative)
.....................................................................

Declarative mappings may also be provided with a pre-existing
Table object, or otherwise a Table or other arbitrary
FromClause construct (such as a Join or
Subquery) that is constructed separately.

This is referred to as a “hybrid declarative” mapping, as the class is
mapped using the declarative style for everything involving the mapper
configuration, however the mapped Table object is produced
separately and passed to the declarative process directly:

     from sqlalchemy.orm import declarative_base
     from sqlalchemy import Column, Integer, String, ForeignKey

     Base = declarative_base()

     # construct a Table directly.  The Base.metadata collection is
     # usually a good choice for MetaData but any MetaData
     # collection may be used.

     user_table = Table(
         "user",
         Base.metadata,
         Column("id", Integer, primary_key=True),
         Column("name", String),
         Column("fullname", String),
         Column("nickname", String),
     )

     # construct the User class using this table.
     class User(Base):
         __table__ = user_table

Above, a Table object is constructed using the approach
described at Describing Databases with MetaData.  It can then
be applied directly to a class that is declaratively mapped.  The
‘__tablename__’ and ‘__table_args__’ declarative class attributes are
not used in this form.  The above configuration is often more readable
as an inline definition:

     class User(Base):
         __table__ = Table(
             "user",
             Base.metadata,
             Column("id", Integer, primary_key=True),
             Column("name", String),
             Column("fullname", String),
             Column("nickname", String),
         )

A natural effect of the above style is that the ‘__table__’ attribute is
itself defined within the class definition block.  As such it may be
immediately referred towards within subsequent attributes, such as the
example below which illustrates referring to the ‘type’ column in a
polymorphic mapper configuration:

     class Person(Base):
         __table__ = Table(
             'person',
             Base.metadata,
             Column('id', Integer, primary_key=True),
             Column('name', String(50)),
             Column('type', String(50))
         )

         __mapper_args__ = {
             "polymorphic_on": __table__.c.type,
             "polymorhpic_identity": "person"
         }

The “imperative table” form is also used when a non-see Table
construct, such as a Join or Subquery object, is
to be mapped.  An example below:

     from sqlalchemy import select, func

     subq = select(
         func.count(orders.c.id).label('order_count'),
         func.max(orders.c.price).label('highest_order'),
         orders.c.customer_id
     ).group_by(orders.c.customer_id).subquery()

     customer_select = select(customers, subq).join_from(
         customers, subq, customers.c.id == subq.c.customer_id
     ).subquery()

     class Customer(Base):
         __table__ = customer_select

For background on mapping to non-see Table constructs see the
sections Mapping a Class against Multiple Tables and
Mapping a Class against Arbitrary Subqueries.

The “imperative table” form is of particular use when the class itself
is using an alternative form of attribute declaration, such as Python
dataclasses.  See the section Declarative Mapping with Dataclasses and Attrs
for detail.

See also
........

See Describing Databases with MetaData.

See Declarative Mapping with Dataclasses and Attrs.

3.2.2.8 Mapping Declaratively with Reflected Tables
...................................................

There are several patterns available which provide for producing mapped
classes against a series of Table objects that were
introspected from the database, using the reflection process described
at Reflecting Database Objects.

A very simple way to map a class to a table reflected from the database
is to use a declarative hybrid mapping, passing the
Table.autoload_with parameter to the Table:

     engine = create_engine("postgresql://user:pass@hostname/my_existing_database")

     class MyClass(Base):
         __table__ = Table(
             'mytable',
             Base.metadata,
             autoload_with=engine
         )

A major downside of the above approach however is that it requires the
database connectivity source to be present while the application classes
are being declared; it’s typical that classes are declared as the
modules of an application are being imported, but database connectivity
isn’t available until the application starts running code so that it can
consume configuration information and create an engine.

3.2.2.9 Using DeferredReflection
................................

To accommodate this case, a simple extension called the
DeferredReflection mixin is available, which alters the
declarative mapping process to be delayed until a special class-level
DeferredReflection.prepare() method is called, which will
perform the reflection process against a target database, and will
integrate the results with the declarative table mapping process, that
is, classes which use the ‘__tablename__’ attribute:

     from sqlalchemy.orm import declarative_base
     from sqlalchemy.ext.declarative import DeferredReflection

     Base = declarative_base()

     class Reflected(DeferredReflection):
         __abstract__ = True

     class Foo(Reflected, Base):
         __tablename__ = 'foo'
         bars = relationship("Bar")

     class Bar(Reflected, Base):
         __tablename__ = 'bar'

         foo_id = Column(Integer, ForeignKey('foo.id'))

Above, we create a mixin class ‘Reflected’ that will serve as a base for
classes in our declarative hierarchy that should become mapped when the
‘Reflected.prepare’ method is called.  The above mapping is not complete
until we do so, given an Engine:

     engine = create_engine("postgresql://user:pass@hostname/my_existing_database")
     Reflected.prepare(engine)

The purpose of the ‘Reflected’ class is to define the scope at which
classes should be reflectively mapped.  The plugin will search among the
subclass tree of the target against which ‘.prepare()’ is called and
reflect all tables.

3.2.2.10 Using Automap
......................

A more automated solution to mapping against an existing database where
table reflection is to be used is to use the Automap
extension.  This extension will generate entire mapped classes from a
database schema, and allows several hooks for customization including
the ability to explicitly map some or all classes while still making use
of reflection to fill in the remaining columns.

See also
........

See Automap.

3.2.2.11 Mapper Configuration with Declarative
..............................................

The section Mapper Configuration Overview discusses the
general configurational elements of a Mapper construct,
which is the structure that defines how a particular user defined class
is mapped to a database table or other SQL construct.  The following
sections describe specific details about how the declarative system goes
about constructing the Mapper.

3.2.2.12 Defining Mapped Properties with Declarative
....................................................

The examples given at Table Configuration with Declarative
illustrate mappings against table-bound columns; the mapping of an
individual column to an ORM class attribute is represented internally by
the ColumnProperty construct.  There are many other
varieties of mapper properties, the most common being the
relationship() construct.  Other kinds of properties include
synonyms to columns which are defined using the synonym()
construct, SQL expressions that are defined using the
column_property() construct, and deferred columns and SQL
expressions which load only when accessed, defined using the
deferred() construct.

While an imperative mapping makes use of the
properties dictionary to establish all the mapped class
attributes, in the declarative mapping, these properties are all
specified inline with the class definition, which in the case of a
declarative table mapping are inline with the Column objects
that will be used to generate a Table object.

Working with the example mapping of ‘User’ and ‘Address’, we may
illustrate a declarative table mapping that includes not just
Column objects but also relationships and SQL expressions:

     # mapping attributes using declarative with declarative table
     # i.e. __tablename__

     from sqlalchemy import Column, Integer, String, Text, ForeignKey
     from sqlalchemy.orm import column_property, relationship, deferred
     from sqlalchemy.orm import declarative_base

     Base = declarative_base()

     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         name = Column(String)
         firstname = Column(String(50))
         lastname = Column(String(50))

         fullname = column_property(firstname + " " + lastname)

         addresses = relationship("Address", back_populates="user")

     class Address(Base):
         __tablename__ = 'address'

         id = Column(Integer, primary_key=True)
         user_id = Column(ForeignKey("user.id"))
         email_address = Column(String)
         address_statistics = deferred(Column(Text))

         user = relationship("User", back_populates="addresses")

The above declarative table mapping features two tables, each with a
relationship() referring to the other, as well as a simple
SQL expression mapped by column_property(), and an additional
Column that will be loaded on a “deferred” basis as defined
by the deferred() construct.  More documentation on these
particular concepts may be found at Basic Relationship Patterns,
see Using column_property, and Deferred Column Loading.

Properties may be specified with a declarative mapping as above using
“hybrid table” style as well; the Column objects that are
directly part of a table move into the Table definition but
everything else, including composed SQL expressions, would still be
inline with the class definition.  Constructs that need to refer to a
Column directly would reference it in terms of the
Table object.  To illustrate the above mapping using hybrid table
style:

     # mapping attributes using declarative with imperative table
     # i.e. __table__

     from sqlalchemy import Table
     from sqlalchemy import Column, Integer, String, Text, ForeignKey
     from sqlalchemy.orm import column_property, relationship, deferred
     from sqlalchemy.orm import declarative_base

     Base = declarative_base()

     class User(Base):
         __table__ = Table(
             "user",
             Base.metadata,
             Column("id", Integer, primary_key=True),
             Column("name", String),
             Column("firstname", String(50)),
             Column("lastname", String(50))
         )

         fullname = column_property(__table__.c.firstname + " " + __table__.c.lastname)

         addresses = relationship("Address", back_populates="user")

     class Address(Base):
         __table__ = Table(
             "address",
             Base.metadata,
             Column("id", Integer, primary_key=True),
             Column("user_id", ForeignKey("user.id")),
             Column("email_address", String),
             Column("address_statistics", Text)
         )

         address_statistics = deferred(__table__.c.address_statistics)

         user = relationship("User", back_populates="addresses")

Things to note above:

   * The address Table contains a column called
     ‘address_statistics’, however we re-map this column under the same
     attribute name to be under the control of a deferred()
     construct.

   * With both declararative table and hybrid table mappings, when we
     define a ForeignKey construct, we always name the target
     table using the `table name', and not the mapped class name.

   * When we define relationship() constructs, as these
     constructs create a linkage between two mapped classes where one
     necessarily is defined before the other, we can refer to the remote
     class using its string name.  This functionality also extends into
     the area of other arguments specified on the relationship()
     such as the “primary join” and “order by” arguments.  See the
     section Late-Evaluation of Relationship Arguments for
     details on this.

3.2.2.13 Mapper Configuration Options with Declarative
......................................................

With all mapping forms, the mapping of the class is configured through
parameters that become part of the Mapper object.  The
function which ultimately receives these arguments is the
mapper() function, and are delivered to it from one of the
front-facing mapping functions defined on the registry
object.

For the declarative form of mapping, mapper arguments are specified
using the ‘__mapper_args__’ declarative class variable, which is a
dictionary that is passed as keyword arguments to the mapper()
function.  Some examples:

`Version ID Column'

The mapper.version_id_col and
mapper.version_id_generator parameters:

     from datetime import datetime

     class Widget(Base):
         __tablename__ = 'widgets'

         id = Column(Integer, primary_key=True)
         timestamp = Column(DateTime, nullable=False)

         __mapper_args__ = {
             'version_id_col': timestamp,
             'version_id_generator': lambda v:datetime.now()
         }

`Single Table Inheritance'

The mapper.polymorphic_on and
mapper.polymorphic_identity parameters:

     class Person(Base):
         __tablename__ = 'person'

         person_id = Column(Integer, primary_key=True)
         type = Column(String, nullable=False)

         __mapper_args__ = dict(
             polymorphic_on=type,
             polymorphic_identity="person"
         )

     class Employee(Person):
         __mapper_args__ = dict(
             polymorphic_identity="employee"
         )

The ‘__mapper_args__’ dictionary may be generated from a class-bound
descriptor method rather than from a fixed dictionary by making use of
the declared_attr() construct.  The section Composing Mapped Hierarchies with Mixins
discusses this concept further.

See also
........

See Composing Mapped Hierarchies with Mixins.

3.2.2.14 Other Declarative Mapping Directives
.............................................

3.2.2.15 ‘__declare_last__()’
.............................

The ‘__declare_last__()’ hook allows definition of a class level
function that is automatically called by the
MapperEvents.after_configured() event, which occurs after mappings
are assumed to be completed and the ‘configure’ step has finished:

     class MyClass(Base):
         @classmethod
         def __declare_last__(cls):
             ""
             # do something with mappings

3.2.2.16 ‘__declare_first__()’
..............................

Like ‘__declare_last__()’, but is called at the beginning of mapper
configuration via the MapperEvents.before_configured()
event:

     class MyClass(Base):
         @classmethod
         def __declare_first__(cls):
             ""
             # do something before mappings are configured

New in version 0.9.3.

3.2.2.17 ‘__abstract__’
.......................

‘__abstract__’ causes declarative to skip the production of a table or
mapper for the class entirely.  A class can be added within a hierarchy
in the same way as mixin (see Mixin and Custom Base Classes),
allowing subclasses to extend just from the special class:

     class SomeAbstractBase(Base):
         __abstract__ = True

         def some_helpful_method(self):
             ""

         @declared_attr
         def __mapper_args__(cls):
             return {"helpful mapper arguments":True}

     class MyMappedClass(SomeAbstractBase):
         ""

One possible use of ‘__abstract__’ is to use a distinct MetaData
for different bases:

     Base = declarative_base()

     class DefaultBase(Base):
         __abstract__ = True
         metadata = MetaData()

     class OtherBase(Base):
         __abstract__ = True
         metadata = MetaData()

Above, classes which inherit from ‘DefaultBase’ will use one
MetaData as the registry of tables, and those which inherit from
‘OtherBase’ will use a different one.  The tables themselves can then be
created perhaps within distinct databases:

     DefaultBase.metadata.create_all(some_engine)
     OtherBase.metadata.create_all(some_other_engine)

3.2.2.18 ‘__table_cls__’
........................

Allows the callable / class used to generate a Table to be
customized.  This is a very open-ended hook that can allow special
customizations to a Table that one generates here:

     class MyMixin(object):
         @classmethod
         def __table_cls__(cls, name, metadata, *arg, **kw):
             return Table(
                 "my_" + name,
                 metadata, *arg, **kw
             )

The above mixin would cause all Table objects generated to
include the prefix ‘"my_"’, followed by the name normally specified
using the ‘__tablename__’ attribute.

‘__table_cls__’ also supports the case of returning ‘None’, which causes
the class to be considered as single-table inheritance vs.  its
subclass.  This may be useful in some customization schemes to determine
that single-table inheritance should take place based on the arguments
for the table itself, such as, define as single-inheritance if there is
no primary key present:

     class AutoTable(object):
         @declared_attr
         def __tablename__(cls):
             return cls.__name__

         @classmethod
         def __table_cls__(cls, *arg, **kw):
             for obj in arg[1:]:
                 if (isinstance(obj, Column) and obj.primary_key) or \
                         isinstance(obj, PrimaryKeyConstraint):
                     return Table(*arg, **kw)

             return None

     class Person(AutoTable, Base):
         id = Column(Integer, primary_key=True)

     class Employee(Person):
         employee_name = Column(String)

The above ‘Employee’ class would be mapped as single-table inheritance
against ‘Person’; the ‘employee_name’ column would be added as a member
of the ‘Person’ table.

3.2.2.19 Composing Mapped Hierarchies with Mixins
.................................................

A common need when mapping classes using the Declarative
style is to share some functionality, such as a set of common columns,
some common table options, or other mapped properties, across many
classes.  The standard Python idioms for this is to have the classes
inherit from a superclass which includes these common features.

When using declarative mappings, this idiom is allowed via the usage of
mixin classes, as well as via augmenting the declarative base produced
by either the registry.generate_base() method or
declarative_base() functions.

An example of some commonly mixed-in idioms is below:

     from sqlalchemy.orm import declared_attr

     class MyMixin(object):

         @declared_attr
         def __tablename__(cls):
             return cls.__name__.lower()

         __table_args__ = {'mysql_engine': 'InnoDB'}
         __mapper_args__= {'always_refresh': True}

         id =  Column(Integer, primary_key=True)

     class MyModel(MyMixin, Base):
         name = Column(String(1000))

Where above, the class ‘MyModel’ will contain an “id” column as the
primary key, a ‘__tablename__’ attribute that derives from the name of
the class itself, as well as ‘__table_args__’ and ‘__mapper_args__’
defined by the ‘MyMixin’ mixin class.

There’s no fixed convention over whether ‘MyMixin’ precedes ‘Base’ or
not.  Normal Python method resolution rules apply, and the above example
would work just as well with:

     class MyModel(Base, MyMixin):
         name = Column(String(1000))

This works because ‘Base’ here doesn’t define any of the variables that
‘MyMixin’ defines, i.e.  ‘__tablename__’, ‘__table_args__’, ‘id’, etc.
If the ‘Base’ did define an attribute of the same name, the class placed
first in the inherits list would determine which attribute is used on
the newly defined class.

3.2.2.20 Augmenting the Base
............................

In addition to using a pure mixin, most of the techniques in this
section can also be applied to the base class itself, for patterns that
should apply to all classes derived from a particular base.  This is
achieved using the ‘cls’ argument of the declarative_base()
function:

     from sqlalchemy.orm import declared_attr

     class Base(object):
         @declared_attr
         def __tablename__(cls):
             return cls.__name__.lower()

         __table_args__ = {'mysql_engine': 'InnoDB'}

         id =  Column(Integer, primary_key=True)

     from sqlalchemy.orm import declarative_base

     Base = declarative_base(cls=Base)

     class MyModel(Base):
         name = Column(String(1000))

Where above, ‘MyModel’ and all other classes that derive from ‘Base’
will have a table name derived from the class name, an ‘id’ primary key
column, as well as the “InnoDB” engine for MySQL.

3.2.2.21 Mixing in Columns
..........................

The most basic way to specify a column on a mixin is by simple
declaration:

     class TimestampMixin(object):
         created_at = Column(DateTime, default=func.now())

     class MyModel(TimestampMixin, Base):
         __tablename__ = 'test'

         id =  Column(Integer, primary_key=True)
         name = Column(String(1000))

Where above, all declarative classes that include ‘TimestampMixin’ will
also have a column ‘created_at’ that applies a timestamp to all row
insertions.

Those familiar with the SQLAlchemy expression language know that the
object identity of clause elements defines their role in a schema.  Two
‘Table’ objects ‘a’ and ‘b’ may both have a column called ‘id’, but the
way these are differentiated is that ‘a.c.id’ and ‘b.c.id’ are two
distinct Python objects, referencing their parent tables ‘a’ and ‘b’
respectively.

In the case of the mixin column, it seems that only one Column
object is explicitly created, yet the ultimate ‘created_at’ column
above must exist as a distinct Python object for each separate
destination class.  To accomplish this, the declarative extension
creates a `copy' of each Column object encountered on a class
that is detected as a mixin.

This copy mechanism is limited to simple columns that have no foreign
keys, as a ForeignKey itself contains references to columns
which can’t be properly recreated at this level.  For columns that have
foreign keys, as well as for the variety of mapper-level constructs that
require destination-explicit context, the declared_attr
decorator is provided so that patterns common to many classes can be
defined as callables:

     from sqlalchemy.orm import declared_attr

     class ReferenceAddressMixin(object):
         @declared_attr
         def address_id(cls):
             return Column(Integer, ForeignKey('address.id'))

     class User(ReferenceAddressMixin, Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)

Where above, the ‘address_id’ class-level callable is executed at the
point at which the ‘User’ class is constructed, and the declarative
extension can use the resulting Column object as returned by
the method without the need to copy it.

Columns generated by declared_attr can also be referenced by
‘__mapper_args__’ to a limited degree, currently by ‘polymorphic_on’ and
‘version_id_col’; the declarative extension will resolve them at class
construction time:

     class MyMixin:
         @declared_attr
         def type_(cls):
             return Column(String(50))

         __mapper_args__= {'polymorphic_on':type_}

     class MyModel(MyMixin, Base):
         __tablename__='test'
         id =  Column(Integer, primary_key=True)

3.2.2.22 Mixing in Relationships
................................

Relationships created by relationship() are provided with
declarative mixin classes exclusively using the declared_attr
approach, eliminating any ambiguity which could arise when copying
a relationship and its possibly column-bound contents.  Below is an
example which combines a foreign key column and a relationship so that
two classes ‘Foo’ and ‘Bar’ can both be configured to reference a common
target class via many-to-one:

     class RefTargetMixin(object):
         @declared_attr
         def target_id(cls):
             return Column('target_id', ForeignKey('target.id'))

         @declared_attr
         def target(cls):
             return relationship("Target")

     class Foo(RefTargetMixin, Base):
         __tablename__ = 'foo'
         id = Column(Integer, primary_key=True)

     class Bar(RefTargetMixin, Base):
         __tablename__ = 'bar'
         id = Column(Integer, primary_key=True)

     class Target(Base):
         __tablename__ = 'target'
         id = Column(Integer, primary_key=True)

3.2.2.23 Using Advanced Relationship Arguments (e.g. ‘primaryjoin’, etc.)
.........................................................................

relationship() definitions which require explicit
primaryjoin, order_by etc.  expressions should in all but the most
simplistic cases use `late bound' forms for these arguments, meaning,
using either the string form or a function/lambda.  The reason for this
is that the related Column objects which are to be configured
using ‘@declared_attr’ are not available to another ‘@declared_attr’
attribute; while the methods will work and return new Column
objects, those are not the Column objects that Declarative
will be using as it calls the methods on its own, thus using `different'
Column objects.

The canonical example is the primaryjoin condition that depends upon
another mixed-in column:

     class RefTargetMixin(object):
         @declared_attr
         def target_id(cls):
             return Column('target_id', ForeignKey('target.id'))

         @declared_attr
         def target(cls):
             return relationship(Target,
                 primaryjoin=Target.id==cls.target_id   # this is *incorrect*
             )

Mapping a class using the above mixin, we will get an error like:

     sqlalchemy.exc.InvalidRequestError: this ForeignKey's parent column is not
     yet associated with a Table.

This is because the ‘target_id’ Column we’ve called upon in
our ‘target()’ method is not the same Column that declarative
is actually going to map to our table.

The condition above is resolved using a lambda:

     class RefTargetMixin(object):
         @declared_attr
         def target_id(cls):
             return Column('target_id', ForeignKey('target.id'))

         @declared_attr
         def target(cls):
             return relationship(Target,
                 primaryjoin=lambda: Target.id==cls.target_id
             )

or alternatively, the string form (which ultimately generates a lambda):

     class RefTargetMixin(object):
         @declared_attr
         def target_id(cls):
             return Column('target_id', ForeignKey('target.id'))

         @declared_attr
         def target(cls):
             return relationship("Target",
                 primaryjoin="Target.id==%s.target_id" % cls.__name__
             )

See also
........

See Late-Evaluation of Relationship Arguments.

3.2.2.24 Mixing in deferred(), column_property(), and other MapperProperty classes
..................................................................................

Like relationship(), all ‘MapperProperty’ subclasses such as
deferred(), column_property(), etc.  ultimately
involve references to columns, and therefore, when used with declarative
mixins, have the declared_attr requirement so that no
reliance on copying is needed:

     class SomethingMixin(object):

         @declared_attr
         def dprop(cls):
             return deferred(Column(Integer))

     class Something(SomethingMixin, Base):
         __tablename__ = "something"

The column_property() or other construct may refer to other
columns from the mixin.  These are copied ahead of time before the
declared_attr is invoked:

     class SomethingMixin(object):
         x = Column(Integer)

         y = Column(Integer)

         @declared_attr
         def x_plus_y(cls):
             return column_property(cls.x + cls.y)

Changed in version 1.0.0: mixin columns are copied to the final mapped
class so that declared_attr methods can access the actual
column that will be mapped.

3.2.2.25 Mixing in Association Proxy and Other Attributes
.........................................................

Mixins can specify user-defined attributes as well as other extension
units such as association_proxy().  The usage of
declared_attr is required in those cases where the attribute must
be tailored specifically to the target subclass.  An example is when
constructing multiple association_proxy() attributes which
each target a different type of child object.  Below is an
association_proxy() mixin example which provides a scalar list of
string values to an implementing class:

     from sqlalchemy import Column, Integer, ForeignKey, String
     from sqlalchemy.orm import relationship
     from sqlalchemy.ext.associationproxy import association_proxy
     from sqlalchemy.orm import declarative_base, declared_attr

     Base = declarative_base()

     class HasStringCollection(object):
         @declared_attr
         def _strings(cls):
             class StringAttribute(Base):
                 __tablename__ = cls.string_table_name
                 id = Column(Integer, primary_key=True)
                 value = Column(String(50), nullable=False)
                 parent_id = Column(Integer,
                                 ForeignKey('%s.id' % cls.__tablename__),
                                 nullable=False)
                 def __init__(self, value):
                     self.value = value

             return relationship(StringAttribute)

         @declared_attr
         def strings(cls):
             return association_proxy('_strings', 'value')

     class TypeA(HasStringCollection, Base):
         __tablename__ = 'type_a'
         string_table_name = 'type_a_strings'
         id = Column(Integer(), primary_key=True)

     class TypeB(HasStringCollection, Base):
         __tablename__ = 'type_b'
         string_table_name = 'type_b_strings'
         id = Column(Integer(), primary_key=True)

Above, the ‘HasStringCollection’ mixin produces a relationship()
which refers to a newly generated class called ‘StringAttribute’.
The ‘StringAttribute’ class is generated with its own Table
definition which is local to the parent class making usage of the
‘HasStringCollection’ mixin.  It also produces an
association_proxy() object which proxies references to the
‘strings’ attribute onto the ‘value’ attribute of each ‘StringAttribute’
instance.

‘TypeA’ or ‘TypeB’ can be instantiated given the constructor argument
‘strings’, a list of strings:

     ta = TypeA(strings=['foo', 'bar'])
     tb = TypeB(strings=['bat', 'bar'])

This list will generate a collection of ‘StringAttribute’ objects, which
are persisted into a table that’s local to either the ‘type_a_strings’
or ‘type_b_strings’ table:

     >>> print(ta._strings)
     [<__main__.StringAttribute object at 0x10151cd90>,
         <__main__.StringAttribute object at 0x10151ce10>]

When constructing the association_proxy(), the
declared_attr decorator must be used so that a distinct
association_proxy() object is created for each of the ‘TypeA’ and
‘TypeB’ classes.

3.2.2.26 Controlling table inheritance with mixins
..................................................

The ‘__tablename__’ attribute may be used to provide a function that
will determine the name of the table used for each class in an
inheritance hierarchy, as well as whether a class has its own distinct
table.

This is achieved using the declared_attr indicator in
conjunction with a method named ‘__tablename__()’.  Declarative will
always invoke declared_attr for the special names
‘__tablename__’, ‘__mapper_args__’ and ‘__table_args__’ function `for
each mapped class in the hierarchy, except if overridden in a subclass'.
The function therefore needs to expect to receive each class
individually and to provide the correct answer for each.

For example, to create a mixin that gives every class a simple table
name based on class name:

     from sqlalchemy.orm import declared_attr

     class Tablename:
         @declared_attr
         def __tablename__(cls):
             return cls.__name__.lower()

     class Person(Tablename, Base):
         id = Column(Integer, primary_key=True)
         discriminator = Column('type', String(50))
         __mapper_args__ = {'polymorphic_on': discriminator}

     class Engineer(Person):
         __tablename__ = None
         __mapper_args__ = {'polymorphic_identity': 'engineer'}
         primary_language = Column(String(50))

Alternatively, we can modify our ‘__tablename__’ function to return
‘None’ for subclasses, using has_inherited_table().  This has
the effect of those subclasses being mapped with single table
inheritance against the parent:

     from sqlalchemy.orm import declared_attr
     from sqlalchemy.orm import has_inherited_table

     class Tablename(object):
         @declared_attr
         def __tablename__(cls):
             if has_inherited_table(cls):
                 return None
             return cls.__name__.lower()

     class Person(Tablename, Base):
         id = Column(Integer, primary_key=True)
         discriminator = Column('type', String(50))
         __mapper_args__ = {'polymorphic_on': discriminator}

     class Engineer(Person):
         primary_language = Column(String(50))
         __mapper_args__ = {'polymorphic_identity': 'engineer'}

3.2.2.27 Mixing in Columns in Inheritance Scenarios
...................................................

In contrast to how ‘__tablename__’ and other special names are handled
when used with declared_attr, when we mix in columns and
properties (e.g.  relationships, column properties, etc.), the function
is invoked for the `base class only' in the hierarchy.  Below, only the
‘Person’ class will receive a column called ‘id’; the mapping will fail
on ‘Engineer’, which is not given a primary key:

     class HasId(object):
         @declared_attr
         def id(cls):
             return Column('id', Integer, primary_key=True)

     class Person(HasId, Base):
         __tablename__ = 'person'
         discriminator = Column('type', String(50))
         __mapper_args__ = {'polymorphic_on': discriminator}

     class Engineer(Person):
         __tablename__ = 'engineer'
         primary_language = Column(String(50))
         __mapper_args__ = {'polymorphic_identity': 'engineer'}

It is usually the case in joined-table inheritance that we want
distinctly named columns on each subclass.  However in this case, we may
want to have an ‘id’ column on every table, and have them refer to each
other via foreign key.  We can achieve this as a mixin by using the
declared_attr.cascading modifier, which indicates that the
function should be invoked `for each class in the hierarchy', in
`almost' (see warning below) the same way as it does for
‘__tablename__’:

     class HasIdMixin(object):
         @declared_attr.cascading
         def id(cls):
             if has_inherited_table(cls):
                 return Column(ForeignKey('person.id'), primary_key=True)
             else:
                 return Column(Integer, primary_key=True)

     class Person(HasIdMixin, Base):
         __tablename__ = 'person'
         discriminator = Column('type', String(50))
         __mapper_args__ = {'polymorphic_on': discriminator}

     class Engineer(Person):
         __tablename__ = 'engineer'
         primary_language = Column(String(50))
         __mapper_args__ = {'polymorphic_identity': 'engineer'}

     Warning: The declared_attr.cascading feature currently
     does `not' allow for a subclass to override the attribute with a
     different function or value.  This is a current limitation in the
     mechanics of how ‘@declared_attr’ is resolved, and a warning is
     emitted if this condition is detected.  This limitation does `not'
     exist for the special attribute names such as ‘__tablename__’,
     which resolve in a different way internally than that of
     declared_attr.cascading.

New in version 1.0.0: added declared_attr.cascading.

3.2.2.28 Combining Table/Mapper Arguments from Multiple Mixins
..............................................................

In the case of ‘__table_args__’ or ‘__mapper_args__’ specified with
declarative mixins, you may want to combine some parameters from several
mixins with those you wish to define on the class itself.  The
declared_attr decorator can be used here to create user-defined
collation routines that pull from multiple collections:

     from sqlalchemy.orm import declared_attr

     class MySQLSettings(object):
         __table_args__ = {'mysql_engine':'InnoDB'}

     class MyOtherMixin(object):
         __table_args__ = {'info':'foo'}

     class MyModel(MySQLSettings, MyOtherMixin, Base):
         __tablename__='my_model'

         @declared_attr
         def __table_args__(cls):
             args = dict()
             args.update(MySQLSettings.__table_args__)
             args.update(MyOtherMixin.__table_args__)
             return args

         id =  Column(Integer, primary_key=True)

3.2.2.29 Creating Indexes with Mixins
.....................................

To define a named, potentially multicolumn Index that
applies to all tables derived from a mixin, use the “inline” form of
Index and establish it as part of ‘__table_args__’:

     class MyMixin(object):
         a =  Column(Integer)
         b =  Column(Integer)

         @declared_attr
         def __table_args__(cls):
             return (Index('test_idx_%s' % cls.__tablename__, 'a', 'b'),)

     class MyModel(MyMixin, Base):
         __tablename__ = 'atable'
         c =  Column(Integer,primary_key=True)

3.2.3 Mapping Columns and Expressions
-------------------------------------

The following sections discuss how table columns and SQL expressions are
mapped to individual object attributes.

3.2.3.1 Mapping Table Columns
.............................

The default behavior of mapper() is to assemble all the
columns in the mapped Table into mapped object attributes,
each of which are named according to the name of the column itself
(specifically, the ‘key’ attribute of Column).  This behavior
can be modified in several ways.

3.2.3.2 Naming Columns Distinctly from Attribute Names
......................................................

A mapping by default shares the same name for a Column as
that of the mapped attribute - specifically it matches the ‘Column.key’
attribute on Column, which by default is the same as the
‘Column.name’.

The name assigned to the Python attribute which maps to Column
can be different from either ‘Column.name’ or ‘Column.key’ just by
assigning it that way, as we illustrate here in a Declarative mapping:

     class User(Base):
         __tablename__ = 'user'
         id = Column('user_id', Integer, primary_key=True)
         name = Column('user_name', String(50))

Where above ‘User.id’ resolves to a column named ‘user_id’ and
‘User.name’ resolves to a column named ‘user_name’.

When mapping to an existing table, the Column object can be
referenced directly:

     class User(Base):
         __table__ = user_table
         id = user_table.c.user_id
         name = user_table.c.user_name

The corresponding technique for an imperative mapping is to place the
desired key in the mapper.properties dictionary with the
desired key:

     mapper_registry.map_imperatively(User, user_table, properties={
        'id': user_table.c.user_id,
        'name': user_table.c.user_name,
     })

In the next section we’ll examine the usage of ‘.key’ more closely.

3.2.3.3 Automating Column Naming Schemes from Reflected Tables
..............................................................

In the previous section Naming Columns Distinctly from Attribute Names,
we showed how a Column explicitly mapped to a
class can have a different attribute name than the column.  But what if
we aren’t listing out Column objects explicitly, and instead
are automating the production of Table objects using
reflection (e.g.  as described in Reflecting Database Objects)
?  In this case we can make use of the
DDLEvents.column_reflect() event to intercept the production of
Column objects and provide them with the ‘Column.key’ of our
choice.  The event is most easily associated with the MetaData
object that’s in use, such as below we use the one linked to the
declarative_base instance:

     @event.listens_for(Base.metadata, "column_reflect")
     def column_reflect(inspector, table, column_info):
         # set column.key = "attr_<lower_case_name>"
         column_info['key'] = "attr_%s" % column_info['name'].lower()

With the above event, the reflection of Column objects will
be intercepted with our event that adds a new “.key” element, such as in
a mapping as below:

     class MyClass(Base):
         __table__ = Table("some_table", Base.metadata,
                     autoload_with=some_engine)

The approach also works with the Automap extension.  See the
section Intercepting Column Definitions for background.

See also
........

See DDLEvents.column_reflect().

See Intercepting Column Definitions. - in the Automap
documentation

3.2.3.4 Naming All Columns with a Prefix
........................................

A quick approach to prefix column names, typically when mapping to an
existing Table object, is to use ‘column_prefix’:

     class User(Base):
         __table__ = user_table
         __mapper_args__ = {'column_prefix':'_'}

The above will place attribute names such as ‘_user_id’, ‘_user_name’,
‘_password’ etc.  on the mapped ‘User’ class.

This approach is uncommon in modern usage.  For dealing with reflected
tables, a more flexible approach is to use that described in
Automating Column Naming Schemes from Reflected Tables.

3.2.3.5 Using column_property for column level options
......................................................

Options can be specified when mapping a Column using the
column_property() function.  This function explicitly
creates the ColumnProperty used by the mapper()
to keep track of the Column; normally, the mapper()
creates this automatically.  Using column_property(), we
can pass additional arguments about how we’d like the Column
to be mapped.  Below, we pass an option ‘active_history’, which
specifies that a change to this column’s value should result in the
former value being loaded first:

     from sqlalchemy.orm import column_property

     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         name = column_property(Column(String(50)), active_history=True)

column_property() is also used to map a single attribute to
multiple columns.  This use case arises when mapping to a join()
which has attributes which are equated to each other:

     class User(Base):
         __table__ = user.join(address)

         # assign "user.id", "address.user_id" to the
         # "id" attribute
         id = column_property(user_table.c.id, address_table.c.user_id)

For more examples featuring this usage, see Mapping a Class against Multiple Tables.

Another place where column_property() is needed is to
specify SQL expressions as mapped attributes, such as below where we
create an attribute ‘fullname’ that is the string concatenation of the
‘firstname’ and ‘lastname’ columns:

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         firstname = Column(String(50))
         lastname = Column(String(50))
         fullname = column_property(firstname + " " + lastname)

See examples of this usage at SQL Expressions as Mapped Attributes.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See column_property.(*columns,Provide a column-level property for use with a mapping.
**kwargs)

 -- Function: sqlalchemy.orm.column_property (*columns, **kwargs)

     Provide a column-level property for use with a mapping.

     Column-based properties can normally be applied to the mapper’s
     ‘properties’ dictionary using the Column element
     directly.  Use this function when the given column is not directly
     present within the mapper’s selectable; examples include SQL
     expressions, functions, and scalar SELECT queries.

     The column_property() function returns an instance of
     ColumnProperty.

     Columns that aren’t present in the mapper’s selectable won’t be
     persisted by the mapper and are effectively “read-only” attributes.

     Parameters:

        * ‘*cols’ – list of Column objects to be mapped.

        * ‘active_history=False’ – When ‘True’, indicates that the
          “previous” value for a scalar attribute should be loaded when
          replaced, if not already loaded.  Normally, history tracking
          logic for simple non-primary-key scalar values only needs to
          be aware of the “new” value in order to perform a flush.  This
          flag is available for applications that make use of
          get_history() or Session.is_modified() which
          also need to know the “previous” value of the attribute.

        * ‘comparator_factory’ – a class which extends Comparator
          which provides custom SQL clause generation for
          comparison operations.

        * ‘group’ – a group name for this property when marked as
          deferred.

        * ‘deferred’ – when True, the column property is “deferred”,
          meaning that it does not load immediately, and is instead
          loaded when the attribute is first accessed on an instance.
          See also deferred().

        * ‘doc’ – optional string that will be applied as the doc on the
          class-bound descriptor.

        * ‘expire_on_flush=True’ – Disable expiry on flush.  A
          column_property() which refers to a SQL expression (and not a
          single table-bound column) is considered to be a “read only”
          property; populating it has no effect on the state of data,
          and it can only return database state.  For this reason a
          column_property()’s value is expired whenever the parent
          object is involved in a flush, that is, has any kind of
          “dirty” state within a flush.  Setting this parameter to
          ‘False’ will have the effect of leaving any existing value
          present after the flush proceeds.  Note however that the
          Session with default expiration settings still expires
          all attributes after a Session.commit() call,
          however.

        * ‘info’ – Optional data dictionary which will be populated into
          the MapperProperty.info attribute of this object.

        * ‘raiseload’ – if True, indicates the column should raise an
          error when undeferred, rather than loading the value.  This
          can be altered at query time by using the deferred()
          option with raiseload=False.

          New in version 1.4.

          See also
          ........

          See Raiseload for Deferred Columns.

     See also
     ........

     See Using column_property for column level options. - to map
     columns while including mapping options

     See Using column_property. - to map SQL expressions

3.2.3.6 Mapping a Subset of Table Columns
.........................................

Sometimes, a Table object was made available using the
reflection process described at Reflecting Database Objects
to load the table’s structure from the database.  For such a table that
has lots of columns that don’t need to be referenced in the application,
the ‘include_properties’ or ‘exclude_properties’ arguments can specify
that only a subset of columns should be mapped.  For example:

     class User(Base):
         __table__ = user_table
         __mapper_args__ = {
             'include_properties' :['user_id', 'user_name']
         }

…will map the ‘User’ class to the ‘user_table’ table, only including the
‘user_id’ and ‘user_name’ columns - the rest are not referenced.
Similarly:

     class Address(Base):
         __table__ = address_table
         __mapper_args__ = {
             'exclude_properties' : ['street', 'city', 'state', 'zip']
         }

…will map the ‘Address’ class to the ‘address_table’ table, including
all columns present except ‘street’, ‘city’, ‘state’, and ‘zip’.

When this mapping is used, the columns that are not included will not be
referenced in any SELECT statements emitted by Query, nor
will there be any mapped attribute on the mapped class which represents
the column; assigning an attribute of that name will have no effect
beyond that of a normal Python attribute assignment.

In some cases, multiple columns may have the same name, such as when
mapping to a join of two or more tables that share some column name.
‘include_properties’ and ‘exclude_properties’ can also accommodate
Column objects to more accurately describe which columns should be
included or excluded:

     class UserAddress(Base):
         __table__ = user_table.join(addresses_table)
         __mapper_args__ = {
             'exclude_properties' :[address_table.c.id],
             'primary_key' : [user_table.c.id]
         }

     Note: insert and update defaults configured on individual
     Column objects, i.e.  those described at Column INSERT/UPDATE Defaults
     including those configured by the
     Column.default, Column.onupdate,
     Column.server_default and Column.server_onupdate
     parameters, will continue to function normally even if those
     Column objects are not mapped.  This is because in the case of
     Column.default and Column.onupdate, the
     Column object is still present on the underlying
     Table, thus allowing the default functions to take place when
     the ORM emits an INSERT or UPDATE, and in the case of
     Column.server_default and Column.server_onupdate,
     the relational database itself emits these defaults as a server
     side behavior.

3.2.3.7 SQL Expressions as Mapped Attributes
............................................

Attributes on a mapped class can be linked to SQL expressions, which can
be used in queries.

3.2.3.8 Using a Hybrid
......................

The easiest and most flexible way to link relatively simple SQL
expressions to a class is to use a so-called “hybrid attribute”,
described in the section Hybrid Attributes.  The hybrid
provides for an expression that works at both the Python level as well
as at the SQL expression level.  For example, below we map a class
‘User’, containing attributes ‘firstname’ and ‘lastname’, and include a
hybrid that will provide for us the ‘fullname’, which is the string
concatenation of the two:

     from sqlalchemy.ext.hybrid import hybrid_property

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         firstname = Column(String(50))
         lastname = Column(String(50))

         @hybrid_property
         def fullname(self):
             return self.firstname + " " + self.lastname

Above, the ‘fullname’ attribute is interpreted at both the instance and
class level, so that it is available from an instance:

     some_user = session.query(User).first()
     print(some_user.fullname)

as well as usable within queries:

     some_user = session.query(User).filter(User.fullname == "John Smith").first()

The string concatenation example is a simple one, where the Python
expression can be dual purposed at the instance and class level.  Often,
the SQL expression must be distinguished from the Python expression,
which can be achieved using hybrid_property.expression().
Below we illustrate the case where a conditional needs to be present
inside the hybrid, using the ‘if’ statement in Python and the
case() construct for SQL expressions:

     from sqlalchemy.ext.hybrid import hybrid_property
     from sqlalchemy.sql import case

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         firstname = Column(String(50))
         lastname = Column(String(50))

         @hybrid_property
         def fullname(self):
             if self.firstname is not None:
                 return self.firstname + " " + self.lastname
             else:
                 return self.lastname

         @fullname.expression
         def fullname(cls):
             return case([
                 (cls.firstname != None, cls.firstname + " " + cls.lastname),
             ], else_ = cls.lastname)

3.2.3.9 Using column_property
.............................

The column_property() function can be used to map a SQL
expression in a manner similar to a regularly mapped Column.
With this technique, the attribute is loaded along with all other
column-mapped attributes at load time.  This is in some cases an
advantage over the usage of hybrids, as the value can be loaded up front
at the same time as the parent row of the object, particularly if the
expression is one which links to other tables (typically as a correlated
subquery) to access data that wouldn’t normally be available on an
already loaded object.

Disadvantages to using column_property() for SQL expressions
include that the expression must be compatible with the SELECT statement
emitted for the class as a whole, and there are also some
configurational quirks which can occur when using
column_property() from declarative mixins.

Our “fullname” example can be expressed using column_property()
as follows:

     from sqlalchemy.orm import column_property

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         firstname = Column(String(50))
         lastname = Column(String(50))
         fullname = column_property(firstname + " " + lastname)

Correlated subqueries may be used as well.  Below we use the
select() construct to create a SELECT that links together the count
of ‘Address’ objects available for a particular ‘User’:

     from sqlalchemy.orm import column_property
     from sqlalchemy import select, func
     from sqlalchemy import Column, Integer, String, ForeignKey

     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class Address(Base):
         __tablename__ = 'address'
         id = Column(Integer, primary_key=True)
         user_id = Column(Integer, ForeignKey('user.id'))

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         address_count = column_property(
             select(func.count(Address.id)).\
                 where(Address.user_id==id).\
                 correlate_except(Address)
         )

In the above example, we define a select() construct like the
following:

     select(func.count(Address.id)).\
         where(Address.user_id==id).\
         correlate_except(Address)

The meaning of the above statement is, select the count of ‘Address.id’
rows where the ‘Address.user_id’ column is equated to ‘id’, which in the
context of the ‘User’ class is the Column named ‘id’ (note
that ‘id’ is also the name of a Python built in function, which is not
what we want to use here - if we were outside of the ‘User’ class
definition, we’d use ‘User.id’).

The ‘select.correlate_except()’ directive indicates that each element in
the FROM clause of this select() may be omitted from the FROM
list (that is, correlated to the enclosing SELECT statement against
‘User’) except for the one corresponding to ‘Address’.  This isn’t
strictly necessary, but prevents ‘Address’ from being inadvertently
omitted from the FROM list in the case of a long string of joins between
‘User’ and ‘Address’ tables where SELECT statements against ‘Address’
are nested.

If import issues prevent the column_property() from being
defined inline with the class, it can be assigned to the class after
both are configured.  In Declarative this has the effect of calling
Mapper.add_property() to add an additional property after
the fact:

     User.address_count = column_property(
             select(func.count(Address.id)).\
                 where(Address.user_id==User.id)
         )

For a column_property() that refers to columns linked from a
many-to-many relationship, use and_() to join the fields of
the association table to both tables in a relationship:

     from sqlalchemy import and_

     class Author(Base):
         # ...

         book_count = column_property(
             select(func.count(books.c.id)
             ).where(
                 and_(
                     book_authors.c.author_id==authors.c.id,
                     book_authors.c.book_id==books.c.id
                 )
             )
         )

3.2.3.10 Composing from Column Properties at Mapping Time
.........................................................

It is possible to create mappings that combine multiple
ColumnProperty objects together.  The ColumnProperty
will be interpreted as a SQL expression when used in a Core expression
context, provided that it is targeted by an existing expression object;
this works by the Core detecting that the object has a
‘__clause_element__()’ method which returns a SQL expression.  However,
if the ColumnProperty is used as a lead object in an
expression where there is no other Core SQL expression object to target
it, the ColumnProperty.expression attribute will return the
underlying SQL expression so that it can be used to build SQL
expressions consistently.  Below, the ‘File’ class contains an attribute
‘File.path’ that concatenates a string token to the ‘File.filename’
attribute, which is itself a ColumnProperty:

     class File(Base):
         __tablename__ = 'file'

         id = Column(Integer, primary_key=True)
         name = Column(String(64))
         extension = Column(String(8))
         filename = column_property(name + '.' + extension)
         path = column_property('C:/' + filename.expression)

When the ‘File’ class is used in expressions normally, the attributes
assigned to ‘filename’ and ‘path’ are usable directly.  The use of the
ColumnProperty.expression attribute is only necessary when
using the ColumnProperty directly within the mapping
definition:

     q = session.query(File.path).filter(File.filename == 'foo.txt')

3.2.3.11 Using a plain descriptor
.................................

In cases where a SQL query more elaborate than what
column_property() or hybrid_property can provide must
be emitted, a regular Python function accessed as an attribute can be
used, assuming the expression only needs to be available on an
already-loaded instance.  The function is decorated with Python’s own
‘@property’ decorator to mark it as a read-only attribute.  Within the
function, see object_session() is used to locate the
Session corresponding to the current object, which is then used to
emit a query:

     from sqlalchemy.orm import object_session
     from sqlalchemy import select, func

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         firstname = Column(String(50))
         lastname = Column(String(50))

         @property
         def address_count(self):
             return object_session(self).\
                 scalar(
                     select(func.count(Address.id)).\
                         where(Address.user_id==self.id)
                 )

The plain descriptor approach is useful as a last resort, but is less
performant in the usual case than both the hybrid and column property
approaches, in that it needs to emit a SQL query upon each access.

3.2.3.12 Query-time SQL expressions as mapped attributes
........................................................

When using Session.query(), we have the option to specify not
just mapped entities but ad-hoc SQL expressions as well.  Suppose if a
class ‘A’ had integer attributes ‘.x’ and ‘.y’, we could query for ‘A’
objects, and additionally the sum of ‘.x’ and ‘.y’, as follows:

     q = session.query(A, A.x + A.y)

The above query returns tuples of the form ‘(A object, integer)’.

An option exists which can apply the ad-hoc ‘A.x + A.y’ expression to
the returned ‘A’ objects instead of as a separate tuple entry; this is
the with_expression() query option in conjunction with the
query_expression() attribute mapping.  The class is mapped
to include a placeholder attribute where any particular SQL expression
may be applied:

     from sqlalchemy.orm import query_expression

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)
         x = Column(Integer)
         y = Column(Integer)

         expr = query_expression()

We can then query for objects of type ‘A’, applying an arbitrary SQL
expression to be populated into ‘A.expr’:

     from sqlalchemy.orm import with_expression
     q = session.query(A).options(
         with_expression(A.expr, A.x + A.y))

The query_expression() mapping has these caveats:

   * On an object where query_expression() were not used to
     populate the attribute, the attribute on an object instance will
     have the value ‘None’, unless the
     query_expression.default_expr parameter is set to an
     alternate SQL expression.

   * The query_expression value `does not populate on an object that is
     already loaded'.  That is, this will `not work':

          obj = session.query(A).first()

          obj = session.query(A).options(with_expression(A.expr, some_expr)).first()

     To ensure the attribute is re-loaded, use
     Query.populate_existing():

          obj = session.query(A).populate_existing().options(
              with_expression(A.expr, some_expr)).first()

   * The query_expression value `does not refresh when the object is
     expired'.  Once the object is expired, either via
     Session.expire() or via the expire_on_commit behavior of
     Session.commit(), the value is removed from the attribute
     and will return ‘None’ on subsequent access.  Only by running a new
     Query that touches the object which includes a new
     with_expression() directive will the attribute be set
     to a non-None value.

   * The mapped attribute currently `cannot' be applied to other parts
     of the query, such as the WHERE clause, the ORDER BY clause, and
     make use of the ad-hoc expression; that is, this won’t work:

          # wont work
          q = session.query(A).options(
              with_expression(A.expr, A.x + A.y)
          ).filter(A.expr > 5).order_by(A.expr)

     The ‘A.expr’ expression will resolve to NULL in the above WHERE
     clause and ORDER BY clause.  To use the expression throughout the
     query, assign to a variable and use that:

          a_expr = A.x + A.y
          q = session.query(A).options(
              with_expression(A.expr, a_expr)
          ).filter(a_expr > 5).order_by(a_expr)

New in version 1.2.

3.2.3.13 Changing Attribute Behavior
....................................

3.2.3.14 Simple Validators
..........................

A quick way to add a “validation” routine to an attribute is to use the
validates() decorator.  An attribute validator can raise an
exception, halting the process of mutating the attribute’s value, or can
change the given value into something different.  Validators, like all
attribute extensions, are only called by normal userland code; they are
not issued when the ORM is populating the object:

     from sqlalchemy.orm import validates

     class EmailAddress(Base):
         __tablename__ = 'address'

         id = Column(Integer, primary_key=True)
         email = Column(String)

         @validates('email')
         def validate_email(self, key, address):
             assert '@' in address
             return address

Changed in version 1.0.0: - validators are no longer triggered within
the flush process when the newly fetched values for primary key columns
as well as some python- or server-side defaults are fetched.  Prior to
1.0, validators may be triggered in those cases as well.

Validators also receive collection append events, when items are added
to a collection:

     from sqlalchemy.orm import validates

     class User(Base):
         # ...

         addresses = relationship("Address")

         @validates('addresses')
         def validate_address(self, key, address):
             assert '@' in address.email
             return address

The validation function by default does not get emitted for collection
remove events, as the typical expectation is that a value being
discarded doesn’t require validation.  However, see validates()
supports reception of these events by specifying ‘include_removes=True’
to the decorator.  When this flag is set, the validation function must
receive an additional boolean argument which if ‘True’ indicates that
the operation is a removal:

     from sqlalchemy.orm import validates

     class User(Base):
         # ...

         addresses = relationship("Address")

         @validates('addresses', include_removes=True)
         def validate_address(self, key, address, is_remove):
             if is_remove:
                 raise ValueError(
                         "not allowed to remove items from the collection")
             else:
                 assert '@' in address.email
                 return address

The case where mutually dependent validators are linked via a backref
can also be tailored, using the ‘include_backrefs=False’ option; this
option, when set to ‘False’, prevents a validation function from
emitting if the event occurs as a result of a backref:

     from sqlalchemy.orm import validates

     class User(Base):
         # ...

         addresses = relationship("Address", backref='user')

         @validates('addresses', include_backrefs=False)
         def validate_address(self, key, address):
             assert '@' in address.email
             return address

Above, if we were to assign to ‘Address.user’ as in ‘some_address.user =
some_user’, the ‘validate_address()’ function would `not' be emitted,
even though an append occurs to ‘some_user.addresses’ - the event is
caused by a backref.

Note that the validates() decorator is a convenience
function built on top of attribute events.  An application that requires
more control over configuration of attribute change behavior can make
use of this system, described at AttributeEvents.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See validates.(*names,Decorate a method as a ‘validator’ for one or more named properties.
**kw)

 -- Function: sqlalchemy.orm.validates (*names, **kw)

     Decorate a method as a ‘validator’ for one or more named
     properties.

     Designates a method as a validator, a method which receives the
     name of the attribute as well as a value to be assigned, or in the
     case of a collection, the value to be added to the collection.  The
     function can then raise validation exceptions to halt the process
     from continuing (where Python’s built-in ‘ValueError’ and
     ‘AssertionError’ exceptions are reasonable choices), or can modify
     or replace the value before proceeding.  The function should
     otherwise return the given value.

     Note that a validator for a collection `cannot' issue a load of
     that collection within the validation routine - this usage raises
     an assertion to avoid recursion overflows.  This is a reentrant
     condition which is not supported.

     Parameters:

        * ‘*names’ – list of attribute names to be validated.

        * ‘include_removes’ – if True, “remove” events will be sent as
          well - the validation function must accept an additional
          argument “is_remove” which will be a boolean.

        * ‘include_backrefs’ – defaults to ‘True’; if ‘False’, the
          validation function will not emit if the originator is an
          attribute event related via a backref.  This can be used for
          bi-directional validates() usage where only one
          validator should emit per attribute operation.

          New in version 0.9.0.

     See also
     ........

     See Simple Validators. - usage examples for
     validates().

3.2.3.15 Using Custom Datatypes at the Core Level
.................................................

A non-ORM means of affecting the value of a column in a way that suits
converting data between how it is represented in Python, vs.  how it is
represented in the database, can be achieved by using a custom datatype
that is applied to the mapped Table metadata.  This is more
common in the case of some style of encoding / decoding that occurs both
as data goes to the database and as it is returned; read more about this
in the Core documentation at Augmenting Existing Types.

3.2.3.16 Using Descriptors and Hybrids
......................................

A more comprehensive way to produce modified behavior for an attribute
is to use descriptors.  These are commonly used in Python using the
‘property()’ function.  The standard SQLAlchemy technique for
descriptors is to create a plain descriptor, and to have it read/write
from a mapped attribute with a different name.  Below we illustrate this
using Python 2.6-style properties:

     class EmailAddress(Base):
         __tablename__ = 'email_address'

         id = Column(Integer, primary_key=True)

         # name the attribute with an underscore,
         # different from the column name
         _email = Column("email", String)

         # then create an ".email" attribute
         # to get/set "._email"
         @property
         def email(self):
             return self._email

         @email.setter
         def email(self, email):
             self._email = email

The approach above will work, but there’s more we can add.  While our
‘EmailAddress’ object will shuttle the value through the ‘email’
descriptor and into the ‘_email’ mapped attribute, the class level
‘EmailAddress.email’ attribute does not have the usual expression
semantics usable with Query.  To provide these, we instead
use the hybrid extension as follows:

     from sqlalchemy.ext.hybrid import hybrid_property

     class EmailAddress(Base):
         __tablename__ = 'email_address'

         id = Column(Integer, primary_key=True)

         _email = Column("email", String)

         @hybrid_property
         def email(self):
             return self._email

         @email.setter
         def email(self, email):
             self._email = email

The ‘.email’ attribute, in addition to providing getter/setter behavior
when we have an instance of ‘EmailAddress’, also provides a SQL
expression when used at the class level, that is, from the
‘EmailAddress’ class directly:

     from sqlalchemy.orm import Session
     session = Session()

     {sql}address = session.query(EmailAddress).\
                      filter(EmailAddress.email == 'address@example.com').\
                      one()
     SELECT address.email AS address_email, address.id AS address_id
     FROM address
     WHERE address.email = ?
     ('address@example.com',)
     {stop}

     address.email = 'otheraddress@example.com'
     {sql}session.commit()
     UPDATE address SET email=? WHERE address.id = ?
     ('otheraddress@example.com', 1)
     COMMIT
     {stop}

The hybrid_property also allows us to change the behavior of
the attribute, including defining separate behaviors when the attribute
is accessed at the instance level versus at the class/expression level,
using the hybrid_property.expression() modifier.  Such as,
if we wanted to add a host name automatically, we might define two sets
of string manipulation logic:

     class EmailAddress(Base):
         __tablename__ = 'email_address'

         id = Column(Integer, primary_key=True)

         _email = Column("email", String)

         @hybrid_property
         def email(self):
             """Return the value of _email up until the last twelve
             characters."""

             return self._email[:-12]

         @email.setter
         def email(self, email):
             """Set the value of _email, tacking on the twelve character
             value @example.com."""

             self._email = email + "@example.com"

         @email.expression
         def email(cls):
             """Produce a SQL expression that represents the value
             of the _email column, minus the last twelve characters."""

             return func.substr(cls._email, 0, func.length(cls._email) - 12)

Above, accessing the ‘email’ property of an instance of ‘EmailAddress’
will return the value of the ‘_email’ attribute, removing or adding the
hostname ‘@example.com’ from the value.  When we query against the
‘email’ attribute, a SQL function is rendered which produces the same
effect:

     {sql}address = session.query(EmailAddress).filter(EmailAddress.email == 'address').one()
     SELECT address.email AS address_email, address.id AS address_id
     FROM address
     WHERE substr(address.email, ?, length(address.email) - ?) = ?
     (0, 12, 'address')
     {stop}

Read more about Hybrids at Hybrid Attributes.

3.2.3.17 Synonyms
.................

Synonyms are a mapper-level construct that allow any attribute on a
class to “mirror” another attribute that is mapped.

In the most basic sense, the synonym is an easy way to make a certain
attribute available by an additional name:

     from sqlalchemy.orm import synonym

     class MyClass(Base):
         __tablename__ = 'my_table'

         id = Column(Integer, primary_key=True)
         job_status = Column(String(50))

         status = synonym("job_status")

The above class ‘MyClass’ has two attributes, ‘.job_status’ and
‘.status’ that will behave as one attribute, both at the expression
level:

     >>> print(MyClass.job_status == 'some_status')
     my_table.job_status = :job_status_1

     >>> print(MyClass.status == 'some_status')
     my_table.job_status = :job_status_1

and at the instance level:

     >>> m1 = MyClass(status='x')
     >>> m1.status, m1.job_status
     ('x', 'x')

     >>> m1.job_status = 'y'
     >>> m1.status, m1.job_status
     ('y', 'y')

The synonym() can be used for any kind of mapped attribute
that subclasses MapperProperty, including mapped columns and
relationships, as well as synonyms themselves.

Beyond a simple mirror, see synonym() can also be made to
reference a user-defined descriptor.  We can supply our ‘status’ synonym
with a ‘@property’:

     class MyClass(Base):
         __tablename__ = 'my_table'

         id = Column(Integer, primary_key=True)
         status = Column(String(50))

         @property
         def job_status(self):
             return "Status: " + self.status

         job_status = synonym("status", descriptor=job_status)

When using Declarative, the above pattern can be expressed more
succinctly using the synonym_for() decorator:

     from sqlalchemy.ext.declarative import synonym_for

     class MyClass(Base):
         __tablename__ = 'my_table'

         id = Column(Integer, primary_key=True)
         status = Column(String(50))

         @synonym_for("status")
         @property
         def job_status(self):
             return "Status: " + self.status

While the synonym() is useful for simple mirroring, the use
case of augmenting attribute behavior with descriptors is better handled
in modern usage using the hybrid attribute feature, which is
more oriented towards Python descriptors.  Technically, a
synonym() can do everything that a hybrid_property can
do, as it also supports injection of custom SQL capabilities, but the
hybrid is more straightforward to use in more complex situations.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See synonym.(name[,Denote an attribute name as a synonym to a mapped property, in that the attribute will
map_column,    mirror the value and expression behavior of another attribute.
descriptor,
comparator_factory,
...])

 -- Function: sqlalchemy.orm.synonym (name, map_column=None,
          descriptor=None, comparator_factory=None, doc=None, info=None)

     Denote an attribute name as a synonym to a mapped property, in that
     the attribute will mirror the value and expression behavior of
     another attribute.

     e.g.:

          class MyClass(Base):
              __tablename__ = 'my_table'

              id = Column(Integer, primary_key=True)
              job_status = Column(String(50))

              status = synonym("job_status")

     Parameters:

        * ‘name’ – the name of the existing mapped property.  This can
          refer to the string name ORM-mapped attribute configured on
          the class, including column-bound attributes and
          relationships.

        * ‘descriptor’ – a Python descriptor that will be used as a
          getter (and potentially a setter) when this attribute is
          accessed at the instance level.

        * ‘map_column’ – `For classical mappings and mappings against an
          existing Table object only'.  if ‘True’, the synonym()
          construct will locate the Column object upon
          the mapped table that would normally be associated with the
          attribute name of this synonym, and produce a new
          ColumnProperty that instead maps this Column
          to the alternate name given as the “name” argument of the
          synonym; in this way, the usual step of redefining the mapping
          of the Column to be under a different name is
          unnecessary.  This is usually intended to be used when a
          Column is to be replaced with an attribute that also uses
          a descriptor, that is, in conjunction with the
          synonym.descriptor parameter:

               my_table = Table(
                   "my_table", metadata,
                   Column('id', Integer, primary_key=True),
                   Column('job_status', String(50))
               )

               class MyClass(object):
                   @property
                   def _job_status_descriptor(self):
                       return "Status: %s" % self._job_status

               mapper(
                   MyClass, my_table, properties={
                       "job_status": synonym(
                           "_job_status", map_column=True,
                           descriptor=MyClass._job_status_descriptor)
                   }
               )

          Above, the attribute named ‘_job_status’ is automatically
          mapped to the ‘job_status’ column:

               >>> j1 = MyClass()
               >>> j1._job_status = "employed"
               >>> j1.job_status
               Status: employed

          When using Declarative, in order to provide a descriptor in
          conjunction with a synonym, use the
          ‘sqlalchemy.ext.declarative.synonym_for()’ helper.  However,
          note that the hybrid properties feature should
          usually be preferred, particularly when redefining attribute
          behavior.

        * ‘info’ – Optional data dictionary which will be populated into
          the ‘InspectionAttr.info’ attribute of this object.

          New in version 1.0.0.

        * ‘comparator_factory’ – A subclass of PropComparator
          that will provide custom comparison behavior at the SQL
          expression level.

               Note: For the use case of providing an attribute which
               redefines both Python-level and SQL-expression level
               behavior of an attribute, please refer to the Hybrid
               attribute introduced at Using Descriptors and Hybrids
               for a more effective technique.

     See also
     ........

     See Synonyms. - Overview of synonyms

     See synonym_for(). - a helper oriented towards Declarative

     See Using Descriptors and Hybrids. - The Hybrid Attribute
     extension provides an updated approach to augmenting attribute
     behavior more flexibly than can be achieved with synonyms.

3.2.3.18 Operator Customization
...............................

The “operators” used by the SQLAlchemy ORM and Core expression language
are fully customizable.  For example, the comparison expression
‘User.name == 'ed'’ makes usage of an operator built into Python itself
called ‘operator.eq’ - the actual SQL construct which SQLAlchemy
associates with such an operator can be modified.  New operations can be
associated with column expressions as well.  The operators which take
place for column expressions are most directly redefined at the type
level - see the section Redefining and Creating New Operators
for a description.

ORM level functions like column_property(),
relationship(), and composite() also provide for
operator redefinition at the ORM level, by passing a
PropComparator subclass to the ‘comparator_factory’ argument of
each function.  Customization of operators at this level is a rare use
case.  See the documentation at PropComparator for an
overview.

3.2.3.19 Composite Column Types
...............................

Sets of columns can be associated with a single user-defined datatype.
The ORM provides a single attribute which represents the group of
columns using the class you provide.

A simple example represents pairs of columns as a ‘Point’ object.
‘Point’ represents such a pair as ‘.x’ and ‘.y’:

     class Point(object):
         def __init__(self, x, y):
             self.x = x
             self.y = y

         def __composite_values__(self):
             return self.x, self.y

         def __repr__(self):
             return "Point(x=%r, y=%r)" % (self.x, self.y)

         def __eq__(self, other):
             return isinstance(other, Point) and \
                 other.x == self.x and \
                 other.y == self.y

         def __ne__(self, other):
             return not self.__eq__(other)

The requirements for the custom datatype class are that it have a
constructor which accepts positional arguments corresponding to its
column format, and also provides a method ‘__composite_values__()’ which
returns the state of the object as a list or tuple, in order of its
column-based attributes.  It also should supply adequate ‘__eq__()’ and
‘__ne__()’ methods which test the equality of two instances.

We will create a mapping to a table ‘vertices’, which represents two
points as ‘x1/y1’ and ‘x2/y2’.  These are created normally as
Column objects.  Then, the composite() function is used
to assign new attributes that will represent sets of columns via the
‘Point’ class:

     from sqlalchemy import Column, Integer
     from sqlalchemy.orm import composite
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class Vertex(Base):
         __tablename__ = 'vertices'

         id = Column(Integer, primary_key=True)
         x1 = Column(Integer)
         y1 = Column(Integer)
         x2 = Column(Integer)
         y2 = Column(Integer)

         start = composite(Point, x1, y1)
         end = composite(Point, x2, y2)

A classical mapping above would define each composite()
against the existing table:

     mapper_registry.map_imperatively(Vertex, vertices_table, properties={
         'start':composite(Point, vertices_table.c.x1, vertices_table.c.y1),
         'end':composite(Point, vertices_table.c.x2, vertices_table.c.y2),
     })

We can now persist and use ‘Vertex’ instances, as well as query for
them, using the ‘.start’ and ‘.end’ attributes against ad-hoc ‘Point’
instances:

     >>> v = Vertex(start=Point(3, 4), end=Point(5, 6))
     >>> session.add(v)
     >>> q = session.query(Vertex).filter(Vertex.start == Point(3, 4))
     {sql}>>> print(q.first().start)
     BEGIN (implicit)
     INSERT INTO vertices (x1, y1, x2, y2) VALUES (?, ?, ?, ?)
     (3, 4, 5, 6)
     SELECT vertices.id AS vertices_id,
             vertices.x1 AS vertices_x1,
             vertices.y1 AS vertices_y1,
             vertices.x2 AS vertices_x2,
             vertices.y2 AS vertices_y2
     FROM vertices
     WHERE vertices.x1 = ? AND vertices.y1 = ?
      LIMIT ? OFFSET ?
     (3, 4, 1, 0)
     {stop}Point(x=3, y=4)

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See composite.(class_,Return a composite column-based property for use with a Mapper.
*attrs,
**kwargs)

 -- Function: sqlalchemy.orm.composite (class_, *attrs, **kwargs)

     Return a composite column-based property for use with a Mapper.

     See the mapping documentation section Composite Column Types
     for a full usage example.

     The MapperProperty returned by composite()
     is the CompositeProperty.

     Parameters:

        * ‘class_’ – The “composite type” class, or any classmethod or
          callable which will produce a new instance of the composite
          object given the column values in order.

        * ‘*cols’ – List of Column objects to be mapped.

        * ‘active_history=False’ – When ‘True’, indicates that the
          “previous” value for a scalar attribute should be loaded when
          replaced, if not already loaded.  See the same flag on
          column_property().

        * ‘group’ – A group name for this property when marked as
          deferred.

        * ‘deferred’ – When True, the column property is “deferred”,
          meaning that it does not load immediately, and is instead
          loaded when the attribute is first accessed on an instance.
          See also deferred().

        * ‘comparator_factory’ – a class which extends Comparator
          which provides custom SQL clause generation for
          comparison operations.

        * ‘doc’ – optional string that will be applied as the doc on the
          class-bound descriptor.

        * ‘info’ – Optional data dictionary which will be populated into
          the MapperProperty.info attribute of this object.

3.2.3.20 Tracking In-Place Mutations on Composites
..................................................

In-place changes to an existing composite value are not tracked
automatically.  Instead, the composite class needs to provide events to
its parent object explicitly.  This task is largely automated via the
usage of the MutableComposite mixin, which uses events to
associate each user-defined composite object with all parent
associations.  Please see the example in Establishing Mutability on Composites.

3.2.3.21 Redefining Comparison Operations for Composites
........................................................

The “equals” comparison operation by default produces an AND of all
corresponding columns equated to one another.  This can be changed using
the ‘comparator_factory’ argument to composite(), where we
specify a custom Comparator class to define existing or new
operations.  Below we illustrate the “greater than” operator,
implementing the same expression that the base “greater than” does:

     from sqlalchemy.orm.properties import CompositeProperty
     from sqlalchemy import sql

     class PointComparator(CompositeProperty.Comparator):
         def __gt__(self, other):
             """redefine the 'greater than' operation"""

             return sql.and_(*[a>b for a, b in
                               zip(self.__clause_element__().clauses,
                                   other.__composite_values__())])

     class Vertex(Base):
         ___tablename__ = 'vertices'

         id = Column(Integer, primary_key=True)
         x1 = Column(Integer)
         y1 = Column(Integer)
         x2 = Column(Integer)
         y2 = Column(Integer)

         start = composite(Point, x1, y1,
                             comparator_factory=PointComparator)
         end = composite(Point, x2, y2,
                             comparator_factory=PointComparator)

3.2.3.22 Nesting Composites
...........................

Composite objects can be defined to work in simple nested schemes, by
redefining behaviors within the composite class to work as desired, then
mapping the composite class to the full length of individual columns
normally.  Typically, it is convenient to define separate constructors
for user-defined use and generate-from-row use.  Below we reorganize the
‘Vertex’ class to itself be a composite object, which is then mapped to
a class ‘HasVertex’:

     from sqlalchemy.orm import composite

     class Point(object):
         def __init__(self, x, y):
             self.x = x
             self.y = y

         def __composite_values__(self):
             return self.x, self.y

         def __repr__(self):
             return "Point(x=%r, y=%r)" % (self.x, self.y)

         def __eq__(self, other):
             return isinstance(other, Point) and \
                 other.x == self.x and \
                 other.y == self.y

         def __ne__(self, other):
             return not self.__eq__(other)

     class Vertex(object):
         def __init__(self, start, end):
             self.start = start
             self.end = end

         @classmethod
         def _generate(self, x1, y1, x2, y2):
             """generate a Vertex from a row"""
             return Vertex(
                 Point(x1, y1),
                 Point(x2, y2)
             )

         def __composite_values__(self):
             return \
                 self.start.__composite_values__() + \
                 self.end.__composite_values__()

     class HasVertex(Base):
         __tablename__ = 'has_vertex'
         id = Column(Integer, primary_key=True)
         x1 = Column(Integer)
         y1 = Column(Integer)
         x2 = Column(Integer)
         y2 = Column(Integer)

         vertex = composite(Vertex._generate, x1, y1, x2, y2)

We can then use the above mapping as:

     hv = HasVertex(vertex=Vertex(Point(1, 2), Point(3, 4)))

     s.add(hv)
     s.commit()

     hv = s.query(HasVertex).filter(
         HasVertex.vertex == Vertex(Point(1, 2), Point(3, 4))).first()
     print(hv.vertex.start)
     print(hv.vertex.end)

3.2.4 Mapping Class Inheritance Hierarchies
-------------------------------------------

SQLAlchemy supports three forms of inheritance: `single table
inheritance', where several types of classes are represented by a single
table, `concrete table inheritance', where each type of class is
represented by independent tables, and `joined table inheritance', where
the class hierarchy is broken up among dependent tables, each class
represented by its own table that only includes those attributes local
to that class.

The most common forms of inheritance are single and joined table, while
concrete inheritance presents more configurational challenges.

When mappers are configured in an inheritance relationship, SQLAlchemy
has the ability to load elements polymorphically, meaning that a single
query can return objects of multiple types.

See also
........

See Inheritance Mapping Recipes. - complete examples of joined,
single and concrete inheritance

3.2.4.1 Joined Table Inheritance
................................

In joined table inheritance, each class along a hierarchy of classes is
represented by a distinct table.  Querying for a particular subclass in
the hierarchy will render as a SQL JOIN along all tables in its
inheritance path.  If the queried class is the base class, the `default
behavior is to include only the base table' in a SELECT statement.  In
all cases, the ultimate class to instantiate for a given row is
determined by a discriminator column or an expression that works against
the base table.  When a subclass is loaded `only' against a base table,
resulting objects will have base attributes populated at first;
attributes that are local to the subclass will lazy load when they are
accessed.  Alternatively, there are options which can change the default
behavior, allowing the query to include columns corresponding to
multiple tables/subclasses up front.

The base class in a joined inheritance hierarchy is configured with
additional arguments that will refer to the polymorphic discriminator
column as well as the identifier for the base class:

     class Employee(Base):
         __tablename__ = 'employee'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         type = Column(String(50))

         __mapper_args__ = {
             'polymorphic_identity':'employee',
             'polymorphic_on':type
         }

Above, an additional column ‘type’ is established to act as the
`discriminator', configured as such using the
mapper.polymorphic_on parameter.  This column will store a value
which indicates the type of object represented within the row.  The
column may be of any datatype, though string and integer are the most
common.  The actual data value to be applied to this column for a
particular row in the database is specified using the
mapper.polymorphic_identity parameter, described below.

While a polymorphic discriminator expression is not strictly necessary,
it is required if polymorphic loading is desired.  Establishing a simple
column on the base table is the easiest way to achieve this, however
very sophisticated inheritance mappings may even configure a SQL
expression such as a CASE statement as the polymorphic discriminator.

     Note: Currently, `only one discriminator column or SQL expression
     may be configured for the entire inheritance hierarchy', typically
     on the base- most class in the hierarchy.  “Cascading” polymorphic
     discriminator expressions are not yet supported.

We next define ‘Engineer’ and ‘Manager’ subclasses of ‘Employee’.  Each
contains columns that represent the attributes unique to the subclass
they represent.  Each table also must contain a primary key column (or
columns), as well as a foreign key reference to the parent table:

     class Engineer(Employee):
         __tablename__ = 'engineer'
         id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
         engineer_name = Column(String(30))

         __mapper_args__ = {
             'polymorphic_identity':'engineer',
         }

     class Manager(Employee):
         __tablename__ = 'manager'
         id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
         manager_name = Column(String(30))

         __mapper_args__ = {
             'polymorphic_identity':'manager',
         }

In the above example, each mapping specifies the
mapper.polymorphic_identity parameter within its mapper arguments.
This value populates the column designated by the
mapper.polymorphic_on parameter established on the base mapper.
The mapper.polymorphic_identity parameter should be unique
to each mapped class across the whole hierarchy, and there should only
be one “identity” per mapped class; as noted above, “cascading”
identities where some subclasses introduce a second identity are not
supported.

The ORM uses the value set up by mapper.polymorphic_identity
in order to determine which class a row belongs towards when loading
rows polymorphically.  In the example above, every row which represents
an ‘Employee’ will have the value ‘'employee'’ in its ‘type’ row;
similarly, every ‘Engineer’ will get the value ‘'engineer'’, and each
‘Manager’ will get the value ‘'manager'’.  Regardless of whether the
inheritance mapping uses distinct joined tables for subclasses as in
joined table inheritance, or all one table as in single table
inheritance, this value is expected to be persisted and available to the
ORM when querying.  The mapper.polymorphic_identity
parameter also applies to concrete table inheritance, but is not
actually persisted; see the later section at Concrete Table Inheritance
for details.

In a polymorphic setup, it is most common that the foreign key
constraint is established on the same column or columns as the primary
key itself, however this is not required; a column distinct from the
primary key may also be made to refer to the parent via foreign key.
The way that a JOIN is constructed from the base table to subclasses is
also directly customizable, however this is rarely necessary.

Joined inheritance primary keys
...............................

One natural effect of the joined table inheritance configuration is that
the identity of any mapped object can be determined entirely from rows
in the base table alone.  This has obvious advantages, so SQLAlchemy
always considers the primary key columns of a joined inheritance class
to be those of the base table only.  In other words, the ‘id’ columns of
both the ‘engineer’ and ‘manager’ tables are not used to locate
‘Engineer’ or ‘Manager’ objects - only the value in ‘employee.id’ is
considered.  ‘engineer.id’ and ‘manager.id’ are still of course critical
to the proper operation of the pattern overall as they are used to
locate the joined row, once the parent row has been determined within a
statement.

With the joined inheritance mapping complete, querying against
‘Employee’ will return a combination of ‘Employee’, ‘Engineer’ and
‘Manager’ objects.  Newly saved ‘Engineer’, ‘Manager’, and ‘Employee’
objects will automatically populate the ‘employee.type’ column with the
correct “discriminator” value in this case ‘"engineer"’, ‘"manager"’, or
‘"employee"’, as appropriate.

3.2.4.2 Relationships with Joined Inheritance
.............................................

Relationships are fully supported with joined table inheritance.  The
relationship involving a joined-inheritance class should target the
class in the hierarchy that also corresponds to the foreign key
constraint; below, as the ‘employee’ table has a foreign key constraint
back to the ‘company’ table, the relationships are set up between
‘Company’ and ‘Employee’:

     class Company(Base):
         __tablename__ = 'company'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         employees = relationship("Employee", back_populates="company")

     class Employee(Base):
         __tablename__ = 'employee'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         type = Column(String(50))
         company_id = Column(ForeignKey('company.id'))
         company = relationship("Company", back_populates="employees")

         __mapper_args__ = {
             'polymorphic_identity':'employee',
             'polymorphic_on':type
         }

     class Manager(Employee):
         # ...

     class Engineer(Employee):
         # ...

If the foreign key constraint is on a table corresponding to a subclass,
the relationship should target that subclass instead.  In the example
below, there is a foreign key constraint from ‘manager’ to ‘company’, so
the relationships are established between the ‘Manager’ and ‘Company’
classes:

     class Company(Base):
         __tablename__ = 'company'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         managers = relationship("Manager", back_populates="company")

     class Employee(Base):
         __tablename__ = 'employee'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         type = Column(String(50))

         __mapper_args__ = {
             'polymorphic_identity':'employee',
             'polymorphic_on':type
         }

     class Manager(Employee):
         __tablename__ = 'manager'
         id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
         manager_name = Column(String(30))

         company_id = Column(ForeignKey('company.id'))
         company = relationship("Company", back_populates="managers")

         __mapper_args__ = {
             'polymorphic_identity':'manager',
         }

     class Engineer(Employee):
         # ...

Above, the ‘Manager’ class will have a ‘Manager.company’ attribute;
‘Company’ will have a ‘Company.managers’ attribute that always loads
against a join of the ‘employee’ and ‘manager’ tables together.

3.2.4.3 Loading Joined Inheritance Mappings
...........................................

See the sections Loading Inheritance Hierarchies and
Loading objects with joined table inheritance for background on
inheritance loading techniques, including configuration of tables to be
queried both at mapper configuration time as well as query time.

3.2.4.4 Single Table Inheritance
................................

Single table inheritance represents all attributes of all subclasses
within a single table.  A particular subclass that has attributes unique
to that class will persist them within columns in the table that are
otherwise NULL if the row refers to a different kind of object.

Querying for a particular subclass in the hierarchy will render as a
SELECT against the base table, which will include a WHERE clause that
limits rows to those with a particular value or values present in the
discriminator column or expression.

Single table inheritance has the advantage of simplicity compared to
joined table inheritance; queries are much more efficient as only one
table needs to be involved in order to load objects of every represented
class.

Single-table inheritance configuration looks much like joined-table
inheritance, except only the base class specifies ‘__tablename__’.  A
discriminator column is also required on the base table so that classes
can be differentiated from each other.

Even though subclasses share the base table for all of their attributes,
when using Declarative, see Column objects may still be specified
on subclasses, indicating that the column is to be mapped only to that
subclass; the Column will be applied to the same base
Table object:

     class Employee(Base):
         __tablename__ = 'employee'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         type = Column(String(20))

         __mapper_args__ = {
             'polymorphic_on':type,
             'polymorphic_identity':'employee'
         }

     class Manager(Employee):
         manager_data = Column(String(50))

         __mapper_args__ = {
             'polymorphic_identity':'manager'
         }

     class Engineer(Employee):
         engineer_info = Column(String(50))

         __mapper_args__ = {
             'polymorphic_identity':'engineer'
         }

Note that the mappers for the derived classes Manager and Engineer omit
the ‘__tablename__’, indicating they do not have a mapped table of their
own.

3.2.4.5 Resolving Column Conflicts
..................................

Note in the previous section that the ‘manager_name’ and ‘engineer_info’
columns are “moved up” to be applied to ‘Employee.__table__’, as a
result of their declaration on a subclass that has no table of its own.
A tricky case comes up when two subclasses want to specify `the same'
column, as below:

     class Employee(Base):
         __tablename__ = 'employee'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         type = Column(String(20))

         __mapper_args__ = {
             'polymorphic_on':type,
             'polymorphic_identity':'employee'
         }

     class Engineer(Employee):
         __mapper_args__ = {'polymorphic_identity': 'engineer'}
         start_date = Column(DateTime)

     class Manager(Employee):
         __mapper_args__ = {'polymorphic_identity': 'manager'}
         start_date = Column(DateTime)

Above, the ‘start_date’ column declared on both ‘Engineer’ and ‘Manager’
will result in an error:

     sqlalchemy.exc.ArgumentError: Column 'start_date' on class
     <class '__main__.Manager'> conflicts with existing
     column 'employee.start_date'

The above scenario presents an ambiguity to the Declarative mapping
system that may be resolved by using declared_attr to define
the Column conditionally, taking care to return the `existing
column' via the parent ‘__table__’ if it already exists:

     from sqlalchemy.orm import declared_attr

     class Employee(Base):
         __tablename__ = 'employee'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         type = Column(String(20))

         __mapper_args__ = {
             'polymorphic_on':type,
             'polymorphic_identity':'employee'
         }

     class Engineer(Employee):
         __mapper_args__ = {'polymorphic_identity': 'engineer'}

         @declared_attr
         def start_date(cls):
             "Start date column, if not present already."
             return Employee.__table__.c.get('start_date', Column(DateTime))

     class Manager(Employee):
         __mapper_args__ = {'polymorphic_identity': 'manager'}

         @declared_attr
         def start_date(cls):
             "Start date column, if not present already."
             return Employee.__table__.c.get('start_date', Column(DateTime))

Above, when ‘Manager’ is mapped, the ‘start_date’ column is already
present on the ‘Employee’ class; by returning the existing Column
object, the declarative system recognizes that this is the same
column to be mapped to the two different subclasses separately.

A similar concept can be used with mixin classes (see Composing Mapped Hierarchies with Mixins)
to define a particular series of
columns and/or other mapped attributes from a reusable mixin class:

     class Employee(Base):
         __tablename__ = 'employee'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         type = Column(String(20))

         __mapper_args__ = {
             'polymorphic_on':type,
             'polymorphic_identity':'employee'
         }

     class HasStartDate:
         @declared_attr
         def start_date(cls):
             return cls.__table__.c.get('start_date', Column(DateTime))

     class Engineer(HasStartDate, Employee):
         __mapper_args__ = {'polymorphic_identity': 'engineer'}

     class Manager(HasStartDate, Employee):
         __mapper_args__ = {'polymorphic_identity': 'manager'}

3.2.4.6 Relationships with Single Table Inheritance
...................................................

Relationships are fully supported with single table inheritance.
Configuration is done in the same manner as that of joined inheritance;
a foreign key attribute should be on the same class that’s the “foreign”
side of the relationship:

     class Company(Base):
         __tablename__ = 'company'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         employees = relationship("Employee", back_populates="company")

     class Employee(Base):
         __tablename__ = 'employee'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         type = Column(String(50))
         company_id = Column(ForeignKey('company.id'))
         company = relationship("Company", back_populates="employees")

         __mapper_args__ = {
             'polymorphic_identity':'employee',
             'polymorphic_on':type
         }

     class Manager(Employee):
         manager_data = Column(String(50))

         __mapper_args__ = {
             'polymorphic_identity':'manager'
         }

     class Engineer(Employee):
         engineer_info = Column(String(50))

         __mapper_args__ = {
             'polymorphic_identity':'engineer'
         }

Also, like the case of joined inheritance, we can create relationships
that involve a specific subclass.  When queried, the SELECT statement
will include a WHERE clause that limits the class selection to that
subclass or subclasses:

     class Company(Base):
         __tablename__ = 'company'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         managers = relationship("Manager", back_populates="company")

     class Employee(Base):
         __tablename__ = 'employee'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         type = Column(String(50))

         __mapper_args__ = {
             'polymorphic_identity':'employee',
             'polymorphic_on':type
         }

     class Manager(Employee):
         manager_name = Column(String(30))

         company_id = Column(ForeignKey('company.id'))
         company = relationship("Company", back_populates="managers")

         __mapper_args__ = {
             'polymorphic_identity':'manager',
         }

     class Engineer(Employee):
         engineer_info = Column(String(50))

         __mapper_args__ = {
             'polymorphic_identity':'engineer'
         }

Above, the ‘Manager’ class will have a ‘Manager.company’ attribute;
‘Company’ will have a ‘Company.managers’ attribute that always loads
against the ‘employee’ with an additional WHERE clause that limits rows
to those with ‘type = 'manager'’.

3.2.4.7 Loading Single Inheritance Mappings
...........................................

The loading techniques for single-table inheritance are mostly identical
to those used for joined-table inheritance, and a high degree of
abstraction is provided between these two mapping types such that it is
easy to switch between them as well as to intermix them in a single
hierarchy (just omit ‘__tablename__’ from whichever subclasses are to be
single-inheriting).  See the sections Loading Inheritance Hierarchies
and Loading objects with single table inheritance
for documentation on inheritance loading techniques,
including configuration of classes to be queried both at mapper
configuration time as well as query time.

3.2.4.8 Concrete Table Inheritance
..................................

Concrete inheritance maps each subclass to its own distinct table, each
of which contains all columns necessary to produce an instance of that
class.  A concrete inheritance configuration by default queries
non-polymorphically; a query for a particular class will only query that
class’ table and only return instances of that class.  Polymorphic
loading of concrete classes is enabled by configuring within the mapper
a special SELECT that typically is produced as a UNION of all the
tables.

     Warning: Concrete table inheritance is `much more complicated' than
     joined or single table inheritance, and is `much more limited in
     functionality' especially pertaining to using it with
     relationships, eager loading, and polymorphic loading.  When used
     polymorphically it produces `very large queries' with UNIONS that
     won’t perform as well as simple joins.  It is strongly advised that
     if flexibility in relationship loading and polymorphic loading is
     required, that joined or single table inheritance be used if at all
     possible.  If polymorphic loading isn’t required, then plain
     non-inheriting mappings can be used if each class refers to its own
     table completely.

Whereas joined and single table inheritance are fluent in “polymorphic”
loading, it is a more awkward affair in concrete inheritance.  For this
reason, concrete inheritance is more appropriate when `polymorphic
loading is not required'.  Establishing relationships that involve
concrete inheritance classes is also more awkward.

To establish a class as using concrete inheritance, add the
mapper.concrete parameter within the ‘__mapper_args__’.  This
indicates to Declarative as well as the mapping that the superclass
table should not be considered as part of the mapping:

     class Employee(Base):
         __tablename__ = 'employee'

         id = Column(Integer, primary_key=True)
         name = Column(String(50))

     class Manager(Employee):
         __tablename__ = 'manager'

         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         manager_data = Column(String(50))

         __mapper_args__ = {
             'concrete': True
         }

     class Engineer(Employee):
         __tablename__ = 'engineer'

         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         engineer_info = Column(String(50))

         __mapper_args__ = {
             'concrete': True
         }

Two critical points should be noted:

   * We must `define all columns explicitly' on each subclass, even
     those of the same name.  A column such as ‘Employee.name’ here is
     `not' copied out to the tables mapped by ‘Manager’ or ‘Engineer’
     for us.

   * while the ‘Engineer’ and ‘Manager’ classes are mapped in an
     inheritance relationship with ‘Employee’, they still `do not
     include polymorphic loading'.  Meaning, if we query for ‘Employee’
     objects, the ‘manager’ and ‘engineer’ tables are not queried at
     all.

3.2.4.9 Concrete Polymorphic Loading Configuration
..................................................

Polymorphic loading with concrete inheritance requires that a
specialized SELECT is configured against each base class that should
have polymorphic loading.  This SELECT needs to be capable of accessing
all the mapped tables individually, and is typically a UNION statement
that is constructed using a SQLAlchemy helper polymorphic_union().

As discussed in Loading Inheritance Hierarchies, mapper
inheritance configurations of any type can be configured to load from a
special selectable by default using the mapper.with_polymorphic
argument.  Current public API requires that this argument is set on
a Mapper when it is first constructed.

However, in the case of Declarative, both the mapper and the
Table that is mapped are created at once, the moment the mapped
class is defined.  This means that the mapper.with_polymorphic
argument cannot be provided yet, since the Table objects
that correspond to the subclasses haven’t yet been defined.

There are a few strategies available to resolve this cycle, however
Declarative provides helper classes ConcreteBase and
AbstractConcreteBase which handle this issue behind the scenes.

Using ConcreteBase, we can set up our concrete mapping in
almost the same way as we do other forms of inheritance mappings:

     from sqlalchemy.ext.declarative import ConcreteBase

     class Employee(ConcreteBase, Base):
         __tablename__ = 'employee'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))

         __mapper_args__ = {
             'polymorphic_identity': 'employee',
             'concrete': True
         }

     class Manager(Employee):
         __tablename__ = 'manager'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         manager_data = Column(String(40))

         __mapper_args__ = {
             'polymorphic_identity': 'manager',
             'concrete': True
         }

     class Engineer(Employee):
         __tablename__ = 'engineer'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         engineer_info = Column(String(40))

         __mapper_args__ = {
             'polymorphic_identity': 'engineer',
             'concrete': True
         }

Above, Declarative sets up the polymorphic selectable for the ‘Employee’
class at mapper “initialization” time; this is the late-configuration
step for mappers that resolves other dependent mappers.  The
ConcreteBase helper uses the polymorphic_union()
function to create a UNION of all concrete-mapped tables after all the
other classes are set up, and then configures this statement with the
already existing base-class mapper.

Upon select, the polymorphic union produces a query like this:

     session.query(Employee).all()
     {opensql}
     SELECT
         pjoin.id AS pjoin_id,
         pjoin.name AS pjoin_name,
         pjoin.type AS pjoin_type,
         pjoin.manager_data AS pjoin_manager_data,
         pjoin.engineer_info AS pjoin_engineer_info
     FROM (
         SELECT
             employee.id AS id,
             employee.name AS name,
             CAST(NULL AS VARCHAR(50)) AS manager_data,
             CAST(NULL AS VARCHAR(50)) AS engineer_info,
             'employee' AS type
         FROM employee
         UNION ALL
         SELECT
             manager.id AS id,
             manager.name AS name,
             manager.manager_data AS manager_data,
             CAST(NULL AS VARCHAR(50)) AS engineer_info,
             'manager' AS type
         FROM manager
         UNION ALL
         SELECT
             engineer.id AS id,
             engineer.name AS name,
             CAST(NULL AS VARCHAR(50)) AS manager_data,
             engineer.engineer_info AS engineer_info,
             'engineer' AS type
         FROM engineer
     ) AS pjoin

The above UNION query needs to manufacture “NULL” columns for each
subtable in order to accommodate for those columns that aren’t members
of that particular subclass.

3.2.4.10 Abstract Concrete Classes
..................................

The concrete mappings illustrated thus far show both the subclasses as
well as the base class mapped to individual tables.  In the concrete
inheritance use case, it is common that the base class is not
represented within the database, only the subclasses.  In other words,
the base class is “abstract”.

Normally, when one would like to map two different subclasses to
individual tables, and leave the base class unmapped, this can be
achieved very easily.  When using Declarative, just declare the base
class with the ‘__abstract__’ indicator:

     class Employee(Base):
         __abstract__ = True

     class Manager(Employee):
         __tablename__ = 'manager'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         manager_data = Column(String(40))

         __mapper_args__ = {
             'polymorphic_identity': 'manager',
         }

     class Engineer(Employee):
         __tablename__ = 'engineer'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         engineer_info = Column(String(40))

         __mapper_args__ = {
             'polymorphic_identity': 'engineer',
         }

Above, we are not actually making use of SQLAlchemy’s inheritance
mapping facilities; we can load and persist instances of ‘Manager’ and
‘Engineer’ normally.  The situation changes however when we need to
`query polymorphically', that is, we’d like to emit
‘session.query(Employee)’ and get back a collection of ‘Manager’ and
‘Engineer’ instances.  This brings us back into the domain of concrete
inheritance, and we must build a special mapper against ‘Employee’ in
order to achieve this.

Mappers can always SELECT
.........................

In SQLAlchemy, a mapper for a class always has to refer to some
“selectable”, which is normally a Table but may also refer to
any select() object as well.  While it may appear that a
“single table inheritance” mapper does not map to a table, these mappers
in fact implicitly refer to the table that is mapped by a superclass.

To modify our concrete inheritance example to illustrate an “abstract”
base that is capable of polymorphic loading, we will have only an
‘engineer’ and a ‘manager’ table and no ‘employee’ table, however the
‘Employee’ mapper will be mapped directly to the “polymorphic union”,
rather than specifying it locally to the mapper.with_polymorphic
parameter.

To help with this, Declarative offers a variant of the
ConcreteBase class called AbstractConcreteBase which
achieves this automatically:

     from sqlalchemy.ext.declarative import AbstractConcreteBase

     class Employee(AbstractConcreteBase, Base):
         pass

     class Manager(Employee):
         __tablename__ = 'manager'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         manager_data = Column(String(40))

         __mapper_args__ = {
             'polymorphic_identity': 'manager',
             'concrete': True
         }

     class Engineer(Employee):
         __tablename__ = 'engineer'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         engineer_info = Column(String(40))

         __mapper_args__ = {
             'polymorphic_identity': 'engineer',
             'concrete': True
         }

The AbstractConcreteBase helper class has a more complex
internal process than that of ConcreteBase, in that the
entire mapping of the base class must be delayed until all the
subclasses have been declared.  With a mapping like the above, only
instances of ‘Manager’ and ‘Engineer’ may be persisted; querying against
the ‘Employee’ class will always produce ‘Manager’ and ‘Engineer’
objects.

3.2.4.11 Classical and Semi-Classical Concrete Polymorphic Configuration
........................................................................

The Declarative configurations illustrated with ConcreteBase
and AbstractConcreteBase are equivalent to two other forms
of configuration that make use of polymorphic_union()
explicitly.  These configurational forms make use of the Table
object explicitly so that the “polymorphic union” can be created
first, then applied to the mappings.  These are illustrated here to
clarify the role of the polymorphic_union() function in
terms of mapping.

A `semi-classical mapping' for example makes use of Declarative, but
establishes the Table objects separately:

     metadata = Base.metadata

     employees_table = Table(
         'employee', metadata,
         Column('id', Integer, primary_key=True),
         Column('name', String(50)),
     )

     managers_table = Table(
         'manager', metadata,
         Column('id', Integer, primary_key=True),
         Column('name', String(50)),
         Column('manager_data', String(50)),
     )

     engineers_table = Table(
         'engineer', metadata,
         Column('id', Integer, primary_key=True),
         Column('name', String(50)),
         Column('engineer_info', String(50)),
     )

Next, the UNION is produced using polymorphic_union():

     from sqlalchemy.orm import polymorphic_union

     pjoin = polymorphic_union({
         'employee': employees_table,
         'manager': managers_table,
         'engineer': engineers_table
     }, 'type', 'pjoin')

With the above Table objects, the mappings can be produced
using “semi-classical” style, where we use Declarative in conjunction
with the ‘__table__’ argument; our polymorphic union above is passed via
‘__mapper_args__’ to the mapper.with_polymorphic parameter:

     class Employee(Base):
         __table__ = employee_table
         __mapper_args__ = {
             'polymorphic_on': pjoin.c.type,
             'with_polymorphic': ('*', pjoin),
             'polymorphic_identity': 'employee'
         }

     class Engineer(Employee):
         __table__ = engineer_table
         __mapper_args__ = {
             'polymorphic_identity': 'engineer',
             'concrete': True}

     class Manager(Employee):
         __table__ = manager_table
         __mapper_args__ = {
             'polymorphic_identity': 'manager',
             'concrete': True}

Alternatively, the same Table objects can be used in fully
“classical” style, without using Declarative at all.  A constructor
similar to that supplied by Declarative is illustrated:

     class Employee(object):
         def __init__(self, **kw):
             for k in kw:
                 setattr(self, k, kw[k])

     class Manager(Employee):
         pass

     class Engineer(Employee):
         pass

     employee_mapper = mapper_registry.map_imperatively(
         Employee,
         pjoin,
         with_polymorphic=('*', pjoin),
         polymorphic_on=pjoin.c.type,
     )
     manager_mapper = mapper_registry.map_imperatively(
         Manager,
         managers_table,
         inherits=employee_mapper,
         concrete=True,
         polymorphic_identity='manager',
     )
     engineer_mapper = mapper_registry.map_imperatively(
         Engineer,
         engineers_table,
         inherits=employee_mapper,
         concrete=True,
         polymorphic_identity='engineer',
     )

The “abstract” example can also be mapped using “semi-classical” or
“classical” style.  The difference is that instead of applying the
“polymorphic union” to the mapper.with_polymorphic
parameter, we apply it directly as the mapped selectable on our basemost
mapper.  The semi-classical mapping is illustrated below:

     from sqlalchemy.orm import polymorphic_union

     pjoin = polymorphic_union({
         'manager': managers_table,
         'engineer': engineers_table
     }, 'type', 'pjoin')

     class Employee(Base):
         __table__ = pjoin
         __mapper_args__ = {
             'polymorphic_on': pjoin.c.type,
             'with_polymorphic': '*',
             'polymorphic_identity': 'employee'
         }

     class Engineer(Employee):
         __table__ = engineer_table
         __mapper_args__ = {
             'polymorphic_identity': 'engineer',
             'concrete': True}

     class Manager(Employee):
         __table__ = manager_table
         __mapper_args__ = {
             'polymorphic_identity': 'manager',
             'concrete': True}

Above, we use polymorphic_union() in the same manner as
before, except that we omit the ‘employee’ table.

See also
........

See Imperative (a.k.a. Classical) Mappings. - background
information on “classical” mappings

3.2.4.12 Relationships with Concrete Inheritance
................................................

In a concrete inheritance scenario, mapping relationships is challenging
since the distinct classes do not share a table.  If the relationships
only involve specific classes, such as a relationship between ‘Company’
in our previous examples and ‘Manager’, special steps aren’t needed as
these are just two related tables.

However, if ‘Company’ is to have a one-to-many relationship to
‘Employee’, indicating that the collection may include both ‘Engineer’
and ‘Manager’ objects, that implies that ‘Employee’ must have
polymorphic loading capabilities and also that each table to be related
must have a foreign key back to the ‘company’ table.  An example of such
a configuration is as follows:

     from sqlalchemy.ext.declarative import ConcreteBase

     class Company(Base):
         __tablename__ = 'company'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         employees = relationship("Employee")

     class Employee(ConcreteBase, Base):
         __tablename__ = 'employee'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         company_id = Column(ForeignKey('company.id'))

         __mapper_args__ = {
             'polymorphic_identity': 'employee',
             'concrete': True
         }

     class Manager(Employee):
         __tablename__ = 'manager'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         manager_data = Column(String(40))
         company_id = Column(ForeignKey('company.id'))

         __mapper_args__ = {
             'polymorphic_identity': 'manager',
             'concrete': True
         }

     class Engineer(Employee):
         __tablename__ = 'engineer'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         engineer_info = Column(String(40))
         company_id = Column(ForeignKey('company.id'))

         __mapper_args__ = {
             'polymorphic_identity': 'engineer',
             'concrete': True
         }

The next complexity with concrete inheritance and relationships involves
when we’d like one or all of ‘Employee’, ‘Manager’ and ‘Engineer’ to
themselves refer back to ‘Company’.  For this case, SQLAlchemy has
special behavior in that a relationship() placed on
‘Employee’ which links to ‘Company’ `does not work' against the
‘Manager’ and ‘Engineer’ classes, when exercised at the instance level.
Instead, a distinct relationship() must be applied to each
class.  In order to achieve bi-directional behavior in terms of three
separate relationships which serve as the opposite of
‘Company.employees’, the relationship.back_populates
parameter is used between each of the relationships:

     from sqlalchemy.ext.declarative import ConcreteBase

     class Company(Base):
         __tablename__ = 'company'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         employees = relationship("Employee", back_populates="company")

     class Employee(ConcreteBase, Base):
         __tablename__ = 'employee'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         company_id = Column(ForeignKey('company.id'))
         company = relationship("Company", back_populates="employees")

         __mapper_args__ = {
             'polymorphic_identity': 'employee',
             'concrete': True
         }

     class Manager(Employee):
         __tablename__ = 'manager'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         manager_data = Column(String(40))
         company_id = Column(ForeignKey('company.id'))
         company = relationship("Company", back_populates="employees")

         __mapper_args__ = {
             'polymorphic_identity': 'manager',
             'concrete': True
         }

     class Engineer(Employee):
         __tablename__ = 'engineer'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         engineer_info = Column(String(40))
         company_id = Column(ForeignKey('company.id'))
         company = relationship("Company", back_populates="employees")

         __mapper_args__ = {
             'polymorphic_identity': 'engineer',
             'concrete': True
         }

The above limitation is related to the current implementation, including
that concrete inheriting classes do not share any of the attributes of
the superclass and therefore need distinct relationships to be set up.

3.2.4.13 Loading Concrete Inheritance Mappings
..............................................

The options for loading with concrete inheritance are limited;
generally, if polymorphic loading is configured on the mapper using one
of the declarative concrete mixins, it can’t be modified at query time
in current SQLAlchemy versions.  Normally, the with_polymorphic()
function would be able to override the style of loading used by
concrete, however due to current limitations this is not yet supported.

3.2.5 Non-Traditional Mappings
------------------------------

3.2.5.1 Mapping a Class against Multiple Tables
...............................................

Mappers can be constructed against arbitrary relational units (called
`selectables') in addition to plain tables.  For example, the
join() function creates a selectable unit comprised of multiple
tables, complete with its own composite primary key, which can be mapped
in the same way as a Table:

     from sqlalchemy import Table, Column, Integer, \
             String, MetaData, join, ForeignKey
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.orm import column_property

     metadata = MetaData()

     # define two Table objects
     user_table = Table('user', metadata,
                 Column('id', Integer, primary_key=True),
                 Column('name', String),
             )

     address_table = Table('address', metadata,
                 Column('id', Integer, primary_key=True),
                 Column('user_id', Integer, ForeignKey('user.id')),
                 Column('email_address', String)
                 )

     # define a join between them.  This
     # takes place across the user.id and address.user_id
     # columns.
     user_address_join = join(user_table, address_table)

     Base = declarative_base()

     # map to it
     class AddressUser(Base):
         __table__ = user_address_join

         id = column_property(user_table.c.id, address_table.c.user_id)
         address_id = address_table.c.id

In the example above, the join expresses columns for both the ‘user’ and
the ‘address’ table.  The ‘user.id’ and ‘address.user_id’ columns are
equated by foreign key, so in the mapping they are defined as one
attribute, ‘AddressUser.id’, using column_property() to
indicate a specialized column mapping.  Based on this part of the
configuration, the mapping will copy new primary key values from
‘user.id’ into the ‘address.user_id’ column when a flush occurs.

Additionally, the ‘address.id’ column is mapped explicitly to an
attribute named ‘address_id’.  This is to `disambiguate' the mapping of
the ‘address.id’ column from the same-named ‘AddressUser.id’ attribute,
which here has been assigned to refer to the ‘user’ table combined with
the ‘address.user_id’ foreign key.

The natural primary key of the above mapping is the composite of
‘(user.id, address.id)’, as these are the primary key columns of the
‘user’ and ‘address’ table combined together.  The identity of an
‘AddressUser’ object will be in terms of these two values, and is
represented from an ‘AddressUser’ object as ‘(AddressUser.id,
AddressUser.address_id)’.

When referring to the ‘AddressUser.id’ column, most SQL expressions will
make use of only the first column in the list of columns mapped, as the
two columns are synonymous.  However, for the special use case such as a
GROUP BY expression where both columns must be referenced at the same
time while making use of the proper context, that is, accommodating for
aliases and similar, the accessor Comparator.expressions may
be used:

     q = session.query(AddressUser).group_by(*AddressUser.id.expressions)

New in version 1.3.17: Added the Comparator.expressions
accessor.

     Note: A mapping against multiple tables as illustrated above
     supports persistence, that is, INSERT, UPDATE and DELETE of rows
     within the targeted tables.  However, it does not support an
     operation that would UPDATE one table and perform INSERT or DELETE
     on others at the same time for one record.  That is, if a record
     PtoQ is mapped to tables “p” and “q”, where it has a row based on a
     LEFT OUTER JOIN of “p” and “q”, if an UPDATE proceeds that is to
     alter data in the “q” table in an existing record, the row in “q”
     must exist; it won’t emit an INSERT if the primary key identity is
     already present.  If the row does not exist, for most DBAPI drivers
     which support reporting the number of rows affected by an UPDATE,
     the ORM will fail to detect an updated row and raise an error;
     otherwise, the data would be silently ignored.

     A recipe to allow for an on-the-fly “insert” of the related row
     might make use of the .MapperEvents.before_update event and look
     like:

          from sqlalchemy import event

          @event.listens_for(PtoQ, 'before_update')
          def receive_before_update(mapper, connection, target):
             if target.some_required_attr_on_q is None:
                  connection.execute(q_table.insert(), {"id": target.id})

     where above, a row is INSERTed into the ‘q_table’ table by creating
     an INSERT construct with Table.insert(), then executing
     it using the given Connection which is the same one
     being used to emit other SQL for the flush process.  The
     user-supplied logic would have to detect that the LEFT OUTER JOIN
     from “p” to “q” does not have an entry for the “q” side.

3.2.5.2 Mapping a Class against Arbitrary Subqueries
....................................................

Similar to mapping against a join, a plain select() object
can be used with a mapper as well.  The example fragment below
illustrates mapping a class called ‘Customer’ to a select()
which includes a join to a subquery:

     from sqlalchemy import select, func

     subq = select(
         func.count(orders.c.id).label('order_count'),
         func.max(orders.c.price).label('highest_order'),
         orders.c.customer_id
     ).group_by(orders.c.customer_id).subquery()

     customer_select = select(customers, subq).join_from(
         customers, subq, customers.c.id == subq.c.customer_id
     ).subquery()

     class Customer(Base):
         __table__ = customer_select

Above, the full row represented by ‘customer_select’ will be all the
columns of the ‘customers’ table, in addition to those columns exposed
by the ‘subq’ subquery, which are ‘order_count’, ‘highest_order’, and
‘customer_id’.  Mapping the ‘Customer’ class to this selectable then
creates a class which will contain those attributes.

When the ORM persists new instances of ‘Customer’, only the ‘customers’
table will actually receive an INSERT. This is because the primary key
of the ‘orders’ table is not represented in the mapping; the ORM will
only emit an INSERT into a table for which it has mapped the primary
key.

     Note: The practice of mapping to arbitrary SELECT statements,
     especially complex ones as above, is almost never needed; it
     necessarily tends to produce complex queries which are often less
     efficient than that which would be produced by direct query
     construction.  The practice is to some degree based on the very
     early history of SQLAlchemy where the mapper()
     construct was meant to represent the primary querying interface; in
     modern usage, the Query object can be used to construct
     virtually any SELECT statement, including complex composites, and
     should be favored over the “map-to-selectable” approach.

3.2.5.3 Multiple Mappers for One Class
......................................

In modern SQLAlchemy, a particular class is mapped by only one so-called
`primary' mapper at a time.  This mapper is involved in three main areas
of functionality: querying, persistence, and instrumentation of the
mapped class.  The rationale of the primary mapper relates to the fact
that the mapper() modifies the class itself, not only
persisting it towards a particular Table, but also
instrumenting attributes upon the class which are structured
specifically according to the table metadata.  It’s not possible for
more than one mapper to be associated with a class in equal measure,
since only one mapper can actually instrument the class.

The concept of a “non-primary” mapper had existed for many versions of
SQLAlchemy however as of version 1.3 this feature is deprecated.  The
one case where such a non-primary mapper is useful is when constructing
a relationship to a class against an alternative selectable.  This use
case is now suited using the ‘aliased’ construct and is described at
Relationship to Aliased Class.

As far as the use case of a class that can actually be fully persisted
to different tables under different scenarios, very early versions of
SQLAlchemy offered a feature for this adapted from Hibernate, known as
the “entity name” feature.  However, this use case became infeasible
within SQLAlchemy once the mapped class itself became the source of SQL
expression construction; that is, the class’ attributes themselves link
directly to mapped table columns.  The feature was removed and replaced
with a simple recipe-oriented approach to accomplishing this task
without any ambiguity of instrumentation - to create new subclasses,
each mapped individually.  This pattern is now available as a recipe at
Entity Name(1).

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/wiki/UsageRecipes/EntityName

3.2.6 Configuring a Version Counter
-----------------------------------

The Mapper supports management of a version id column, which
is a single table column that increments or otherwise updates its value
each time an ‘UPDATE’ to the mapped table occurs.  This value is checked
each time the ORM emits an ‘UPDATE’ or ‘DELETE’ against the row to
ensure that the value held in memory matches the database value.

     Warning: Because the versioning feature relies upon comparison of
     the `in memory' record of an object, the feature only applies to
     the Session.flush() process, where the ORM flushes
     individual in-memory rows to the database.  It does `not' take
     effect when performing a multirow UPDATE or DELETE using
     Query.update() or Query.delete() methods, as
     these methods only emit an UPDATE or DELETE statement but otherwise
     do not have direct access to the contents of those rows being
     affected.

The purpose of this feature is to detect when two concurrent
transactions are modifying the same row at roughly the same time, or
alternatively to provide a guard against the usage of a “stale” row in a
system that might be re-using data from a previous transaction without
refreshing (e.g.  if one sets ‘expire_on_commit=False’ with a
Session, it is possible to re-use the data from a previous
transaction).

Concurrent transaction updates
..............................

When detecting concurrent updates within transactions, it is typically
the case that the database’s transaction isolation level is below the
level of repeatable read; otherwise, the transaction will not be exposed
to a new row value created by a concurrent update which conflicts with
the locally updated value.  In this case, the SQLAlchemy versioning
feature will typically not be useful for in-transaction conflict
detection, though it still can be used for cross-transaction staleness
detection.

The database that enforces repeatable reads will typically either have
locked the target row against a concurrent update, or is employing some
form of multi version concurrency control such that it will emit an
error when the transaction is committed.  SQLAlchemy’s version_id_col is
an alternative which allows version tracking to occur for specific
tables within a transaction that otherwise might not have this isolation
level set.

See also
........

Repeatable Read Isolation Level(1) - PostgreSQL’s implementation of
repeatable read, including a description of the error condition.

   ---------- Footnotes ----------

   (1)
http://www.postgresql.org/docs/9.1/static/transaction-iso.html#XACT-REPEATABLE-READ

3.2.6.1 Simple Version Counting
...............................

The most straightforward way to track versions is to add an integer
column to the mapped table, then establish it as the ‘version_id_col’
within the mapper options:

     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         version_id = Column(Integer, nullable=False)
         name = Column(String(50), nullable=False)

         __mapper_args__ = {
             "version_id_col": version_id
         }

     Note: It is `strongly recommended' that the ‘version_id’ column be
     made NOT NULL. The versioning feature `does not support' a NULL
     value in the versioning column.

Above, the ‘User’ mapping tracks integer versions using the column
‘version_id’.  When an object of type ‘User’ is first flushed, the
‘version_id’ column will be given a value of “1”.  Then, an UPDATE of
the table later on will always be emitted in a manner similar to the
following:

     UPDATE user SET version_id=:version_id, name=:name
     WHERE user.id = :user_id AND user.version_id = :user_version_id
     {"name": "new name", "version_id": 2, "user_id": 1, "user_version_id": 1}

The above UPDATE statement is updating the row that not only matches
‘user.id = 1’, it also is requiring that ‘user.version_id = 1’, where
“1” is the last version identifier we’ve been known to use on this
object.  If a transaction elsewhere has modified the row independently,
this version id will no longer match, and the UPDATE statement will
report that no rows matched; this is the condition that SQLAlchemy
tests, that exactly one row matched our UPDATE (or DELETE) statement.
If zero rows match, that indicates our version of the data is stale, and
a StaleDataError is raised.

3.2.6.2 Custom Version Counters / Types
.......................................

Other kinds of values or counters can be used for versioning.  Common
types include dates and GUIDs.  When using an alternate type or counter
scheme, SQLAlchemy provides a hook for this scheme using the
‘version_id_generator’ argument, which accepts a version generation
callable.  This callable is passed the value of the current known
version, and is expected to return the subsequent version.

For example, if we wanted to track the versioning of our ‘User’ class
using a randomly generated GUID, we could do this (note that some
backends support a native GUID type, but we illustrate here using a
simple string):

     import uuid

     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         version_uuid = Column(String(32), nullable=False)
         name = Column(String(50), nullable=False)

         __mapper_args__ = {
             'version_id_col':version_uuid,
             'version_id_generator':lambda version: uuid.uuid4().hex
         }

The persistence engine will call upon ‘uuid.uuid4()’ each time a ‘User’
object is subject to an INSERT or an UPDATE. In this case, our version
generation function can disregard the incoming value of ‘version’, as
the ‘uuid4()’ function generates identifiers without any prerequisite
value.  If we were using a sequential versioning scheme such as numeric
or a special character system, we could make use of the given ‘version’
in order to help determine the subsequent value.

See also
........

See Backend-agnostic GUID Type.

3.2.6.3 Server Side Version Counters
....................................

The ‘version_id_generator’ can also be configured to rely upon a value
that is generated by the database.  In this case, the database would
need some means of generating new identifiers when a row is subject to
an INSERT as well as with an UPDATE. For the UPDATE case, typically an
update trigger is needed, unless the database in question supports some
other native version identifier.  The PostgreSQL database in particular
supports a system column called xmin(1) which provides UPDATE
versioning.  We can make use of the PostgreSQL ‘xmin’ column to version
our ‘User’ class as follows:

     from sqlalchemy import FetchedValue

     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         name = Column(String(50), nullable=False)
         xmin = Column("xmin", String, system=True, server_default=FetchedValue())

         __mapper_args__ = {
             'version_id_col': xmin,
             'version_id_generator': False
         }

With the above mapping, the ORM will rely upon the ‘xmin’ column for
automatically providing the new value of the version id counter.

creating tables that refer to system columns
............................................

In the above scenario, as ‘xmin’ is a system column provided by
PostgreSQL, we use the ‘system=True’ argument to mark it as a
system-provided column, omitted from the ‘CREATE TABLE’ statement.  The
datatype of this column is an internal PostgreSQL type called ‘xid’
which acts mostly like a string, so we use the String
datatype.

The ORM typically does not actively fetch the values of
database-generated values when it emits an INSERT or UPDATE, instead
leaving these columns as “expired” and to be fetched when they are next
accessed, unless the ‘eager_defaults’ mapper() flag is set.
However, when a server side version column is used, the ORM needs to
actively fetch the newly generated value.  This is so that the version
counter is set up `before' any concurrent transaction may update it
again.  This fetching is also best done simultaneously within the INSERT
or UPDATE statement using RETURNING, otherwise if emitting a SELECT
statement afterwards, there is still a potential race condition where
the version counter may change before it can be fetched.

When the target database supports RETURNING, an INSERT statement for our
‘User’ class will look like this:

     INSERT INTO "user" (name) VALUES (%(name)s) RETURNING "user".id, "user".xmin
     {'name': 'ed'}

Where above, the ORM can acquire any newly generated primary key values
along with server-generated version identifiers in one statement.  When
the backend does not support RETURNING, an additional SELECT must be
emitted for `every' INSERT and UPDATE, which is much less efficient, and
also introduces the possibility of missed version counters:

     INSERT INTO "user" (name) VALUES (%(name)s)
     {'name': 'ed'}

     SELECT "user".version_id AS user_version_id FROM "user" where
     "user".id = :param_1
     {"param_1": 1}

It is `strongly recommended' that server side version counters only be
used when absolutely necessary and only on backends that support
RETURNING, e.g.  PostgreSQL, Oracle, SQL Server (though SQL Server has
major caveats(2) when triggers are used), Firebird.

New in version 0.9.0: Support for server side version identifier
tracking.

   ---------- Footnotes ----------

   (1) http://www.postgresql.org/docs/9.1/static/ddl-system-columns.html

   (2)
http://blogs.msdn.com/b/sqlprogrammability/archive/2008/07/11/update-with-output-clause-triggers-and-sqlmoreresults.aspx

3.2.6.4 Programmatic or Conditional Version Counters
....................................................

When ‘version_id_generator’ is set to False, we can also
programmatically (and conditionally) set the version identifier on our
object in the same way we assign any other mapped attribute.  Such as if
we used our UUID example, but set ‘version_id_generator’ to ‘False’, we
can set the version identifier at our choosing:

     import uuid

     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         version_uuid = Column(String(32), nullable=False)
         name = Column(String(50), nullable=False)

         __mapper_args__ = {
             'version_id_col':version_uuid,
             'version_id_generator': False
         }

     u1 = User(name='u1', version_uuid=uuid.uuid4())

     session.add(u1)

     session.commit()

     u1.name = 'u2'
     u1.version_uuid = uuid.uuid4()

     session.commit()

We can update our ‘User’ object without incrementing the version counter
as well; the value of the counter will remain unchanged, and the UPDATE
statement will still check against the previous value.  This may be
useful for schemes where only certain classes of UPDATE are sensitive to
concurrency issues:

     # will leave version_uuid unchanged
     u1.name = 'u3'
     session.commit()

New in version 0.9.0: Support for programmatic and conditional version
identifier tracking.

3.2.7 Class Mapping API
-----------------------

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See as_declarative.(**kw)Class decorator which will adapt a given class into a declarative_base().

See class_mapper.(class_[,Given a class, return the primary Mapper associated with the key.
configure])

See clear_mappers.()Remove all mappers from all classes.

See configure_mappers.()Initialize the inter-mapper relationships of all mappers that have been constructed thus far
               across all registry collections.

See declarative_base.([bind,Construct a base class for declarative class definitions.
metadata,
mapper, cls,
...])

See declared_attr.Mark a class-level method as representing the definition of a mapped property or special
               declarative member name.

See has_inherited_table.(cls)Given a class, return True if any of the classes it inherits from has a mapped table,
               otherwise return False.

See identity_key.(*args,Generate “identity key” tuples, as are used as keys in the Session.identity_map.
**kwargs)      dictionary.

See mapper.(class_[,Direct constructor for a new Mapper object.
local_table,
properties,
primary_key,
...])

See Mapper.Define the correlation of class attributes to database table columns.

See object_mapper.(instance)Given an object, return the primary Mapper associated with the object instance.

See polymorphic_union.(table_map,Create a ‘UNION’ statement used by a polymorphic mapper.
typecolname[,
aliasname,
cast_nulls])

See registry.Generalized registry for mapping classes.

See synonym_for.(name[,Decorator that produces an synonym() attribute in conjunction with a Python
map_column])   descriptor.

 -- Class: sqlalchemy.orm.registry (metadata=None, class_registry=None,
          constructor=<function _declarative_constructor>, _bind=None)

     Generalized registry for mapping classes.

     The registry serves as the basis for maintaining a
     collection of mappings, and provides configurational hooks used to
     map classes.

     The three general kinds of mappings supported are Declarative Base,
     Declarative Decorator, and Imperative Mapping.  All of these
     mapping styles may be used interchangeably:

        * registry.generate_base() returns a new declarative
          base class, and is the underlying implementation of the
          declarative_base() function.

        * registry.mapped() provides a class decorator that
          will apply declarative mapping to a class without the use of a
          declarative base class.

        * registry.map_imperatively() will produce a
          Mapper for a class without scanning the class for
          declarative class attributes.  This method suits the use case
          historically provided by the mapper() classical
          mapping function.

     New in version 1.4.

     See also
     ........

     See Mapping Python Classes. - overview of class mapping
     styles.

      -- Method: sqlalchemy.orm.registry..__init__
               (metadata=None, class_registry=None,
               constructor=<function _declarative_constructor>,
               _bind=None)

          Construct a new registry.

          Parameters:

             * ‘metadata’ – An optional MetaData instance.
               All Table objects generated using declarative
               table mapping will make use of this MetaData
               collection.  If this argument is left at its default of
               ‘None’, a blank MetaData collection is
               created.

             * ‘constructor’ – Specify the implementation for the
               ‘__init__’ function on a mapped class that has no
               ‘__init__’ of its own.  Defaults to an implementation
               that assigns **kwargs for declared fields and
               relationships to an instance.  If ‘None’ is supplied, no
               __init__ will be provided and construction will fall back
               to cls.__init__ by way of the normal Python semantics.

             * ‘class_registry’ – optional dictionary that will serve as
               the registry of class names-> mapped classes when string
               names are used to identify classes inside of
               relationship() and others.  Allows two or more
               declarative base classes to share the same registry of
               class names for simplified inter-base relationships.

      -- Method: sqlalchemy.orm.registry..as_declarative_base
               (**kw)

          Class decorator which will invoke
          registry.generate_base() for a given base class.

          E.g.:

               from sqlalchemy.orm import registry

               mapper_registry = registry()

               @mapper_registry.as_declarative_base()
               class Base(object):
                   @declared_attr
                   def __tablename__(cls):
                       return cls.__name__.lower()
                   id = Column(Integer, primary_key=True)

               class MyMappedClass(Base):
                   # ...

          All keyword arguments passed to
          registry.as_declarative_base() are passed along to
          registry.generate_base().

      -- Method: sqlalchemy.orm.registry..configure
               (cascade=False)

          Configure all as-yet unconfigured mappers in this
          registry.

          The configure step is used to reconcile and initialize the
          relationship() linkages between mapped classes, as
          well as to invoke configuration events such as the
          MapperEvents.before_configured() and
          MapperEvents.after_configured(), which may be used by ORM
          extensions or user-defined extension hooks.

          If one or more mappers in this registry contain
          relationship() constructs that refer to mapped classes in
          other registries, this registry is said to be `dependent' on
          those registries.  In order to configure those dependent
          registries automatically, the configure.cascade
          flag should be set to ‘True’.  Otherwise, if they are not
          configured, an exception will be raised.  The rationale behind
          this behavior is to allow an application to programmatically
          invoke configuration of registries while controlling whether
          or not the process implicitly reaches other registries.

          As an alternative to invoking registry.configure(),
          the ORM function configure_mappers() function may
          be used to ensure configuration is complete for all
          registry objects in memory.  This is generally simpler to
          use and also predates the usage of registry objects
          overall.  However, this function will impact all mappings
          throughout the running Python process and may be more
          memory/time consuming for an application that has many
          registries in use for different purposes that may not be
          needed immediately.

          See also
          ........

          See configure_mappers().

          New in version 1.4.0b2.

      -- Method: sqlalchemy.orm.registry..dispose
               (cascade=False)

          Dispose of all mappers in this registry.

          After invocation, all the classes that were mapped within this
          registry will no longer have class instrumentation associated
          with them.  This method is the per-see registry
          analogue to the application-wide clear_mappers()
          function.

          If this registry contains mappers that are dependencies of
          other registries, typically via relationship()
          links, then those registries must be disposed as well.  When
          such registries exist in relation to this one, their
          registry.dispose() method will also be called, if the
          dispose.cascade flag is set to ‘True’; otherwise,
          an error is raised if those registries were not already
          disposed.

          New in version 1.4.0b2.

          See also
          ........

          See clear_mappers().

      -- Method: sqlalchemy.orm.registry..generate_base
               (mapper=None, cls=<class 'object'>, name='Base',
               metaclass=<class
               'sqlalchemy.orm.decl_api.DeclarativeMeta'>)

          Generate a declarative base class.

          Classes that inherit from the returned class object will be
          automatically mapped using declarative mapping.

          E.g.:

               from sqlalchemy.orm import registry

               mapper_registry = registry()

               Base = mapper_registry.generate_base()

               class MyClass(Base):
                   __tablename__ = "my_table"
                   id = Column(Integer, primary_key=True)

          The above dynamically generated class is equivalent to the
          non-dynamic example below:

               from sqlalchemy.orm import registry
               from sqlalchemy.orm.decl_api import DeclarativeMeta

               mapper_registry = registry()

               class Base(metaclass=DeclarativeMeta):
                   __abstract__ = True
                   registry = mapper_registry
                   metadata = mapper_registry.metadata

          The registry.generate_base() method provides the
          implementation for the declarative_base() function,
          which creates the registry and base class all at
          once.

          See the section Declarative Mapping for background
          and examples.

          Parameters:

             * ‘mapper’ – An optional callable, defaults to
               mapper().  This function is used to generate new
               Mapper objects.

             * ‘cls’ – Defaults to ‘object’.  A type to use as the base
               for the generated declarative base class.  May be a class
               or tuple of classes.

             * ‘name’ – Defaults to ‘Base’.  The display name for the
               generated class.  Customizing this is not required, but
               can improve clarity in tracebacks and debugging.

             * ‘metaclass’ – Defaults to ‘DeclarativeMeta’.  A metaclass
               or __metaclass__ compatible callable to use as the meta
               type of the generated declarative base class.

          See also
          ........

          See Declarative Mapping.

          See declarative_base().

      -- Method: sqlalchemy.orm.registry..map_declaratively
               (cls: type) -> Mapper

          Map a class declaratively.

          In this form of mapping, the class is scanned for mapping
          information, including for columns to be associated with a
          table, and/or an actual table object.

          Returns the Mapper object.

          E.g.:

               from sqlalchemy.orm import registry

               mapper_registry = registry()

               class Foo:
                   __tablename__ = 'some_table'

                   id = Column(Integer, primary_key=True)
                   name = Column(String)

               mapper = mapper_registry.map_declaratively(Foo)

          This function is more conveniently invoked indirectly via
          either the registry.mapped() class decorator or by
          subclassing a declarative metaclass generated from
          registry.generate_base().

          See the section Declarative Mapping for complete
          details and examples.

          Parameters: ‘cls’ – class to be mapped.

          Returns: a Mapper object.

          See also
          ........

          See Declarative Mapping.

          See registry.mapped(). - more common decorator
          interface to this function.

          See registry.map_imperatively().

      -- Method: sqlalchemy.orm.registry..map_imperatively
               (class_, local_table=None, **kw)

          Map a class imperatively.

          In this form of mapping, the class is not scanned for any
          mapping information.  Instead, all mapping constructs are
          passed as arguments.

          This method is intended to be fully equivalent to the classic
          SQLAlchemy mapper() function, except that it’s in
          terms of a particular registry.

          E.g.:

               from sqlalchemy.orm import registry

               mapper_registry = registry()

               my_table = Table(
                   "my_table",
                   mapper_registry.metadata,
                   Column('id', Integer, primary_key=True)
               )

               class MyClass:
                   pass

               mapper_registry.map_imperatively(MyClass, my_table)

          See the section Imperative (a.k.a. Classical) Mappings
          for complete background and usage examples.

          Parameters:

             * ‘class_’ – The class to be mapped.  Corresponds to the
               mapper.class_ parameter.

             * ‘local_table’ – the Table or other
               FromClause object that is the subject of the
               mapping.  Corresponds to the mapper.local_table
               parameter.

             * ‘**kw’ – all other keyword arguments are passed to the
               mapper() function directly.

          See also
          ........

          See Imperative (a.k.a. Classical) Mappings.

          See Declarative Mapping.

      -- Method: sqlalchemy.orm.registry..mapped (cls)

          Class decorator that will apply the Declarative mapping
          process to a given class.

          E.g.:

               from sqlalchemy.orm import registry

               mapper_registry = registry()

               @mapper_registry.mapped
               class Foo:
                   __tablename__ = 'some_table'

                   id = Column(Integer, primary_key=True)
                   name = Column(String)

          See the section Declarative Mapping for complete
          details and examples.

          Parameters: ‘cls’ – class to be mapped.

          Returns: the class that was passed.

          See also
          ........

          See Declarative Mapping.

          See registry.generate_base(). - generates a base class
          that will apply Declarative mapping to subclasses
          automatically using a Python metaclass.

      -- Attribute: sqlalchemy.orm.registry..mappers

          read only collection of all Mapper objects.

 -- Function: sqlalchemy.orm.declarative_base (bind=None, metadata=None,
          mapper=None, cls=<class 'object'>, name='Base',
          constructor=<function _declarative_constructor>,
          class_registry=None, metaclass=<class
          'sqlalchemy.orm.decl_api.DeclarativeMeta'>)

     Construct a base class for declarative class definitions.

     The new base class will be given a metaclass that produces
     appropriate Table objects and makes the appropriate
     mapper() calls based on the information provided
     declaratively in the class and any subclasses of the class.

     The declarative_base() function is a shorthand version
     of using the registry.generate_base() method.  That is,
     the following:

          from sqlalchemy.orm import declarative_base

          Base = declarative_base()

     Is equivalent to:

          from sqlalchemy.orm import registry

          mapper_registry = registry()
          Base = mapper_registry.generate_base()

     See the docstring for registry and
     registry.generate_base() for more details.

     Changed in version 1.4: The declarative_base() function
     is now a specialization of the more generic registry
     class.  The function also moves to the ‘sqlalchemy.orm’ package
     from the ‘declarative.ext’ package.

     Parameters:

        * ‘bind’ – An optional ‘Connectable’, will be assigned the
          ‘bind’ attribute on the MetaData instance.

          Deprecated since version 1.4: The “bind” argument to
          declarative_base is deprecated and will be removed in
          SQLAlchemy 2.0.

        * ‘metadata’ – An optional MetaData instance.  All
          Table objects implicitly declared by subclasses of
          the base will share this MetaData.  A MetaData instance will
          be created if none is provided.  The MetaData
          instance will be available via the ‘metadata’ attribute of the
          generated declarative base class.

        * ‘mapper’ – An optional callable, defaults to mapper().
          Will be used to map subclasses to their Tables.

        * ‘cls’ – Defaults to ‘object’.  A type to use as the base for
          the generated declarative base class.  May be a class or tuple
          of classes.

        * ‘name’ – Defaults to ‘Base’.  The display name for the
          generated class.  Customizing this is not required, but can
          improve clarity in tracebacks and debugging.

        * ‘constructor’ – Specify the implementation for the ‘__init__’
          function on a mapped class that has no ‘__init__’ of its own.
          Defaults to an implementation that assigns **kwargs for
          declared fields and relationships to an instance.  If ‘None’
          is supplied, no __init__ will be provided and construction
          will fall back to cls.__init__ by way of the normal Python
          semantics.

        * ‘class_registry’ – optional dictionary that will serve as the
          registry of class names-> mapped classes when string names are
          used to identify classes inside of relationship()
          and others.  Allows two or more declarative base classes to
          share the same registry of class names for simplified
          inter-base relationships.

        * ‘metaclass’ – Defaults to ‘DeclarativeMeta’.  A metaclass or
          __metaclass__ compatible callable to use as the meta type of
          the generated declarative base class.

     See also
     ........

     See registry.

 -- Function: sqlalchemy.orm.as_declarative (**kw)

     Class decorator which will adapt a given class into a
     declarative_base().

     This function makes use of the
     registry.as_declarative_base() method, by first creating a
     registry automatically and then invoking the decorator.

     E.g.:

          from sqlalchemy.orm import as_declarative

          @as_declarative()
          class Base(object):
              @declared_attr
              def __tablename__(cls):
                  return cls.__name__.lower()
              id = Column(Integer, primary_key=True)

          class MyMappedClass(Base):
              # ...

     See also
     ........

     See registry.as_declarative_base().

 -- Class: sqlalchemy.orm.declared_attr (fget, cascading=False,
          _is_dataclass=False)

     Mark a class-level method as representing the definition of a
     mapped property or special declarative member name.

     declared_attr is typically applied as a decorator to a
     class level method, turning the attribute into a scalar-like
     property that can be invoked from the uninstantiated class.  The
     Declarative mapping process looks for these declared_attr
     callables as it scans classe, and assumes any attribute marked
     with declared_attr will be a callable that will produce
     an object specific to the Declarative mapping or table
     configuration.

     declared_attr is usually applicable to mixins, to
     define relationships that are to be applied to different
     implementors of the class.  It is also used to define Column
     objects that include the ForeignKey construct, as
     these cannot be easily reused across different mappings.  The
     example below illustrates both:

          class ProvidesUser(object):
              "A mixin that adds a 'user' relationship to classes."

              @declared_attr
              def user_id(self):
                  return Column(ForeignKey("user_account.id"))

              @declared_attr
              def user(self):
                  return relationship("User")

     declared_attr can also be applied to mapped classes,
     such as to provide a “polymorphic” scheme for inheritance:

          class Employee(Base):
              id = Column(Integer, primary_key=True)
              type = Column(String(50), nullable=False)

              @declared_attr
              def __tablename__(cls):
                  return cls.__name__.lower()

              @declared_attr
              def __mapper_args__(cls):
                  if cls.__name__ == 'Employee':
                      return {
                              "polymorphic_on":cls.type,
                              "polymorphic_identity":"Employee"
                      }
                  else:
                      return {"polymorphic_identity":cls.__name__}

     To use declared_attr inside of a Python dataclass as
     discussed at Example Two - Dataclasses with Declarative Table,
     it may be placed directly inside the field metadata
     using a lambda:

          @dataclass
          class AddressMixin:
              __sa_dataclass_metadata_key__ = "sa"

              user_id: int = field(
                  init=False, metadata={"sa": declared_attr(lambda: Column(ForeignKey("user.id")))}
              )
              user: User = field(
                  init=False, metadata={"sa": declared_attr(lambda: relationship(User))}
              )

     declared_attr also may be omitted from this form using
     a lambda directly, as in:

          user: User = field(
              init=False, metadata={"sa": lambda: relationship(User)}
          )

     See also
     ........

     See Composing Mapped Hierarchies with Mixins. - illustrates
     how to use Declarative Mixins which is the primary use case for
     declared_attr.

     See Using Declarative Mixins with Dataclasses. - illustrates
     special forms for use with Python dataclasses

     `Class signature'

     class sqlalchemy.orm.declared_attr.
     (‘sqlalchemy.orm.base._MappedAttribute’, ‘builtins.property’)

      -- Attribute: sqlalchemy.orm.declared_attr..cascading

          Mark a declared_attr as cascading.

          This is a special-use modifier which indicates that a column
          or MapperProperty-based declared attribute should be
          configured distinctly per mapped subclass, within a
          mapped-inheritance scenario.

               Warning: The declared_attr.cascading modifier
               has several limitations:

                  * The flag `only' applies to the use of
                    declared_attr on declarative mixin classes and
                    ‘__abstract__’ classes; it currently has no effect
                    when used on a mapped class directly.

                  * The flag `only' applies to normally-named
                    attributes, e.g.  not any special underscore
                    attributes such as ‘__tablename__’.  On these
                    attributes it has `no' effect.

                  * The flag currently `does not allow further
                    overrides' down the class hierarchy; if a subclass
                    tries to override the attribute, a warning is
                    emitted and the overridden attribute is skipped.
                    This is a limitation that it is hoped will be
                    resolved at some point.

          Below, both MyClass as well as MySubClass will have a distinct
          ‘id’ Column object established:

               class HasIdMixin(object):
                   @declared_attr.cascading
                   def id(cls):
                       if has_inherited_table(cls):
                           return Column(
                               ForeignKey('myclass.id'), primary_key=True
                           )
                       else:
                           return Column(Integer, primary_key=True)

               class MyClass(HasIdMixin, Base):
                   __tablename__ = 'myclass'
                   # ...

               class MySubClass(MyClass):
                   ""
                   # ...

          The behavior of the above configuration is that ‘MySubClass’
          will refer to both its own ‘id’ column as well as that of
          ‘MyClass’ underneath the attribute named ‘some_id’.

          See also
          ........

          See Declarative Inheritance.

          See Mixing in Columns in Inheritance Scenarios.

 -- Function: sqlalchemy.orm.has_inherited_table (cls)

     Given a class, return True if any of the classes it inherits from
     has a mapped table, otherwise return False.

     This is used in declarative mixins to build attributes that behave
     differently for the base class vs.  a subclass in an inheritance
     hierarchy.

     See also
     ........

     See Controlling table inheritance with mixins.

 -- Function: sqlalchemy.orm.synonym_for (name, map_column=False)

     Decorator that produces an synonym() attribute in
     conjunction with a Python descriptor.

     The function being decorated is passed to synonym() as
     the synonym.descriptor parameter:

          class MyClass(Base):
              __tablename__ = 'my_table'

              id = Column(Integer, primary_key=True)
              _job_status = Column("job_status", String(50))

              @synonym_for("job_status")
              @property
              def job_status(self):
                  return "Status: %s" % self._job_status

     The hybrid properties feature of SQLAlchemy is
     typically preferred instead of synonyms, which is a more legacy
     feature.

     See also
     ........

     See Synonyms. - Overview of synonyms

     See synonym(). - the mapper-level function

     See Using Descriptors and Hybrids. - The Hybrid Attribute
     extension provides an updated approach to augmenting attribute
     behavior more flexibly than can be achieved with synonyms.

 -- Function: sqlalchemy.orm.mapper (class_, local_table=None,
          properties=None, primary_key=None, non_primary=False,
          inherits=None, inherit_condition=None,
          inherit_foreign_keys=None, always_refresh=False,
          version_id_col=None, version_id_generator=None,
          polymorphic_on=None, _polymorphic_map=None,
          polymorphic_identity=None, concrete=False,
          with_polymorphic=None, polymorphic_load=None,
          allow_partial_pks=True, batch=True, column_prefix=None,
          include_properties=None, exclude_properties=None,
          passive_updates=True, passive_deletes=False,
          confirm_deleted_rows=True, eager_defaults=False,
          legacy_is_orphan=False, _compiled_cache_size=100)

     Direct constructor for a new Mapper object.

     The mapper() function is normally invoked through the
     use of the registry object through either the
     Declarative or Imperative mapping styles.

     Changed in version 1.4: The mapper() function should
     not be called directly for classical mapping; for a classical
     mapping configuration, use the registry.map_imperatively()
     method.  The mapper() function may become private
     in a future release.

     Parameters documented below may be passed to either the
     registry.map_imperatively() method, or may be passed in the
     ‘__mapper_args__’ declarative class attribute described at
     Mapper Configuration Options with Declarative.

     Parameters:

        * ‘class_’ – The class to be mapped.  When using Declarative,
          this argument is automatically passed as the declared class
          itself.

        * ‘local_table’ – The Table or other selectable to
          which the class is mapped.  May be ‘None’ if this mapper
          inherits from another mapper using single-table inheritance.
          When using Declarative, this argument is automatically passed
          by the extension, based on what is configured via the
          ‘__table__’ argument or via the Table produced as a
          result of the ‘__tablename__’ and Column arguments
          present.

        * ‘always_refresh’ – If True, all query operations for this
          mapped class will overwrite all data within object instances
          that already exist within the session, erasing any in-memory
          changes with whatever information was loaded from the
          database.  Usage of this flag is highly discouraged; as an
          alternative, see the method Query.populate_existing().

        * ‘allow_partial_pks’ – Defaults to True.  Indicates that a
          composite primary key with some NULL values should be
          considered as possibly existing within the database.  This
          affects whether a mapper will assign an incoming row to an
          existing identity, as well as if Session.merge()
          will check the database first for a particular primary key
          value.  A “partial primary key” can occur if one has mapped to
          an OUTER JOIN, for example.

        * ‘batch’ – Defaults to ‘True’, indicating that save operations
          of multiple entities can be batched together for efficiency.
          Setting to False indicates that an instance will be fully
          saved before saving the next instance.  This is used in the
          extremely rare case that a MapperEvents listener
          requires being called in between individual row persistence
          operations.

        * ‘column_prefix’ – A string which will be prepended to the
          mapped attribute name when Column objects are
          automatically assigned as attributes to the mapped class.
          Does not affect explicitly specified column-based properties.

          See the section Naming All Columns with a Prefix
          for an example.

        * ‘concrete’ – If True, indicates this mapper should use
          concrete table inheritance with its parent mapper.

          See the section Concrete Table Inheritance for an
          example.

        * ‘confirm_deleted_rows’ – defaults to True; when a DELETE
          occurs of one more rows based on specific primary keys, a
          warning is emitted when the number of rows matched does not
          equal the number of rows expected.  This parameter may be set
          to False to handle the case where database ON DELETE CASCADE
          rules may be deleting some of those rows automatically.  The
          warning may be changed to an exception in a future release.

          New in version 0.9.4: - added
          mapper.confirm_deleted_rows as well as conditional
          matched row checking on delete.

        * ‘eager_defaults’ – if True, the ORM will immediately fetch the
          value of server-generated default values after an INSERT or
          UPDATE, rather than leaving them as expired to be fetched on
          next access.  This can be used for event schemes where the
          server-generated values are needed immediately before the
          flush completes.  By default, this scheme will emit an
          individual ‘SELECT’ statement per row inserted or updated,
          which note can add significant performance overhead.  However,
          if the target database supports RETURNING, the default values
          will be returned inline with the INSERT or UPDATE statement,
          which can greatly enhance performance for an application that
          needs frequent access to just-generated server defaults.

          See also
          ........

          See Fetching Server-Generated Defaults.

          Changed in version 0.9.0: The ‘eager_defaults’ option can now
          make use of RETURNING for backends which support it.

        * ‘exclude_properties’ – A list or set of string column names to
          be excluded from mapping.

          See Mapping a Subset of Table Columns for an
          example.

        * ‘include_properties’ – An inclusive list or set of string
          column names to map.

          See Mapping a Subset of Table Columns for an
          example.

        * ‘inherits’ – A mapped class or the corresponding Mapper
          of one indicating a superclass to which this
          Mapper should `inherit' from.  The mapped class here
          must be a subclass of the other mapper’s class.  When using
          Declarative, this argument is passed automatically as a result
          of the natural class hierarchy of the declared classes.

          See also
          ........

          See Mapping Class Inheritance Hierarchies.

        * ‘inherit_condition’ – For joined table inheritance, a SQL
          expression which will define how the two tables are joined;
          defaults to a natural join between the two tables.

        * ‘inherit_foreign_keys’ – When ‘inherit_condition’ is used and
          the columns present are missing a ForeignKey
          configuration, this parameter can be used to specify which
          columns are “foreign”.  In most cases can be left as ‘None’.

        * ‘legacy_is_orphan’ – Boolean, defaults to ‘False’.  When
          ‘True’, specifies that “legacy” orphan consideration is to be
          applied to objects mapped by this mapper, which means that a
          pending (that is, not persistent) object is auto-expunged from
          an owning Session only when it is de-associated
          from `all' parents that specify a ‘delete-orphan’ cascade
          towards this mapper.  The new default behavior is that the
          object is auto-expunged when it is de-associated with `any' of
          its parents that specify ‘delete-orphan’ cascade.  This
          behavior is more consistent with that of a persistent object,
          and allows behavior to be consistent in more scenarios
          independently of whether or not an orphan object has been
          flushed yet or not.

          See the change note and example at *note The consideration of
          a “pending” object as an “orphan” has been made more
          aggressive: 39b. for more detail on this change.

        * ‘non_primary’ –

          Specify that this Mapper.

               is in addition to the “primary” mapper, that is, the one
               used for persistence.  The Mapper created
               here may be used for ad-hoc mapping of the class to an
               alternate selectable, for loading only.

               Deprecated since version 1.3: The
               mapper.non_primary parameter is deprecated, and
               will be removed in a future release.  The functionality
               of non primary mappers is now better suited using the
               AliasedClass construct, which can also be
               used as the target of a relationship() in 1.3.

          See also
          ........

          See Relationship to Aliased Class. - the new pattern
          that removes the need for the Mapper.non_primary
          flag.

        * ‘passive_deletes’ – Indicates DELETE behavior of foreign key
          columns when a joined-table inheritance entity is being
          deleted.  Defaults to ‘False’ for a base mapper; for an
          inheriting mapper, defaults to ‘False’ unless the value is set
          to ‘True’ on the superclass mapper.

          When ‘True’, it is assumed that ON DELETE CASCADE is
          configured on the foreign key relationships that link this
          mapper’s table to its superclass table, so that when the unit
          of work attempts to delete the entity, it need only emit a
          DELETE statement for the superclass table, and not this table.

          When ‘False’, a DELETE statement is emitted for this mapper’s
          table individually.  If the primary key attributes local to
          this table are unloaded, then a SELECT must be emitted in
          order to validate these attributes; note that the primary key
          columns of a joined-table subclass are not part of the
          “primary key” of the object as a whole.

          Note that a value of ‘True’ is `always' forced onto the
          subclass mappers; that is, it’s not possible for a superclass
          to specify passive_deletes without this taking effect for all
          subclass mappers.

          New in version 1.1.

          See also
          ........

          See Using foreign key ON DELETE cascade with ORM relationships.
          - description of similar feature as used
          with relationship().

          See mapper.passive_updates. - supporting ON UPDATE
          CASCADE for joined-table inheritance mappers

        * ‘passive_updates’ – Indicates UPDATE behavior of foreign key
          columns when a primary key column changes on a joined-table
          inheritance mapping.  Defaults to ‘True’.

          When True, it is assumed that ON UPDATE CASCADE is configured
          on the foreign key in the database, and that the database will
          handle propagation of an UPDATE from a source column to
          dependent columns on joined-table rows.

          When False, it is assumed that the database does not enforce
          referential integrity and will not be issuing its own CASCADE
          operation for an update.  The unit of work process will emit
          an UPDATE statement for the dependent columns during a primary
          key change.

          See also
          ........

          See Mutable Primary Keys / Update Cascades. -
          description of a similar feature as used with
          relationship().

          See mapper.passive_deletes. - supporting ON DELETE
          CASCADE for joined-table inheritance mappers

        * ‘polymorphic_load’ –

          Specifies “polymorphic loading” behavior

               for a subclass in an inheritance hierarchy (joined and
               single table inheritance only).  Valid values are:

                       * “‘inline’” - specifies this class should be
                         part of the “with_polymorphic” mappers, e.g.
                         its columns will be included in a SELECT query
                         against the base.

                       * “‘selectin’” - specifies that when instances of
                         this class are loaded, an additional SELECT
                         will be emitted to retrieve the columns
                         specific to this subclass.  The SELECT uses IN
                         to fetch multiple subclasses at once.

          New in version 1.2.

          See also
          ........

          See Setting with_polymorphic at mapper configuration time.

          See Polymorphic Selectin Loading.

        * ‘polymorphic_on’ – Specifies the column, attribute, or SQL
          expression used to determine the target class for an incoming
          row, when inheriting classes are present.

          This value is commonly a Column object that’s
          present in the mapped Table:

               class Employee(Base):
                   __tablename__ = 'employee'

                   id = Column(Integer, primary_key=True)
                   discriminator = Column(String(50))

                   __mapper_args__ = {
                       "polymorphic_on":discriminator,
                       "polymorphic_identity":"employee"
                   }

          It may also be specified as a SQL expression, as in this
          example where we use the case() construct to
          provide a conditional approach:

               class Employee(Base):
                   __tablename__ = 'employee'

                   id = Column(Integer, primary_key=True)
                   discriminator = Column(String(50))

                   __mapper_args__ = {
                       "polymorphic_on":case([
                           (discriminator == "EN", "engineer"),
                           (discriminator == "MA", "manager"),
                       ], else_="employee"),
                       "polymorphic_identity":"employee"
                   }

          It may also refer to any attribute configured with
          column_property(), or to the string name of one:

               class Employee(Base):
                   __tablename__ = 'employee'

                   id = Column(Integer, primary_key=True)
                   discriminator = Column(String(50))
                   employee_type = column_property(
                       case([
                           (discriminator == "EN", "engineer"),
                           (discriminator == "MA", "manager"),
                       ], else_="employee")
                   )

                   __mapper_args__ = {
                       "polymorphic_on":employee_type,
                       "polymorphic_identity":"employee"
                   }

          When setting ‘polymorphic_on’ to reference an attribute or
          expression that’s not present in the locally mapped
          Table, yet the value of the discriminator should be
          persisted to the database, the value of the discriminator is
          not automatically set on new instances; this must be handled
          by the user, either through manual means or via event
          listeners.  A typical approach to establishing such a listener
          looks like:

               from sqlalchemy import event
               from sqlalchemy.orm import object_mapper

               @event.listens_for(Employee, "init", propagate=True)
               def set_identity(instance, *arg, **kw):
                   mapper = object_mapper(instance)
                   instance.discriminator = mapper.polymorphic_identity

          Where above, we assign the value of ‘polymorphic_identity’ for
          the mapped class to the ‘discriminator’ attribute, thus
          persisting the value to the ‘discriminator’ column in the
          database.

               Warning: Currently, `only one discriminator column may be
               set', typically on the base-most class in the hierarchy.
               “Cascading” polymorphic columns are not yet supported.

          See also
          ........

          See Mapping Class Inheritance Hierarchies.

        * ‘polymorphic_identity’ – Specifies the value which identifies
          this particular class as returned by the column expression
          referred to by the ‘polymorphic_on’ setting.  As rows are
          received, the value corresponding to the ‘polymorphic_on’
          column expression is compared to this value, indicating which
          subclass should be used for the newly reconstructed object.

        * ‘properties’ – A dictionary mapping the string names of object
          attributes to MapperProperty instances, which
          define the persistence behavior of that attribute.  Note that
          Column objects present in the mapped Table
          are automatically placed into ‘ColumnProperty’ instances
          upon mapping, unless overridden.  When using Declarative, this
          argument is passed automatically, based on all those
          MapperProperty instances declared in the declared class
          body.

        * ‘primary_key’ – A list of Column objects which
          define the primary key to be used against this mapper’s
          selectable unit.  This is normally simply the primary key of
          the ‘local_table’, but can be overridden here.

        * ‘version_id_col’ – A Column that will be used to
          keep a running version id of rows in the table.  This is used
          to detect concurrent updates or the presence of stale data in
          a flush.  The methodology is to detect if an UPDATE statement
          does not match the last known version id, a
          StaleDataError exception is thrown.  By default, the
          column must be of Integer type, unless
          ‘version_id_generator’ specifies an alternative version
          generator.

          See also
          ........

          See Configuring a Version Counter. - discussion of
          version counting and rationale.

        * ‘version_id_generator’ – Define how new version ids should be
          generated.  Defaults to ‘None’, which indicates that a simple
          integer counting scheme be employed.  To provide a custom
          versioning scheme, provide a callable function of the form:

               def generate_version(version):
                   return next_version

          Alternatively, server-side versioning functions such as
          triggers, or programmatic versioning schemes outside of the
          version id generator may be used, by specifying the value
          ‘False’.  Please see Server Side Version Counters
          for a discussion of important points when using this option.

          New in version 0.9.0: ‘version_id_generator’ supports
          server-side version number generation.

          See also
          ........

          See Custom Version Counters / Types.

          See Server Side Version Counters.

        * ‘with_polymorphic’ – A tuple in the form ‘(<classes>,
          <selectable>)’ indicating the default style of “polymorphic”
          loading, that is, which tables are queried at once.  <classes>
          is any single or list of mappers and/or classes indicating the
          inherited classes that should be loaded at once.  The special
          value ‘'*'’ may be used to indicate all descending classes
          should be loaded immediately.  The second tuple argument
          <selectable> indicates a selectable that will be used to query
          for multiple classes.

          See also
          ........

          See Using with_polymorphic. - discussion of polymorphic
          querying techniques.

 -- Function: sqlalchemy.orm.object_mapper (instance)

     Given an object, return the primary Mapper associated with the
     object instance.

     Raises sqlalchemy.orm.exc.UnmappedInstanceError if no
     mapping is configured.

     This function is available via the inspection system as:

          inspect(instance).mapper

     Using the inspection system will raise
     sqlalchemy.exc.NoInspectionAvailable if the instance is not
     part of a mapping.

 -- Function: sqlalchemy.orm.class_mapper (class_, configure=True)

     Given a class, return the primary Mapper associated
     with the key.

     Raises UnmappedClassError if no mapping is configured
     on the given class, or ArgumentError if a non-class
     object is passed.

     Equivalent functionality is available via the inspect()
     function as:

          inspect(some_mapped_class)

     Using the inspection system will raise
     sqlalchemy.exc.NoInspectionAvailable if the class is not
     mapped.

 -- Function: sqlalchemy.orm.configure_mappers ()

     Initialize the inter-mapper relationships of all mappers that have
     been constructed thus far across all registry
     collections.

     The configure step is used to reconcile and initialize the
     relationship() linkages between mapped classes, as well as to
     invoke configuration events such as the
     MapperEvents.before_configured() and
     MapperEvents.after_configured(), which may be used by ORM
     extensions or user-defined extension hooks.

     Mapper configuration is normally invoked automatically, the first
     time mappings from a particular registry are used, as
     well as whenever mappings are used and additional
     not-yet-configured mappers have been constructed.  The automatic
     configuration process however is local only to the registry
     involving the target mapper and any related registry
     objects which it may depend on; this is equivalent to invoking the
     registry.configure() method on a particular
     registry.

     By contrast, the configure_mappers() function will
     invoke the configuration process on all registry objects
     that exist in memory, and may be useful for scenarios where many
     individual registry objects that are nonetheless
     interrelated are in use.

     Changed in version 1.4: As of SQLAlchemy 1.4.0b2, this function
     works on a per-see registry basis, locating all
     registry objects present and invoking the
     registry.configure() method on each.  The
     registry.configure() method may be preferred to limit the
     configuration of mappers to those local to a particular
     registry and/or declarative base class.

     Points at which automatic configuration is invoked include when a
     mapped class is instantiated into an instance, as well as when ORM
     queries are emitted using Session.query() or
     Session.execute() with an ORM-enabled statement.

     The mapper configure process, whether invoked by
     configure_mappers() or from registry.configure(),
     provides several event hooks that can be used to augment the mapper
     configuration step.  These hooks include:

        * MapperEvents.before_configured(). - called once
          before configure_mappers() or
          registry.configure() does any work; this can be used to
          establish additional options, properties, or related mappings
          before the operation proceeds.

        * MapperEvents.mapper_configured(). - called as each
          individual Mapper is configured within the
          process; will include all mapper state except for backrefs set
          up by other mappers that are still to be configured.

        * MapperEvents.after_configured(). - called once
          after configure_mappers() or
          registry.configure() is complete; at this stage, all
          Mapper objects that fall within the scope of the
          configuration operation will be fully configured.  Note that
          the calling application may still have other mappings that
          haven’t been produced yet, such as if they are in modules as
          yet unimported, and may also have mappings that are still to
          be configured, if they are in other registry
          collections not part of the current scope of configuration.

 -- Function: sqlalchemy.orm.clear_mappers ()

     Remove all mappers from all classes.

     Changed in version 1.4: This function now locates all
     registry objects and calls upon the registry.dispose()
     method of each.

     This function removes all instrumentation from classes and disposes
     of their associated mappers.  Once called, the classes are unmapped
     and can be later re-mapped with new mappers.

     clear_mappers() is `not' for normal use, as there is
     literally no valid usage for it outside of very specific testing
     scenarios.  Normally, mappers are permanent structural components
     of user-defined classes, and are never discarded independently of
     their class.  If a mapped class itself is garbage collected, its
     mapper is automatically disposed of as well.  As such, see
     clear_mappers() is only for usage in test suites that re-use
     the same classes with different mappings, which is itself an
     extremely rare use case - the only such use case is in fact
     SQLAlchemy’s own test suite, and possibly the test suites of other
     ORM extension libraries which intend to test various combinations
     of mapper construction upon a fixed set of classes.

 -- Function: sqlalchemy.orm.util.identity_key (*args, **kwargs)

     Generate “identity key” tuples, as are used as keys in the
     Session.identity_map dictionary.

     This function has several call styles:

        * ‘identity_key(class, ident, identity_token=token)’

          This form receives a mapped class and a primary key scalar or
          tuple as an argument.

          E.g.:

               >>> identity_key(MyClass, (1, 2))
               (<class '__main__.MyClass'>, (1, 2), None)

          param class: mapped class (must be a positional argument)

          param ident: primary key, may be a scalar or tuple argument.

          param identity_token: optional identity token

          New in version 1.2: added identity_token

        * ‘identity_key(instance=instance)’

          This form will produce the identity key for a given instance.
          The instance need not be persistent, only that its primary key
          attributes are populated (else the key will contain ‘None’ for
          those missing values).

          E.g.:

               >>> instance = MyClass(1, 2)
               >>> identity_key(instance=instance)
               (<class '__main__.MyClass'>, (1, 2), None)

          In this form, the given instance is ultimately run though
          Mapper.identity_key_from_instance(), which will
          have the effect of performing a database check for the
          corresponding row if the object is expired.

          param instance: object instance (must be given as a keyword
          arg)

        * ‘identity_key(class, row=row, identity_token=token)’

          This form is similar to the class/tuple form, except is passed
          a database result row as a Row object.

          E.g.:

               >>> row = engine.execute(\
                   text("select * from table where a=1 and b=2")\
                   ).first()
               >>> identity_key(MyClass, row=row)
               (<class '__main__.MyClass'>, (1, 2), None)

          param class: mapped class (must be a positional argument)

          param row: Row row returned by a
          CursorResult. (must be given as a keyword arg)

          param identity_token: optional identity token

          New in version 1.2: added identity_token

 -- Function: sqlalchemy.orm.polymorphic_union (table_map, typecolname,
          aliasname='p_union', cast_nulls=True)

     Create a ‘UNION’ statement used by a polymorphic mapper.

     See Concrete Table Inheritance for an example of how
     this is used.

     Parameters:

        * ‘table_map’ – mapping of polymorphic identities to
          Table objects.

        * ‘typecolname’ – string name of a “discriminator” column, which
          will be derived from the query, producing the polymorphic
          identity for each row.  If ‘None’, no polymorphic
          discriminator is generated.

        * ‘aliasname’ – name of the alias() construct
          generated.

        * ‘cast_nulls’ – if True, non-existent columns, which are
          represented as labeled NULLs, will be passed into CAST. This
          is a legacy behavior that is problematic on some backends such
          as Oracle - in which case it can be set to False.

 -- Class: sqlalchemy.orm.Mapper (class_, local_table=None,
          properties=None, primary_key=None, non_primary=False,
          inherits=None, inherit_condition=None,
          inherit_foreign_keys=None, always_refresh=False,
          version_id_col=None, version_id_generator=None,
          polymorphic_on=None, _polymorphic_map=None,
          polymorphic_identity=None, concrete=False,
          with_polymorphic=None, polymorphic_load=None,
          allow_partial_pks=True, batch=True, column_prefix=None,
          include_properties=None, exclude_properties=None,
          passive_updates=True, passive_deletes=False,
          confirm_deleted_rows=True, eager_defaults=False,
          legacy_is_orphan=False, _compiled_cache_size=100)

     Define the correlation of class attributes to database table
     columns.

     The Mapper object is instantiated using the
     mapper() function.  For information about instantiating new
     Mapper objects, see that function’s documentation.

     When mapper() is used explicitly to link a user defined
     class with table metadata, this is referred to as `classical
     mapping'.  Modern SQLAlchemy usage tends to favor the
     sqlalchemy.ext.declarative extension for class configuration,
     which makes usage of mapper() behind the scenes.

     Given a particular class known to be mapped by the ORM, the
     Mapper which maintains it can be acquired using the
     inspect() function:

          from sqlalchemy import inspect

          mapper = inspect(MyClass)

     A class which was mapped by the sqlalchemy.ext.declarative
     extension will also have its mapper available via the
     ‘__mapper__’ attribute.

     `Class signature'

     class sqlalchemy.orm.Mapper.
     (‘sqlalchemy.orm.ORMFromClauseRole’,
     ‘sqlalchemy.orm.ORMEntityColumnsClauseRole’,
     ‘sqlalchemy.sql.traversals.MemoizedHasCacheKey’,
     ‘sqlalchemy.orm.base.InspectionAttr’)

      -- Method: sqlalchemy.orm.Mapper..__init__ (class_,
               local_table=None, properties=None, primary_key=None,
               non_primary=False, inherits=None, inherit_condition=None,
               inherit_foreign_keys=None, always_refresh=False,
               version_id_col=None, version_id_generator=None,
               polymorphic_on=None, _polymorphic_map=None,
               polymorphic_identity=None, concrete=False,
               with_polymorphic=None, polymorphic_load=None,
               allow_partial_pks=True, batch=True, column_prefix=None,
               include_properties=None, exclude_properties=None,
               passive_updates=True, passive_deletes=False,
               confirm_deleted_rows=True, eager_defaults=False,
               legacy_is_orphan=False, _compiled_cache_size=100)

          Construct a new Mapper object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.orm.mapper() for a full usage and
          argument description.

      -- Method: sqlalchemy.orm.Mapper..add_properties
               (dict_of_properties)

          Add the given dictionary of properties to this mapper, using
          ‘add_property’.

      -- Method: sqlalchemy.orm.Mapper..add_property (key,
               prop)

          Add an individual MapperProperty to this mapper.

          If the mapper has not been configured yet, just adds the
          property to the initial properties dictionary sent to the
          constructor.  If this Mapper has already been configured, then
          the given MapperProperty is configured immediately.

      -- Attribute: sqlalchemy.orm.Mapper..
               all_orm_descriptors

          A namespace of all InspectionAttr attributes
          associated with the mapped class.

          These attributes are in all cases Python descriptors
          associated with the mapped class or its superclasses.

          This namespace includes attributes that are mapped to the
          class as well as attributes declared by extension modules.  It
          includes any Python descriptor type that inherits from
          InspectionAttr.  This includes QueryableAttribute,
          as well as extension types such as hybrid_property,
          see hybrid_method and AssociationProxy.

          To distinguish between mapped attributes and extension
          attributes, the attribute InspectionAttr.extension_type
          will refer to a constant that distinguishes between
          different extension types.

          The sorting of the attributes is based on the following rules:

            1. Iterate through the class and its superclasses in order
               from subclass to superclass (i.e.  iterate through
               ‘cls.__mro__’)

            2. For each class, yield the attributes in the order in
               which they appear in ‘__dict__’, with the exception of
               those in step 3 below.  In Python 3.6 and above this
               ordering will be the same as that of the class’
               construction, with the exception of attributes that were
               added after the fact by the application or the mapper.

            3. If a certain attribute key is also in the superclass
               ‘__dict__’, then it’s included in the iteration for that
               class, and not the class in which it first appeared.

          The above process produces an ordering that is deterministic
          in terms of the order in which attributes were assigned to the
          class.

          Changed in version 1.3.19: ensured deterministic ordering for
          Mapper.all_orm_descriptors().

          When dealing with a QueryableAttribute, the
          QueryableAttribute.property attribute refers to the
          MapperProperty property, which is what you get
          when referring to the collection of mapped properties via
          Mapper.attrs.

               Warning: The Mapper.all_orm_descriptors
               accessor namespace is an instance of ‘OrderedProperties’.
               This is a dictionary-like object which includes a small
               number of named methods such as
               ‘OrderedProperties.items()’ and
               ‘OrderedProperties.values()’.  When accessing attributes
               dynamically, favor using the dict-access scheme, e.g.
               ‘mapper.all_orm_descriptors[somename]’ over
               ‘getattr(mapper.all_orm_descriptors, somename)’ to avoid
               name collisions.

          See also
          ........

          See Mapper.attrs.

      -- Attribute: sqlalchemy.orm.Mapper..attrs

          A namespace of all MapperProperty objects
          associated this mapper.

          This is an object that provides each property based on its key
          name.  For instance, the mapper for a ‘User’ class which has
          ‘User.name’ attribute would provide ‘mapper.attrs.name’, which
          would be the ColumnProperty representing the
          ‘name’ column.  The namespace object can also be iterated,
          which would yield each MapperProperty.

          Mapper has several pre-filtered views of this
          attribute which limit the types of properties returned,
          including synonyms, column_attrs,
          relationships, and composites.

               Warning: The Mapper.attrs accessor namespace
               is an instance of ‘OrderedProperties’.  This is a
               dictionary-like object which includes a small number of
               named methods such as ‘OrderedProperties.items()’ and
               ‘OrderedProperties.values()’.  When accessing attributes
               dynamically, favor using the dict-access scheme, e.g.
               ‘mapper.attrs[somename]’ over ‘getattr(mapper.attrs,
               somename)’ to avoid name collisions.

          See also
          ........

          See Mapper.all_orm_descriptors.

      -- Attribute: sqlalchemy.orm.Mapper..base_mapper = None

          The base-most Mapper in an inheritance chain.

          In a non-inheriting scenario, this attribute will always be
          this Mapper.  In an inheritance scenario, it
          references the Mapper which is parent to all other
          Mapper objects in the inheritance chain.

          This is a `read only' attribute determined during mapper
          construction.  Behavior is undefined if directly modified.

      -- Attribute: sqlalchemy.orm.Mapper..c = None

          A synonym for Mapper.columns.

      -- Method: sqlalchemy.orm.Mapper..cascade_iterator
               (type_, state, halt_on=None)

          Iterate each element and its mapper in an object graph, for
          all relationships that meet the given cascade rule.

          Parameters:

             * ‘type_’ – The name of the cascade rule (i.e.
               ‘"save-update"’, ‘"delete"’, etc.).

                    Note: the ‘"all"’ cascade is not accepted here.  For
                    a generic object traversal function, see *note How
                    do I walk all objects that are related to a given
                    object?: 3c2.

             * ‘state’ – The lead InstanceState.  child items will be
               processed per the relationships defined for this object’s
               mapper.

          Returns: the method yields individual object instances.

          See also
          ........

          See Cascades.

          See How do I walk all objects that are related to a given object?.
          - illustrates a generic function to traverse all
          objects without relying on cascades.

      -- Attribute: sqlalchemy.orm.Mapper..class_ = None

          The Python class which this Mapper maps.

          This is a `read only' attribute determined during mapper
          construction.  Behavior is undefined if directly modified.

      -- Attribute: sqlalchemy.orm.Mapper..class_manager =
               None

          The ClassManager which maintains event listeners
          and class-bound descriptors for this Mapper.

          This is a `read only' attribute determined during mapper
          construction.  Behavior is undefined if directly modified.

      -- Attribute: sqlalchemy.orm.Mapper..column_attrs

          Return a namespace of all ColumnProperty
          properties maintained by this Mapper.

          See also
          ........

          See Mapper.attrs. - namespace of all
          MapperProperty objects.

      -- Attribute: sqlalchemy.orm.Mapper..columns = None

          A collection of Column or other scalar expression
          objects maintained by this Mapper.

          The collection behaves the same as that of the ‘c’ attribute
          on any Table object, except that only those columns
          included in this mapping are present, and are keyed based on
          the attribute name defined in the mapping, not necessarily the
          ‘key’ attribute of the Column itself.
          Additionally, scalar expressions mapped by
          column_property() are also present here.

          This is a `read only' attribute determined during mapper
          construction.  Behavior is undefined if directly modified.

      -- Method: sqlalchemy.orm.Mapper..common_parent (other)

          Return true if the given mapper shares a common inherited
          parent as this mapper.

      -- Attribute: sqlalchemy.orm.Mapper..composites

          Return a namespace of all CompositeProperty
          properties maintained by this Mapper.

          See also
          ........

          See Mapper.attrs. - namespace of all
          MapperProperty objects.

      -- Attribute: sqlalchemy.orm.Mapper..concrete = None

          Represent ‘True’ if this Mapper is a concrete
          inheritance mapper.

          This is a `read only' attribute determined during mapper
          construction.  Behavior is undefined if directly modified.

      -- Attribute: sqlalchemy.orm.Mapper..configured = False

          Represent ‘True’ if this Mapper has been
          configured.

          This is a `read only' attribute determined during mapper
          construction.  Behavior is undefined if directly modified.

          See also
          ........

          See configure_mappers().

      -- Attribute: sqlalchemy.orm.Mapper..entity

          Part of the inspection API.

          Returns self.class_.

      -- Method: sqlalchemy.orm.Mapper..get_property (key,
               _configure_mappers=True)

          return a MapperProperty associated with the given key.

      -- Method: sqlalchemy.orm.Mapper..
               get_property_by_column (column)

          Given a Column object, return the
          MapperProperty which maps this column.

      -- Method: sqlalchemy.orm.Mapper..
               identity_key_from_instance (instance)

          Return the identity key for the given instance, based on its
          primary key attributes.

          If the instance’s state is expired, calling this method will
          result in a database check to see if the object has been
          deleted.  If the row no longer exists, see
          ObjectDeletedError is raised.

          This value is typically also found on the instance state under
          the attribute name ‘key’.

      -- Method: sqlalchemy.orm.Mapper..
               identity_key_from_primary_key (primary_key,
               identity_token=None)

          Return an identity-map key for use in storing/retrieving an
          item from an identity map.

          Parameters: ‘primary_key’ – A list of values indicating the
          identifier.

      -- Method: sqlalchemy.orm.Mapper..identity_key_from_row
               (row, identity_token=None, adapter=None)

          Return an identity-map key for use in storing/retrieving an
          item from the identity map.

          Parameters: ‘row’ – A Row instance.  The columns
          which are mapped by this Mapper should be
          locatable in the row, preferably via the Column
          object directly (as is the case when a select()
          construct is executed), or via string names of the form
          ‘<tablename>_<colname>’.

      -- Attribute: sqlalchemy.orm.Mapper..inherits = None

          References the Mapper which this Mapper
          inherits from, if any.

          This is a `read only' attribute determined during mapper
          construction.  Behavior is undefined if directly modified.

      -- Attribute: sqlalchemy.orm.Mapper..is_mapper = True

          Part of the inspection API.

      -- Method: sqlalchemy.orm.Mapper..is_sibling (other)

          return true if the other mapper is an inheriting sibling to
          this one.  common parent but different branch

      -- Method: sqlalchemy.orm.Mapper..isa (other)

          Return True if the this mapper inherits from the given mapper.

      -- Attribute: sqlalchemy.orm.Mapper..iterate_properties

          return an iterator of all MapperProperty objects.

      -- Attribute: sqlalchemy.orm.Mapper..local_table = None

          The Selectable which this Mapper
          manages.

          Typically is an instance of Table or Alias.
          May also be ‘None’.

          The “local” table is the selectable that the Mapper
          is directly responsible for managing from an attribute
          access and flush perspective.  For non-inheriting mappers, the
          local table is the same as the “mapped” table.  For
          joined-table inheritance mappers, local_table will be the
          particular sub-table of the overall “join” which this
          Mapper represents.  If this mapper is a single-table
          inheriting mapper, local_table will be ‘None’.

          See also
          ........

          See Mapper.persist_selectable.

      -- Attribute: sqlalchemy.orm.Mapper..mapped_table

          Deprecated since version 1.3: Use .persist_selectable

      -- Attribute: sqlalchemy.orm.Mapper..mapper

          Part of the inspection API.

          Returns self.

      -- Attribute: sqlalchemy.orm.Mapper..non_primary = None

          Represent ‘True’ if this Mapper is a “non-primary”
          mapper, e.g.  a mapper that is used only to select rows but
          not for persistence management.

          This is a `read only' attribute determined during mapper
          construction.  Behavior is undefined if directly modified.

      -- Attribute: sqlalchemy.orm.Mapper..persist_selectable
               = None

          The Selectable to which this Mapper is
          mapped.

          Typically an instance of Table, Join, or
          Alias.

          The Mapper.persist_selectable is separate from
          Mapper.selectable in that the former represents
          columns that are mapped on this class or its superclasses,
          whereas the latter may be a “polymorphic” selectable that
          contains additional columns which are in fact mapped on
          subclasses only.

          “persist selectable” is the “thing the mapper writes to” and
          “selectable” is the “thing the mapper selects from”.

          Mapper.persist_selectable is also separate from
          Mapper.local_table, which represents the set of
          columns that are locally mapped on this class directly.

          See also
          ........

          See Mapper.selectable.

          See Mapper.local_table.

      -- Attribute: sqlalchemy.orm.Mapper..
               polymorphic_identity = None

          Represent an identifier which is matched against the
          Mapper.polymorphic_on column during result row loading.

          Used only with inheritance, this object can be of any type
          which is comparable to the type of column represented by
          Mapper.polymorphic_on.

          This is a `read only' attribute determined during mapper
          construction.  Behavior is undefined if directly modified.

      -- Method: sqlalchemy.orm.Mapper..polymorphic_iterator
               ()

          Iterate through the collection including this mapper and all
          descendant mappers.

          This includes not just the immediately inheriting mappers but
          all their inheriting mappers as well.

          To iterate through an entire hierarchy, use
          ‘mapper.base_mapper.polymorphic_iterator()’.

      -- Attribute: sqlalchemy.orm.Mapper..polymorphic_map =
               None

          A mapping of “polymorphic identity” identifiers mapped to
          Mapper instances, within an inheritance scenario.

          The identifiers can be of any type which is comparable to the
          type of column represented by Mapper.polymorphic_on.

          An inheritance chain of mappers will all reference the same
          polymorphic map object.  The object is used to correlate
          incoming result rows to target mappers.

          This is a `read only' attribute determined during mapper
          construction.  Behavior is undefined if directly modified.

      -- Attribute: sqlalchemy.orm.Mapper..polymorphic_on =
               None

          The Column or SQL expression specified as the
          ‘polymorphic_on’ argument for this Mapper, within
          an inheritance scenario.

          This attribute is normally a Column instance but
          may also be an expression, such as one derived from
          cast().

          This is a `read only' attribute determined during mapper
          construction.  Behavior is undefined if directly modified.

      -- Attribute: sqlalchemy.orm.Mapper..primary_key = None

          An iterable containing the collection of Column
          objects which comprise the ‘primary key’ of the mapped table,
          from the perspective of this Mapper.

          This list is against the selectable in
          Mapper.persist_selectable.  In the case of inheriting
          mappers, some columns may be managed by a superclass mapper.
          For example, in the case of a Join, the primary key
          is determined by all of the primary key columns across all
          tables referenced by the Join.

          The list is also not necessarily the same as the primary key
          column collection associated with the underlying tables; the
          Mapper features a ‘primary_key’ argument that can
          override what the Mapper considers as primary key
          columns.

          This is a `read only' attribute determined during mapper
          construction.  Behavior is undefined if directly modified.

      -- Method: sqlalchemy.orm.Mapper..
               primary_key_from_instance (instance)

          Return the list of primary key values for the given instance.

          If the instance’s state is expired, calling this method will
          result in a database check to see if the object has been
          deleted.  If the row no longer exists, see
          ObjectDeletedError is raised.

      -- Method: sqlalchemy.orm.Mapper..primary_mapper ()

          Return the primary mapper corresponding to this mapper’s class
          key (class).

      -- Attribute: sqlalchemy.orm.Mapper..relationships

          A namespace of all RelationshipProperty properties
          maintained by this Mapper.

               Warning: the Mapper.relationships accessor
               namespace is an instance of ‘OrderedProperties’.  This is
               a dictionary-like object which includes a small number of
               named methods such as ‘OrderedProperties.items()’ and
               ‘OrderedProperties.values()’.  When accessing attributes
               dynamically, favor using the dict-access scheme, e.g.
               ‘mapper.relationships[somename]’ over
               ‘getattr(mapper.relationships, somename)’ to avoid name
               collisions.

          See also
          ........

          See Mapper.attrs. - namespace of all
          MapperProperty objects.

      -- Attribute: sqlalchemy.orm.Mapper..selectable

          The ‘FromClause’ construct this Mapper selects
          from by default.

          Normally, this is equivalent to persist_selectable,
          unless the ‘with_polymorphic’ feature is in use, in which case
          the full “polymorphic” selectable is returned.

      -- Attribute: sqlalchemy.orm.Mapper..
               self_and_descendants

          The collection including this mapper and all descendant
          mappers.

          This includes not just the immediately inheriting mappers but
          all their inheriting mappers as well.

      -- Attribute: sqlalchemy.orm.Mapper..single = None

          Represent ‘True’ if this Mapper is a single table
          inheritance mapper.

          Mapper.local_table will be ‘None’ if this flag is
          set.

          This is a `read only' attribute determined during mapper
          construction.  Behavior is undefined if directly modified.

      -- Attribute: sqlalchemy.orm.Mapper..synonyms

          Return a namespace of all SynonymProperty
          properties maintained by this Mapper.

          See also
          ........

          See Mapper.attrs. - namespace of all
          MapperProperty objects.

      -- Attribute: sqlalchemy.orm.Mapper..tables = None

          An iterable containing the collection of Table
          objects which this Mapper is aware of.

          If the mapper is mapped to a Join, or an
          Alias representing a Select, the individual
          Table objects that comprise the full construct will
          be represented here.

          This is a `read only' attribute determined during mapper
          construction.  Behavior is undefined if directly modified.

      -- Attribute: sqlalchemy.orm.Mapper..validators = None

          An immutable dictionary of attributes which have been
          decorated using the validates() decorator.

          The dictionary contains string attribute names as keys mapped
          to the actual validation method.

      -- Attribute: sqlalchemy.orm.Mapper..
               with_polymorphic_mappers

          The list of Mapper objects included in the default
          “polymorphic” query.

3.3 Relationship Configuration
==============================

This section describes the relationship() function and in
depth discussion of its usage.  For an introduction to relationships,
start with the Object Relational Tutorial (1.x API) and head
into Building a Relationship.

3.3.1 Basic Relationship Patterns
---------------------------------

A quick walkthrough of the basic relational patterns.

The imports used for each of the following sections is as follows:

     from sqlalchemy import Table, Column, Integer, ForeignKey
     from sqlalchemy.orm import relationship
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

3.3.1.1 One To Many
...................

A one to many relationship places a foreign key on the child table
referencing the parent.  relationship() is then specified on
the parent, as referencing a collection of items represented by the
child:

     class Parent(Base):
         __tablename__ = 'parent'
         id = Column(Integer, primary_key=True)
         children = relationship("Child")

     class Child(Base):
         __tablename__ = 'child'
         id = Column(Integer, primary_key=True)
         parent_id = Column(Integer, ForeignKey('parent.id'))

To establish a bidirectional relationship in one-to-many, where the
“reverse” side is a many to one, specify an additional
relationship() and connect the two using the
relationship.back_populates parameter:

     class Parent(Base):
         __tablename__ = 'parent'
         id = Column(Integer, primary_key=True)
         children = relationship("Child", back_populates="parent")

     class Child(Base):
         __tablename__ = 'child'
         id = Column(Integer, primary_key=True)
         parent_id = Column(Integer, ForeignKey('parent.id'))
         parent = relationship("Parent", back_populates="children")

‘Child’ will get a ‘parent’ attribute with many-to-one semantics.

Alternatively, the relationship.backref option may be used
on a single relationship() instead of using
relationship.back_populates:

     class Parent(Base):
         __tablename__ = 'parent'
         id = Column(Integer, primary_key=True)
         children = relationship("Child", backref="parent")

3.3.1.2 Configuring Delete Behavior for One to Many
...................................................

It is often the case that all ‘Child’ objects should be deleted when
their owning ‘Parent’ is deleted.  To configure this behavior, the
‘delete’ cascade option described at delete is used.  An
additional option is that a ‘Child’ object can itself be deleted when it
is deassociated from its parent.  This behavior is described at
delete-orphan.

See also
........

See delete.

See Using foreign key ON DELETE cascade with ORM relationships.

See delete-orphan.

3.3.1.3 Many To One
...................

Many to one places a foreign key in the parent table referencing the
child.  relationship() is declared on the parent, where a new
scalar-holding attribute will be created:

     class Parent(Base):
         __tablename__ = 'parent'
         id = Column(Integer, primary_key=True)
         child_id = Column(Integer, ForeignKey('child.id'))
         child = relationship("Child")

     class Child(Base):
         __tablename__ = 'child'
         id = Column(Integer, primary_key=True)

Bidirectional behavior is achieved by adding a second
relationship() and applying the relationship.back_populates
parameter in both directions:

     class Parent(Base):
         __tablename__ = 'parent'
         id = Column(Integer, primary_key=True)
         child_id = Column(Integer, ForeignKey('child.id'))
         child = relationship("Child", back_populates="parents")

     class Child(Base):
         __tablename__ = 'child'
         id = Column(Integer, primary_key=True)
         parents = relationship("Parent", back_populates="child")

Alternatively, the relationship.backref parameter may be
applied to a single relationship(), such as ‘Parent.child’:

     class Parent(Base):
         __tablename__ = 'parent'
         id = Column(Integer, primary_key=True)
         child_id = Column(Integer, ForeignKey('child.id'))
         child = relationship("Child", backref="parents")

3.3.1.4 One To One
..................

One To One is essentially a bidirectional relationship with a scalar
attribute on both sides.  To achieve this, the
relationship.uselist flag indicates the placement of a scalar
attribute instead of a collection on the “many” side of the
relationship.  To convert one-to-many into one-to-one:

     class Parent(Base):
         __tablename__ = 'parent'
         id = Column(Integer, primary_key=True)
         child = relationship("Child", uselist=False, back_populates="parent")

     class Child(Base):
         __tablename__ = 'child'
         id = Column(Integer, primary_key=True)
         parent_id = Column(Integer, ForeignKey('parent.id'))
         parent = relationship("Parent", back_populates="child")

Or for many-to-one:

     class Parent(Base):
         __tablename__ = 'parent'
         id = Column(Integer, primary_key=True)
         child_id = Column(Integer, ForeignKey('child.id'))
         child = relationship("Child", back_populates="parent")

     class Child(Base):
         __tablename__ = 'child'
         id = Column(Integer, primary_key=True)
         parent = relationship("Parent", back_populates="child", uselist=False)

As always, the relationship.backref and backref()
functions may be used in lieu of the
relationship.back_populates approach; to specify ‘uselist’ on a
backref, use the backref() function:

     from sqlalchemy.orm import backref

     class Parent(Base):
         __tablename__ = 'parent'
         id = Column(Integer, primary_key=True)
         child_id = Column(Integer, ForeignKey('child.id'))
         child = relationship("Child", backref=backref("parent", uselist=False))

3.3.1.5 Many To Many
....................

Many to Many adds an association table between two classes.  The
association table is indicated by the relationship.secondary
argument to relationship().  Usually, the Table
uses the MetaData object associated with the declarative base
class, so that the ForeignKey directives can locate the
remote tables with which to link:

     association_table = Table('association', Base.metadata,
         Column('left_id', Integer, ForeignKey('left.id')),
         Column('right_id', Integer, ForeignKey('right.id'))
     )

     class Parent(Base):
         __tablename__ = 'left'
         id = Column(Integer, primary_key=True)
         children = relationship("Child",
                         secondary=association_table)

     class Child(Base):
         __tablename__ = 'right'
         id = Column(Integer, primary_key=True)

For a bidirectional relationship, both sides of the relationship contain
a collection.  Specify using relationship.back_populates, and
for each relationship() specify the common association table:

     association_table = Table('association', Base.metadata,
         Column('left_id', Integer, ForeignKey('left.id')),
         Column('right_id', Integer, ForeignKey('right.id'))
     )

     class Parent(Base):
         __tablename__ = 'left'
         id = Column(Integer, primary_key=True)
         children = relationship(
             "Child",
             secondary=association_table,
             back_populates="parents")

     class Child(Base):
         __tablename__ = 'right'
         id = Column(Integer, primary_key=True)
         parents = relationship(
             "Parent",
             secondary=association_table,
             back_populates="children")

When using the relationship.backref parameter instead of
relationship.back_populates, the backref will automatically
use the same relationship.secondary argument for the reverse
relationship:

     association_table = Table('association', Base.metadata,
         Column('left_id', Integer, ForeignKey('left.id')),
         Column('right_id', Integer, ForeignKey('right.id'))
     )

     class Parent(Base):
         __tablename__ = 'left'
         id = Column(Integer, primary_key=True)
         children = relationship("Child",
                         secondary=association_table,
                         backref="parents")

     class Child(Base):
         __tablename__ = 'right'
         id = Column(Integer, primary_key=True)

The relationship.secondary argument of relationship()
also accepts a callable that returns the ultimate argument, which is
evaluated only when mappers are first used.  Using this, we can define
the ‘association_table’ at a later point, as long as it’s available to
the callable after all module initialization is complete:

     class Parent(Base):
         __tablename__ = 'left'
         id = Column(Integer, primary_key=True)
         children = relationship("Child",
                         secondary=lambda: association_table,
                         backref="parents")

With the declarative extension in use, the traditional “string name of
the table” is accepted as well, matching the name of the table as stored
in ‘Base.metadata.tables’:

     class Parent(Base):
         __tablename__ = 'left'
         id = Column(Integer, primary_key=True)
         children = relationship("Child",
                         secondary="association",
                         backref="parents")

     Warning: When passed as a Python-evaluable string, the
     relationship.secondary argument is interpreted using Python’s
     ‘eval()’ function.  `DO NOT PASS UNTRUSTED INPUT TO THIS STRING'.
     See Evaluation of relationship arguments for details on
     declarative evaluation of relationship() arguments.

3.3.1.6 Deleting Rows from the Many to Many Table
.................................................

A behavior which is unique to the relationship.secondary
argument to relationship() is that the Table which
is specified here is automatically subject to INSERT and DELETE
statements, as objects are added or removed from the collection.  There
is `no need to delete from this table manually'.  The act of removing a
record from the collection will have the effect of the row being deleted
on flush:

     # row will be deleted from the "secondary" table
     # automatically
     myparent.children.remove(somechild)

A question which often arises is how the row in the “secondary” table
can be deleted when the child object is handed directly to
Session.delete():

     session.delete(somechild)

There are several possibilities here:

   * If there is a relationship() from ‘Parent’ to ‘Child’,
     but there is `not' a reverse-relationship that links a particular
     ‘Child’ to each ‘Parent’, SQLAlchemy will not have any awareness
     that when deleting this particular ‘Child’ object, it needs to
     maintain the “secondary” table that links it to the ‘Parent’.  No
     delete of the “secondary” table will occur.

   * If there is a relationship that links a particular ‘Child’ to each
     ‘Parent’, suppose it’s called ‘Child.parents’, SQLAlchemy by
     default will load in the ‘Child.parents’ collection to locate all
     ‘Parent’ objects, and remove each row from the “secondary” table
     which establishes this link.  Note that this relationship does not
     need to be bidirectional; SQLAlchemy is strictly looking at every
     relationship() associated with the ‘Child’ object being
     deleted.

   * A higher performing option here is to use ON DELETE CASCADE
     directives with the foreign keys used by the database.  Assuming
     the database supports this feature, the database itself can be made
     to automatically delete rows in the “secondary” table as
     referencing rows in “child” are deleted.  SQLAlchemy can be
     instructed to forego actively loading in the ‘Child.parents’
     collection in this case using the
     relationship.passive_deletes directive on
     relationship(); see Using foreign key ON DELETE cascade with ORM relationships
     for more details on this.

Note again, these behaviors are `only' relevant to the
relationship.secondary option used with relationship().
If dealing with association tables that are mapped explicitly and are
`not' present in the relationship.secondary option of a
relevant relationship(), cascade rules can be used instead to
automatically delete entities in reaction to a related entity being
deleted - see Cascades for information on this feature.

See also
........

See Using delete cascade with many-to-many relationships.

See Using foreign key ON DELETE with many-to-many relationships.

3.3.1.7 Association Object
..........................

The association object pattern is a variant on many-to-many: it’s used
when your association table contains additional columns beyond those
which are foreign keys to the left and right tables.  Instead of using
the relationship.secondary argument, you map a new class
directly to the association table.  The left side of the relationship
references the association object via one-to-many, and the association
class references the right side via many-to-one.  Below we illustrate an
association table mapped to the ‘Association’ class which includes a
column called ‘extra_data’, which is a string value that is stored along
with each association between ‘Parent’ and ‘Child’:

     class Association(Base):
         __tablename__ = 'association'
         left_id = Column(Integer, ForeignKey('left.id'), primary_key=True)
         right_id = Column(Integer, ForeignKey('right.id'), primary_key=True)
         extra_data = Column(String(50))
         child = relationship("Child")

     class Parent(Base):
         __tablename__ = 'left'
         id = Column(Integer, primary_key=True)
         children = relationship("Association")

     class Child(Base):
         __tablename__ = 'right'
         id = Column(Integer, primary_key=True)

As always, the bidirectional version makes use of
relationship.back_populates or relationship.backref:

     class Association(Base):
         __tablename__ = 'association'
         left_id = Column(Integer, ForeignKey('left.id'), primary_key=True)
         right_id = Column(Integer, ForeignKey('right.id'), primary_key=True)
         extra_data = Column(String(50))
         child = relationship("Child", back_populates="parents")
         parent = relationship("Parent", back_populates="children")

     class Parent(Base):
         __tablename__ = 'left'
         id = Column(Integer, primary_key=True)
         children = relationship("Association", back_populates="parent")

     class Child(Base):
         __tablename__ = 'right'
         id = Column(Integer, primary_key=True)
         parents = relationship("Association", back_populates="child")

Working with the association pattern in its direct form requires that
child objects are associated with an association instance before being
appended to the parent; similarly, access from parent to child goes
through the association object:

     # create parent, append a child via association
     p = Parent()
     a = Association(extra_data="some data")
     a.child = Child()
     p.children.append(a)

     # iterate through child objects via association, including association
     # attributes
     for assoc in p.children:
         print(assoc.extra_data)
         print(assoc.child)

To enhance the association object pattern such that direct access to the
‘Association’ object is optional, SQLAlchemy provides the
Association Proxy extension.  This extension allows the
configuration of attributes which will access two “hops” with a single
access, one “hop” to the associated object, and a second to a target
attribute.

     Warning: The association object pattern `does not coordinate
     changes with a separate relationship that maps the association
     table as “secondary”'.

     Below, changes made to ‘Parent.children’ will not be coordinated
     with changes made to ‘Parent.child_associations’ or
     ‘Child.parent_associations’ in Python; while all of these
     relationships will continue to function normally by themselves,
     changes on one will not show up in another until the Session
     is expired, which normally occurs automatically after
     Session.commit():

          class Association(Base):
              __tablename__ = 'association'

              left_id = Column(Integer, ForeignKey('left.id'), primary_key=True)
              right_id = Column(Integer, ForeignKey('right.id'), primary_key=True)
              extra_data = Column(String(50))

              child = relationship("Child", backref="parent_associations")
              parent = relationship("Parent", backref="child_associations")

          class Parent(Base):
              __tablename__ = 'left'
              id = Column(Integer, primary_key=True)

              children = relationship("Child", secondary="association")

          class Child(Base):
              __tablename__ = 'right'
              id = Column(Integer, primary_key=True)

     Additionally, just as changes to one relationship aren’t reflected
     in the others automatically, writing the same data to both
     relationships will cause conflicting INSERT or DELETE statements as
     well, such as below where we establish the same relationship
     between a ‘Parent’ and ‘Child’ object twice:

          p1 = Parent()
          c1 = Child()
          p1.children.append(c1)

          # redundant, will cause a duplicate INSERT on Association
          p1.child_associations.append(Association(child=c1))

     It’s fine to use a mapping like the above if you know what you’re
     doing, though it may be a good idea to apply the ‘viewonly=True’
     parameter to the “secondary” relationship to avoid the issue of
     redundant changes being logged.  However, to get a foolproof
     pattern that allows a simple two-object ‘Parent->Child’
     relationship while still using the association object pattern, use
     the association proxy extension as documented at Association Proxy.

3.3.2 Late-Evaluation of Relationship Arguments
-----------------------------------------------

Many of the examples in the preceding sections illustrate mappings where
the various relationship() constructs refer to their target
classes using a string name, rather than the class itself:

     class Parent(Base):
         # ...

         children = relationship("Child", back_populates="parent")

     class Child(Base):
         # ...

         parent = relationship("Parent", back_populates="children")

These string names are resolved into classes in the mapper resolution
stage, which is an internal process that occurs typically after all
mappings have been defined and is normally triggered by the first usage
of the mappings themselves.  The registry object is the
container in which these names are stored and resolved to the mapped
classes they refer towards.

In addition to the main class argument for relationship(),
other arguments which depend upon the columns present on an as-yet
undefined class may also be specified either as Python functions, or
more commonly as strings.  For most of these arguments except that of
the main argument, string inputs are `evaluated as Python expressions
using Python’s built-in eval() function', as they are intended to
recieve complete SQL expressions.

     Warning: As the Python ‘eval()’ function is used to interpret the
     late-evaluated string arguments passed to relationship()
     mapper configuration construct, these arguments should `not' be
     repurposed such that they would receive untrusted user input;
     ‘eval()’ is `not secure' against untrusted user input.

The full namespace available within this evaluation includes all classes
mapped for this declarative base, as well as the contents of the
‘sqlalchemy’ package, including expression functions like desc()
and ‘sqlalchemy.sql.functions.func’:

     class Parent(Base):
         # ...

         children = relationship(
             "Child",
             order_by="desc(Child.email_address)",
             primaryjoin="Parent.id == Child.parent_id"
         )

For the case where more than one module contains a class of the same
name, string class names can also be specified as module-qualified paths
within any of these string expressions:

     class Parent(Base):
         # ...

         children = relationship(
             "myapp.mymodel.Child",
             order_by="desc(myapp.mymodel.Child.email_address)",
             primaryjoin="myapp.mymodel.Parent.id == myapp.mymodel.Child.parent_id"
         )

The qualified path can be any partial path that removes ambiguity
between the names.  For example, to disambiguate between
‘myapp.model1.Child’ and ‘myapp.model2.Child’, we can specify
‘model1.Child’ or ‘model2.Child’:

     class Parent(Base):
         # ...

         children = relationship(
             "model1.Child",
             order_by="desc(mymodel1.Child.email_address)",
             primaryjoin="Parent.id == model1.Child.parent_id"
         )

The relationship() construct also accepts Python functions or
lambdas as input for these arguments.  This has the advantage of
providing more compile-time safety and better support for IDEs and PEP
484(1) scenarios.

A Python functional approach might look like the following:

     from sqlalchemy import desc

     def _resolve_child_model():
          from myapplication import Child
          return Child

     class Parent(Base):
         # ...

         children = relationship(
             _resolve_child_model(),
             order_by=lambda: desc(_resolve_child_model().email_address),
             primaryjoin=lambda: Parent.id == _resolve_child_model().parent_id
         )

The full list of parameters which accept Python functions/lambdas or
strings that will be passed to ‘eval()’ are:

   * relationship.order_by.

   * relationship.primaryjoin.

   * relationship.secondaryjoin.

   * relationship.secondary.

   * relationship.remote_side.

   * relationship.foreign_keys.

   * relationship._user_defined_foreign_keys.

Changed in version 1.3.16: Prior to SQLAlchemy 1.3.16, the main
relationship.argument to relationship() was also
evaluated throught ‘eval()’ As of 1.3.16 the string name is resolved
from the class resolver directly without supporting custom Python
expressions.

     Warning: As stated previously, the above parameters to
     relationship() are `evaluated as Python code expressions using
     eval().  DO NOT PASS UNTRUSTED INPUT TO THESE ARGUMENTS.'

It should also be noted that in a similar way as described at
Adding New Columns, any MapperProperty construct can be
added to a declarative base mapping at any time.  If we wanted to
implement this relationship() after the ‘Address’ class were
available, we could also apply it afterwards:

     # first, module A, where Child has not been created yet,
     # we create a Parent class which knows nothing about Child

     class Parent(Base):
         # ...

     #... later, in Module B, which is imported after module A:

     class Child(Base):
         # ...

     from module_a import Parent

     # assign the User.addresses relationship as a class variable.  The
     # declarative base class will intercept this and map the relationship.
     Parent.children = relationship(
         Child,
         primaryjoin=Child.parent_id==Parent.id
     )

     Note: assignment of mapped properties to a declaratively mapped
     class will only function correctly if the “declarative base” class
     is used, which also provides for a metaclass-driven ‘__setattr__()’
     method which will intercept these operations.  It will `not' work
     if the declarative decorator provided by registry.mapped()
     is used, nor will it work for an imperatively mapped class
     mapped by registry.map_imperatively().

   ---------- Footnotes ----------

   (1) https://www.python.org/dev/peps/pep-0484

3.3.2.1 Late-Evaluation for a many-to-many relationship
.......................................................

Many-to-many relationships include a reference to an additional,
typically non-mapped Table object that is typically present
in the MetaData collection referred towards by the
registry.  The late-evaluation system also includes support for
having this attribute be specified as a string argument which will be
resolved from this MetaData collection.  Below we specify an
association table ‘keyword_author’, sharing the MetaData
collection associated with our declarative base and its registry.
We can then refer to this Table by name in the
relationship.secondary parameter:

     keyword_author = Table(
         'keyword_author', Base.metadata,
         Column('author_id', Integer, ForeignKey('authors.id')),
         Column('keyword_id', Integer, ForeignKey('keywords.id'))
         )

     class Author(Base):
         __tablename__ = 'authors'
         id = Column(Integer, primary_key=True)
         keywords = relationship("Keyword", secondary="keyword_author")

For additional detail on many-to-many relationships see the section
Many To Many.

3.3.3 Adjacency List Relationships
----------------------------------

The `adjacency list' pattern is a common relational pattern whereby a
table contains a foreign key reference to itself.  This is the most
common way to represent hierarchical data in flat tables.  Other methods
include `nested sets', sometimes called “modified preorder”, as well as
`materialized path'.  Despite the appeal that modified preorder has when
evaluated for its fluency within SQL queries, the adjacency list model
is probably the most appropriate pattern for the large majority of
hierarchical storage needs, for reasons of concurrency, reduced
complexity, and that modified preorder has little advantage over an
application which can fully load subtrees into the application space.

In this example, we’ll work with a single mapped class called ‘Node’,
representing a tree structure:

     class Node(Base):
         __tablename__ = 'node'
         id = Column(Integer, primary_key=True)
         parent_id = Column(Integer, ForeignKey('node.id'))
         data = Column(String(50))
         children = relationship("Node")

With this structure, a graph such as the following:

     root --+---> child1
            +---> child2 --+--> subchild1
            |              +--> subchild2
            +---> child3

Would be represented with data such as:

     id       parent_id     data
     ---      -------       ----
     1        NULL          root
     2        1             child1
     3        1             child2
     4        3             subchild1
     5        3             subchild2
     6        1             child3

The relationship() configuration here works in the same way
as a “normal” one-to-many relationship, with the exception that the
“direction”, i.e.  whether the relationship is one-to-many or
many-to-one, is assumed by default to be one-to-many.  To establish the
relationship as many-to-one, an extra directive is added known as
relationship.remote_side, which is a Column or
collection of Column objects that indicate those which should
be considered to be “remote”:

     class Node(Base):
         __tablename__ = 'node'
         id = Column(Integer, primary_key=True)
         parent_id = Column(Integer, ForeignKey('node.id'))
         data = Column(String(50))
         parent = relationship("Node", remote_side=[id])

Where above, the ‘id’ column is applied as the
relationship.remote_side of the ‘parent’ relationship(),
thus establishing ‘parent_id’ as the “local” side, and the relationship
then behaves as a many-to-one.

As always, both directions can be combined into a bidirectional
relationship using the backref() function:

     class Node(Base):
         __tablename__ = 'node'
         id = Column(Integer, primary_key=True)
         parent_id = Column(Integer, ForeignKey('node.id'))
         data = Column(String(50))
         children = relationship("Node",
                     backref=backref('parent', remote_side=[id])
                 )

There are several examples included with SQLAlchemy illustrating
self-referential strategies; these include Adjacency List
and XML Persistence.

3.3.3.1 Composite Adjacency Lists
.................................

A sub-category of the adjacency list relationship is the rare case where
a particular column is present on both the “local” and “remote” side of
the join condition.  An example is the ‘Folder’ class below; using a
composite primary key, the ‘account_id’ column refers to itself, to
indicate sub folders which are within the same account as that of the
parent; while ‘folder_id’ refers to a specific folder within that
account:

     class Folder(Base):
         __tablename__ = 'folder'
         __table_args__ = (
           ForeignKeyConstraint(
               ['account_id', 'parent_id'],
               ['folder.account_id', 'folder.folder_id']),
         )

         account_id = Column(Integer, primary_key=True)
         folder_id = Column(Integer, primary_key=True)
         parent_id = Column(Integer)
         name = Column(String)

         parent_folder = relationship("Folder",
                             backref="child_folders",
                             remote_side=[account_id, folder_id]
                       )

Above, we pass ‘account_id’ into the relationship.remote_side
list.  relationship() recognizes that the ‘account_id’
column here is on both sides, and aligns the “remote” column along with
the ‘folder_id’ column, which it recognizes as uniquely present on the
“remote” side.

3.3.3.2 Self-Referential Query Strategies
.........................................

Querying of self-referential structures works like any other query:

     # get all nodes named 'child2'
     session.query(Node).filter(Node.data=='child2')

However extra care is needed when attempting to join along the foreign
key from one level of the tree to the next.  In SQL, a join from a table
to itself requires that at least one side of the expression be “aliased”
so that it can be unambiguously referred to.

Recall from Using Aliases in the ORM tutorial that the
aliased() construct is normally used to provide an “alias” of an
ORM entity.  Joining from ‘Node’ to itself using this technique looks
like:

     from sqlalchemy.orm import aliased

     nodealias = aliased(Node)
     {sql}session.query(Node).filter(Node.data=='subchild1').\
                     join(Node.parent.of_type(nodealias)).\
                     filter(nodealias.data=="child2").\
                     all()
     SELECT node.id AS node_id,
             node.parent_id AS node_parent_id,
             node.data AS node_data
     FROM node JOIN node AS node_1
         ON node.parent_id = node_1.id
     WHERE node.data = ?
         AND node_1.data = ?
     ['subchild1', 'child2']

For an example of using aliased() to join across an
arbitrarily long chain of self-referential nodes, see XML Persistence.

3.3.3.3 Configuring Self-Referential Eager Loading
..................................................

Eager loading of relationships occurs using joins or outerjoins from
parent to child table during a normal query operation, such that the
parent and its immediate child collection or reference can be populated
from a single SQL statement, or a second statement for all immediate
child collections.  SQLAlchemy’s joined and subquery eager loading use
aliased tables in all cases when joining to related items, so are
compatible with self-referential joining.  However, to use eager loading
with a self-referential relationship, SQLAlchemy needs to be told how
many levels deep it should join and/or query; otherwise the eager load
will not take place at all.  This depth setting is configured via
‘relationships.join_depth’:

     class Node(Base):
         __tablename__ = 'node'
         id = Column(Integer, primary_key=True)
         parent_id = Column(Integer, ForeignKey('node.id'))
         data = Column(String(50))
         children = relationship("Node",
                         lazy="joined",
                         join_depth=2)

     {sql}session.query(Node).all()
     SELECT node_1.id AS node_1_id,
             node_1.parent_id AS node_1_parent_id,
             node_1.data AS node_1_data,
             node_2.id AS node_2_id,
             node_2.parent_id AS node_2_parent_id,
             node_2.data AS node_2_data,
             node.id AS node_id,
             node.parent_id AS node_parent_id,
             node.data AS node_data
     FROM node
         LEFT OUTER JOIN node AS node_2
             ON node.id = node_2.parent_id
         LEFT OUTER JOIN node AS node_1
             ON node_2.id = node_1.parent_id
     []

3.3.4 Linking Relationships with Backref
----------------------------------------

The relationship.backref keyword argument was first
introduced in Object Relational Tutorial (1.x API), and has
been mentioned throughout many of the examples here.  What does it
actually do ?  Let’s start with the canonical ‘User’ and ‘Address’
scenario:

     from sqlalchemy import Integer, ForeignKey, String, Column
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.orm import relationship

     Base = declarative_base()

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         name = Column(String)

         addresses = relationship("Address", backref="user")

     class Address(Base):
         __tablename__ = 'address'
         id = Column(Integer, primary_key=True)
         email = Column(String)
         user_id = Column(Integer, ForeignKey('user.id'))

The above configuration establishes a collection of ‘Address’ objects on
‘User’ called ‘User.addresses’.  It also establishes a ‘.user’ attribute
on ‘Address’ which will refer to the parent ‘User’ object.

In fact, the relationship.backref keyword is only a common
shortcut for placing a second relationship() onto the
‘Address’ mapping, including the establishment of an event listener on
both sides which will mirror attribute operations in both directions.
The above configuration is equivalent to:

     from sqlalchemy import Integer, ForeignKey, String, Column
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.orm import relationship

     Base = declarative_base()

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         name = Column(String)

         addresses = relationship("Address", back_populates="user")

     class Address(Base):
         __tablename__ = 'address'
         id = Column(Integer, primary_key=True)
         email = Column(String)
         user_id = Column(Integer, ForeignKey('user.id'))

         user = relationship("User", back_populates="addresses")

Above, we add a ‘.user’ relationship to ‘Address’ explicitly.  On both
relationships, the relationship.back_populates directive
tells each relationship about the other one, indicating that they should
establish “bidirectional” behavior between each other.  The primary
effect of this configuration is that the relationship adds event
handlers to both attributes which have the behavior of “when an append
or set event occurs here, set ourselves onto the incoming attribute
using this particular attribute name”.  The behavior is illustrated as
follows.  Start with a ‘User’ and an ‘Address’ instance.  The
‘.addresses’ collection is empty, and the ‘.user’ attribute is ‘None’:

     >>> u1 = User()
     >>> a1 = Address()
     >>> u1.addresses
     []
     >>> print(a1.user)
     None

However, once the ‘Address’ is appended to the ‘u1.addresses’
collection, both the collection and the scalar attribute have been
populated:

     >>> u1.addresses.append(a1)
     >>> u1.addresses
     [<__main__.Address object at 0x12a6ed0>]
     >>> a1.user
     <__main__.User object at 0x12a6590>

This behavior of course works in reverse for removal operations as well,
as well as for equivalent operations on both sides.  Such as when
‘.user’ is set again to ‘None’, the ‘Address’ object is removed from the
reverse collection:

     >>> a1.user = None
     >>> u1.addresses
     []

The manipulation of the ‘.addresses’ collection and the ‘.user’
attribute occurs entirely in Python without any interaction with the SQL
database.  Without this behavior, the proper state would be apparent on
both sides once the data has been flushed to the database, and later
reloaded after a commit or expiration operation occurs.  The
relationship.backref./see relationship.back_populates
behavior has the advantage that common bidirectional operations can
reflect the correct state without requiring a database round trip.

Remember, when the relationship.backref keyword is used on a
single relationship, it’s exactly the same as if the above two
relationships were created individually using
relationship.back_populates on each.

3.3.4.1 Backref Arguments
.........................

We’ve established that the relationship.backref keyword is
merely a shortcut for building two individual relationship()
constructs that refer to each other.  Part of the behavior of this
shortcut is that certain configurational arguments applied to the
relationship() will also be applied to the other direction - namely
those arguments that describe the relationship at a schema level, and
are unlikely to be different in the reverse direction.  The usual case
here is a many-to-many relationship() that has a
relationship.secondary argument, or a one-to-many or many-to-one
which has a relationship.primaryjoin argument (the
relationship.primaryjoin argument is discussed in Specifying Alternate Join Conditions).
Such as if we limited the list of
‘Address’ objects to those which start with “tony”:

     from sqlalchemy import Integer, ForeignKey, String, Column
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.orm import relationship

     Base = declarative_base()

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         name = Column(String)

         addresses = relationship("Address",
                         primaryjoin="and_(User.id==Address.user_id, "
                             "Address.email.startswith('tony'))",
                         backref="user")

     class Address(Base):
         __tablename__ = 'address'
         id = Column(Integer, primary_key=True)
         email = Column(String)
         user_id = Column(Integer, ForeignKey('user.id'))

We can observe, by inspecting the resulting property, that both sides of
the relationship have this join condition applied:

     >>> print(User.addresses.property.primaryjoin)
     "user".id = address.user_id AND address.email LIKE :email_1 || '%%'
     >>>
     >>> print(Address.user.property.primaryjoin)
     "user".id = address.user_id AND address.email LIKE :email_1 || '%%'
     >>>

This reuse of arguments should pretty much do the “right thing” - it
uses only arguments that are applicable, and in the case of a many-to-
many relationship, will reverse the usage of
relationship.primaryjoin and relationship.secondaryjoin
to correspond to the other direction (see the example in
Self-Referential Many-to-Many Relationship for this).

It’s very often the case however that we’d like to specify arguments
that are specific to just the side where we happened to place the
“backref”.  This includes relationship() arguments like
relationship.lazy, relationship.remote_side,
relationship.cascade and relationship.cascade_backrefs.
For this case we use the backref() function in place of a
string:

     # <other imports>
     from sqlalchemy.orm import backref

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         name = Column(String)

         addresses = relationship("Address",
                         backref=backref("user", lazy="joined"))

Where above, we placed a ‘lazy="joined"’ directive only on the
‘Address.user’ side, indicating that when a query against ‘Address’ is
made, a join to the ‘User’ entity should be made automatically which
will populate the ‘.user’ attribute of each returned ‘Address’.  The
backref() function formatted the arguments we gave it into a
form that is interpreted by the receiving relationship() as
additional arguments to be applied to the new relationship it creates.

3.3.4.2 Setting cascade for backrefs
....................................

A key behavior that occurs in the 1.x series of SQLAlchemy regarding
backrefs is that cascades will occur bidirectionally by
default.  This basically means, if one starts with an ‘User’ object
that’s been persisted in the Session:

     user = session.query(User).filter(User.id == 1).first()

The above ‘User’ is persistent in the Session.  It usually is
intuitive that if we create an ‘Address’ object and append to the
‘User.addresses’ collection, it is automatically added to the
Session as in the example below:

     user = session.query(User).filter(User.id == 1).first()
     address = Address(email_address='foo')
     user.addresses.append(address)

The above behavior is known as the “save update cascade” and is
described in the section Cascades.

However, if we instead created a new ‘Address’ object, and associated
the ‘User’ object with the ‘Address’ as follows:

     address = Address(email_address='foo', user=user)

In the above example, it is `not' as intuitive that the ‘Address’ would
automatically be added to the Session.  However, the backref
behavior of ‘Address.user’ indicates that the ‘Address’ object is also
appended to the ‘User.addresses’ collection.  This in turn initiates a
`cascade' operation which indicates that this ‘Address’ should be placed
into the Session as a pending object.

Since this behavior has been identified as counter-intuitive to most
people, it can be disabled by setting
relationship.cascade_backrefs to False, as in:

     class User(Base):
         # ...

         addresses = relationship("Address", back_populates="user", cascade_backrefs=False)

See the example in Controlling Cascade on Backrefs for
further information.

See also
........

See Controlling Cascade on Backrefs.

3.3.4.3 One Way Backrefs
........................

An unusual case is that of the “one way backref”.  This is where the
“back-populating” behavior of the backref is only desirable in one
direction.  An example of this is a collection which contains a
filtering relationship.primaryjoin condition.  We’d like to
append items to this collection as needed, and have them populate the
“parent” object on the incoming object.  However, we’d also like to have
items that are not part of the collection, but still have the same
“parent” association - these items should never be in the collection.

Taking our previous example, where we established a
relationship.primaryjoin that limited the collection only to
‘Address’ objects whose email address started with the word ‘tony’, the
usual backref behavior is that all items populate in both directions.
We wouldn’t want this behavior for a case like the following:

     >>> u1 = User()
     >>> a1 = Address(email='mary')
     >>> a1.user = u1
     >>> u1.addresses
     [<__main__.Address object at 0x1411910>]

Above, the ‘Address’ object that doesn’t match the criterion of “starts
with ‘tony’” is present in the ‘addresses’ collection of ‘u1’.  After
these objects are flushed, the transaction committed and their
attributes expired for a re-load, the ‘addresses’ collection will hit
the database on next access and no longer have this ‘Address’ object
present, due to the filtering condition.  But we can do away with this
unwanted side of the “backref” behavior on the Python side by using two
separate relationship() constructs, placing
relationship.back_populates only on one side:

     from sqlalchemy import Integer, ForeignKey, String, Column
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.orm import relationship

     Base = declarative_base()

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         name = Column(String)
         addresses = relationship("Address",
                         primaryjoin="and_(User.id==Address.user_id, "
                             "Address.email.startswith('tony'))",
                         back_populates="user")

     class Address(Base):
         __tablename__ = 'address'
         id = Column(Integer, primary_key=True)
         email = Column(String)
         user_id = Column(Integer, ForeignKey('user.id'))
         user = relationship("User")

With the above scenario, appending an ‘Address’ object to the
‘.addresses’ collection of a ‘User’ will always establish the ‘.user’
attribute on that ‘Address’:

     >>> u1 = User()
     >>> a1 = Address(email='tony')
     >>> u1.addresses.append(a1)
     >>> a1.user
     <__main__.User object at 0x1411850>

However, applying a ‘User’ to the ‘.user’ attribute of an ‘Address’,
will not append the ‘Address’ object to the collection:

     >>> a2 = Address(email='mary')
     >>> a2.user = u1
     >>> a2 in u1.addresses
     False

Of course, we’ve disabled some of the usefulness of
relationship.backref here, in that when we do append an ‘Address’
that corresponds to the criteria of ‘email.startswith('tony')’, it won’t
show up in the ‘User.addresses’ collection until the session is flushed,
and the attributes reloaded after a commit or expire operation.  While
we could consider an attribute event that checks this criterion in
Python, this starts to cross the line of duplicating too much SQL
behavior in Python.  The backref behavior itself is only a slight
transgression of this philosophy - SQLAlchemy tries to keep these to a
minimum overall.

3.3.5 Configuring how Relationship Joins
----------------------------------------

relationship() will normally create a join between two tables
by examining the foreign key relationship between the two tables to
determine which columns should be compared.  There are a variety of
situations where this behavior needs to be customized.

3.3.5.1 Handling Multiple Join Paths
....................................

One of the most common situations to deal with is when there are more
than one foreign key path between two tables.

Consider a ‘Customer’ class that contains two foreign keys to an
‘Address’ class:

     from sqlalchemy import Integer, ForeignKey, String, Column
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.orm import relationship

     Base = declarative_base()

     class Customer(Base):
         __tablename__ = 'customer'
         id = Column(Integer, primary_key=True)
         name = Column(String)

         billing_address_id = Column(Integer, ForeignKey("address.id"))
         shipping_address_id = Column(Integer, ForeignKey("address.id"))

         billing_address = relationship("Address")
         shipping_address = relationship("Address")

     class Address(Base):
         __tablename__ = 'address'
         id = Column(Integer, primary_key=True)
         street = Column(String)
         city = Column(String)
         state = Column(String)
         zip = Column(String)

The above mapping, when we attempt to use it, will produce the error:

     sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join
     condition between parent/child tables on relationship
     Customer.billing_address - there are multiple foreign key
     paths linking the tables.  Specify the 'foreign_keys' argument,
     providing a list of those columns which should be
     counted as containing a foreign key reference to the parent table.

The above message is pretty long.  There are many potential messages
that relationship() can return, which have been carefully
tailored to detect a variety of common configurational issues; most will
suggest the additional configuration that’s needed to resolve the
ambiguity or other missing information.

In this case, the message wants us to qualify each relationship()
by instructing for each one which foreign key column should be
considered, and the appropriate form is as follows:

     class Customer(Base):
         __tablename__ = 'customer'
         id = Column(Integer, primary_key=True)
         name = Column(String)

         billing_address_id = Column(Integer, ForeignKey("address.id"))
         shipping_address_id = Column(Integer, ForeignKey("address.id"))

         billing_address = relationship("Address", foreign_keys=[billing_address_id])
         shipping_address = relationship("Address", foreign_keys=[shipping_address_id])

Above, we specify the ‘foreign_keys’ argument, which is a Column
or list of Column objects which indicate those columns to
be considered “foreign”, or in other words, the columns that contain a
value referring to a parent table.  Loading the
‘Customer.billing_address’ relationship from a ‘Customer’ object will
use the value present in ‘billing_address_id’ in order to identify the
row in ‘Address’ to be loaded; similarly, ‘shipping_address_id’ is used
for the ‘shipping_address’ relationship.  The linkage of the two columns
also plays a role during persistence; the newly generated primary key of
a just-inserted ‘Address’ object will be copied into the appropriate
foreign key column of an associated ‘Customer’ object during a flush.

When specifying ‘foreign_keys’ with Declarative, we can also use string
names to specify, however it is important that if using a list, the
`list is part of the string':

     billing_address = relationship("Address", foreign_keys="[Customer.billing_address_id]")

In this specific example, the list is not necessary in any case as
there’s only one Column we need:

     billing_address = relationship("Address", foreign_keys="Customer.billing_address_id")

     Warning: When passed as a Python-evaluable string, the
     relationship.foreign_keys argument is interpreted using
     Python’s ‘eval()’ function.  `DO NOT PASS UNTRUSTED INPUT TO THIS
     STRING'. See Evaluation of relationship arguments for
     details on declarative evaluation of relationship()
     arguments.

3.3.5.2 Specifying Alternate Join Conditions
............................................

The default behavior of relationship() when constructing a
join is that it equates the value of primary key columns on one side to
that of foreign-key-referring columns on the other.  We can change this
criterion to be anything we’d like using the
relationship.primaryjoin argument, as well as the
relationship.secondaryjoin argument in the case when a “secondary”
table is used.

In the example below, using the ‘User’ class as well as an ‘Address’
class which stores a street address, we create a relationship
‘boston_addresses’ which will only load those ‘Address’ objects which
specify a city of “Boston”:

     from sqlalchemy import Integer, ForeignKey, String, Column
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.orm import relationship

     Base = declarative_base()

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         name = Column(String)
         boston_addresses = relationship("Address",
                         primaryjoin="and_(User.id==Address.user_id, "
                             "Address.city=='Boston')")

     class Address(Base):
         __tablename__ = 'address'
         id = Column(Integer, primary_key=True)
         user_id = Column(Integer, ForeignKey('user.id'))

         street = Column(String)
         city = Column(String)
         state = Column(String)
         zip = Column(String)

Within this string SQL expression, we made use of the and_()
conjunction construct to establish two distinct predicates for the join
condition - joining both the ‘User.id’ and ‘Address.user_id’ columns to
each other, as well as limiting rows in ‘Address’ to just
‘city='Boston'’.  When using Declarative, rudimentary SQL functions like
and_() are automatically available in the evaluated namespace
of a string relationship() argument.

     Warning: When passed as a Python-evaluable string, the
     relationship.primaryjoin argument is interpreted using
     Python’s ‘eval()’ function.  `DO NOT PASS UNTRUSTED INPUT TO THIS
     STRING'. See Evaluation of relationship arguments for
     details on declarative evaluation of relationship()
     arguments.

The custom criteria we use in a relationship.primaryjoin is
generally only significant when SQLAlchemy is rendering SQL in order to
load or represent this relationship.  That is, it’s used in the SQL
statement that’s emitted in order to perform a per-attribute lazy load,
or when a join is constructed at query time, such as via
Query.join(), or via the eager “joined” or “subquery” styles of
loading.  When in-memory objects are being manipulated, we can place any
‘Address’ object we’d like into the ‘boston_addresses’ collection,
regardless of what the value of the ‘.city’ attribute is.  The objects
will remain present in the collection until the attribute is expired and
re-loaded from the database where the criterion is applied.  When a
flush occurs, the objects inside of ‘boston_addresses’ will be flushed
unconditionally, assigning value of the primary key ‘user.id’ column
onto the foreign-key-holding ‘address.user_id’ column for each row.  The
‘city’ criteria has no effect here, as the flush process only cares
about synchronizing primary key values into referencing foreign key
values.

3.3.5.3 Creating Custom Foreign Conditions
..........................................

Another element of the primary join condition is how those columns
considered “foreign” are determined.  Usually, some subset of
Column objects will specify ForeignKey, or otherwise be
part of a ForeignKeyConstraint that’s relevant to the join
condition.  relationship() looks to this foreign key status
as it decides how it should load and persist data for this relationship.
However, the relationship.primaryjoin argument can be used
to create a join condition that doesn’t involve any “schema” level
foreign keys.  We can combine relationship.primaryjoin along
with relationship.foreign_keys and
relationship.remote_side explicitly in order to establish such a
join.

Below, a class ‘HostEntry’ joins to itself, equating the string
‘content’ column to the ‘ip_address’ column, which is a PostgreSQL type
called ‘INET’.  We need to use cast() in order to cast one
side of the join to the type of the other:

     from sqlalchemy import cast, String, Column, Integer
     from sqlalchemy.orm import relationship
     from sqlalchemy.dialects.postgresql import INET

     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class HostEntry(Base):
         __tablename__ = 'host_entry'

         id = Column(Integer, primary_key=True)
         ip_address = Column(INET)
         content = Column(String(50))

         # relationship() using explicit foreign_keys, remote_side
         parent_host = relationship("HostEntry",
                             primaryjoin=ip_address == cast(content, INET),
                             foreign_keys=content,
                             remote_side=ip_address
                         )

The above relationship will produce a join like:

     SELECT host_entry.id, host_entry.ip_address, host_entry.content
     FROM host_entry JOIN host_entry AS host_entry_1
     ON host_entry_1.ip_address = CAST(host_entry.content AS INET)

An alternative syntax to the above is to use the foreign()
and remote() annotations, inline within the
relationship.primaryjoin expression.  This syntax represents the
annotations that relationship() normally applies by itself to
the join condition given the relationship.foreign_keys and
relationship.remote_side arguments.  These functions may be
more succinct when an explicit join condition is present, and
additionally serve to mark exactly the column that is “foreign” or
“remote” independent of whether that column is stated multiple times or
within complex SQL expressions:

     from sqlalchemy.orm import foreign, remote

     class HostEntry(Base):
         __tablename__ = 'host_entry'

         id = Column(Integer, primary_key=True)
         ip_address = Column(INET)
         content = Column(String(50))

         # relationship() using explicit foreign() and remote() annotations
         # in lieu of separate arguments
         parent_host = relationship("HostEntry",
                             primaryjoin=remote(ip_address) == \
                                     cast(foreign(content), INET),
                         )

3.3.5.4 Using custom operators in join conditions
.................................................

Another use case for relationships is the use of custom operators, such
as PostgreSQL’s “is contained within” ‘<<’ operator when joining with
types such as INET and CIDR.  For custom
operators we use the Operators.op() function:

     inet_column.op("<<")(cidr_column)

However, if we construct a relationship.primaryjoin using
this operator, see relationship() will still need more
information.  This is because when it examines our primaryjoin
condition, it specifically looks for operators used for `comparisons',
and this is typically a fixed list containing known comparison operators
such as ‘==’, ‘<’, etc.  So for our custom operator to participate in
this system, we need it to register as a comparison operator using the
Operators.op.is_comparison parameter:

     inet_column.op("<<", is_comparison=True)(cidr_column)

A complete example:

     class IPA(Base):
         __tablename__ = 'ip_address'

         id = Column(Integer, primary_key=True)
         v4address = Column(INET)

         network = relationship("Network",
                             primaryjoin="IPA.v4address.op('<<', is_comparison=True)"
                                 "(foreign(Network.v4representation))",
                             viewonly=True
                         )
     class Network(Base):
         __tablename__ = 'network'

         id = Column(Integer, primary_key=True)
         v4representation = Column(CIDR)

Above, a query such as:

     session.query(IPA).join(IPA.network)

Will render as:

     SELECT ip_address.id AS ip_address_id, ip_address.v4address AS ip_address_v4address
     FROM ip_address JOIN network ON ip_address.v4address << network.v4representation

New in version 0.9.2: - Added the Operators.op.is_comparison
flag to assist in the creation of relationship() constructs
using custom operators.

3.3.5.5 Custom operators based on SQL functions
...............................................

A variant to the use case for Operators.op.is_comparison is
when we aren’t using an operator, but a SQL function.  The typical
example of this use case is the PostgreSQL PostGIS functions however any
SQL function on any database that resolves to a binary condition may
apply.  To suit this use case, the
FunctionElement.as_comparison() method can modify any SQL
function, such as those invoked from the func namespace, to
indicate to the ORM that the function produces a comparison of two
expressions.  The below example illustrates this with the Geoalchemy2(1)
library:

     from geoalchemy2 import Geometry
     from sqlalchemy import Column, Integer, func
     from sqlalchemy.orm import relationship, foreign

     class Polygon(Base):
         __tablename__ = "polygon"
         id = Column(Integer, primary_key=True)
         geom = Column(Geometry("POLYGON", srid=4326))
         points = relationship(
             "Point",
             primaryjoin="func.ST_Contains(foreign(Polygon.geom), Point.geom).as_comparison(1, 2)",
             viewonly=True,
         )

     class Point(Base):
         __tablename__ = "point"
         id = Column(Integer, primary_key=True)
         geom = Column(Geometry("POINT", srid=4326))

Above, the FunctionElement.as_comparison() indicates that
the ‘func.ST_Contains()’ SQL function is comparing the ‘Polygon.geom’
and ‘Point.geom’ expressions.  The foreign() annotation
additionally notes which column takes on the “foreign key” role in this
particular relationship.

New in version 1.3: Added FunctionElement.as_comparison().

   ---------- Footnotes ----------

   (1) https://geoalchemy-2.readthedocs.io/

3.3.5.6 Overlapping Foreign Keys
................................

A rare scenario can arise when composite foreign keys are used, such
that a single column may be the subject of more than one column referred
to via foreign key constraint.

Consider an (admittedly complex) mapping such as the ‘Magazine’ object,
referred to both by the ‘Writer’ object and the ‘Article’ object using a
composite primary key scheme that includes ‘magazine_id’ for both; then
to make ‘Article’ refer to ‘Writer’ as well, ‘Article.magazine_id’ is
involved in two separate relationships; ‘Article.magazine’ and
‘Article.writer’:

     class Magazine(Base):
         __tablename__ = 'magazine'

         id = Column(Integer, primary_key=True)

     class Article(Base):
         __tablename__ = 'article'

         article_id = Column(Integer)
         magazine_id = Column(ForeignKey('magazine.id'))
         writer_id = Column()

         magazine = relationship("Magazine")
         writer = relationship("Writer")

         __table_args__ = (
             PrimaryKeyConstraint('article_id', 'magazine_id'),
             ForeignKeyConstraint(
                 ['writer_id', 'magazine_id'],
                 ['writer.id', 'writer.magazine_id']
             ),
         )

     class Writer(Base):
         __tablename__ = 'writer'

         id = Column(Integer, primary_key=True)
         magazine_id = Column(ForeignKey('magazine.id'), primary_key=True)
         magazine = relationship("Magazine")

When the above mapping is configured, we will see this warning emitted:

     SAWarning: relationship 'Article.writer' will copy column
     writer.magazine_id to column article.magazine_id,
     which conflicts with relationship(s): 'Article.magazine'
     (copies magazine.id to article.magazine_id). Consider applying
     viewonly=True to read-only relationships, or provide a primaryjoin
     condition marking writable columns with the foreign() annotation.

What this refers to originates from the fact that ‘Article.magazine_id’
is the subject of two different foreign key constraints; it refers to
‘Magazine.id’ directly as a source column, but also refers to
‘Writer.magazine_id’ as a source column in the context of the composite
key to ‘Writer’.  If we associate an ‘Article’ with a particular
‘Magazine’, but then associate the ‘Article’ with a ‘Writer’ that’s
associated with a `different' ‘Magazine’, the ORM will overwrite
‘Article.magazine_id’ non-deterministically, silently changing which
magazine we refer towards; it may also attempt to place NULL into this
column if we de-associate a ‘Writer’ from an ‘Article’.  The warning
lets us know this is the case.

To solve this, we need to break out the behavior of ‘Article’ to include
all three of the following features:

  1. ‘Article’ first and foremost writes to ‘Article.magazine_id’ based
     on data persisted in the ‘Article.magazine’ relationship only, that
     is a value copied from ‘Magazine.id’.

  2. ‘Article’ can write to ‘Article.writer_id’ on behalf of data
     persisted in the ‘Article.writer’ relationship, but only the
     ‘Writer.id’ column; the ‘Writer.magazine_id’ column should not be
     written into ‘Article.magazine_id’ as it ultimately is sourced from
     ‘Magazine.id’.

  3. ‘Article’ takes ‘Article.magazine_id’ into account when loading
     ‘Article.writer’, even though it `doesn’t' write to it on behalf of
     this relationship.

To get just #1 and #2, we could specify only ‘Article.writer_id’ as the
“foreign keys” for ‘Article.writer’:

     class Article(Base):
         # ...

         writer = relationship("Writer", foreign_keys='Article.writer_id')

However, this has the effect of ‘Article.writer’ not taking
‘Article.magazine_id’ into account when querying against ‘Writer’:

     SELECT article.article_id AS article_article_id,
         article.magazine_id AS article_magazine_id,
         article.writer_id AS article_writer_id
     FROM article
     JOIN writer ON writer.id = article.writer_id

Therefore, to get at all of #1, #2, and #3, we express the join
condition as well as which columns to be written by combining
relationship.primaryjoin fully, along with either the
relationship.foreign_keys argument, or more succinctly by
annotating with foreign():

     class Article(Base):
         # ...

         writer = relationship(
             "Writer",
             primaryjoin="and_(Writer.id == foreign(Article.writer_id), "
                         "Writer.magazine_id == Article.magazine_id)")

Changed in version 1.0.0: the ORM will attempt to warn when a column is
used as the synchronization target from more than one relationship
simultaneously.

3.3.5.7 Non-relational Comparisons / Materialized Path
......................................................

     Warning: this section details an experimental feature.

Using custom expressions means we can produce unorthodox join conditions
that don’t obey the usual primary/foreign key model.  One such example
is the materialized path pattern, where we compare strings for
overlapping path tokens in order to produce a tree structure.

Through careful use of foreign() and remote(), we
can build a relationship that effectively produces a rudimentary
materialized path system.  Essentially, when foreign() and
remote() are on the `same' side of the comparison
expression, the relationship is considered to be “one to many”; when
they are on `different' sides, the relationship is considered to be
“many to one”.  For the comparison we’ll use here, we’ll be dealing with
collections so we keep things configured as “one to many”:

     class Element(Base):
         __tablename__ = 'element'

         path = Column(String, primary_key=True)

         descendants = relationship('Element',
                                primaryjoin=
                                     remote(foreign(path)).like(
                                             path.concat('/%')),
                                viewonly=True,
                                order_by=path)

Above, if given an ‘Element’ object with a path attribute of
‘"/foo/bar2"’, we seek for a load of ‘Element.descendants’ to look like:

     SELECT element.path AS element_path
     FROM element
     WHERE element.path LIKE ('/foo/bar2' || '/%') ORDER BY element.path

New in version 0.9.5: Support has been added to allow a single-column
comparison to itself within a primaryjoin condition, as well as for
primaryjoin conditions that use ColumnOperators.like() as
the comparison operator.

3.3.5.8 Self-Referential Many-to-Many Relationship
..................................................

Many to many relationships can be customized by one or both of
relationship.primaryjoin and relationship.secondaryjoin.
- the latter is significant for a relationship that specifies a
many-to-many reference using the relationship.secondary
argument.  A common situation which involves the usage of
relationship.primaryjoin and relationship.secondaryjoin
is when establishing a many-to-many relationship from a class to
itself, as shown below:

     from sqlalchemy import Integer, ForeignKey, String, Column, Table
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.orm import relationship

     Base = declarative_base()

     node_to_node = Table("node_to_node", Base.metadata,
         Column("left_node_id", Integer, ForeignKey("node.id"), primary_key=True),
         Column("right_node_id", Integer, ForeignKey("node.id"), primary_key=True)
     )

     class Node(Base):
         __tablename__ = 'node'
         id = Column(Integer, primary_key=True)
         label = Column(String)
         right_nodes = relationship("Node",
                             secondary=node_to_node,
                             primaryjoin=id==node_to_node.c.left_node_id,
                             secondaryjoin=id==node_to_node.c.right_node_id,
                             backref="left_nodes"
         )

Where above, SQLAlchemy can’t know automatically which columns should
connect to which for the ‘right_nodes’ and ‘left_nodes’ relationships.
The relationship.primaryjoin and
relationship.secondaryjoin arguments establish how we’d like to
join to the association table.  In the Declarative form above, as we are
declaring these conditions within the Python block that corresponds to
the ‘Node’ class, the ‘id’ variable is available directly as the
Column object we wish to join with.

Alternatively, we can define the relationship.primaryjoin
and relationship.secondaryjoin arguments using strings,
which is suitable in the case that our configuration does not have
either the ‘Node.id’ column object available yet or the ‘node_to_node’
table perhaps isn’t yet available.  When referring to a plain
Table object in a declarative string, we use the string name of the
table as it is present in the MetaData:

     class Node(Base):
         __tablename__ = 'node'
         id = Column(Integer, primary_key=True)
         label = Column(String)
         right_nodes = relationship("Node",
                             secondary="node_to_node",
                             primaryjoin="Node.id==node_to_node.c.left_node_id",
                             secondaryjoin="Node.id==node_to_node.c.right_node_id",
                             backref="left_nodes"
         )

     Warning: When passed as a Python-evaluable string, the
     relationship.primaryjoin and
     relationship.secondaryjoin arguments are interpreted using
     Python’s ‘eval()’ function.  `DO NOT PASS UNTRUSTED INPUT TO THESE
     STRINGS'. See Evaluation of relationship arguments for
     details on declarative evaluation of relationship()
     arguments.

A classical mapping situation here is similar, where ‘node_to_node’ can
be joined to ‘node.c.id’:

     from sqlalchemy import Integer, ForeignKey, String, Column, Table, MetaData
     from sqlalchemy.orm import relationship, registry

     metadata = MetaData()
     mapper_registry = registry()

     node_to_node = Table("node_to_node", metadata,
         Column("left_node_id", Integer, ForeignKey("node.id"), primary_key=True),
         Column("right_node_id", Integer, ForeignKey("node.id"), primary_key=True)
     )

     node = Table("node", metadata,
         Column('id', Integer, primary_key=True),
         Column('label', String)
     )
     class Node(object):
         pass

     mapper_registry.map_imperatively(Node, node, properties={
         'right_nodes':relationship(Node,
                             secondary=node_to_node,
                             primaryjoin=node.c.id==node_to_node.c.left_node_id,
                             secondaryjoin=node.c.id==node_to_node.c.right_node_id,
                             backref="left_nodes"
                         )})

Note that in both examples, the relationship.backref keyword
specifies a ‘left_nodes’ backref - when relationship()
creates the second relationship in the reverse direction, it’s smart
enough to reverse the relationship.primaryjoin and
relationship.secondaryjoin arguments.

3.3.5.9 Composite “Secondary” Joins
...................................

     Note: This section features far edge cases that are somewhat
     supported by SQLAlchemy, however it is recommended to solve
     problems like these in simpler ways whenever possible, by using
     reasonable relational layouts and / or in-Python attributes.

Sometimes, when one seeks to build a relationship() between
two tables there is a need for more than just two or three tables to be
involved in order to join them.  This is an area of
relationship() where one seeks to push the boundaries of what’s
possible, and often the ultimate solution to many of these exotic use
cases needs to be hammered out on the SQLAlchemy mailing list.

In more recent versions of SQLAlchemy, the relationship.secondary
parameter can be used in some of these cases in order to provide a
composite target consisting of multiple tables.  Below is an example of
such a join condition (requires version 0.9.2 at least to function as
is):

     class A(Base):
         __tablename__ = 'a'

         id = Column(Integer, primary_key=True)
         b_id = Column(ForeignKey('b.id'))

         d = relationship("D",
                     secondary="join(B, D, B.d_id == D.id)."
                                 "join(C, C.d_id == D.id)",
                     primaryjoin="and_(A.b_id == B.id, A.id == C.a_id)",
                     secondaryjoin="D.id == B.d_id",
                     uselist=False,
                     viewonly=True
                     )

     class B(Base):
         __tablename__ = 'b'

         id = Column(Integer, primary_key=True)
         d_id = Column(ForeignKey('d.id'))

     class C(Base):
         __tablename__ = 'c'

         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey('a.id'))
         d_id = Column(ForeignKey('d.id'))

     class D(Base):
         __tablename__ = 'd'

         id = Column(Integer, primary_key=True)

In the above example, we provide all three of
relationship.secondary, relationship.primaryjoin, and
relationship.secondaryjoin, in the declarative style
referring to the named tables ‘a’, ‘b’, ‘c’, ‘d’ directly.  A query from
‘A’ to ‘D’ looks like:

     sess.query(A).join(A.d).all()

     {opensql}SELECT a.id AS a_id, a.b_id AS a_b_id
     FROM a JOIN (
         b AS b_1 JOIN d AS d_1 ON b_1.d_id = d_1.id
             JOIN c AS c_1 ON c_1.d_id = d_1.id)
         ON a.b_id = b_1.id AND a.id = c_1.a_id JOIN d ON d.id = b_1.d_id

In the above example, we take advantage of being able to stuff multiple
tables into a “secondary” container, so that we can join across many
tables while still keeping things “simple” for relationship(),
in that there’s just “one” table on both the “left” and the “right”
side; the complexity is kept within the middle.

     Warning: A relationship like the above is typically marked as
     ‘viewonly=True’ and should be considered as read-only.  While there
     are sometimes ways to make relationships like the above writable,
     this is generally complicated and error prone.

3.3.5.10 Relationship to Aliased Class
......................................

New in version 1.3: The AliasedClass construct can now be
specified as the target of a relationship(), replacing the
previous approach of using non-primary mappers, which had limitations
such that they did not inherit sub-relationships of the mapped entity as
well as that they required complex configuration against an alternate
selectable.  The recipes in this section are now updated to use
AliasedClass.

In the previous section, we illustrated a technique where we used
relationship.secondary in order to place additional tables within
a join condition.  There is one complex join case where even this
technique is not sufficient; when we seek to join from ‘A’ to ‘B’,
making use of any number of ‘C’, ‘D’, etc.  in between, however there
are also join conditions between ‘A’ and ‘B’ `directly'.  In this case,
the join from ‘A’ to ‘B’ may be difficult to express with just a complex
relationship.primaryjoin condition, as the intermediary
tables may need special handling, and it is also not expressible with a
relationship.secondary object, since the ‘A->secondary->B’
pattern does not support any references between ‘A’ and ‘B’ directly.
When this `extremely advanced' case arises, we can resort to creating a
second mapping as a target for the relationship.  This is where we use
AliasedClass in order to make a mapping to a class that
includes all the additional tables we need for this join.  In order to
produce this mapper as an “alternative” mapping for our class, we use
the aliased() function to produce the new construct, then
use relationship() against the object as though it were a
plain mapped class.

Below illustrates a relationship() with a simple join from
‘A’ to ‘B’, however the primaryjoin condition is augmented with two
additional entities ‘C’ and ‘D’, which also must have rows that line up
with the rows in both ‘A’ and ‘B’ simultaneously:

     class A(Base):
         __tablename__ = 'a'

         id = Column(Integer, primary_key=True)
         b_id = Column(ForeignKey('b.id'))

     class B(Base):
         __tablename__ = 'b'

         id = Column(Integer, primary_key=True)

     class C(Base):
         __tablename__ = 'c'

         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey('a.id'))

     class D(Base):
         __tablename__ = 'd'

         id = Column(Integer, primary_key=True)
         c_id = Column(ForeignKey('c.id'))
         b_id = Column(ForeignKey('b.id'))

     # 1. set up the join() as a variable, so we can refer
     # to it in the mapping multiple times.
     j = join(B, D, D.b_id == B.id).join(C, C.id == D.c_id)

     # 2. Create an AliasedClass to B
     B_viacd = aliased(B, j, flat=True)

     A.b = relationship(B_viacd, primaryjoin=A.b_id == j.c.b_id)

With the above mapping, a simple join looks like:

     sess.query(A).join(A.b).all()

     {opensql}SELECT a.id AS a_id, a.b_id AS a_b_id
     FROM a JOIN (b JOIN d ON d.b_id = b.id JOIN c ON c.id = d.c_id) ON a.b_id = b.id

3.3.5.11 Row-Limited Relationships with Window Functions
........................................................

Another interesting use case for relationships to AliasedClass
objects are situations where the relationship needs to join to a
specialized SELECT of any form.  One scenario is when the use of a
window function is desired, such as to limit how many rows should be
returned for a relationship.  The example below illustrates a
non-primary mapper relationship that will load the first ten items for
each collection:

     class A(Base):
         __tablename__ = 'a'

         id = Column(Integer, primary_key=True)

     class B(Base):
         __tablename__ = 'b'
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey("a.id"))

     partition = select(
         B,
         func.row_number().over(
             order_by=B.id, partition_by=B.a_id
         ).label('index')
     ).alias()

     partitioned_b = aliased(B, partition)

     A.partitioned_bs = relationship(
         partitioned_b,
         primaryjoin=and_(partitioned_b.a_id == A.id, partition.c.index < 10)
     )

We can use the above ‘partitioned_bs’ relationship with most of the
loader strategies, such as selectinload():

     for a1 in s.query(A).options(selectinload(A.partitioned_bs)):
         print(a1.partitioned_bs)   # <-- will be no more than ten objects

Where above, the “selectinload” query looks like:

     SELECT
         a_1.id AS a_1_id, anon_1.id AS anon_1_id, anon_1.a_id AS anon_1_a_id,
         anon_1.data AS anon_1_data, anon_1.index AS anon_1_index
     FROM a AS a_1
     JOIN (
         SELECT b.id AS id, b.a_id AS a_id, b.data AS data,
         row_number() OVER (PARTITION BY b.a_id ORDER BY b.id) AS index
         FROM b) AS anon_1
     ON anon_1.a_id = a_1.id AND anon_1.index < %(index_1)s
     WHERE a_1.id IN ( ... primary key collection ...)
     ORDER BY a_1.id

Above, for each matching primary key in “a”, we will get the first ten
“bs” as ordered by “b.id”.  By partitioning on “a_id” we ensure that
each “row number” is local to the parent “a_id”.

Such a mapping would ordinarily also include a “plain” relationship from
“A” to “B”, for persistence operations as well as when the full set of
“B” objects per “A” is desired.

3.3.5.12 Building Query-Enabled Properties
..........................................

Very ambitious custom join conditions may fail to be directly
persistable, and in some cases may not even load correctly.  To remove
the persistence part of the equation, use the flag
relationship.viewonly on the relationship(), which
establishes it as a read-only attribute (data written to the collection
will be ignored on flush()).  However, in extreme cases, consider using
a regular Python property in conjunction with Query as
follows:

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)

         @property
         def addresses(self):
             return object_session(self).query(Address).with_parent(self).filter(...).all()

In other cases, the descriptor can be built to make use of existing
in-Python data.  See the section on Using Descriptors and Hybrids
for more general discussion of special Python attributes.

See also
........

See Using Descriptors and Hybrids.

3.3.6 Collection Configuration and Techniques
---------------------------------------------

The relationship() function defines a linkage between two
classes.  When the linkage defines a one-to-many or many-to-many
relationship, it’s represented as a Python collection when objects are
loaded and manipulated.  This section presents additional information
about collection configuration and techniques.

3.3.6.1 Working with Large Collections
......................................

The default behavior of relationship() is to fully load the
collection of items in, as according to the loading strategy of the
relationship.  Additionally, the Session by default only
knows how to delete objects which are actually present within the
session.  When a parent instance is marked for deletion and flushed, the
Session loads its full list of child items in so that they
may either be deleted as well, or have their foreign key value set to
null; this is to avoid constraint violations.  For large collections of
child items, there are several strategies to bypass full loading of
child items both at load time as well as deletion time.

3.3.6.2 Dynamic Relationship Loaders
....................................

     Note: This is a legacy feature.  Using the with_parent()
     filter in conjunction with select() is the 2.0
     style method of use.  For relationships that shouldn’t load, set
     relationship.lazy to ‘noload’.

A relationship() which corresponds to a large collection can
be configured so that it returns a legacy Query object when
accessed, which allows filtering of the relationship on criteria.  The
class is a special class AppenderQuery returned in place of
a collection when accessed.  Filtering criterion may be applied as well
as limits and offsets, either explicitly or via array slices:

     class User(Base):
         __tablename__ = 'user'

         posts = relationship(Post, lazy="dynamic")

     jack = session.query(User).get(id)

     # filter Jack's blog posts
     posts = jack.posts.filter(Post.headline=='this is a post')

     # apply array slices
     posts = jack.posts[5:20]

The dynamic relationship supports limited write operations, via the
‘AppenderQuery.append()’ and ‘AppenderQuery.remove()’ methods:

     oldpost = jack.posts.filter(Post.headline=='old post').one()
     jack.posts.remove(oldpost)

     jack.posts.append(Post('new post'))

Since the read side of the dynamic relationship always queries the
database, changes to the underlying collection will not be visible until
the data has been flushed.  However, as long as “autoflush” is enabled
on the Session in use, this will occur automatically each
time the collection is about to emit a query.

To place a dynamic relationship on a backref, use the backref()
function in conjunction with ‘lazy='dynamic'’:

     class Post(Base):
         __table__ = posts_table

         user = relationship(User,
                     backref=backref('posts', lazy='dynamic')
                 )

Note that eager/lazy loading options cannot be used in conjunction
dynamic relationships at this time.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See AppenderQuery.A dynamic query that supports basic collection storage operations.

 -- Class: sqlalchemy.orm.AppenderQuery (attr, state)

     A dynamic query that supports basic collection storage operations.

     `Class signature'

     class sqlalchemy.orm.AppenderQuery.
     (‘sqlalchemy.orm.dynamic.AppenderMixin’, see
     sqlalchemy.orm.Query)

     Note: The dynamic_loader() function is essentially the
     same as relationship() with the ‘lazy='dynamic'’
     argument specified.

     Warning: The “dynamic” loader applies to `collections only'.  It is
     not valid to use “dynamic” loaders with many-to-one, one-to-one, or
     uselist=False relationships.  Newer versions of SQLAlchemy emit
     warnings or exceptions in these cases.

3.3.6.3 Setting Noload, RaiseLoad
.................................

A “noload” relationship never loads from the database, even when
accessed.  It is configured using ‘lazy='noload'’:

     class MyClass(Base):
         __tablename__ = 'some_table'

         children = relationship(MyOtherClass, lazy='noload')

Above, the ‘children’ collection is fully writeable, and changes to it
will be persisted to the database as well as locally available for
reading at the time they are added.  However when instances of ‘MyClass’
are freshly loaded from the database, the ‘children’ collection stays
empty.  The noload strategy is also available on a query option basis
using the noload() loader option.

Alternatively, a “raise”-loaded relationship will raise an
InvalidRequestError where the attribute would normally emit a lazy
load:

     class MyClass(Base):
         __tablename__ = 'some_table'

         children = relationship(MyOtherClass, lazy='raise')

Above, attribute access on the ‘children’ collection will raise an
exception if it was not previously eagerloaded.  This includes read
access but for collections will also affect write access, as collections
can’t be mutated without first loading them.  The rationale for this is
to ensure that an application is not emitting any unexpected lazy loads
within a certain context.  Rather than having to read through SQL logs
to determine that all necessary attributes were eager loaded, the
“raise” strategy will cause unloaded attributes to raise immediately if
accessed.  The raise strategy is also available on a query option basis
using the raiseload() loader option.

New in version 1.1: added the “raise” loader strategy.

See also
........

See Preventing unwanted lazy loads using raiseload.

3.3.6.4 Using Passive Deletes
.............................

See Using foreign key ON DELETE cascade with ORM relationships
for this section.

3.3.6.5 Customizing Collection Access
.....................................

Mapping a one-to-many or many-to-many relationship results in a
collection of values accessible through an attribute on the parent
instance.  By default, this collection is a ‘list’:

     class Parent(Base):
         __tablename__ = 'parent'
         parent_id = Column(Integer, primary_key=True)

         children = relationship(Child)

     parent = Parent()
     parent.children.append(Child())
     print(parent.children[0])

Collections are not limited to lists.  Sets, mutable sequences and
almost any other Python object that can act as a container can be used
in place of the default list, by specifying the
relationship.collection_class option on relationship():

     class Parent(Base):
         __tablename__ = 'parent'
         parent_id = Column(Integer, primary_key=True)

         # use a set
         children = relationship(Child, collection_class=set)

     parent = Parent()
     child = Child()
     parent.children.add(child)
     assert child in parent.children

3.3.6.6 Dictionary Collections
..............................

A little extra detail is needed when using a dictionary as a collection.
This because objects are always loaded from the database as lists, and a
key-generation strategy must be available to populate the dictionary
correctly.  The attribute_mapped_collection() function is by
far the most common way to achieve a simple dictionary collection.  It
produces a dictionary class that will apply a particular attribute of
the mapped class as a key.  Below we map an ‘Item’ class containing a
dictionary of ‘Note’ items keyed to the ‘Note.keyword’ attribute:

     from sqlalchemy import Column, Integer, String, ForeignKey
     from sqlalchemy.orm import relationship
     from sqlalchemy.orm.collections import attribute_mapped_collection
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class Item(Base):
         __tablename__ = 'item'
         id = Column(Integer, primary_key=True)
         notes = relationship("Note",
                     collection_class=attribute_mapped_collection('keyword'),
                     cascade="all, delete-orphan")

     class Note(Base):
         __tablename__ = 'note'
         id = Column(Integer, primary_key=True)
         item_id = Column(Integer, ForeignKey('item.id'), nullable=False)
         keyword = Column(String)
         text = Column(String)

         def __init__(self, keyword, text):
             self.keyword = keyword
             self.text = text

‘Item.notes’ is then a dictionary:

     >>> item = Item()
     >>> item.notes['a'] = Note('a', 'atext')
     >>> item.notes.items()
     {'a': <__main__.Note object at 0x2eaaf0>}

attribute_mapped_collection() will ensure that the
‘.keyword’ attribute of each ‘Note’ complies with the key in the
dictionary.  Such as, when assigning to ‘Item.notes’, the dictionary key
we supply must match that of the actual ‘Note’ object:

     item = Item()
     item.notes = {
                 'a': Note('a', 'atext'),
                 'b': Note('b', 'btext')
             }

The attribute which attribute_mapped_collection() uses as a
key does not need to be mapped at all!  Using a regular Python
‘@property’ allows virtually any detail or combination of details about
the object to be used as the key, as below when we establish it as a
tuple of ‘Note.keyword’ and the first ten letters of the ‘Note.text’
field:

     class Item(Base):
         __tablename__ = 'item'
         id = Column(Integer, primary_key=True)
         notes = relationship("Note",
                     collection_class=attribute_mapped_collection('note_key'),
                     backref="item",
                     cascade="all, delete-orphan")

     class Note(Base):
         __tablename__ = 'note'
         id = Column(Integer, primary_key=True)
         item_id = Column(Integer, ForeignKey('item.id'), nullable=False)
         keyword = Column(String)
         text = Column(String)

         @property
         def note_key(self):
             return (self.keyword, self.text[0:10])

         def __init__(self, keyword, text):
             self.keyword = keyword
             self.text = text

Above we added a ‘Note.item’ backref.  Assigning to this reverse
relationship, the ‘Note’ is added to the ‘Item.notes’ dictionary and the
key is generated for us automatically:

     >>> item = Item()
     >>> n1 = Note("a", "atext")
     >>> n1.item = item
     >>> item.notes
     {('a', 'atext'): <__main__.Note object at 0x2eaaf0>}

Other built-in dictionary types include
column_mapped_collection(), which is almost like
attribute_mapped_collection() except given the Column
object directly:

     from sqlalchemy.orm.collections import column_mapped_collection

     class Item(Base):
         __tablename__ = 'item'
         id = Column(Integer, primary_key=True)
         notes = relationship("Note",
                     collection_class=column_mapped_collection(Note.__table__.c.keyword),
                     cascade="all, delete-orphan")

as well as mapped_collection() which is passed any callable
function.  Note that it’s usually easier to use
attribute_mapped_collection() along with a ‘@property’ as
mentioned earlier:

     from sqlalchemy.orm.collections import mapped_collection

     class Item(Base):
         __tablename__ = 'item'
         id = Column(Integer, primary_key=True)
         notes = relationship("Note",
                     collection_class=mapped_collection(lambda note: note.text[0:10]),
                     cascade="all, delete-orphan")

Dictionary mappings are often combined with the “Association Proxy”
extension to produce streamlined dictionary views.  See Proxying to Dictionary Based Collections
and Composite Association Proxies
for examples.

3.3.6.7 Dealing with Key Mutations and back-populating for Dictionary collections
.................................................................................

When using attribute_mapped_collection(), the “key” for the
dictionary is taken from an attribute on the target object.  `Changes to
this key are not tracked'.  This means that the key must be assigned
towards when it is first used, and if the key changes, the collection
will not be mutated.  A typical example where this might be an issue is
when relying upon backrefs to populate an attribute mapped collection.
Given the following:

     class A(Base):
         __tablename__ = "a"

         id = Column(Integer, primary_key=True)
         bs = relationship(
             "B",
             collection_class=attribute_mapped_collection("data"),
             back_populates="a",
         )

     class B(Base):
         __tablename__ = "b"
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey("a.id"))
         data = Column(String)

         a = relationship("A", back_populates="bs")

Above, if we create a ‘B()’ that refers to a specific ‘A()’, the back
populates will then add the ‘B()’ to the ‘A.bs’ collection, however if
the value of ‘B.data’ is not set yet, the key will be ‘None’:

     >>> a1 = A()
     >>> b1 = B(a=a1)
     >>> a1.bs
     {None: <test3.B object at 0x7f7b1023ef70>}

Setting ‘b1.data’ after the fact does not update the collection:

     >>> b1.data = 'the key'
     >>> a1.bs
     {None: <test3.B object at 0x7f7b1023ef70>}

This can also be seen if one attempts to set up ‘B()’ in the
constructor.  The order of arguments changes the result:

     >>> B(a=a1, data='the key')
     <test3.B object at 0x7f7b10114280>
     >>> a1.bs
     {None: <test3.B object at 0x7f7b10114280>}

vs:

     >>> B(data='the key', a=a1)
     <test3.B object at 0x7f7b10114340>
     >>> a1.bs
     {'the key': <test3.B object at 0x7f7b10114340>}

If backrefs are being used in this way, ensure that attributes are
populated in the correct order using an ‘__init__’ method.

An event handler such as the following may also be used to track changes
in the collection as well:

     from sqlalchemy import event

     from sqlalchemy.orm import attributes

     @event.listens_for(B.data, "set")
     def set_item(obj, value, previous, initiator):
         if obj.a is not None:
             previous = None if previous == attributes.NO_VALUE else previous
             obj.a.bs[value] = obj
             obj.a.bs.pop(previous)

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See attribute_mapped_collection.(attr_name)A dictionary-based collection type with attribute-based keying.

See column_mapped_collection.(mapping_spec)A dictionary-based collection type with column-based keying.

See mapped_collection.(keyfunc)A dictionary-based collection type with arbitrary keying.

 -- Function: sqlalchemy.orm.collections.attribute_mapped_collection
          (attr_name)

     A dictionary-based collection type with attribute-based keying.

     Returns a MappedCollection factory with a keying based
     on the ‘attr_name’ attribute of entities in the collection, where
     ‘attr_name’ is the string name of the attribute.

          Warning: the key value must be assigned to its final value
          `before' it is accessed by the attribute mapped collection.
          Additionally, changes to the key attribute are `not tracked'
          automatically, which means the key in the dictionary is not
          automatically synchronized with the key value on the target
          object itself.  See the section Dealing with Key Mutations and back-populating for Dictionary collections
          for an example.

 -- Function: sqlalchemy.orm.collections.column_mapped_collection
          (mapping_spec)

     A dictionary-based collection type with column-based keying.

     Returns a MappedCollection factory with a keying
     function generated from mapping_spec, which may be a Column or a
     sequence of Columns.

     The key value must be immutable for the lifetime of the object.
     You can not, for example, map on foreign key values if those key
     values will change during the session, i.e.  from None to a
     database-assigned integer after a session flush.

 -- Function: sqlalchemy.orm.collections.mapped_collection (keyfunc)

     A dictionary-based collection type with arbitrary keying.

     Returns a MappedCollection factory with a keying
     function generated from keyfunc, a callable that takes an entity
     and returns a key value.

     The key value must be immutable for the lifetime of the object.
     You can not, for example, map on foreign key values if those key
     values will change during the session, i.e.  from None to a
     database-assigned integer after a session flush.

3.3.6.8 Custom Collection Implementations
.........................................

You can use your own types for collections as well.  In simple cases,
inheriting from ‘list’ or ‘set’, adding custom behavior, is all that’s
needed.  In other cases, special decorators are needed to tell
SQLAlchemy more detail about how the collection operates.

Do I need a custom collection implementation?
.............................................

In most cases not at all!  The most common use cases for a “custom”
collection is one that validates or marshals incoming values into a new
form, such as a string that becomes a class instance, or one which goes
a step beyond and represents the data internally in some fashion,
presenting a “view” of that data on the outside of a different form.

For the first use case, the validates() decorator is by far
the simplest way to intercept incoming values in all cases for the
purposes of validation and simple marshaling.  See Simple Validators
for an example of this.

For the second use case, the Association Proxy extension is
a well-tested, widely used system that provides a read/write “view” of a
collection in terms of some attribute present on the target object.  As
the target attribute can be a ‘@property’ that returns virtually
anything, a wide array of “alternative” views of a collection can be
constructed with just a few functions.  This approach leaves the
underlying mapped collection unaffected and avoids the need to carefully
tailor collection behavior on a method-by-method basis.

Customized collections are useful when the collection needs to have
special behaviors upon access or mutation operations that can’t
otherwise be modeled externally to the collection.  They can of course
be combined with the above two approaches.

Collections in SQLAlchemy are transparently `instrumented'.
Instrumentation means that normal operations on the collection are
tracked and result in changes being written to the database at flush
time.  Additionally, collection operations can fire `events' which
indicate some secondary operation must take place.  Examples of a
secondary operation include saving the child item in the parent’s
‘Session’ (i.e.  the ‘save-update’ cascade), as well as synchronizing
the state of a bi-directional relationship (i.e.  a backref()).

The collections package understands the basic interface of lists, sets
and dicts and will automatically apply instrumentation to those built-in
types and their subclasses.  Object-derived types that implement a basic
collection interface are detected and instrumented via duck-typing:

     class ListLike(object):
         def __init__(self):
             self.data = []
         def append(self, item):
             self.data.append(item)
         def remove(self, item):
             self.data.remove(item)
         def extend(self, items):
             self.data.extend(items)
         def __iter__(self):
             return iter(self.data)
         def foo(self):
             return 'foo'

‘append’, ‘remove’, and ‘extend’ are known list-like methods, and will
be instrumented automatically.  ‘__iter__’ is not a mutator method and
won’t be instrumented, and ‘foo’ won’t be either.

Duck-typing (i.e.  guesswork) isn’t rock-solid, of course, so you can be
explicit about the interface you are implementing by providing an
‘__emulates__’ class attribute:

     class SetLike(object):
         __emulates__ = set

         def __init__(self):
             self.data = set()
         def append(self, item):
             self.data.add(item)
         def remove(self, item):
             self.data.remove(item)
         def __iter__(self):
             return iter(self.data)

This class looks list-like because of ‘append’, but ‘__emulates__’
forces it to set-like.  ‘remove’ is known to be part of the set
interface and will be instrumented.

But this class won’t work quite yet: a little glue is needed to adapt it
for use by SQLAlchemy.  The ORM needs to know which methods to use to
append, remove and iterate over members of the collection.  When using a
type like ‘list’ or ‘set’, the appropriate methods are well-known and
used automatically when present.  This set-like class does not provide
the expected ‘add’ method, so we must supply an explicit mapping for the
ORM via a decorator.

3.3.6.9 Annotating Custom Collections via Decorators
....................................................

Decorators can be used to tag the individual methods the ORM needs to
manage collections.  Use them when your class doesn’t quite meet the
regular interface for its container type, or when you otherwise would
like to use a different method to get the job done.

     from sqlalchemy.orm.collections import collection

     class SetLike(object):
         __emulates__ = set

         def __init__(self):
             self.data = set()

         @collection.appender
         def append(self, item):
             self.data.add(item)

         def remove(self, item):
             self.data.remove(item)

         def __iter__(self):
             return iter(self.data)

And that’s all that’s needed to complete the example.  SQLAlchemy will
add instances via the ‘append’ method.  ‘remove’ and ‘__iter__’ are the
default methods for sets and will be used for removing and iteration.
Default methods can be changed as well:

     from sqlalchemy.orm.collections import collection

     class MyList(list):
         @collection.remover
         def zark(self, item):
             # do something special...

         @collection.iterator
         def hey_use_this_instead_for_iteration(self):
             # ...

There is no requirement to be list-, or set-like at all.  Collection
classes can be any shape, so long as they have the append, remove and
iterate interface marked for SQLAlchemy’s use.  Append and remove
methods will be called with a mapped entity as the single argument, and
iterator methods are called with no arguments and must return an
iterator.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See collection.Decorators for entity collection classes.

 -- Class: sqlalchemy.orm.collections.collection

     Decorators for entity collection classes.

     The decorators fall into two groups: annotations and interception
     recipes.

     The annotating decorators (appender, remover, iterator, converter,
     internally_instrumented) indicate the method’s purpose and take no
     arguments.  They are not written with parens:

          @collection.appender
          def append(self, append): ...

     The recipe decorators all require parens, even those that take no
     arguments:

          @collection.adds('entity')
          def insert(self, position, entity): ...

          @collection.removes_return()
          def popitem(self): ...

      -- Method: sqlalchemy.orm.collections.collection..
               static adds (arg)

          Mark the method as adding an entity to the collection.

          Adds “add to collection” handling to the method.  The
          decorator argument indicates which method argument holds the
          SQLAlchemy-relevant value.  Arguments can be specified
          positionally (i.e.  integer) or by name:

               @collection.adds(1)
               def push(self, item): ...

               @collection.adds('entity')
               def do_stuff(self, thing, entity=None): ...

      -- Method: sqlalchemy.orm.collections.collection..
               static appender (fn)

          Tag the method as the collection appender.

          The appender method is called with one positional argument:
          the value to append.  The method will be automatically
          decorated with ‘adds(1)’ if not already decorated:

               @collection.appender
               def add(self, append): ...

               # or, equivalently
               @collection.appender
               @collection.adds(1)
               def add(self, append): ...

               # for mapping type, an 'append' may kick out a previous value
               # that occupies that slot.  consider d['a'] = 'foo'- any previous
               # value in d['a'] is discarded.
               @collection.appender
               @collection.replaces(1)
               def add(self, entity):
                   key = some_key_func(entity)
                   previous = None
                   if key in self:
                       previous = self[key]
                   self[key] = entity
                   return previous

          If the value to append is not allowed in the collection, you
          may raise an exception.  Something to remember is that the
          appender will be called for each object mapped by a database
          query.  If the database contains rows that violate your
          collection semantics, you will need to get creative to fix the
          problem, as access via the collection will not work.

          If the appender method is internally instrumented, you must
          also receive the keyword argument ‘_sa_initiator’ and ensure
          its promulgation to collection events.

      -- Method: sqlalchemy.orm.collections.collection..
               static converter (fn)

          Tag the method as the collection converter.

          Deprecated since version 1.3: The
          collection.converter() handler is deprecated and will be
          removed in a future release.  Please refer to the
          ‘bulk_replace’ listener interface in conjunction with the
          listen() function.

          This optional method will be called when a collection is being
          replaced entirely, as in:

               myobj.acollection = [newvalue1, newvalue2]

          The converter method will receive the object being assigned
          and should return an iterable of values suitable for use by
          the ‘appender’ method.  A converter must not assign values or
          mutate the collection, its sole job is to adapt the value the
          user provides into an iterable of values for the ORM’s use.

          The default converter implementation will use duck-typing to
          do the conversion.  A dict-like collection will be convert
          into an iterable of dictionary values, and other types will
          simply be iterated:

               @collection.converter
               def convert(self, other): ...

          If the duck-typing of the object does not match the type of
          this collection, a TypeError is raised.

          Supply an implementation of this method if you want to expand
          the range of possible types that can be assigned in bulk or
          perform validation on the values about to be assigned.

      -- Method: sqlalchemy.orm.collections.collection..
               static internally_instrumented (fn)

          Tag the method as instrumented.

          This tag will prevent any decoration from being applied to the
          method.  Use this if you are orchestrating your own calls to
          ‘collection_adapter()’ in one of the basic SQLAlchemy
          interface methods, or to prevent an automatic ABC method
          decoration from wrapping your implementation:

               # normally an 'extend' method on a list-like class would be
               # automatically intercepted and re-implemented in terms of
               # SQLAlchemy events and append().  your implementation will
               # never be called, unless:
               @collection.internally_instrumented
               def extend(self, items): ...

      -- Method: sqlalchemy.orm.collections.collection..
               static iterator (fn)

          Tag the method as the collection remover.

          The iterator method is called with no arguments.  It is
          expected to return an iterator over all collection members:

               @collection.iterator
               def __iter__(self): ...

      -- Method: sqlalchemy.orm.collections.collection..
               static remover (fn)

          Tag the method as the collection remover.

          The remover method is called with one positional argument: the
          value to remove.  The method will be automatically decorated
          with removes_return() if not already decorated:

               @collection.remover
               def zap(self, entity): ...

               # or, equivalently
               @collection.remover
               @collection.removes_return()
               def zap(self, ): ...

          If the value to remove is not present in the collection, you
          may raise an exception or return None to ignore the error.

          If the remove method is internally instrumented, you must also
          receive the keyword argument ‘_sa_initiator’ and ensure its
          promulgation to collection events.

      -- Method: sqlalchemy.orm.collections.collection..
               static removes (arg)

          Mark the method as removing an entity in the collection.

          Adds “remove from collection” handling to the method.  The
          decorator argument indicates which method argument holds the
          SQLAlchemy-relevant value to be removed.  Arguments can be
          specified positionally (i.e.  integer) or by name:

               @collection.removes(1)
               def zap(self, item): ...

          For methods where the value to remove is not known at
          call-time, use collection.removes_return.

      -- Method: sqlalchemy.orm.collections.collection..
               static removes_return ()

          Mark the method as removing an entity in the collection.

          Adds “remove from collection” handling to the method.  The
          return value of the method, if any, is considered the value to
          remove.  The method arguments are not inspected:

               @collection.removes_return()
               def pop(self): ...

          For methods where the value to remove is known at call-time,
          use collection.remove.

      -- Method: sqlalchemy.orm.collections.collection..
               static replaces (arg)

          Mark the method as replacing an entity in the collection.

          Adds “add to collection” and “remove from collection” handling
          to the method.  The decorator argument indicates which method
          argument holds the SQLAlchemy-relevant value to be added, and
          return value, if any will be considered the value to remove.

          Arguments can be specified positionally (i.e.  integer) or by
          name:

               @collection.replaces(2)
               def __setitem__(self, index, item): ...

3.3.6.10 Custom Dictionary-Based Collections
............................................

The MappedCollection class can be used as a base class for
your custom types or as a mix-in to quickly add ‘dict’ collection
support to other classes.  It uses a keying function to delegate to
‘__setitem__’ and ‘__delitem__’:

     from sqlalchemy.util import OrderedDict
     from sqlalchemy.orm.collections import MappedCollection

     class NodeMap(OrderedDict, MappedCollection):
         """Holds 'Node' objects, keyed by the 'name' attribute with insert order maintained."""

         def __init__(self, *args, **kw):
             MappedCollection.__init__(self, keyfunc=lambda node: node.name)
             OrderedDict.__init__(self, *args, **kw)

When subclassing MappedCollection, user-defined versions of
‘__setitem__()’ or ‘__delitem__()’ should be decorated with
collection.internally_instrumented(), `if' they call down to those
same methods on MappedCollection.  This because the methods
on MappedCollection are already instrumented - calling them
from within an already instrumented call can cause events to be fired
off repeatedly, or inappropriately, leading to internal state corruption
in rare cases:

     from sqlalchemy.orm.collections import MappedCollection,\
                                         collection

     class MyMappedCollection(MappedCollection):
         """Use @internally_instrumented when your methods
         call down to already-instrumented methods.

         """

         @collection.internally_instrumented
         def __setitem__(self, key, value, _sa_initiator=None):
             # do something with key, value
             super(MyMappedCollection, self).__setitem__(key, value, _sa_initiator)

         @collection.internally_instrumented
         def __delitem__(self, key, _sa_initiator=None):
             # do something with key
             super(MyMappedCollection, self).__delitem__(key, _sa_initiator)

The ORM understands the ‘dict’ interface just like lists and sets, and
will automatically instrument all dict-like methods if you choose to
subclass ‘dict’ or provide dict-like collection behavior in a duck-typed
class.  You must decorate appender and remover methods, however- there
are no compatible methods in the basic dictionary interface for
SQLAlchemy to use by default.  Iteration will go through ‘itervalues()’
unless otherwise decorated.

     Note: Due to a bug in MappedCollection prior to version 0.7.6, this
     workaround usually needs to be called before a custom subclass of
     MappedCollection which uses
     collection.internally_instrumented() can be used:

          from sqlalchemy.orm.collections import _instrument_class, MappedCollection
          _instrument_class(MappedCollection)

     This will ensure that the MappedCollection has been
     properly initialized with custom ‘__setitem__()’ and
     ‘__delitem__()’ methods before used in a custom subclass.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See MappedCollection.A basic dictionary-based collection class.

 -- Class: sqlalchemy.orm.collections.MappedCollection (keyfunc)

     A basic dictionary-based collection class.

     Extends dict with the minimal bag semantics that collection classes
     require.  ‘set’ and ‘remove’ are implemented in terms of a keying
     function: any callable that takes an object and returns an object
     for use as a dictionary key.

     `Class signature'

     class sqlalchemy.orm.collections.MappedCollection.
     (‘builtins.dict’)

      -- Method: sqlalchemy.orm.collections.MappedCollection..
               __init__ (keyfunc)

          Create a new collection with keying provided by keyfunc.

          keyfunc may be any callable that takes an object and returns
          an object for use as a dictionary key.

          The keyfunc will be called every time the ORM needs to add a
          member by value-only (such as when loading instances from the
          database) or remove a member.  The usual cautions about
          dictionary keying apply- ‘keyfunc(object)’ should return the
          same output for the life of the collection.  Keying based on
          mutable properties can result in unreachable instances “lost”
          in the collection.

      -- Method: sqlalchemy.orm.collections.MappedCollection..
               clear () -> None. Remove all items from D.

      -- Method: sqlalchemy.orm.collections.MappedCollection..
               pop (k[, d]) -> v, remove specified key and return
               the corresponding value.

          If key is not found, d is returned if given, otherwise
          KeyError is raised

      -- Method: sqlalchemy.orm.collections.MappedCollection..
               popitem ()

          Remove and return a (key, value) pair as a 2-tuple.

          Pairs are returned in LIFO (last-in, first-out) order.  Raises
          KeyError if the dict is empty.

      -- Method: sqlalchemy.orm.collections.MappedCollection..
               remove (value, _sa_initiator=None)

          Remove an item by value, consulting the keyfunc for the key.

      -- Method: sqlalchemy.orm.collections.MappedCollection..
               set (value, _sa_initiator=None)

          Add an item by value, consulting the keyfunc for the key.

      -- Method: sqlalchemy.orm.collections.MappedCollection..
               setdefault (key, default=None)

          Insert key with a value of default if key is not in the
          dictionary.

          Return the value for key if key is in the dictionary, else
          default.

      -- Method: sqlalchemy.orm.collections.MappedCollection..
               update ([E], **F) -> None. Update D from
               dict/iterable E and F.

          If E is present and has a .keys() method, then does: for k in
          E: D[k] = E[k] If E is present and lacks a .keys() method,
          then does: for k, v in E: D[k] = v In either case, this is
          followed by: for k in F: D[k] = F[k]

3.3.6.11 Instrumentation and Custom Types
.........................................

Many custom types and existing library classes can be used as a entity
collection type as-is without further ado.  However, it is important to
note that the instrumentation process will modify the type, adding
decorators around methods automatically.

The decorations are lightweight and no-op outside of relationships, but
they do add unneeded overhead when triggered elsewhere.  When using a
library class as a collection, it can be good practice to use the
“trivial subclass” trick to restrict the decorations to just your usage
in relationships.  For example:

     class MyAwesomeList(some.great.library.AwesomeList):
         pass

     # ... relationship(..., collection_class=MyAwesomeList)

The ORM uses this approach for built-ins, quietly substituting a trivial
subclass when a ‘list’, ‘set’ or ‘dict’ is used directly.

3.3.6.12 Collection Internals
.............................

Various internal methods.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See bulk_replace.(values,Load a new collection, firing events based on prior like membership.
existing_adapter,
new_adapter[,
initiator])

See collection.Decorators for entity collection classes.

See collection_adapter.Fetch the CollectionAdapter for a collection.

See CollectionAdapter.Bridges between the ORM and arbitrary Python collections.

See InstrumentedDict.An instrumented version of the built-in dict.

See InstrumentedList.An instrumented version of the built-in list.

See InstrumentedSet.An instrumented version of the built-in set.

See prepare_instrumentation.(factory)Prepare a callable for future use as a collection class factory.

 -- Function: sqlalchemy.orm.collections.bulk_replace (values,
          existing_adapter, new_adapter, initiator=None)

     Load a new collection, firing events based on prior like
     membership.

     Appends instances in ‘values’ onto the ‘new_adapter’.  Events will
     be fired for any instance not present in the ‘existing_adapter’.
     Any instances in ‘existing_adapter’ not present in ‘values’ will
     have remove events fired upon them.

     Parameters:

        * ‘values’ – An iterable of collection member instances

        * ‘existing_adapter’ – A CollectionAdapter of
          instances to be replaced

        * ‘new_adapter’ – An empty CollectionAdapter to load
          with ‘values’

 -- Class: sqlalchemy.orm.collections.collection

     Decorators for entity collection classes.

     The decorators fall into two groups: annotations and interception
     recipes.

     The annotating decorators (appender, remover, iterator, converter,
     internally_instrumented) indicate the method’s purpose and take no
     arguments.  They are not written with parens:

          @collection.appender
          def append(self, append): ...

     The recipe decorators all require parens, even those that take no
     arguments:

          @collection.adds('entity')
          def insert(self, position, entity): ...

          @collection.removes_return()
          def popitem(self): ...

 -- Data: sqlalchemy.orm.collections.collection_adapter =
          operator.attrgetter('_sa_adapter')

     Fetch the CollectionAdapter for a collection.

 -- Class: sqlalchemy.orm.collections.CollectionAdapter (attr,
          owner_state, data)

     Bridges between the ORM and arbitrary Python collections.

     Proxies base-level collection operations (append, remove, iterate)
     to the underlying Python collection, and emits add/remove events
     for entities entering or leaving the collection.

     The ORM uses CollectionAdapter exclusively for
     interaction with entity collections.

 -- Class: sqlalchemy.orm.collections.InstrumentedDict

     An instrumented version of the built-in dict.

     `Class signature'

     class sqlalchemy.orm.collections.InstrumentedDict.
     (‘builtins.dict’)

 -- Class: sqlalchemy.orm.collections.InstrumentedList (iterable=(), /)

     An instrumented version of the built-in list.

     `Class signature'

     class sqlalchemy.orm.collections.InstrumentedList.
     (‘builtins.list’)

 -- Class: sqlalchemy.orm.collections.InstrumentedSet

     An instrumented version of the built-in set.

     `Class signature'

     class sqlalchemy.orm.collections.InstrumentedSet.
     (‘builtins.set’)

 -- Function: sqlalchemy.orm.collections.prepare_instrumentation
          (factory)

     Prepare a callable for future use as a collection class factory.

     Given a collection class factory (either a type or no-arg
     callable), return another factory that will produce compatible
     instances when called.

     This function is responsible for converting collection_class=list
     into the run-time behavior of collection_class=InstrumentedList.

3.3.7 Special Relationship Persistence Patterns
-----------------------------------------------

3.3.7.1 Rows that point to themselves / Mutually Dependent Rows
...............................................................

This is a very specific case where relationship() must perform an INSERT
and a second UPDATE in order to properly populate a row (and vice versa
an UPDATE and DELETE in order to delete without violating foreign key
constraints).  The two use cases are:

   * A table contains a foreign key to itself, and a single row will
     have a foreign key value pointing to its own primary key.

   * Two tables each contain a foreign key referencing the other table,
     with a row in each table referencing the other.

For example:

               user
     ---------------------------------
     user_id    name   related_user_id
        1       'ed'          1

Or:

                  widget                                                  entry
     -------------------------------------------             ---------------------------------
     widget_id     name        favorite_entry_id             entry_id      name      widget_id
        1       'somewidget'          5                         5       'someentry'     1

In the first case, a row points to itself.  Technically, a database that
uses sequences such as PostgreSQL or Oracle can INSERT the row at once
using a previously generated value, but databases which rely upon
autoincrement-style primary key identifiers cannot.  The
relationship() always assumes a “parent/child” model of row
population during flush, so unless you are populating the primary
key/foreign key columns directly, see relationship() needs to use
two statements.

In the second case, the “widget” row must be inserted before any
referring “entry” rows, but then the “favorite_entry_id” column of that
“widget” row cannot be set until the “entry” rows have been generated.
In this case, it’s typically impossible to insert the “widget” and
“entry” rows using just two INSERT statements; an UPDATE must be
performed in order to keep foreign key constraints fulfilled.  The
exception is if the foreign keys are configured as “deferred until
commit” (a feature some databases support) and if the identifiers were
populated manually (again essentially bypassing relationship()).

To enable the usage of a supplementary UPDATE statement, we use the
relationship.post_update option of relationship().
This specifies that the linkage between the two rows should be created
using an UPDATE statement after both rows have been INSERTED; it also
causes the rows to be de-associated with each other via UPDATE before a
DELETE is emitted.  The flag should be placed on just `one' of the
relationships, preferably the many-to-one side.  Below we illustrate a
complete example, including two ForeignKey constructs:

     from sqlalchemy import Integer, ForeignKey, Column
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.orm import relationship

     Base = declarative_base()

     class Entry(Base):
         __tablename__ = 'entry'
         entry_id = Column(Integer, primary_key=True)
         widget_id = Column(Integer, ForeignKey('widget.widget_id'))
         name = Column(String(50))

     class Widget(Base):
         __tablename__ = 'widget'

         widget_id = Column(Integer, primary_key=True)
         favorite_entry_id = Column(Integer,
                                 ForeignKey('entry.entry_id',
                                 name="fk_favorite_entry"))
         name = Column(String(50))

         entries = relationship(Entry, primaryjoin=
                                         widget_id==Entry.widget_id)
         favorite_entry = relationship(Entry,
                                     primaryjoin=
                                         favorite_entry_id==Entry.entry_id,
                                     post_update=True)

When a structure against the above configuration is flushed, the
“widget” row will be INSERTed minus the “favorite_entry_id” value, then
all the “entry” rows will be INSERTed referencing the parent “widget”
row, and then an UPDATE statement will populate the “favorite_entry_id”
column of the “widget” table (it’s one row at a time for the time
being):

     >>> w1 = Widget(name='somewidget')
     >>> e1 = Entry(name='someentry')
     >>> w1.favorite_entry = e1
     >>> w1.entries = [e1]
     >>> session.add_all([w1, e1])
     {sql}>>> session.commit()
     BEGIN (implicit)
     INSERT INTO widget (favorite_entry_id, name) VALUES (?, ?)
     (None, 'somewidget')
     INSERT INTO entry (widget_id, name) VALUES (?, ?)
     (1, 'someentry')
     UPDATE widget SET favorite_entry_id=? WHERE widget.widget_id = ?
     (1, 1)
     COMMIT

An additional configuration we can specify is to supply a more
comprehensive foreign key constraint on ‘Widget’, such that it’s
guaranteed that ‘favorite_entry_id’ refers to an ‘Entry’ that also
refers to this ‘Widget’.  We can use a composite foreign key, as
illustrated below:

     from sqlalchemy import Integer, ForeignKey, String, \
             Column, UniqueConstraint, ForeignKeyConstraint
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.orm import relationship

     Base = declarative_base()

     class Entry(Base):
         __tablename__ = 'entry'
         entry_id = Column(Integer, primary_key=True)
         widget_id = Column(Integer, ForeignKey('widget.widget_id'))
         name = Column(String(50))
         __table_args__ = (
             UniqueConstraint("entry_id", "widget_id"),
         )

     class Widget(Base):
         __tablename__ = 'widget'

         widget_id = Column(Integer, autoincrement='ignore_fk', primary_key=True)
         favorite_entry_id = Column(Integer)

         name = Column(String(50))

         __table_args__ = (
             ForeignKeyConstraint(
                 ["widget_id", "favorite_entry_id"],
                 ["entry.widget_id", "entry.entry_id"],
                 name="fk_favorite_entry"
             ),
         )

         entries = relationship(Entry, primaryjoin=
                                         widget_id==Entry.widget_id,
                                         foreign_keys=Entry.widget_id)
         favorite_entry = relationship(Entry,
                                     primaryjoin=
                                         favorite_entry_id==Entry.entry_id,
                                     foreign_keys=favorite_entry_id,
                                     post_update=True)

The above mapping features a composite ForeignKeyConstraint
bridging the ‘widget_id’ and ‘favorite_entry_id’ columns.  To ensure
that ‘Widget.widget_id’ remains an “autoincrementing” column we specify
Column.autoincrement to the value ‘"ignore_fk"’ on
Column, and additionally on each relationship() we must
limit those columns considered as part of the foreign key for the
purposes of joining and cross-population.

3.3.7.2 Mutable Primary Keys / Update Cascades
..............................................

When the primary key of an entity changes, related items which reference
the primary key must also be updated as well.  For databases which
enforce referential integrity, the best strategy is to use the
database’s ON UPDATE CASCADE functionality in order to propagate primary
key changes to referenced foreign keys - the values cannot be out of
sync for any moment unless the constraints are marked as “deferrable”,
that is, not enforced until the transaction completes.

It is `highly recommended' that an application which seeks to employ
natural primary keys with mutable values to use the ‘ON UPDATE CASCADE’
capabilities of the database.  An example mapping which illustrates this
is:

     class User(Base):
         __tablename__ = 'user'
         __table_args__ = {'mysql_engine': 'InnoDB'}

         username = Column(String(50), primary_key=True)
         fullname = Column(String(100))

         addresses = relationship("Address")

     class Address(Base):
         __tablename__ = 'address'
         __table_args__ = {'mysql_engine': 'InnoDB'}

         email = Column(String(50), primary_key=True)
         username = Column(String(50),
                     ForeignKey('user.username', onupdate="cascade")
                 )

Above, we illustrate ‘onupdate="cascade"’ on the ForeignKey
object, and we also illustrate the ‘mysql_engine='InnoDB'’ setting
which, on a MySQL backend, ensures that the ‘InnoDB’ engine supporting
referential integrity is used.  When using SQLite, referential integrity
should be enabled, using the configuration described at Foreign Key Support.

See also
........

See Using foreign key ON DELETE cascade with ORM relationships. -
supporting ON DELETE CASCADE with relationships

See mapper.passive_updates. - similar feature on mapper().

3.3.7.3 Simulating limited ON UPDATE CASCADE without foreign key support
........................................................................

In those cases when a database that does not support referential
integrity is used, and natural primary keys with mutable values are in
play, SQLAlchemy offers a feature in order to allow propagation of
primary key values to already-referenced foreign keys to a `limited'
extent, by emitting an UPDATE statement against foreign key columns that
immediately reference a primary key column whose value has changed.  The
primary platforms without referential integrity features are MySQL when
the ‘MyISAM’ storage engine is used, and SQLite when the ‘PRAGMA
foreign_keys=ON’ pragma is not used.  The Oracle database also has no
support for ‘ON UPDATE CASCADE’, but because it still enforces
referential integrity, needs constraints to be marked as deferrable so
that SQLAlchemy can emit UPDATE statements.

The feature is enabled by setting the
relationship.passive_updates flag to ‘False’, most preferably on a
one-to-many or many-to-many relationship().  When “updates”
are no longer “passive” this indicates that SQLAlchemy will issue UPDATE
statements individually for objects referenced in the collection
referred to by the parent object with a changing primary key value.
This also implies that collections will be fully loaded into memory if
not already locally present.

Our previous mapping using ‘passive_updates=False’ looks like:

     class User(Base):
         __tablename__ = 'user'

         username = Column(String(50), primary_key=True)
         fullname = Column(String(100))

         # passive_updates=False *only* needed if the database
         # does not implement ON UPDATE CASCADE
         addresses = relationship("Address", passive_updates=False)

     class Address(Base):
         __tablename__ = 'address'

         email = Column(String(50), primary_key=True)
         username = Column(String(50), ForeignKey('user.username'))

Key limitations of ‘passive_updates=False’ include:

   * it performs much more poorly than direct database ON UPDATE
     CASCADE, because it needs to fully pre-load affected collections
     using SELECT and also must emit UPDATE statements against those
     values, which it will attempt to run in “batches” but still runs on
     a per-row basis at the DBAPI level.

   * the feature cannot “cascade” more than one level.  That is, if
     mapping X has a foreign key which refers to the primary key of
     mapping Y, but then mapping Y’s primary key is itself a foreign key
     to mapping Z, ‘passive_updates=False’ cannot cascade a change in
     primary key value from ‘Z’ to ‘X’.

   * Configuring ‘passive_updates=False’ only on the many-to-one side of
     a relationship will not have a full effect, as the unit of work
     searches only through the current identity map for objects that may
     be referencing the one with a mutating primary key, not throughout
     the database.

As virtually all databases other than Oracle now support ‘ON UPDATE
CASCADE’, it is highly recommended that traditional ‘ON UPDATE CASCADE’
support be used in the case that natural and mutable primary key values
are in use.

3.3.8 Relationships API
-----------------------

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See backref.(name,Create a back reference with explicit keyword arguments, which are the same arguments one
**kwargs)      can send to relationship().

See dynamic_loader.(argument,Construct a dynamically-loading mapper property.
**kw)

See foreign.(expr)Annotate a portion of a primaryjoin expression with a ‘foreign’ annotation.

See relation.(*arg,A synonym for relationship().
**kw)

See relationship.(argument[,Provide a relationship between two mapped classes.
secondary,
primaryjoin,
secondaryjoin,
...])

See remote.(expr)Annotate a portion of a primaryjoin expression with a ‘remote’ annotation.

 -- Function: sqlalchemy.orm.relationship (argument, secondary=None,
          primaryjoin=None, secondaryjoin=None, foreign_keys=None,
          uselist=None, order_by=False, backref=None,
          back_populates=None, overlaps=None, post_update=False,
          cascade=False, viewonly=False, lazy='select',
          collection_class=None, passive_deletes=False,
          passive_updates=True, remote_side=None,
          enable_typechecks=True, join_depth=None,
          comparator_factory=None, single_parent=False, innerjoin=False,
          distinct_target_key=None, doc=None, active_history=False,
          cascade_backrefs=True, load_on_pending=False,
          bake_queries=True, _local_remote_pairs=None, query_class=None,
          info=None, omit_join=None, sync_backref=None)

     Provide a relationship between two mapped classes.

     This corresponds to a parent-child or associative table
     relationship.  The constructed class is an instance of
     RelationshipProperty.

     A typical relationship(), used in a classical mapping:

          mapper(Parent, properties={
            'children': relationship(Child)
          })

     Some arguments accepted by relationship() optionally
     accept a callable function, which when called produces the desired
     value.  The callable is invoked by the parent Mapper at
     “mapper initialization” time, which happens only when mappers are
     first used, and is assumed to be after all mappings have been
     constructed.  This can be used to resolve order-of-declaration and
     other dependency issues, such as if ‘Child’ is declared below
     ‘Parent’ in the same file:

          mapper(Parent, properties={
              "children":relationship(lambda: Child,
                                  order_by=lambda: Child.id)
          })

     When using the Declarative Extensions extension, the
     Declarative initializer allows string arguments to be passed to
     relationship().  These string arguments are converted
     into callables that evaluate the string as Python code, using the
     Declarative class-registry as a namespace.  This allows the lookup
     of related classes to be automatic via their string name, and
     removes the need for related classes to be imported into the local
     module space before the dependent classes have been declared.  It
     is still required that the modules in which these related classes
     appear are imported anywhere in the application at some point
     before the related mappings are actually used, else a lookup error
     will be raised when the relationship() attempts to
     resolve the string reference to the related class.  An example of a
     string- resolved class is as follows:

          from sqlalchemy.ext.declarative import declarative_base

          Base = declarative_base()

          class Parent(Base):
              __tablename__ = 'parent'
              id = Column(Integer, primary_key=True)
              children = relationship("Child", order_by="Child.id")

     See also
     ........

     See Relationship Configuration. - Full introductory and
     reference documentation for relationship().

     See Building a Relationship. - ORM tutorial introduction.

     Parameters:

        * ‘argument’ – A mapped class, or actual Mapper.
          instance, representing the target of the relationship.

          relationship.argument may also be passed as a
          callable function which is evaluated at mapper initialization
          time, and may be passed as a string name when using
          Declarative.

               Warning: Prior to SQLAlchemy 1.3.16, this value is
               interpreted using Python’s ‘eval()’ function.  `DO NOT
               PASS UNTRUSTED INPUT TO THIS STRING'. See
               Evaluation of relationship arguments for details on
               declarative evaluation of relationship()
               arguments.

          See also
          ........

          See Configuring Relationships. - further detail on
          relationship configuration when using Declarative.

        * ‘secondary’ – For a many-to-many relationship, specifies the
          intermediary table, and is typically an instance of
          Table.  In less common circumstances, the argument may
          also be specified as an Alias construct, or even a
          Join construct.

          relationship.secondary may also be passed as a
          callable function which is evaluated at mapper initialization
          time.  When using Declarative, it may also be a string
          argument noting the name of a Table that is present
          in the MetaData collection associated with the
          parent-mapped Table.

               Warning: When passed as a Python-evaluable string, the
               argument is interpreted using Python’s ‘eval()’ function.
               `DO NOT PASS UNTRUSTED INPUT TO THIS STRING'. See
               Evaluation of relationship arguments for details on
               declarative evaluation of relationship()
               arguments.

          The relationship.secondary keyword argument is
          typically applied in the case where the intermediary
          Table is not otherwise expressed in any direct class
          mapping.  If the “secondary” table is also explicitly mapped
          elsewhere (e.g.  as in Association Object), one
          should consider applying the relationship.viewonly
          flag so that this relationship() is not used for
          persistence operations which may conflict with those of the
          association object pattern.

          See also
          ........

          See Many To Many. - Reference example of “many to
          many”.

          See Building a Many To Many Relationship. - ORM
          tutorial introduction to many-to-many relationships.

          See Self-Referential Many-to-Many Relationship. -
          Specifics on using many-to-many in a self-referential case.

          See Configuring Many-to-Many Relationships. -
          Additional options when using Declarative.

          See Association Object. - an alternative to
          relationship.secondary when composing association table
          relationships, allowing additional attributes to be specified
          on the association table.

          See Composite “Secondary” Joins. - a lesser-used
          pattern which in some cases can enable complex
          relationship(). SQL conditions to be used.

          New in version 0.9.2: relationship.secondary works
          more effectively when referring to a Join
          instance.

        * ‘active_history=False’ – When ‘True’, indicates that the
          “previous” value for a many-to-one reference should be loaded
          when replaced, if not already loaded.  Normally, history
          tracking logic for simple many-to-ones only needs to be aware
          of the “new” value in order to perform a flush.  This flag is
          available for applications that make use of
          get_history() which also need to know the “previous”
          value of the attribute.

        * ‘backref’ – Indicates the string name of a property to be
          placed on the related mapper’s class that will handle this
          relationship in the other direction.  The other property will
          be created automatically when the mappers are configured.  Can
          also be passed as a backref() object to control
          the configuration of the new relationship.

          See also
          ........

          See Linking Relationships with Backref. - Introductory
          documentation and examples.

          See relationship.back_populates. - alternative form of
          backref specification.

          See backref(). - allows control over
          relationship() configuration when using
          relationship.backref.

        * ‘back_populates’ – Takes a string name and has the same
          meaning as relationship.backref, except the
          complementing property is `not' created automatically, and
          instead must be configured explicitly on the other mapper.
          The complementing property should also indicate
          relationship.back_populates to this relationship to
          ensure proper functioning.

          See also
          ........

          See Linking Relationships with Backref. - Introductory
          documentation and examples.

          See relationship.backref. - alternative form of backref
          specification.

        * ‘overlaps’ – A string name or comma-delimited set of names of
          other relationships on either this mapper, a descendant
          mapper, or a target mapper with which this relationship may
          write to the same foreign keys upon persistence.  The only
          effect this has is to eliminate the warning that this
          relationship will conflict with another upon persistence.
          This is used for such relationships that are truly capable of
          conflicting with each other on write, but the application will
          ensure that no such conflicts occur.

          New in version 1.4.

        * ‘bake_queries=True’ – Use the BakedQuery cache to
          cache the construction of SQL used in lazy loads.  True by
          default.  Set to False if the join condition of the
          relationship has unusual features that might not respond well
          to statement caching.

          Changed in version 1.2: “Baked” loading is the default
          implementation for the “select”, a.k.a.  “lazy” loading
          strategy for relationships.

          New in version 1.0.0.

          See also
          ........

          See Baked Queries.

        * ‘cascade’ – A comma-separated list of cascade rules which
          determines how Session operations should be “cascaded” from
          parent to child.  This defaults to ‘False’, which means the
          default cascade should be used - this default cascade is
          ‘"save-update, merge"’.

          The available cascades are ‘save-update’, ‘merge’, ‘expunge’,
          ‘delete’, ‘delete-orphan’, and ‘refresh-expire’.  An
          additional option, ‘all’ indicates shorthand for
          ‘"save-update, merge, refresh-expire, expunge, delete"’, and
          is often used as in ‘"all, delete-orphan"’ to indicate that
          related objects should follow along with the parent object in
          all cases, and be deleted when de-associated.

          See also
          ........

          See Cascades. - Full detail on each of the available
          cascade options.

          See Configuring delete/delete-orphan Cascade. -
          Tutorial example describing a delete cascade.

        * ‘cascade_backrefs=True’ – A boolean value indicating if the
          ‘save-update’ cascade should operate along an assignment event
          intercepted by a backref.  When set to ‘False’, the attribute
          managed by this relationship will not cascade an incoming
          transient object into the session of a persistent parent, if
          the event is received via backref.

          Deprecated since version 1.4: The
          relationship.cascade_backrefs flag will default to False
          in all cases in SQLAlchemy 2.0.

          See also
          ........

          See Controlling Cascade on Backrefs. - Full discussion
          and examples on how the relationship.cascade_backrefs
          option is used.

        * ‘collection_class’ – A class or callable that returns a new
          list-holding object.  will be used in place of a plain list
          for storing elements.

          See also
          ........

          See Customizing Collection Access. - Introductory
          documentation and examples.

        * ‘comparator_factory’ – A class which extends Comparator
          which provides custom SQL clause generation for
          comparison operations.

          See also
          ........

          See PropComparator. - some detail on redefining
          comparators at this level.

          See Operator Customization. - Brief intro to this
          feature.

        * ‘distinct_target_key=None’ – Indicate if a “subquery” eager
          load should apply the DISTINCT keyword to the innermost SELECT
          statement.  When left as ‘None’, the DISTINCT keyword will be
          applied in those cases when the target columns do not comprise
          the full primary key of the target table.  When set to ‘True’,
          the DISTINCT keyword is applied to the innermost SELECT
          unconditionally.

          It may be desirable to set this flag to False when the
          DISTINCT is reducing performance of the innermost subquery
          beyond that of what duplicate innermost rows may be causing.

          Changed in version 0.9.0: - see
          relationship.distinct_target_key now defaults to ‘None’,
          so that the feature enables itself automatically for those
          cases where the innermost query targets a non-unique key.

          See also
          ........

          See Relationship Loading Techniques. - includes an
          introduction to subquery eager loading.

        * ‘doc’ – Docstring which will be applied to the resulting
          descriptor.

        * ‘foreign_keys’ – A list of columns which are to be used as
          “foreign key” columns, or columns which refer to the value in
          a remote column, within the context of this
          relationship() object’s relationship.primaryjoin
          condition.  That is, if the
          relationship.primaryjoin condition of this
          relationship() is ‘a.id == b.a_id’, and the values in
          ‘b.a_id’ are required to be present in ‘a.id’, then the
          “foreign key” column of this relationship() is
          ‘b.a_id’.

          In normal cases, the relationship.foreign_keys
          parameter is `not required.'  relationship() will
          automatically determine which columns in the
          relationship.primaryjoin condition are to be considered
          “foreign key” columns based on those Column objects
          that specify ForeignKey, or are otherwise listed as
          referencing columns in a ForeignKeyConstraint
          construct.  relationship.foreign_keys is only
          needed when:

                 1. There is more than one way to construct a join from
                    the local table to the remote table, as there are
                    multiple foreign key references present.  Setting
                    ‘foreign_keys’ will limit the relationship()
                    to consider just those columns specified here as
                    “foreign”.

                 2. The Table being mapped does not actually
                    have ForeignKey or
                    ForeignKeyConstraint constructs present, often
                    because the table was reflected from a database that
                    does not support foreign key reflection (MySQL
                    MyISAM).

                 3. The relationship.primaryjoin argument is
                    used to construct a non-standard join condition,
                    which makes use of columns or expressions that do
                    not normally refer to their “parent” column, such as
                    a join condition expressed by a complex comparison
                    using a SQL function.

          The relationship() construct will raise informative
          error messages that suggest the use of the
          relationship.foreign_keys parameter when presented with
          an ambiguous condition.  In typical cases, if
          relationship() doesn’t raise any exceptions, the
          relationship.foreign_keys parameter is usually not
          needed.

          relationship.foreign_keys may also be passed as a
          callable function which is evaluated at mapper initialization
          time, and may be passed as a Python-evaluable string when
          using Declarative.

               Warning: When passed as a Python-evaluable string, the
               argument is interpreted using Python’s ‘eval()’ function.
               `DO NOT PASS UNTRUSTED INPUT TO THIS STRING'. See
               Evaluation of relationship arguments for details on
               declarative evaluation of relationship()
               arguments.

          See also
          ........

          See Handling Multiple Join Paths.

          See Creating Custom Foreign Conditions.

          See foreign(). - allows direct annotation of the
          “foreign” columns within a relationship.primaryjoin
          condition.

        * ‘info’ – Optional data dictionary which will be populated into
          the MapperProperty.info attribute of this object.

        * ‘innerjoin=False’ – When ‘True’, joined eager loads will use
          an inner join to join against related tables instead of an
          outer join.  The purpose of this option is generally one of
          performance, as inner joins generally perform better than
          outer joins.

          This flag can be set to ‘True’ when the relationship
          references an object via many-to-one using local foreign keys
          that are not nullable, or when the reference is one-to-one or
          a collection that is guaranteed to have one or at least one
          entry.

          The option supports the same “nested” and “unnested” options
          as that of joinedload.innerjoin.  See that flag for
          details on nested / unnested behaviors.

          See also
          ........

          See joinedload.innerjoin. - the option as specified by
          loader option, including detail on nesting behavior.

          See What Kind of Loading to Use ?. - Discussion of some
          details of various loader options.

        * ‘join_depth’ – When non-‘None’, an integer value indicating
          how many levels deep “eager” loaders should join on a
          self-referring or cyclical relationship.  The number counts
          how many times the same Mapper shall be present in the loading
          condition along a particular join branch.  When left at its
          default of ‘None’, eager loaders will stop chaining when they
          encounter a the same target mapper which is already higher up
          in the chain.  This option applies both to joined- and
          subquery- eager loaders.

          See also
          ........

          See Configuring Self-Referential Eager Loading. -
          Introductory documentation and examples.

        * ‘lazy='select'’ – specifies How the related items should be
          loaded.  Default value is ‘select’.  Values include:

             * ‘select’ - items should be loaded lazily when the
               property is first accessed, using a separate SELECT
               statement, or identity map fetch for simple many-to-one
               references.

             * ‘immediate’ - items should be loaded as the parents are
               loaded, using a separate SELECT statement, or identity
               map fetch for simple many-to-one references.

             * ‘joined’ - items should be loaded “eagerly” in the same
               query as that of the parent, using a JOIN or LEFT OUTER
               JOIN. Whether the join is “outer” or not is determined by
               the relationship.innerjoin parameter.

             * ‘subquery’ - items should be loaded “eagerly” as the
               parents are loaded, using one additional SQL statement,
               which issues a JOIN to a subquery of the original
               statement, for each collection requested.

             * ‘selectin’ - items should be loaded “eagerly” as the
               parents are loaded, using one or more additional SQL
               statements, which issues a JOIN to the immediate parent
               object, specifying primary key identifiers using an IN
               clause.

               New in version 1.2.

             * ‘noload’ - no loading should occur at any time.  This is
               to support “write-only” attributes, or attributes which
               are populated in some manner specific to the application.

             * ‘raise’ - lazy loading is disallowed; accessing the
               attribute, if its value were not already loaded via eager
               loading, will raise an InvalidRequestError.
               This strategy can be used when objects are to be detached
               from their attached Session after they are
               loaded.

               New in version 1.1.

             * ‘raise_on_sql’ - lazy loading that emits SQL is
               disallowed; accessing the attribute, if its value were
               not already loaded via eager loading, will raise an
               InvalidRequestError, `if the lazy load needs to emit
               SQL'. If the lazy load can pull the related value from
               the identity map or determine that it should be None, the
               value is loaded.  This strategy can be used when objects
               will remain associated with the attached Session,
               however additional SELECT statements should be
               blocked.

               New in version 1.1.

             * ‘dynamic’ - the attribute will return a pre-configured
               Query object for all read operations, onto
               which further filtering operations can be applied before
               iterating the results.  See the section Dynamic Relationship Loaders
               for more details.

             * True - a synonym for ‘select’

             * False - a synonym for ‘joined’

             * None - a synonym for ‘noload’

          See also
          ........

          See Relationship Loading Techniques. - Full
          documentation on relationship loader configuration.

          See Dynamic Relationship Loaders. - detail on the
          ‘dynamic’ option.

          See Setting Noload, RaiseLoad. - notes on “noload” and
          “raise”

        * ‘load_on_pending=False’ – Indicates loading behavior for
          transient or pending parent objects.

          When set to ‘True’, causes the lazy-loader to issue a query
          for a parent object that is not persistent, meaning it has
          never been flushed.  This may take effect for a pending object
          when autoflush is disabled, or for a transient object that has
          been “attached” to a Session but is not part of its
          pending collection.

          The relationship.load_on_pending flag does not
          improve behavior when the ORM is used normally - object
          references should be constructed at the object level, not at
          the foreign key level, so that they are present in an ordinary
          way before a flush proceeds.  This flag is not not intended
          for general use.

          See also
          ........

          See Session.enable_relationship_loading(). - this
          method establishes “load on pending” behavior for the whole
          object, and also allows loading on objects that remain
          transient or detached.

        * ‘order_by’ – Indicates the ordering that should be applied
          when loading these items.  relationship.order_by
          is expected to refer to one of the Column objects
          to which the target class is mapped, or the attribute itself
          bound to the target class which refers to the column.

          relationship.order_by may also be passed as a
          callable function which is evaluated at mapper initialization
          time, and may be passed as a Python-evaluable string when
          using Declarative.

               Warning: When passed as a Python-evaluable string, the
               argument is interpreted using Python’s ‘eval()’ function.
               `DO NOT PASS UNTRUSTED INPUT TO THIS STRING'. See
               Evaluation of relationship arguments for details on
               declarative evaluation of relationship()
               arguments.

        * ‘passive_deletes=False’ – Indicates loading behavior during
          delete operations.

          A value of True indicates that unloaded child items should not
          be loaded during a delete operation on the parent.  Normally,
          when a parent item is deleted, all child items are loaded so
          that they can either be marked as deleted, or have their
          foreign key to the parent set to NULL. Marking this flag as
          True usually implies an ON DELETE <CASCADE|SET NULL> rule is
          in place which will handle updating/deleting child rows on the
          database side.

          Additionally, setting the flag to the string value ‘all’ will
          disable the “nulling out” of the child foreign keys, when the
          parent object is deleted and there is no delete or
          delete-orphan cascade enabled.  This is typically used when a
          triggering or error raise scenario is in place on the database
          side.  Note that the foreign key attributes on in-session
          child objects will not be changed after a flush occurs so this
          is a very special use-case setting.  Additionally, the
          “nulling out” will still occur if the child object is
          de-associated with the parent.

          See also
          ........

          See Using foreign key ON DELETE cascade with ORM relationships.
          - Introductory documentation and examples.

        * ‘passive_updates=True’ – Indicates the persistence behavior to
          take when a referenced primary key value changes in place,
          indicating that the referencing foreign key columns will also
          need their value changed.

          When True, it is assumed that ‘ON UPDATE CASCADE’ is
          configured on the foreign key in the database, and that the
          database will handle propagation of an UPDATE from a source
          column to dependent rows.  When False, the SQLAlchemy
          relationship() construct will attempt to emit its own
          UPDATE statements to modify related targets.  However note
          that SQLAlchemy `cannot' emit an UPDATE for more than one
          level of cascade.  Also, setting this flag to False is not
          compatible in the case where the database is in fact enforcing
          referential integrity, unless those constraints are explicitly
          “deferred”, if the target backend supports it.

          It is highly advised that an application which is employing
          mutable primary keys keeps ‘passive_updates’ set to True, and
          instead uses the referential integrity features of the
          database itself in order to handle the change efficiently and
          fully.

          See also
          ........

          See Mutable Primary Keys / Update Cascades. -
          Introductory documentation and examples.

          See mapper.passive_updates. - a similar flag which
          takes effect for joined-table inheritance mappings.

        * ‘post_update’ – This indicates that the relationship should be
          handled by a second UPDATE statement after an INSERT or before
          a DELETE. Currently, it also will issue an UPDATE after the
          instance was UPDATEd as well, although this technically should
          be improved.  This flag is used to handle saving
          bi-directional dependencies between two individual rows (i.e.
          each row references the other), where it would otherwise be
          impossible to INSERT or DELETE both rows fully since one row
          exists before the other.  Use this flag when a particular
          mapping arrangement will incur two rows that are dependent on
          each other, such as a table that has a one-to-many
          relationship to a set of child rows, and also has a column
          that references a single child row within that list (i.e.
          both tables contain a foreign key to each other).  If a flush
          operation returns an error that a “cyclical dependency” was
          detected, this is a cue that you might want to use
          relationship.post_update to “break” the cycle.

          See also
          ........

          See Rows that point to themselves / Mutually Dependent Rows.
          - Introductory documentation and examples.

        * ‘primaryjoin’ – A SQL expression that will be used as the
          primary join of the child object against the parent object, or
          in a many-to-many relationship the join of the parent object
          to the association table.  By default, this value is computed
          based on the foreign key relationships of the parent and child
          tables (or association table).

          relationship.primaryjoin may also be passed as a
          callable function which is evaluated at mapper initialization
          time, and may be passed as a Python-evaluable string when
          using Declarative.

               Warning: When passed as a Python-evaluable string, the
               argument is interpreted using Python’s ‘eval()’ function.
               `DO NOT PASS UNTRUSTED INPUT TO THIS STRING'. See
               Evaluation of relationship arguments for details on
               declarative evaluation of relationship()
               arguments.

          See also
          ........

          See Specifying Alternate Join Conditions.

        * ‘remote_side’ – Used for self-referential relationships,
          indicates the column or list of columns that form the “remote
          side” of the relationship.

          relationship.remote_side may also be passed as a
          callable function which is evaluated at mapper initialization
          time, and may be passed as a Python-evaluable string when
          using Declarative.

               Warning: When passed as a Python-evaluable string, the
               argument is interpreted using Python’s ‘eval()’ function.
               `DO NOT PASS UNTRUSTED INPUT TO THIS STRING'. See
               Evaluation of relationship arguments for details on
               declarative evaluation of relationship()
               arguments.

          See also
          ........

          See Adjacency List Relationships. - in-depth
          explanation of how relationship.remote_side is
          used to configure self-referential relationships.

          See remote(). - an annotation function that
          accomplishes the same purpose as
          relationship.remote_side, typically when a custom
          relationship.primaryjoin condition is used.

        * ‘query_class’ – A Query subclass that will be used
          internally by the ‘AppenderQuery’ returned by a “dynamic”
          relationship, that is, a relationship that specifies
          ‘lazy="dynamic"’ or was otherwise constructed using the
          dynamic_loader() function.

          See also
          ........

          See Dynamic Relationship Loaders. - Introduction to
          “dynamic” relationship loaders.

        * ‘secondaryjoin’ – A SQL expression that will be used as the
          join of an association table to the child object.  By default,
          this value is computed based on the foreign key relationships
          of the association and child tables.

          relationship.secondaryjoin may also be passed as a
          callable function which is evaluated at mapper initialization
          time, and may be passed as a Python-evaluable string when
          using Declarative.

               Warning: When passed as a Python-evaluable string, the
               argument is interpreted using Python’s ‘eval()’ function.
               `DO NOT PASS UNTRUSTED INPUT TO THIS STRING'. See
               Evaluation of relationship arguments for details on
               declarative evaluation of relationship()
               arguments.

          See also
          ........

          See Specifying Alternate Join Conditions.

        * ‘single_parent’ – When True, installs a validator which will
          prevent objects from being associated with more than one
          parent at a time.  This is used for many-to-one or
          many-to-many relationships that should be treated either as
          one-to-one or one-to-many.  Its usage is optional, except for
          relationship() constructs which are many-to-one or
          many-to-many and also specify the ‘delete-orphan’ cascade
          option.  The relationship() construct itself will
          raise an error instructing when this option is required.

          See also
          ........

          See Cascades. - includes detail on when the
          relationship.single_parent flag may be appropriate.

        * ‘uselist’ – A boolean that indicates if this property should
          be loaded as a list or a scalar.  In most cases, this value is
          determined automatically by relationship() at
          mapper configuration time, based on the type and direction of
          the relationship - one to many forms a list, many to one forms
          a scalar, many to many is a list.  If a scalar is desired
          where normally a list would be present, such as a
          bi-directional one-to-one relationship, set
          relationship.uselist to False.

          The relationship.uselist flag is also available on
          an existing relationship() construct as a read-only
          attribute, which can be used to determine if this
          relationship() deals with collections or scalar
          attributes:

               >>> User.addresses.property.uselist
               True

          See also
          ........

          See One To One. - Introduction to the “one to one”
          relationship pattern, which is typically when the
          relationship.uselist flag is needed.

        * ‘viewonly=False’ – When set to ‘True’, the relationship is
          used only for loading objects, and not for any persistence
          operation.  A relationship() which specifies
          relationship.viewonly can work with a wider range of SQL
          operations within the relationship.primaryjoin
          condition, including operations that feature the use of a
          variety of comparison operators as well as SQL functions such
          as cast().  The relationship.viewonly
          flag is also of general use when defining any kind of
          relationship() that doesn’t represent the full set of
          related objects, to prevent modifications of the collection
          from resulting in persistence operations.

          When using the relationship.viewonly flag in
          conjunction with backrefs, the originating relationship for a
          particular state change will not produce state changes within
          the viewonly relationship.  This is the behavior implied by
          relationship.sync_backref being set to False.

          Changed in version 1.3.17: - the
          relationship.sync_backref flag is set to False when
          using viewonly in conjunction with backrefs.

          See also
          ........

          See relationship.sync_backref.

        * ‘sync_backref’ – A boolean that enables the events used to
          synchronize the in-Python attributes when this relationship is
          target of either relationship.backref or
          relationship.back_populates.

          Defaults to ‘None’, which indicates that an automatic value
          should be selected based on the value of the
          relationship.viewonly flag.  When left at its default,
          changes in state will be back-populated only if neither sides
          of a relationship is viewonly.

          New in version 1.3.17.

          Changed in version 1.4: - A relationship that specifies
          relationship.viewonly automatically implies that
          relationship.sync_backref is ‘False’.

          See also
          ........

          See relationship.viewonly.

        * ‘omit_join’ – Allows manual control over the “selectin”
          automatic join optimization.  Set to ‘False’ to disable the
          “omit join” feature added in SQLAlchemy 1.3; or leave as
          ‘None’ to leave automatic optimization in place.

               Note: This flag may only be set to ‘False’.  It is not
               necessary to set it to ‘True’ as the “omit_join”
               optimization is automatically detected; if it is not
               detected, then the optimization is not supported.

               Changed in version 1.3.11: setting ‘omit_join’ to True
               will now emit a warning as this was not the intended use
               of this flag.

          New in version 1.3.

 -- Function: sqlalchemy.orm.backref (name, **kwargs)

     Create a back reference with explicit keyword arguments, which are
     the same arguments one can send to relationship().

     Used with the ‘backref’ keyword argument to relationship()
     in place of a string argument, e.g.:

          'items':relationship(
              SomeItem, backref=backref('parent', lazy='subquery'))

     See also
     ........

     See Linking Relationships with Backref.

 -- Function: sqlalchemy.orm.relation (*arg, **kw)

     A synonym for relationship().

     Deprecated since version 1.4: The relation construct is considered
     legacy as of the 1.x series of SQLAlchemy and will be removed in
     2.0.  Please use relationship().  (Background on
     SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

 -- Function: sqlalchemy.orm.dynamic_loader (argument, **kw)

     Construct a dynamically-loading mapper property.

     This is essentially the same as using the ‘lazy='dynamic'’ argument
     with relationship():

          dynamic_loader(SomeClass)

          # is the same as

          relationship(SomeClass, lazy="dynamic")

     See the section Dynamic Relationship Loaders for more
     details on dynamic loading.

 -- Function: sqlalchemy.orm.foreign (expr)

     Annotate a portion of a primaryjoin expression with a ‘foreign’
     annotation.

     See the section Creating Custom Foreign Conditions for
     a description of use.

     See also
     ........

     See Creating Custom Foreign Conditions.

     See remote().

 -- Function: sqlalchemy.orm.remote (expr)

     Annotate a portion of a primaryjoin expression with a ‘remote’
     annotation.

     See the section Creating Custom Foreign Conditions for
     a description of use.

     See also
     ........

     See Creating Custom Foreign Conditions.

     See foreign().

3.4 Querying Data, Loading Objects
==================================

The following sections refer to techniques for emitting SELECT
statements within an ORM context.  This involves primarily statements
that return instances of ORM mapped objects, but also involves calling
forms that deliver individual column or groups of columns as well.

For an introduction to querying with the SQLAlchemy ORM, one of the
following tutorials shoud be consulted:

   * SQLAlchemy 1.4 / 2.0 Tutorial. - for 2.0 style usage

   * Object Relational Tutorial (1.x API). - for 1.x style
     usage.

As SQLAlchemy 1.4 represents a transition from 1.x to 2.0 style, the
below sections are currently mixed as far as which style they are using.

3.4.1 ORM Querying Guide
------------------------

This section provides an overview of emitting queries with the
SQLAlchemy ORM using 2.0 style usage.

Readers of this section should be familiar with the SQLAlchemy overview
at SQLAlchemy 1.4 / 2.0 Tutorial, and in particular most of
the content here expands upon the content at Selecting Data.

3.4.1.1 SELECT statements
.........................

SELECT statements are produced by the select() function which
returns a Select object:

     >>> from sqlalchemy import select
     >>> stmt = select(User).where(User.name == 'spongebob')

To invoke a Select with the ORM, it is passed to
Session.execute():

     {sql}>>> result = session.execute(stmt)
     SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     WHERE user_account.name = ?
     [...] ('spongebob',){stop}
     >>> for user_obj in result.scalars():
     ...     print(f"{user_obj.name} {user_obj.fullname}")
     spongebob Spongebob Squarepants

3.4.1.2 Selecting ORM Entities and Attributes
.............................................

The select() construct accepts ORM entities, including mapped
classes as well as class-level attributes representing mapped columns,
which are converted into ORM-annotated FromClause and
ColumnElement elements at construction time.

A Select object that contains ORM-annotated entities is
normally executed using a Session object, and not a
Connection object, so that ORM-related features may take effect,
including that instances of ORM-mapped objects may be returned.  When
using the Connection directly, result rows will only contain
column-level data.

Below we select from the ‘User’ entity, producing a Select
that selects from the mapped Table to which ‘User’ is mapped:

     {sql}>>> result = session.execute(select(User).order_by(User.id))
     SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account ORDER BY user_account.id
     [...] (){stop}

When selecting from ORM entities, the entity itself is returned in the
result as a row with a single element, as opposed to a series of
individual columns; for example above, the Result returns
Row objects that have just a single element per row, that
element holding onto a ‘User’ object:

     >>> result.fetchone()
     (User(id=1, name='spongebob', fullname='Spongebob Squarepants'),)

When selecting a list of single-element rows containing ORM entities, it
is typical to skip the generation of Row objects and instead
receive ORM entities directly, which is achieved using the
Result.scalars() method:

     >>> result.scalars().all()
     [User(id=2, name='sandy', fullname='Sandy Cheeks'),
      User(id=3, name='patrick', fullname='Patrick Star'),
      User(id=4, name='squidward', fullname='Squidward Tentacles'),
      User(id=5, name='ehkrabs', fullname='Eugene H. Krabs')]

ORM Entities are named in the result row based on their class name, such
as below where we SELECT from both ‘User’ and ‘Address’ at the same
time:

     >>> stmt = select(User, Address).join(User.addresses).order_by(User.id, Address.id)

     {sql}>>> for row in session.execute(stmt):
     ...    print(f"{row.User.name} {row.Address.email_address}")
     SELECT user_account.id, user_account.name, user_account.fullname,
     address.id AS id_1, address.user_id, address.email_address
     FROM user_account JOIN address ON user_account.id = address.user_id
     ORDER BY user_account.id, address.id
     [...] (){stop}
     spongebob spongebob@sqlalchemy.org
     sandy sandy@sqlalchemy.org
     sandy squirrel@squirrelpower.org
     patrick pat999@aol.com
     squidward stentcl@sqlalchemy.org

3.4.1.3 Selecting Individual Attributes
.......................................

The attributes on a mapped class, such as ‘User.name’ and
‘Address.email_address’, have a similar behavior as that of the entity
class itself such as ‘User’ in that they are automatically converted
into ORM-annotated Core objects when passed to select().  They
may be used in the same way as table columns are used:

     {sql}>>> result = session.execute(
     ...     select(User.name, Address.email_address).
     ...     join(User.addresses).
     ...     order_by(User.id, Address.id)
     ... )
     SELECT user_account.name, address.email_address
     FROM user_account JOIN address ON user_account.id = address.user_id
     ORDER BY user_account.id, address.id
     [...] (){stop}

ORM attributes, themselves known as InstrumentedAttribute
objects, can be used in the same way as any ColumnElement,
and are delivered in result rows just the same way, such as below where
we refer to their values by column name within each row:

     >>> for row in result:
     ...     print(f"{row.name}  {row.email_address}")
     spongebob  spongebob@sqlalchemy.org
     sandy  sandy@sqlalchemy.org
     sandy  squirrel@squirrelpower.org
     patrick  pat999@aol.com
     squidward  stentcl@sqlalchemy.org

3.4.1.4 Grouping Selected Attributes with Bundles
.................................................

The Bundle construct is an extensible ORM-only construct
that allows sets of column expressions to be grouped in result rows:

     >>> from sqlalchemy.orm import Bundle
     >>> stmt = select(
     ...     Bundle("user", User.name, User.fullname),
     ...     Bundle("email", Address.email_address)
     ... ).join_from(User, Address)
     {sql}>>> for row in session.execute(stmt):
     ...     print(f"{row.user.name} {row.email.email_address}")
     SELECT user_account.name, user_account.fullname, address.email_address
     FROM user_account JOIN address ON user_account.id = address.user_id
     [...] (){stop}
     spongebob spongebob@sqlalchemy.org
     sandy sandy@sqlalchemy.org
     sandy squirrel@squirrelpower.org
     patrick pat999@aol.com
     squidward stentcl@sqlalchemy.org

The Bundle is potentially useful for creating lightweight
views as well as custom column groupings such as mappings.

See also
........

See Column Bundles. - in the ORM loading documentation.

3.4.1.5 Selecting ORM Aliases
.............................

As discussed in the tutorial at Using Aliases, to create a
SQL alias of an ORM entity is achieved using the aliased()
construct against a mapped class:

     >>> from sqlalchemy.orm import aliased
     >>> u1 = aliased(User)
     >>> print(select(u1).order_by(u1.id))
     {opensql}SELECT user_account_1.id, user_account_1.name, user_account_1.fullname
     FROM user_account AS user_account_1 ORDER BY user_account_1.id

As is the case when using Table.alias(), the SQL alias is
anonymously named.  For the case of selecting the entity from a row with
an explicit name, the aliased.name parameter may be passed
as well:

     >>> from sqlalchemy.orm import aliased
     >>> u1 = aliased(User, name="u1")
     >>> stmt = select(u1).order_by(u1.id)
     {sql}>>> row = session.execute(stmt).first()
     SELECT u1.id, u1.name, u1.fullname
     FROM user_account AS u1 ORDER BY u1.id
     [...] (){stop}
     >>> print(f"{row.u1.name}")
     spongebob

The aliased construct is also central to making use of
subqueries with the ORM; the section Joining to Subqueries
discusses this further.

3.4.1.6 Getting ORM Results from Textual and Core Statements
............................................................

The ORM supports loading of entities from SELECT statements that come
from other sources.  The typical use case is that of a textual SELECT
statement, which in SQLAlchemy is represented using the text()
construct.  The text() construct, once constructed, can
be augmented with information about the ORM-mapped columns that the
statement would load; this can then be associated with the ORM entity
itself so that ORM objects can be loaded based on this statement.

Given a textual SQL statement we’d like to load from:

     >>> from sqlalchemy import text
     >>> textual_sql = text("SELECT id, name, fullname FROM user_account ORDER BY id")

We can add column information to the statement by using the
TextClause.columns() method; when this method is invoked, the
TextClause object is converted into a TextualSelect
object, which takes on a role that is comparable to the
Select construct.  The TextClause.columns() method is
typically passed Column objects or equivalent, and in this
case we can make use of the ORM-mapped attributes on the ‘User’ class
directly:

     >>> textual_sql = textual_sql.columns(User.id, User.name, User.fullname)

We now have an ORM-configured SQL construct that as given, can load the
“id”, “name” and “fullname” columns separately.  To use this SELECT
statement as a source of complete ‘User’ entities instead, we can link
these columns to a regular ORM-enabled Select construct using
the Select.from_statement() method:

     >>> # using from_statement()
     >>> orm_sql = select(User).from_statement(textual_sql)
     >>> for user_obj in session.execute(orm_sql).scalars():
     ...     print(user_obj)
     {opensql}SELECT id, name, fullname FROM user_account ORDER BY id
     [...] (){stop}
     User(id=1, name='spongebob', fullname='Spongebob Squarepants')
     User(id=2, name='sandy', fullname='Sandy Cheeks')
     User(id=3, name='patrick', fullname='Patrick Star')
     User(id=4, name='squidward', fullname='Squidward Tentacles')
     User(id=5, name='ehkrabs', fullname='Eugene H. Krabs')

The same TextualSelect object can also be converted into a
subquery using the TextualSelect.subquery() method, and
linked to the ‘User’ entity to it using the aliased()
construct, in a similar manner as discussed below in Joining to Subqueries:

     >>> # using aliased() to select from a subquery
     >>> orm_subquery = aliased(User, textual_sql.subquery())
     >>> stmt = select(orm_subquery)
     >>> for user_obj in session.execute(stmt).scalars():
     ...     print(user_obj)
     {opensql}SELECT anon_1.id, anon_1.name, anon_1.fullname
     FROM (SELECT id, name, fullname FROM user_account ORDER BY id) AS anon_1
     [...] (){stop}
     User(id=1, name='spongebob', fullname='Spongebob Squarepants')
     User(id=2, name='sandy', fullname='Sandy Cheeks')
     User(id=3, name='patrick', fullname='Patrick Star')
     User(id=4, name='squidward', fullname='Squidward Tentacles')
     User(id=5, name='ehkrabs', fullname='Eugene H. Krabs')

The difference between using the TextualSelect directly with
Select.from_statement() versus making use of ‘aliased()’ is
that in the former case, no subquery is produced in the resulting SQL.
This can in some scenarios be advantageous from a performance or
complexity perspective.

See also
........

See Selecting ORM Objects Inline with UPDATE.. RETURNING or INSERT..RETURNING.
- The Select.from_statement() method
also works with DML statements that support RETURNING.

3.4.1.7 Joins
.............

The Select.join() and Select.join_from() methods
are used to construct SQL JOINs against a SELECT statement.

This section will detail ORM use cases for these methods.  For a general
overview of their use from a Core perspective, see Explicit FROM clauses and JOINs
in the SQLAlchemy 1.4 / 2.0 Tutorial.

The usage of Select.join() in an ORM context for 2.0 style
queries is mostly equivalent, minus legacy use cases, to the usage of
the Query.join() method in 1.x style queries.

3.4.1.8 Simple Relationship Joins
.................................

Consider a mapping between two classes ‘User’ and ‘Address’, with a
relationship ‘User.addresses’ representing a collection of ‘Address’
objects associated with each ‘User’.  The most common usage of
Select.join() is to create a JOIN along this relationship, using
the ‘User.addresses’ attribute as an indicator for how this should
occur:

     >>> stmt = select(User).join(User.addresses)

Where above, the call to Select.join() along
‘User.addresses’ will result in SQL approximately equivalent to:

     >>> print(stmt)
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account JOIN address ON user_account.id = address.user_id

In the above example we refer to ‘User.addresses’ as passed to
Select.join() as the “on clause”, that is, it indicates how the
“ON” portion of the JOIN should be constructed.

3.4.1.9 Chaining Multiple Joins
...............................

To construct a chain of joins, multiple Select.join() calls
may be used.  The relationship-bound attribute implies both the left and
right side of the join at once.  Consider additional entities ‘Order’
and ‘Item’, where the ‘User.orders’ relationship refers to the ‘Order’
entity, and the ‘Order.items’ relationship refers to the ‘Item’ entity,
via an association table ‘order_items’.  Two Select.join()
calls will result in a JOIN first from ‘User’ to ‘Order’, and a second
from ‘Order’ to ‘Item’.  However, since ‘Order.items’ is a many to many
relationship, it results in two separate JOIN elements, for a
total of three JOIN elements in the resulting SQL:

     >>> stmt = (
     ...     select(User).
     ...     join(User.orders).
     ...     join(Order.items)
     ... )
     >>> print(stmt)
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     JOIN user_order ON user_account.id = user_order.user_id
     JOIN order_items AS order_items_1 ON user_order.id = order_items_1.order_id
     JOIN item ON item.id = order_items_1.item_id

The order in which each call to the Select.join() method is
significant only to the degree that the “left” side of what we would
like to join from needs to be present in the list of FROMs before we
indicate a new target.  Select.join() would not, for
example, know how to join correctly if we were to specify
‘select(User).join(Order.items).join(User.orders)’, and would raise an
error.  In correct practice, the Select.join() method is
invoked in such a way that lines up with how we would want the JOIN
clauses in SQL to be rendered, and each call should represent a clear
link from what precedes it.

All of the elements that we target in the FROM clause remain available
as potential points to continue joining FROM. We can continue to add
other elements to join FROM the ‘User’ entity above, for example adding
on the ‘User.addresses’ relationship to our chain of joins:

     >>> stmt = (
     ...     select(User).
     ...     join(User.orders).
     ...     join(Order.items).
     ...     join(User.addresses)
     ... )
     >>> print(stmt)
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     JOIN user_order ON user_account.id = user_order.user_id
     JOIN order_items AS order_items_1 ON user_order.id = order_items_1.order_id
     JOIN item ON item.id = order_items_1.item_id
     JOIN address ON user_account.id = address.user_id

3.4.1.10 Joins to a Target Entity or Selectable
...............................................

A second form of Select.join() allows any mapped entity or
core selectable construct as a target.  In this usage, see
Select.join() will attempt to `infer' the ON clause for the JOIN,
using the natural foreign key relationship between two entities:

     >>> stmt = select(User).join(Address)
     >>> print(stmt)
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account JOIN address ON user_account.id = address.user_id

In the above calling form, see Select.join() is called upon to
infer the “on clause” automatically.  This calling form will ultimately
raise an error if either there are no ForeignKeyConstraint
setup between the two mapped Table constructs, or if there
are multiple ForeignKeyConstraint linakges between them such
that the appropriate constraint to use is ambiguous.

     Note: When making use of Select.join() or
     Select.join_from() without indicating an ON clause, ORM
     configured relationship() constructs are `not taken into
     account'.  Only the configured ForeignKeyConstraint
     relationships between the entities at the level of the mapped
     Table objects are consulted when an attempt is made to infer
     an ON clause for the JOIN.

3.4.1.11 Joins to a Target with an ON Clause
............................................

The third calling form allows both the target entity as well as the ON
clause to be passed explicitly.  A example that includes a SQL
expression as the ON clause is as follows:

     >>> stmt = select(User).join(Address, User.id==Address.user_id)
     >>> print(stmt)
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account JOIN address ON user_account.id = address.user_id

The expression-based ON clause may also be the relationship-bound
attribute; this form in fact states the target of ‘Address’ twice,
however this is accepted:

     >>> stmt = select(User).join(Address, User.addresses)
     >>> print(stmt)
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account JOIN address ON user_account.id = address.user_id

The above syntax has more functionality if we use it in terms of aliased
entities.  The default target for ‘User.addresses’ is the ‘Address’
class, however if we pass aliased forms using aliased(), the
aliased() form will be used as the target, as in the example
below:

     >>> a1 = aliased(Address)
     >>> a2 = aliased(Address)
     >>> stmt = (
     ...     select(User).
     ...     join(a1, User.addresses).
     ...     join(a2, User.addresses).
     ...     where(a1.email_address == 'ed@foo.com').
     ...     where(a2.email_address == 'ed@bar.com')
     ... )
     >>> print(stmt)
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     JOIN address AS address_1 ON user_account.id = address_1.user_id
     JOIN address AS address_2 ON user_account.id = address_2.user_id
     WHERE address_1.email_address = :email_address_1
     AND address_2.email_address = :email_address_2

When using relationship-bound attributes, the target entity can also be
substituted with an aliased entity by using the
PropComparator.of_type() method.  The same example using this
method would be:

     >>> stmt = (
     ...     select(User).
     ...     join(User.addresses.of_type(a1)).
     ...     join(User.addresses.of_type(a2)).
     ...     where(a1.email_address == 'ed@foo.com').
     ...     where(a2.email_address == 'ed@bar.com')
     ... )
     >>> print(stmt)
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     JOIN address AS address_1 ON user_account.id = address_1.user_id
     JOIN address AS address_2 ON user_account.id = address_2.user_id
     WHERE address_1.email_address = :email_address_1
     AND address_2.email_address = :email_address_2

3.4.1.12 Augmenting Built-in ON Clauses
.......................................

As a substitute for providing a full custom ON condition for an existing
relationship, the PropComparator.and_() function may be
applied to a relationship attribute to augment additional criteria into
the ON clause; the additional criteria will be combined with the default
criteria using AND. Below, the ON criteria between ‘user_account’ and
‘address’ contains two separate elements joined by ‘AND’, the first one
being the natural join along the foreign key, and the second being a
custom limiting criteria:

     >>> stmt = (
     ...     select(User).
     ...     join(User.addresses.and_(Address.email_address != 'foo@bar.com'))
     ... )
     >>> print(stmt)
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     JOIN address ON user_account.id = address.user_id
     AND address.email_address != :email_address_1

See also
........

The PropComparator.and_() method also works with loader
strategies.  See the section Adding Criteria to loader options
for an example.

3.4.1.13 Joining to Subqueries
..............................

The target of a join may be any “selectable” entity which usefully
includes subuqeries.  When using the ORM, it is typical that these
targets are stated in terms of an aliased() construct, but
this is not strictly required particularly if the joined entity is not
being returned in the results.  For example, to join from the ‘User’
entity to the ‘Address’ entity, where the ‘Address’ entity is
represented as a row limited subquery, we first construct a
Subquery object using Select.subquery(), which may then
be used as the target of the Select.join() method:

     >>> subq = (
     ...     select(Address).
     ...     where(Address.email_address == 'pat999@aol.com').
     ...     subquery()
     ... )
     >>> stmt = select(User).join(subq, User.id == subq.c.user_id)
     >>> print(stmt)
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     JOIN (SELECT address.id AS id,
     address.user_id AS user_id, address.email_address AS email_address
     FROM address
     WHERE address.email_address = :email_address_1) AS anon_1
     ON user_account.id = anon_1.user_id{stop}

The above SELECT statement when invoked via Session.execute()
will return rows that contain ‘User’ entities, but not ‘Address’
entities.  In order to add ‘Address’ entities to the set of entities
that would be returned in result sets, we construct an aliased()
object against the ‘Address’ entity and the custom subquery.  Note
we also apply a name ‘"address"’ to the aliased() construct
so that we may refer to it by name in the result row:

     >>> address_subq = aliased(Address, subq, name="address")
     >>> stmt = select(User, address_subq).join(address_subq)
     >>> for row in session.execute(stmt):
     ...     print(f"{row.User} {row.address}")
     {opensql}SELECT user_account.id, user_account.name, user_account.fullname,
     anon_1.id AS id_1, anon_1.user_id, anon_1.email_address
     FROM user_account
     JOIN (SELECT address.id AS id,
     address.user_id AS user_id, address.email_address AS email_address
     FROM address
     WHERE address.email_address = ?) AS anon_1 ON user_account.id = anon_1.user_id
     [...] ('pat999@aol.com',){stop}
     User(id=3, name='patrick', fullname='Patrick Star') Address(id=4, email_address='pat999@aol.com')

The same subquery may be referred towards by multiple entities as well,
for a subquery that represents more than one entity.  The subquery
itself will remain unique within the statement, while the entities that
are linked to it using aliased refer to distinct sets of
columns:

     >>> user_address_subq = (
     ...        select(User.id, User.name, Address.id, Address.email_address).
     ...        join_from(User, Address).
     ...        where(Address.email_address.in_(['pat999@aol.com', 'squirrel@squirrelpower.org'])).
     ...        subquery()
     ... )
     >>> user_alias = aliased(User, user_address_subq, name="user")
     >>> address_alias = aliased(Address, user_address_subq, name="address")
     >>> stmt = select(user_alias, address_alias).where(user_alias.name == 'sandy')
     >>> for row in session.execute(stmt):
     ...     print(f"{row.user} {row.address}")
     {opensql}SELECT anon_1.id, anon_1.name, anon_1.id_1, anon_1.email_address
     FROM (SELECT user_account.id AS id, user_account.name AS name, address.id AS id_1, address.email_address AS email_address
     FROM user_account JOIN address ON user_account.id = address.user_id
     WHERE address.email_address IN (?, ?)) AS anon_1
     WHERE anon_1.name = ?
     [...] ('pat999@aol.com', 'squirrel@squirrelpower.org', 'sandy'){stop}
     User(id=2, name='sandy', fullname='Sandy Cheeks') Address(id=3, email_address='squirrel@squirrelpower.org')

3.4.1.14 Controlling what to Join From
......................................

In cases where the left side of the current state of Select
is not in line with what we want to join from, the
Select.join_from() method may be used:

     >>> stmt = select(Address).join_from(User, User.addresses).where(User.name == 'sandy')
     >>> print(stmt)
     SELECT address.id, address.user_id, address.email_address
     FROM user_account JOIN address ON user_account.id = address.user_id
     WHERE user_account.name = :name_1

The Select.join_from() method accepts two or three
arguments, either in the form ‘<join from>, <onclause>’, or ‘<join
from>, <join to>, [<onclause>]’:

     >>> stmt = select(Address).join_from(User, Address).where(User.name == 'sandy')
     >>> print(stmt)
     SELECT address.id, address.user_id, address.email_address
     FROM user_account JOIN address ON user_account.id = address.user_id
     WHERE user_account.name = :name_1

To set up the initial FROM clause for a SELECT such that
Select.join() can be used subsequent, the
Select.select_from() method may also be used:

     >>> stmt = select(Address).select_from(User).join(User.addresses).where(User.name == 'sandy')
     >>> print(stmt)
     SELECT address.id, address.user_id, address.email_address
     FROM user_account JOIN address ON user_account.id = address.user_id
     WHERE user_account.name = :name_1

3.4.1.15 Special Relationship Operators
.......................................

As detailed in the SQLAlchemy 1.4 / 2.0 Tutorial at
Using Relationships in Queries, ORM attributes mapped by
relationship() may be used in a variety of ways as SQL construction
helpers.  In addition to the above documentation on Joins,
relationships may produce criteria to be used in the WHERE clause as
well.  See the linked sections below.

See also
........

Sections in the Working with Related Objects section of the
SQLAlchemy 1.4 / 2.0 Tutorial:

   * EXISTS forms; has() / any(). - helpers to generate
     EXISTS clauses using relationship().

   * Common Relationship Operators. - helpers to create
     comparisons in terms of a relationship() in reference to
     a specific object instance

3.4.1.16 ORM Loader Options
...........................

Loader options are objects that are passed to the
Select.options() method which affect the loading of both column
and relationship-oriented attributes.  The majority of loader options
descend from the Load hierarchy.  For a complete overview of
using loader options, see the linked sections below.

See also
........

   * Loading Columns. - details mapper and loading options
     that affect how column and SQL-expression mapped attributes are
     loaded

   * Relationship Loading Techniques. - details relationship
     and loading options that affect how relationship()
     mapped attributes are loaded

3.4.1.17 ORM Execution Options
..............................

Execution options are keyword arguments that are passed to an
“execution_options” method, which take place at the level of statement
execution.  The primary “execution option” method is in Core at
Connection.execution_options().  In the ORM, execution options may
also be passed to Session.execute() using the
Session.execute.execution_options parameter.  Perhaps more
succinctly, most execution options, including those specific to the ORM,
can be assigned to a statement directly, using the
Executable.execution_options() method, so that the options may be
associated directly with the statement instead of being configured
separately.  The examples below will use this form.

3.4.1.18 Populate Existing
..........................

The ‘populate_existing’ execution option ensures that for all rows
loaded, the corresponding instances in the Session will be
fully refreshed, erasing any existing data within the objects (including
pending changes) and replacing with the data loaded from the result.

Example use looks like:

     >>> stmt = select(User).execution_options(populate_existing=True)
     {sql}>>> result = session.execute(stmt)
     SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     ...

Normally, ORM objects are only loaded once, and if they are matched up
to the primary key in a subsequent result row, the row is not applied to
the object.  This is both to preserve pending, unflushed changes on the
object as well as to avoid the overhead and complexity of refreshing
data which is already there.  The Session assumes a default
working model of a highly isolated transaction, and to the degree that
data is expected to change within the transaction outside of the local
changes being made, those use cases would be handled using explicit
steps such as this method.

Another use case for ‘populate_existing’ is in support of various
attribute loading features that can change how an attribute is loaded on
a per-query basis.  Options for which this apply include:

   * The with_expression() option

   * The PropComparator.and_() method that can modify what a
     loader strategy loads

   * The contains_eager() option

   * The with_loader_criteria() option

The ‘populate_existing’ execution option is equvialent to the
Query.populate_existing() method in 1.x style ORM queries.

See also
........

See I’m re-loading data with my Session but it isn’t seeing changes that I committed elsewhere.
- in Frequently Asked Questions.

See Refreshing / Expiring. - in the ORM Session
documentation

3.4.1.19 Autoflush
..................

This option when passed as ‘False’ will cause the Session to
not invoke the “autoflush” step.  It’s equivalent to using the
Session.no_autoflush context manager to disable autoflush:

     >>> stmt = select(User).execution_options(autoflush=False)
     {sql}>>> session.execute(stmt)
     SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     ...

This option will also work on ORM-enabled Update and
Delete queries.

The ‘autoflush’ execution option is equvialent to the
Query.autoflush() method in 1.x style ORM queries.

See also
........

See Flushing.

3.4.1.20 Yield Per
..................

The ‘yield_per’ execution option is an integer value which will cause
the Result to yield only a fixed count of rows at a time.  It
is often useful to use with a result partitioning method such as
Result.partitions(), e.g.:

     >>> stmt = select(User).execution_options(yield_per=10)
     {sql}>>> for partition in session.execute(stmt).partitions(10):
     ...     for row in partition:
     ...         print(row)
     SELECT user_account.id, user_account.name, user_account.fullname
     FROM user_account
     [...] (){stop}
     (User(id=1, name='spongebob', fullname='Spongebob Squarepants'),)
     ...

The purpose of this method is when fetching very large result sets (>
10K rows), to batch results in sub-collections and yield them out
partially, so that the Python interpreter doesn’t need to declare very
large areas of memory which is both time consuming and leads to
excessive memory use.  The performance from fetching hundreds of
thousands of rows can often double when a suitable yield-per setting
(e.g.  approximately 1000) is used, even with DBAPIs that buffer rows
(which are most).

When ‘yield_per’ is used, the
Connection.execution_options.stream_results option is also set for
the Core execution, so that a streaming / server side cursor will be
used if the backend supports it (1)

The ‘yield_per’ execution option `is not compatible with subqueryload
eager loading or joinedload eager loading when using collections'.  It
is potentially compatible with selectinload eager loading, `provided the
database driver supports multiple, independent cursors' (2) .

The ‘yield_per’ execution option is equvialent to the
Query.yield_per() method in 1.x style ORM queries.

See also
........

See Using Server Side Cursors (a.k.a. stream results).

   ---------- Footnotes ----------

   (1) (1) currently known are psycopg2, mysqldb
and pymysql.  Other backends will pre buffer all rows.  The
memory use of raw database rows is much less than that of an ORM-mapped
object, but should still be taken into consideration when benchmarking.

   (2) (2) the psycopg2 and pysqlite drivers are
known to work, drivers for MySQL and SQL Server ODBC drivers do not.

3.4.1.21 ORM Update / Delete with Arbitrary WHERE clause
........................................................

The Session.execute() method, in addition to handling
ORM-enabled Select objects, can also accommodate ORM-enabled
Update and Delete objects, which UPDATE or DELETE
any number of database rows while also being able to synchronize the
state of matching objects locally present in the Session.  See
the section UPDATE and DELETE with arbitrary WHERE clause
for background on this feature.

3.4.2 Loading Columns
---------------------

This section presents additional options regarding the loading of
columns.

3.4.2.1 Deferred Column Loading
...............................

Deferred column loading allows particular columns of a table be loaded
only upon direct access, instead of when the entity is queried using
Query.  This feature is useful when one wants to avoid
loading a large text or binary field into memory when it’s not needed.
Individual columns can be lazy loaded by themselves or placed into
groups that lazy-load together, using the deferred()
function to mark them as “deferred”.  In the example below, we define a
mapping that will load each of ‘.excerpt’ and ‘.photo’ in separate,
individual-row SELECT statements when each attribute is first referenced
on the individual object instance:

     from sqlalchemy.orm import deferred
     from sqlalchemy import Integer, String, Text, Binary, Column

     class Book(Base):
         __tablename__ = 'book'

         book_id = Column(Integer, primary_key=True)
         title = Column(String(200), nullable=False)
         summary = Column(String(2000))
         excerpt = deferred(Column(Text))
         photo = deferred(Column(Binary))

Classical mappings as always place the usage of deferred()
in the ‘properties’ dictionary against the table-bound Column:

     mapper_registry.map_imperatively(Book, book_table, properties={
         'photo':deferred(book_table.c.photo)
     })

Deferred columns can be associated with a “group” name, so that they
load together when any of them are first accessed.  The example below
defines a mapping with a ‘photos’ deferred group.  When one ‘.photo’ is
accessed, all three photos will be loaded in one SELECT statement.  The
‘.excerpt’ will be loaded separately when it is accessed:

     class Book(Base):
         __tablename__ = 'book'

         book_id = Column(Integer, primary_key=True)
         title = Column(String(200), nullable=False)
         summary = Column(String(2000))
         excerpt = deferred(Column(Text))
         photo1 = deferred(Column(Binary), group='photos')
         photo2 = deferred(Column(Binary), group='photos')
         photo3 = deferred(Column(Binary), group='photos')

3.4.2.2 Deferred Column Loader Query Options
............................................

Columns can be marked as “deferred” or reset to “undeferred” at query
time using options which are passed to the Query.options()
method; the most basic query options are defer() and
undefer():

     from sqlalchemy.orm import defer
     from sqlalchemy.orm import undefer

     query = session.query(Book)
     query = query.options(defer('summary'), undefer('excerpt'))
     query.all()

Above, the “summary” column will not load until accessed, and the
“excerpt” column will load immediately even if it was mapped as a
“deferred” column.

deferred() attributes which are marked with a “group” can be
undeferred using undefer_group(), sending in the group name:

     from sqlalchemy.orm import undefer_group

     query = session.query(Book)
     query.options(undefer_group('photos')).all()

3.4.2.3 Deferred Loading across Multiple Entities
.................................................

To specify column deferral for a Query that loads multiple
types of entities at once, the deferral options may be specified more
explicitly using class-bound attributes, rather than string names:

     from sqlalchemy.orm import defer

     query = session.query(Book, Author).join(Book.author)
     query = query.options(defer(Author.bio))

Column deferral options may also indicate that they take place along
various relationship paths, which are themselves often eagerly loaded
with loader options.  All relationship-bound loader options
support chaining onto additional loader options, which include loading
for further levels of relationships, as well as onto column-oriented
attributes at that path.  Such as, to load ‘Author’ instances, then
joined-eager-load the ‘Author.books’ collection for each author, then
apply deferral options to column-oriented attributes onto each ‘Book’
entity from that relationship, the joinedload() loader
option can be combined with the load_only() option
(described later in this section) to defer all ‘Book’ columns except
those explicitly specified:

     from sqlalchemy.orm import joinedload

     query = session.query(Author)
     query = query.options(
                 joinedload(Author.books).load_only(Book.summary, Book.excerpt),
             )

Option structures as above can also be organized in more complex ways,
such as hierarchically using the Load.options() method,
which allows multiple sub-options to be chained to a common parent
option at once.  Any mixture of string names and class-bound attribute
objects may be used:

     from sqlalchemy.orm import defer
     from sqlalchemy.orm import joinedload
     from sqlalchemy.orm import load_only

     query = session.query(Author)
     query = query.options(
                 joinedload(Author.book).options(
                     load_only("summary", "excerpt"),
                     joinedload(Book.citations).options(
                         joinedload(Citation.author),
                         defer(Citation.fulltext)
                     )
                 )
             )

New in version 1.3.6: Added Load.options() to allow easier
construction of hierarchies of loader options.

Another way to apply options to a path is to use the
defaultload() function.  This function is used to indicate a
particular path within a loader option structure without actually
setting any options at that level, so that further sub-options may be
applied.  The defaultload() function can be used to create
the same structure as we did above using Load.options() as:

     query = session.query(Author)
     query = query.options(
         joinedload(Author.book).load_only("summary", "excerpt"),
         defaultload(Author.book).joinedload(Book.citations).joinedload(Citation.author),
         defaultload(Author.book).defaultload(Book.citations).defer(Citation.fulltext)
     )

See also
........

See Relationship Loading with Loader Options. - targeted towards
relationship loading

3.4.2.4 Load Only and Wildcard Options
......................................

The ORM loader option system supports the concept of “wildcard” loader
options, in which a loader option can be passed an asterisk ‘"*"’ to
indicate that a particular option should apply to all applicable
attributes of a mapped class.  Such as, if we wanted to load the ‘Book’
class but only the “summary” and “excerpt” columns, we could say:

     from sqlalchemy.orm import defer
     from sqlalchemy.orm import undefer

     session.query(Book).options(
         defer('*'), undefer("summary"), undefer("excerpt"))

Above, the defer() option is applied using a wildcard to all
column attributes on the ‘Book’ class.  Then, the undefer()
option is used against the “summary” and “excerpt” fields so that they
are the only columns loaded up front.  A query for the above entity will
include only the “summary” and “excerpt” fields in the SELECT, along
with the primary key columns which are always used by the ORM.

A similar function is available with less verbosity by using the
load_only() option.  This is a so-called `exclusionary' option
which will apply deferred behavior to all column attributes except those
that are named:

     from sqlalchemy.orm import load_only

     session.query(Book).options(load_only("summary", "excerpt"))

3.4.2.5 Wildcard and Exclusionary Options with Multiple-Entity Queries
......................................................................

Wildcard options and exclusionary options such as load_only()
may only be applied to a single entity at a time within a
Query.  To suit the less common case where a Query is
returning multiple primary entities at once, a special calling style may
be required in order to apply a wildcard or exclusionary option, which
is to use the Load object to indicate the starting entity
for a deferral option.  Such as, if we were loading ‘Book’ and ‘Author’
at once, the Query will raise an informative error if we try
to apply load_only() to both at once.  Using Load
looks like:

     from sqlalchemy.orm import Load

     query = session.query(Book, Author).join(Book.author)
     query = query.options(
                 Load(Book).load_only("summary", "excerpt")
             )

Above, see Load is used in conjunction with the exclusionary
option load_only() so that the deferral of all other columns
only takes place for the ‘Book’ class and not the ‘Author’ class.
Again, the Query object should raise an informative error
message when the above calling style is actually required that describes
those cases where explicit use of Load is needed.

3.4.2.6 Raiseload for Deferred Columns
......................................

New in version 1.4.

The deferred() loader option and the corresponding loader
strategy also support the concept of “raiseload”, which is a loader
strategy that will raise InvalidRequestError if the
attribute is accessed such that it would need to emit a SQL query in
order to be loaded.  This behavior is the column-based equivalent of the
raiseload() feature for relationship loading, discussed at
Preventing unwanted lazy loads using raiseload.  Using the
defer.raiseload parameter on the defer() option,
an exception is raised if the attribute is accessed:

     book = session.query(Book).options(defer(Book.summary, raiseload=True)).first()

     # would raise an exception
     book.summary

Deferred “raiseload” can be configured at the mapper level via
deferred.raiseload on deferred(), so that an explicit
undefer() is required in order for the attribute to be
usable:

     class Book(Base):
         __tablename__ = 'book'

         book_id = Column(Integer, primary_key=True)
         title = Column(String(200), nullable=False)
         summary = deferred(Column(String(2000)), raiseload=True)
         excerpt = deferred(Column(Text), raiseload=True)

     book_w_excerpt = session.query(Book).options(undefer(Book.excerpt)).first()

3.4.2.7 Column Deferral API
...........................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See defer.(key,Indicate that the given column-oriented attribute should be deferred, e.g.  not loaded until
*addl_attrs,   accessed.
**kw)

See deferred.(*columns,Indicate a column-based mapped attribute that by default will not load unless accessed.
**kw)

See load_only.(*attrs)Indicate that for a particular entity, only the given list of column-based attribute names
               should be loaded; all others will be deferred.

See query_expression.([default_expr])Indicate an attribute that populates from a query-time SQL expression.

See undefer.(key,Indicate that the given column-oriented attribute should be undeferred, e.g.  specified
*addl_attrs)   within the SELECT statement of the entity as a whole.

See undefer_group.(name)Indicate that columns within the given deferred group name should be undeferred.

See with_expression.(key,Apply an ad-hoc SQL expression to a “deferred expression” attribute.
expression)

 -- Function: sqlalchemy.orm.defer (key, *addl_attrs, **kw)

     Indicate that the given column-oriented attribute should be
     deferred, e.g.  not loaded until accessed.

     This function is part of the Load interface and
     supports both method-chained and standalone operation.

     e.g.:

          from sqlalchemy.orm import defer

          session.query(MyClass).options(
                              defer("attribute_one"),
                              defer("attribute_two"))

          session.query(MyClass).options(
                              defer(MyClass.attribute_one),
                              defer(MyClass.attribute_two))

     To specify a deferred load of an attribute on a related class, the
     path can be specified one token at a time, specifying the loading
     style for each link along the chain.  To leave the loading style
     for a link unchanged, use defaultload():

          session.query(MyClass).options(defaultload("someattr").defer("some_column"))

     A Load object that is present on a certain path can
     have Load.defer() called multiple times, each will
     operate on the same parent entity:

          session.query(MyClass).options(
                          defaultload("someattr").
                              defer("some_column").
                              defer("some_other_column").
                              defer("another_column")
              )

     Parameters:

        * ‘key’ – Attribute to be deferred.

        * ‘raiseload’ – raise InvalidRequestError if the
          column value is to be loaded from emitting SQL. Used to
          prevent unwanted SQL from being emitted.

          New in version 1.4.

          See also
          ........

          See Raiseload for Deferred Columns.

        * ‘*addl_attrs’ – This option supports the old 0.8 style of
          specifying a path as a series of attributes, which is now
          superseded by the method-chained style.

               Deprecated since version 0.9: The *addl_attrs on
               defer() is deprecated and will be removed in a
               future release.  Please use method chaining in
               conjunction with defaultload() to indicate a path.

     See also
     ........

     See Deferred Column Loading.

     See undefer().

 -- Function: sqlalchemy.orm.deferred (*columns, **kw)

     Indicate a column-based mapped attribute that by default will not
     load unless accessed.

     Parameters:

        * ‘*columns’ – columns to be mapped.  This is typically a single
          Column object, however a collection is supported in
          order to support multiple columns mapped under the same
          attribute.

        * ‘raiseload’ – boolean, if True, indicates an exception should
          be raised if the load operation is to take place.

          New in version 1.4.

          See also
          ........

          See Raiseload for Deferred Columns.

        * ‘**kw’ – additional keyword arguments passed to
          ColumnProperty.

     See also
     ........

     See Deferred Column Loading.

 -- Function: sqlalchemy.orm.query_expression
          (default_expr=<sqlalchemy.sql.elements.Null object>)

     Indicate an attribute that populates from a query-time SQL
     expression.

     Parameters: ‘default_expr’ – Optional SQL expression object that
     will be used in all cases if not assigned later with
     with_expression().  E.g.:

          from sqlalchemy.sql import literal

          class C(Base):
              #...
              my_expr = query_expression(literal(1))

     New in version 1.3.18.

     New in version 1.2.

     See also
     ........

     See Query-time SQL expressions as mapped attributes.

 -- Function: sqlalchemy.orm.load_only (*attrs)

     Indicate that for a particular entity, only the given list of
     column-based attribute names should be loaded; all others will be
     deferred.

     This function is part of the Load interface and
     supports both method-chained and standalone operation.

     Example - given a class ‘User’, load only the ‘name’ and ‘fullname’
     attributes:

          session.query(User).options(load_only("name", "fullname"))

     Example - given a relationship ‘User.addresses -> Address’, specify
     subquery loading for the ‘User.addresses’ collection, but on each
     ‘Address’ object load only the ‘email_address’ attribute:

          session.query(User).options(
                  subqueryload("addresses").load_only("email_address")
          )

     For a Query that has multiple entities, the lead entity
     can be specifically referred to using the Load
     constructor:

             session.query(User, Address).join(User.addresses).options(
                         Load(User).load_only("name", "fullname"),
                         Load(Address).load_only("email_address")
                     )

          .. note:: This method will still load a :class:`_schema.Column` even
             if the column property is defined with ``deferred=True``
             for the :func:`.column_property` function.

     New in version 0.9.0.

 -- Function: sqlalchemy.orm.undefer (key, *addl_attrs)

     Indicate that the given column-oriented attribute should be
     undeferred, e.g.  specified within the SELECT statement of the
     entity as a whole.

     The column being undeferred is typically set up on the mapping as a
     deferred() attribute.

     This function is part of the Load interface and
     supports both method-chained and standalone operation.

     Examples:

          # undefer two columns
          session.query(MyClass).options(undefer("col1"), undefer("col2"))

          # undefer all columns specific to a single class using Load + *
          session.query(MyClass, MyOtherClass).options(
              Load(MyClass).undefer("*"))

          # undefer a column on a related object
          session.query(MyClass).options(
              defaultload(MyClass.items).undefer('text'))

     Parameters:

        * ‘key’ – Attribute to be undeferred.

        * ‘*addl_attrs’ – This option supports the old 0.8 style of
          specifying a path as a series of attributes, which is now
          superseded by the method-chained style.

               Deprecated since version 0.9: The *addl_attrs on
               undefer() is deprecated and will be removed in a
               future release.  Please use method chaining in
               conjunction with defaultload() to indicate a path.

     See also
     ........

     See Deferred Column Loading.

     See defer().

     See undefer_group().

 -- Function: sqlalchemy.orm.undefer_group (name)

     Indicate that columns within the given deferred group name should
     be undeferred.

     The columns being undeferred are set up on the mapping as
     deferred() attributes and include a “group” name.

     E.g:

          session.query(MyClass).options(undefer_group("large_attrs"))

     To undefer a group of attributes on a related entity, the path can
     be spelled out using relationship loader options, such as
     defaultload():

          session.query(MyClass).options(
              defaultload("someattr").undefer_group("large_attrs"))

     Changed in version 0.9.0: undefer_group() is now
     specific to a particular entity load path.

     See also
     ........

     See Deferred Column Loading.

     See defer().

     See undefer().

 -- Function: sqlalchemy.orm.with_expression (key, expression)

     Apply an ad-hoc SQL expression to a “deferred expression”
     attribute.

     This option is used in conjunction with the
     query_expression() mapper-level construct that indicates an
     attribute which should be the target of an ad-hoc SQL expression.

     E.g.:

          sess.query(SomeClass).options(
              with_expression(SomeClass.x_y_expr, SomeClass.x + SomeClass.y)
          )

     New in version 1.2.

     Parameters:

        * ‘key’ – Attribute to be undeferred.

        * ‘expr’ – SQL expression to be applied to the attribute.

          Note: the target attribute is populated only if the target
          object is `not currently loaded' in the current Session
          unless the Query.populate_existing() method is
          used.  Please refer to Query-time SQL expressions as mapped attributes
          for complete usage details.

     See also
     ........

     See Query-time SQL expressions as mapped attributes.

3.4.2.8 Column Bundles
......................

The Bundle may be used to query for groups of columns under
one namespace.

The bundle allows columns to be grouped together:

     from sqlalchemy.orm import Bundle

     bn = Bundle('mybundle', MyClass.data1, MyClass.data2)
     for row in session.query(bn).filter(bn.c.data1 == 'd1'):
         print(row.mybundle.data1, row.mybundle.data2)

The bundle can be subclassed to provide custom behaviors when results
are fetched.  The method Bundle.create_row_processor() is
given the statement object and a set of “row processor” functions at
query execution time; these processor functions when given a result row
will return the individual attribute value, which can then be adapted
into any kind of return data structure.  Below illustrates replacing the
usual Row return structure with a straight Python dictionary:

     from sqlalchemy.orm import Bundle

     class DictBundle(Bundle):
         def create_row_processor(self, query, procs, labels):
             """Override create_row_processor to return values as dictionaries"""
             def proc(row):
                 return dict(
                             zip(labels, (proc(row) for proc in procs))
                         )
             return proc

     Note: The Bundle construct only applies to column
     expressions.  It does not apply to ORM attributes mapped using
     relationship().

Changed in version 1.0: The ‘proc()’ callable passed to the
‘create_row_processor()’ method of custom Bundle classes now
accepts only a single “row” argument.

A result from the above bundle will return dictionary values:

     bn = DictBundle('mybundle', MyClass.data1, MyClass.data2)
     for row in session.query(bn).filter(bn.c.data1 == 'd1'):
         print(row.mybundle['data1'], row.mybundle['data2'])

The Bundle construct is also integrated into the behavior of
composite(), where it is used to return composite attributes
as objects when queried as individual attributes.

3.4.3 Relationship Loading Techniques
-------------------------------------

A big part of SQLAlchemy is providing a wide range of control over how
related objects get loaded when querying.  By “related objects” we refer
to collections or scalar associations configured on a mapper using
relationship().  This behavior can be configured at mapper
construction time using the relationship.lazy parameter to
the relationship() function, as well as by using options with
the Query object.

The loading of relationships falls into three categories; `lazy'
loading, `eager' loading, and `no' loading.  Lazy loading refers to
objects are returned from a query without the related objects loaded at
first.  When the given collection or reference is first accessed on a
particular object, an additional SELECT statement is emitted such that
the requested collection is loaded.

Eager loading refers to objects returned from a query with the related
collection or scalar reference already loaded up front.  The
Query achieves this either by augmenting the SELECT statement it
would normally emit with a JOIN to load in related rows simultaneously,
or by emitting additional SELECT statements after the primary one to
load collections or scalar references at once.

“No” loading refers to the disabling of loading on a given relationship,
either that the attribute is empty and is just never loaded, or that it
raises an error when it is accessed, in order to guard against unwanted
lazy loads.

The primary forms of relationship loading are:

   * `lazy loading' - available via ‘lazy='select'’ or the
     lazyload() option, this is the form of loading that emits a
     SELECT statement at attribute access time to lazily load a related
     reference on a single object at a time.  Lazy loading is detailed
     at Lazy Loading.

   * `joined loading' - available via ‘lazy='joined'’ or the
     joinedload() option, this form of loading applies a JOIN to
     the given SELECT statement so that related rows are loaded in the
     same result set.  Joined eager loading is detailed at Joined Eager Loading.

   * `subquery loading' - available via ‘lazy='subquery'’ or the
     subqueryload() option, this form of loading emits a second
     SELECT statement which re-states the original query embedded inside
     of a subquery, then JOINs that subquery to the related table to be
     loaded to load all members of related collections / scalar
     references at once.  Subquery eager loading is detailed at
     Subquery Eager Loading.

   * `select IN loading' - available via ‘lazy='selectin'’ or the
     selectinload() option, this form of loading emits a second
     (or more) SELECT statement which assembles the primary key
     identifiers of the parent objects into an IN clause, so that all
     members of related collections / scalar references are loaded at
     once by primary key.  Select IN loading is detailed at Select IN loading.

   * `raise loading' - available via ‘lazy='raise'’,
     ‘lazy='raise_on_sql'’, or the raiseload() option, this
     form of loading is triggered at the same time a lazy load would
     normally occur, except it raises an ORM exception in order to guard
     against the application making unwanted lazy loads.  An
     introduction to raise loading is at Preventing unwanted lazy loads using raiseload.

   * `no loading' - available via ‘lazy='noload'’, or the
     noload() option; this loading style turns the attribute into
     an empty attribute (‘None’) that will never load or have any
     loading effect.  “noload” is a fairly uncommon loader option.

3.4.3.1 Configuring Loader Strategies at Mapping Time
.....................................................

The loader strategy for a particular relationship can be configured at
mapping time to take place in all cases where an object of the mapped
type is loaded, in the absence of any query-level options that modify
it.  This is configured using the relationship.lazy
parameter to relationship(); common values for this parameter
include ‘select’, ‘joined’, ‘subquery’ and ‘selectin’.

For example, to configure a relationship to use joined eager loading
when the parent object is queried:

     class Parent(Base):
         __tablename__ = 'parent'

         id = Column(Integer, primary_key=True)
         children = relationship("Child", lazy='joined')

Above, whenever a collection of ‘Parent’ objects are loaded, each
‘Parent’ will also have its ‘children’ collection populated, using rows
fetched by adding a JOIN to the query for ‘Parent’ objects.  See
Joined Eager Loading for background on this style of loading.

The default value of the relationship.lazy argument is
‘"select"’, which indicates lazy loading.  See Lazy Loading
for further background.

3.4.3.2 Relationship Loading with Loader Options
................................................

The other, and possibly more common way to configure loading strategies
is to set them up on a per-query basis against specific attributes using
the Query.options() method.  Very detailed control over
relationship loading is available using loader options; the most common
are joinedload(), subqueryload(),
selectinload() and lazyload().  The option accepts
either the string name of an attribute against a parent, or for greater
specificity can accommodate a class-bound attribute directly:

     # set children to load lazily
     session.query(Parent).options(lazyload(Parent.children)).all()

     # set children to load eagerly with a join
     session.query(Parent).options(joinedload(Parent.children)).all()

The loader options can also be “chained” using `method chaining' to
specify how loading should occur further levels deep:

     session.query(Parent).options(
         joinedload(Parent.children).
         subqueryload(Child.subelements)).all()

Chained loader options can be applied against a “lazy” loaded
collection.  This means that when a collection or association is lazily
loaded upon access, the specified option will then take effect:

     session.query(Parent).options(
         lazyload(Parent.children).
         subqueryload(Child.subelements)).all()

Above, the query will return ‘Parent’ objects without the ‘children’
collections loaded.  When the ‘children’ collection on a particular
‘Parent’ object is first accessed, it will lazy load the related
objects, but additionally apply eager loading to the ‘subelements’
collection on each member of ‘children’.

The above examples, using Query, are now referred to as 1.x
style queries.  The options system is available as well for 2.0 style
queries using the Select.options() method:

     stmt = select(Parent).options(
           lazyload(Parent.children).
           subqueryload(Child.subelements))

     result = session.execute(stmt)

Under the hood, see Query is ultimately using the above
select based mechanism.

3.4.3.3 Adding Criteria to loader options
.........................................

The relationship attributes used to indicate loader options include the
ability to add additional filtering criteria to the ON clause of the
join that’s created, or to the WHERE criteria involved, depending on the
loader strategy.  This can be achieved using the
PropComparator.and_() method which will pass through an option
such that loaded results are limited to the given filter criteria:

     session.query(A).options(lazyload(A.bs.and_(B.id > 5)))

When using limiting criteria, if a particular collection is already
loaded it won’t be refreshed; to ensure the new criteria takes place,
apply the Query.populate_existing() option:

     session.query(A).options(lazyload(A.bs.and_(B.id > 5))).populate_existing()

In order to add filtering criteria to all occurrences of an entity
throughout a query, regardless of loader strategy or where it occurs in
the loading process, see the with_loader_criteria()
function.

New in version 1.4.

3.4.3.4 Specifying Sub-Options with Load.options()
..................................................

Using method chaining, the loader style of each link in the path is
explicitly stated.  To navigate along a path without changing the
existing loader style of a particular attribute, the
defaultload() method/function may be used:

     session.query(A).options(
         defaultload(A.atob).
         joinedload(B.btoc)).all()

A similar approach can be used to specify multiple sub-options at once,
using the Load.options() method:

     session.query(A).options(
         defaultload(A.atob).options(
           joinedload(B.btoc),
           joinedload(B.btod)
         )).all()

New in version 1.3.6: added Load.options().

See also
........

See Deferred Loading across Multiple Entities. - illustrates
examples of combining relationship and column-oriented loader options.

     Note: The loader options applied to an object’s lazy-loaded
     collections are `“sticky”' to specific object instances, meaning
     they will persist upon collections loaded by that specific object
     for as long as it exists in memory.  For example, given the
     previous example:

          session.query(Parent).options(
              lazyload(Parent.children).
              subqueryload(Child.subelements)).all()

     if the ‘children’ collection on a particular ‘Parent’ object loaded
     by the above query is expired (such as when a Session
     object’s transaction is committed or rolled back, or
     Session.expire_all() is used), when the ‘Parent.children’
     collection is next accessed in order to re-load it, the
     ‘Child.subelements’ collection will again be loaded using subquery
     eager loading.This stays the case even if the above ‘Parent’ object
     is accessed from a subsequent query that specifies a different set
     of options.To change the options on an existing object without
     expunging it and re-loading, they must be set explicitly in
     conjunction with the Query.populate_existing() method:

          # change the options on Parent objects that were already loaded
          session.query(Parent).populate_existing().options(
              lazyload(Parent.children).
              lazyload(Child.subelements)).all()

     If the objects loaded above are fully cleared from the
     Session, such as due to garbage collection or that
     Session.expunge_all() were used, the “sticky” options will
     also be gone and the newly created objects will make use of new
     options if loaded again.

     A future SQLAlchemy release may add more alternatives to
     manipulating the loader options on already-loaded objects.

3.4.3.5 Lazy Loading
....................

By default, all inter-object relationships are `lazy loading'.  The
scalar or collection attribute associated with a relationship()
contains a trigger which fires the first time the attribute is
accessed.  This trigger typically issues a SQL call at the point of
access in order to load the related object or objects:

     >>> jack.addresses
     {opensql}SELECT
         addresses.id AS addresses_id,
         addresses.email_address AS addresses_email_address,
         addresses.user_id AS addresses_user_id
     FROM addresses
     WHERE ? = addresses.user_id
     [5]
     {stop}[<Address(u'jack@google.com')>, <Address(u'j25@yahoo.com')>]

The one case where SQL is not emitted is for a simple many-to-one
relationship, when the related object can be identified by its primary
key alone and that object is already present in the current
Session.  For this reason, while lazy loading can be expensive for
related collections, in the case that one is loading lots of objects
with simple many-to-ones against a relatively small set of possible
target objects, lazy loading may be able to refer to these objects
locally without emitting as many SELECT statements as there are parent
objects.

This default behavior of “load upon attribute access” is known as “lazy”
or “select” loading - the name “select” because a “SELECT” statement is
typically emitted when the attribute is first accessed.

Lazy loading can be enabled for a given attribute that is normally
configured in some other way using the lazyload() loader
option:

     from sqlalchemy.orm import lazyload

     # force lazy loading for an attribute that is set to
     # load some other way normally
     session.query(User).options(lazyload(User.addresses))

3.4.3.6 Preventing unwanted lazy loads using raiseload
......................................................

The lazyload() strategy produces an effect that is one of
the most common issues referred to in object relational mapping; the N
plus one problem, which states that for any N objects loaded, accessing
their lazy-loaded attributes means there will be N+1 SELECT statements
emitted.  In SQLAlchemy, the usual mitigation for the N+1 problem is to
make use of its very capable eager load system.  However, eager loading
requires that the attributes which are to be loaded be specified with
the Query up front.  The problem of code that may access
other attributes that were not eagerly loaded, where lazy loading is not
desired, may be addressed using the raiseload() strategy;
this loader strategy replaces the behavior of lazy loading with an
informative error being raised:

     from sqlalchemy.orm import raiseload
     session.query(User).options(raiseload(User.addresses))

Above, a ‘User’ object loaded from the above query will not have the
‘.addresses’ collection loaded; if some code later on attempts to access
this attribute, an ORM exception is raised.

raiseload() may be used with a so-called “wildcard”
specifier to indicate that all relationships should use this strategy.
For example, to set up only one attribute as eager loading, and all the
rest as raise:

     session.query(Order).options(
         joinedload(Order.items), raiseload('*'))

The above wildcard will apply to `all' relationships not just on ‘Order’
besides ‘items’, but all those on the ‘Item’ objects as well.  To set up
raiseload() for only the ‘Order’ objects, specify a full
path with Load:

     from sqlalchemy.orm import Load

     session.query(Order).options(
         joinedload(Order.items), Load(Order).raiseload('*'))

Conversely, to set up the raise for just the ‘Item’ objects:

     session.query(Order).options(
         joinedload(Order.items).raiseload('*'))

The raiseload() option applies only to relationship
attributes.  For column-oriented attributes, the defer()
option supports the defer.raiseload option which works in
the same way.

Changed in version 1.4.0: The “raiseload” strategies `do not take place'
within the unit of work flush process, as of SQLAlchemy 1.4.0.  This
means that if the unit of work needs to load a particular attribute in
order to complete its work, it will perform the load.  It’s not always
easy to prevent a particular relationship load from occurring within the
UOW process particularly with less common kinds of relationships.  The
lazy=”raise” case is more intended for explicit attribute access within
the application space.

See also
........

See Wildcard Loading Strategies.

See Raiseload for Deferred Columns.

3.4.3.7 Joined Eager Loading
............................

Joined eager loading is the most fundamental style of eager loading in
the ORM. It works by connecting a JOIN (by default a LEFT OUTER join) to
the SELECT statement emitted by a Query and populates the
target scalar/collection from the same result set as that of the parent.

At the mapping level, this looks like:

     class Address(Base):
         # ...

         user = relationship(User, lazy="joined")

Joined eager loading is usually applied as an option to a query, rather
than as a default loading option on the mapping, in particular when used
for collections rather than many-to-one-references.  This is achieved
using the joinedload() loader option:

     >>> jack = session.query(User).\
     ... options(joinedload(User.addresses)).\
     ... filter_by(name='jack').all()
     {opensql}SELECT
         addresses_1.id AS addresses_1_id,
         addresses_1.email_address AS addresses_1_email_address,
         addresses_1.user_id AS addresses_1_user_id,
         users.id AS users_id, users.name AS users_name,
         users.fullname AS users_fullname,
         users.nickname AS users_nickname
     FROM users
     LEFT OUTER JOIN addresses AS addresses_1
         ON users.id = addresses_1.user_id
     WHERE users.name = ?
     ['jack']

The JOIN emitted by default is a LEFT OUTER JOIN, to allow for a lead
object that does not refer to a related row.  For an attribute that is
guaranteed to have an element, such as a many-to-one reference to a
related object where the referencing foreign key is NOT NULL, the query
can be made more efficient by using an inner join; this is available at
the mapping level via the relationship.innerjoin flag:

     class Address(Base):
         # ...

         user_id = Column(ForeignKey('users.id'), nullable=False)
         user = relationship(User, lazy="joined", innerjoin=True)

At the query option level, via the joinedload.innerjoin
flag:

     session.query(Address).options(
         joinedload(Address.user, innerjoin=True))

The JOIN will right-nest itself when applied in a chain that includes an
OUTER JOIN:

     >>> session.query(User).options(
     ...     joinedload(User.addresses).
     ...     joinedload(Address.widgets, innerjoin=True)).all()
     {opensql}SELECT
         widgets_1.id AS widgets_1_id,
         widgets_1.name AS widgets_1_name,
         addresses_1.id AS addresses_1_id,
         addresses_1.email_address AS addresses_1_email_address,
         addresses_1.user_id AS addresses_1_user_id,
         users.id AS users_id, users.name AS users_name,
         users.fullname AS users_fullname,
         users.nickname AS users_nickname
     FROM users
     LEFT OUTER JOIN (
         addresses AS addresses_1 JOIN widgets AS widgets_1 ON
         addresses_1.widget_id = widgets_1.id
     ) ON users.id = addresses_1.user_id

On older versions of SQLite, the above nested right JOIN may be
re-rendered as a nested subquery.  Older versions of SQLAlchemy would
convert right-nested joins into subqueries in all cases.

3.4.3.8 Joined eager loading and result set batching
....................................................

A central concept of joined eager loading when applied to collections is
that the Query object must de-duplicate rows against the
leading entity being queried.  Such as above, if the ‘User’ object we
loaded referred to three ‘Address’ objects, the result of the SQL
statement would have had three rows; yet the Query returns
only one ‘User’ object.  As additional rows are received for a ‘User’
object just loaded in a previous row, the additional columns that refer
to new ‘Address’ objects are directed into additional results within the
‘User.addresses’ collection of that particular object.

This process is very transparent, however does imply that joined eager
loading is incompatible with “batched” query results, provided by the
Query.yield_per() method, when used for collection loading.
Joined eager loading used for scalar references is however compatible
with Query.yield_per().  The Query.yield_per()
method will result in an exception thrown if a collection based joined
eager loader is in play.

To “batch” queries with arbitrarily large sets of result data while
maintaining compatibility with collection-based joined eager loading,
emit multiple SELECT statements, each referring to a subset of rows
using the WHERE clause, e.g.  windowing.  Alternatively, consider using
“select IN” eager loading which is `potentially' compatible with
Query.yield_per(), provided that the database driver in use
supports multiple, simultaneous cursors (SQLite, PostgreSQL drivers, not
MySQL drivers or SQL Server ODBC drivers).

3.4.3.9 The Zen of Joined Eager Loading
.......................................

Since joined eager loading seems to have many resemblances to the use of
Query.join(), it often produces confusion as to when and how
it should be used.  It is critical to understand the distinction that
while Query.join() is used to alter the results of a query,
see joinedload() goes through great lengths to `not' alter the
results of the query, and instead hide the effects of the rendered join
to only allow for related objects to be present.

The philosophy behind loader strategies is that any set of loading
schemes can be applied to a particular query, and `the results don’t
change' - only the number of SQL statements required to fully load
related objects and collections changes.  A particular query might start
out using all lazy loads.  After using it in context, it might be
revealed that particular attributes or collections are always accessed,
and that it would be more efficient to change the loader strategy for
these.  The strategy can be changed with no other modifications to the
query, the results will remain identical, but fewer SQL statements would
be emitted.  In theory (and pretty much in practice), nothing you can do
to the Query would make it load a different set of primary
or related objects based on a change in loader strategy.

How joinedload() in particular achieves this result of not
impacting entity rows returned in any way is that it creates an
anonymous alias of the joins it adds to your query, so that they can’t
be referenced by other parts of the query.  For example, the query below
uses joinedload() to create a LEFT OUTER JOIN from ‘users’
to ‘addresses’, however the ‘ORDER BY’ added against
‘Address.email_address’ is not valid - the ‘Address’ entity is not named
in the query:

     >>> jack = session.query(User).\
     ... options(joinedload(User.addresses)).\
     ... filter(User.name=='jack').\
     ... order_by(Address.email_address).all()
     {opensql}SELECT
         addresses_1.id AS addresses_1_id,
         addresses_1.email_address AS addresses_1_email_address,
         addresses_1.user_id AS addresses_1_user_id,
         users.id AS users_id,
         users.name AS users_name,
         users.fullname AS users_fullname,
         users.nickname AS users_nickname
     FROM users
     LEFT OUTER JOIN addresses AS addresses_1
         ON users.id = addresses_1.user_id
     WHERE users.name = ?
     ORDER BY addresses.email_address   <-- this part is wrong !
     ['jack']

Above, ‘ORDER BY addresses.email_address’ is not valid since ‘addresses’
is not in the FROM list.  The correct way to load the ‘User’ records and
order by email address is to use Query.join():

     >>> jack = session.query(User).\
     ... join(User.addresses).\
     ... filter(User.name=='jack').\
     ... order_by(Address.email_address).all()
     {opensql}
     SELECT
         users.id AS users_id,
         users.name AS users_name,
         users.fullname AS users_fullname,
         users.nickname AS users_nickname
     FROM users
     JOIN addresses ON users.id = addresses.user_id
     WHERE users.name = ?
     ORDER BY addresses.email_address
     ['jack']

The statement above is of course not the same as the previous one, in
that the columns from ‘addresses’ are not included in the result at all.
We can add joinedload() back in, so that there are two joins
- one is that which we are ordering on, the other is used anonymously to
load the contents of the ‘User.addresses’ collection:

     >>> jack = session.query(User).\
     ... join(User.addresses).\
     ... options(joinedload(User.addresses)).\
     ... filter(User.name=='jack').\
     ... order_by(Address.email_address).all()
     {opensql}SELECT
         addresses_1.id AS addresses_1_id,
         addresses_1.email_address AS addresses_1_email_address,
         addresses_1.user_id AS addresses_1_user_id,
         users.id AS users_id, users.name AS users_name,
         users.fullname AS users_fullname,
         users.nickname AS users_nickname
     FROM users JOIN addresses
         ON users.id = addresses.user_id
     LEFT OUTER JOIN addresses AS addresses_1
         ON users.id = addresses_1.user_id
     WHERE users.name = ?
     ORDER BY addresses.email_address
     ['jack']

What we see above is that our usage of Query.join() is to
supply JOIN clauses we’d like to use in subsequent query criterion,
whereas our usage of joinedload() only concerns itself with
the loading of the ‘User.addresses’ collection, for each ‘User’ in the
result.  In this case, the two joins most probably appear redundant -
which they are.  If we wanted to use just one JOIN for collection
loading as well as ordering, we use the contains_eager()
option, described in Routing Explicit Joins/Statements into Eagerly Loaded Collections
below.  But to see why
joinedload() does what it does, consider if we were `filtering' on
a particular ‘Address’:

     >>> jack = session.query(User).\
     ... join(User.addresses).\
     ... options(joinedload(User.addresses)).\
     ... filter(User.name=='jack').\
     ... filter(Address.email_address=='someaddress@foo.com').\
     ... all()
     {opensql}SELECT
         addresses_1.id AS addresses_1_id,
         addresses_1.email_address AS addresses_1_email_address,
         addresses_1.user_id AS addresses_1_user_id,
         users.id AS users_id, users.name AS users_name,
         users.fullname AS users_fullname,
         users.nickname AS users_nickname
     FROM users JOIN addresses
         ON users.id = addresses.user_id
     LEFT OUTER JOIN addresses AS addresses_1
         ON users.id = addresses_1.user_id
     WHERE users.name = ? AND addresses.email_address = ?
     ['jack', 'someaddress@foo.com']

Above, we can see that the two JOINs have very different roles.  One
will match exactly one row, that of the join of ‘User’ and ‘Address’
where ‘Address.email_address=='someaddress@foo.com'’.  The other LEFT
OUTER JOIN will match `all' ‘Address’ rows related to ‘User’, and is
only used to populate the ‘User.addresses’ collection, for those ‘User’
objects that are returned.

By changing the usage of joinedload() to another style of
loading, we can change how the collection is loaded completely
independently of SQL used to retrieve the actual ‘User’ rows we want.
Below we change joinedload() into subqueryload():

     >>> jack = session.query(User).\
     ... join(User.addresses).\
     ... options(subqueryload(User.addresses)).\
     ... filter(User.name=='jack').\
     ... filter(Address.email_address=='someaddress@foo.com').\
     ... all()
     {opensql}SELECT
         users.id AS users_id,
         users.name AS users_name,
         users.fullname AS users_fullname,
         users.nickname AS users_nickname
     FROM users
     JOIN addresses ON users.id = addresses.user_id
     WHERE
         users.name = ?
         AND addresses.email_address = ?
     ['jack', 'someaddress@foo.com']

     # ... subqueryload() emits a SELECT in order
     # to load all address records ...

When using joined eager loading, if the query contains a modifier that
impacts the rows returned externally to the joins, such as when using
DISTINCT, LIMIT, OFFSET or equivalent, the completed statement is first
wrapped inside a subquery, and the joins used specifically for joined
eager loading are applied to the subquery.  SQLAlchemy’s joined eager
loading goes the extra mile, and then ten miles further, to absolutely
ensure that it does not affect the end result of the query, only the way
collections and related objects are loaded, no matter what the format of
the query is.

See also
........

See Routing Explicit Joins/Statements into Eagerly Loaded Collections.
- using contains_eager().

3.4.3.10 Subquery Eager Loading
...............................

Subqueryload eager loading is configured in the same manner as that of
joined eager loading; for the relationship.lazy parameter,
we would specify ‘"subquery"’ rather than ‘"joined"’, and for the option
we use the subqueryload() option rather than the
joinedload() option.

The operation of subquery eager loading is to emit a second SELECT
statement for each relationship to be loaded, across all result objects
at once.  This SELECT statement refers to the original SELECT statement,
wrapped inside of a subquery, so that we retrieve the same list of
primary keys for the primary object being returned, then link that to
the sum of all the collection members to load them at once:

     >>> jack = session.query(User).\
     ... options(subqueryload(User.addresses)).\
     ... filter_by(name='jack').all()
     {opensql}SELECT
         users.id AS users_id,
         users.name AS users_name,
         users.fullname AS users_fullname,
         users.nickname AS users_nickname
     FROM users
     WHERE users.name = ?
     ('jack',)
     SELECT
         addresses.id AS addresses_id,
         addresses.email_address AS addresses_email_address,
         addresses.user_id AS addresses_user_id,
         anon_1.users_id AS anon_1_users_id
     FROM (
         SELECT users.id AS users_id
         FROM users
         WHERE users.name = ?) AS anon_1
     JOIN addresses ON anon_1.users_id = addresses.user_id
     ORDER BY anon_1.users_id, addresses.id
     ('jack',)

The subqueryload strategy has many advantages over joined eager loading
in the area of loading collections.  First, it allows the original query
to proceed without changing it at all, not introducing in particular a
LEFT OUTER JOIN that may make it less efficient.  Secondly, it allows
for many collections to be eagerly loaded without producing a single
query that has many JOINs in it, which can be even less efficient; each
relationship is loaded in a fully separate query.  Finally, because the
additional query only needs to load the collection items and not the
lead object, it can use an inner JOIN in all cases for greater query
efficiency.

Disadvantages of subqueryload include that the complexity of the
original query is transferred to the relationship queries, which when
combined with the use of a subquery, can on some backends in some cases
(notably MySQL) produce significantly slow queries.  Additionally, the
subqueryload strategy can only load the full contents of all collections
at once, is therefore incompatible with “batched” loading supplied by
Query.yield_per(), both for collection and scalar
relationships.

The newer style of loading provided by selectinload() solves
these limitations of subqueryload().

See also
........

See Select IN loading.

3.4.3.11 The Importance of Ordering
...................................

A query which makes use of subqueryload() in conjunction
with a limiting modifier such as Query.first(),
Query.limit(), or Query.offset() should `always'
include Query.order_by() against unique column(s) such as
the primary key, so that the additional queries emitted by
subqueryload() include the same ordering as used by the parent
query.  Without it, there is a chance that the inner query could return
the wrong rows:

     # incorrect, no ORDER BY
     session.query(User).options(
         subqueryload(User.addresses)).first()

     # incorrect if User.name is not unique
     session.query(User).options(
         subqueryload(User.addresses)
     ).order_by(User.name).first()

     # correct
     session.query(User).options(
         subqueryload(User.addresses)
     ).order_by(User.name, User.id).first()

See also
........

See Why is ORDER BY required with LIMIT (especially with subqueryload())?.
- detailed example

3.4.3.12 Select IN loading
..........................

Select IN loading is similar in operation to subquery eager loading,
however the SELECT statement which is emitted has a much simpler
structure than that of subquery eager loading.  In most cases, selectin
loading is the most simple and efficient way to eagerly load collections
of objects.  The only scenario in which selectin eager loading is not
feasible is when the model is using composite primary keys, and the
backend database does not support tuples with IN, which currently
includes SQL Server.

New in version 1.2.

“Select IN” eager loading is provided using the ‘"selectin"’ argument to
relationship.lazy or by using the selectinload()
loader option.  This style of loading emits a SELECT that refers to the
primary key values of the parent object, or in the case of a many-to-one
relationship to the those of the child objects, inside of an IN clause,
in order to load related associations:

     >>> jack = session.query(User).\
     ... options(selectinload(User.addresses)).\
     ... filter(or_(User.name == 'jack', User.name == 'ed')).all()
     {opensql}SELECT
         users.id AS users_id,
         users.name AS users_name,
         users.fullname AS users_fullname,
         users.nickname AS users_nickname
     FROM users
     WHERE users.name = ? OR users.name = ?
     ('jack', 'ed')
     SELECT
         addresses.id AS addresses_id,
         addresses.email_address AS addresses_email_address,
         addresses.user_id AS addresses_user_id
     FROM addresses
     WHERE addresses.user_id IN (?, ?)
     (5, 7)

Above, the second SELECT refers to ‘addresses.user_id IN (5, 7)’, where
the “5” and “7” are the primary key values for the previous two ‘User’
objects loaded; after a batch of objects are completely loaded, their
primary key values are injected into the ‘IN’ clause for the second
SELECT. Because the relationship between ‘User’ and ‘Address’ has a
simple (1) primary join condition and provides that the primary key
values for ‘User’ can be derived from ‘Address.user_id’, the statement
has no joins or subqueries at all.

Changed in version 1.3: selectin loading can omit the JOIN for a simple
one-to-many collection.

For simple (2) many-to-one loads, a JOIN is also not needed as the
foreign key value from the parent object is used:

     >>> session.query(Address).\
     ... options(selectinload(Address.user)).all()
     {opensql}SELECT
         addresses.id AS addresses_id,
         addresses.email_address AS addresses_email_address,
         addresses.user_id AS addresses_user_id
         FROM addresses
     SELECT
         users.id AS users_id,
         users.name AS users_name,
         users.fullname AS users_fullname,
         users.nickname AS users_nickname
     FROM users
     WHERE users.id IN (?, ?)
     (1, 2)

Changed in version 1.3.6: selectin loading can also omit the JOIN for a
simple many-to-one relationship.

Select IN loading also supports many-to-many relationships, where it
currently will JOIN across all three tables to match rows from one side
to the other.

Things to know about this kind of loading include:

   * The SELECT statement emitted by the “selectin” loader strategy,
     unlike that of “subquery”, does not require a subquery nor does it
     inherit any of the performance limitations of the original query;
     the lookup is a simple primary key lookup and should have high
     performance.

   * The special ordering requirements of subqueryload described at
     The Importance of Ordering also don’t apply to selectin
     loading; selectin is always linking directly to a parent primary
     key and can’t really return the wrong result.

   * “selectin” loading, unlike joined or subquery eager loading, always
     emits its SELECT in terms of the immediate parent objects just
     loaded, and not the original type of object at the top of the
     chain.  So if eager loading many levels deep, “selectin” loading
     still will not require any JOINs for simple one-to-many or
     many-to-one relationships.  In comparison, joined and subquery
     eager loading always refer to multiple JOINs up to the original
     parent.

   * The strategy emits a SELECT for up to 500 parent primary key values
     at a time, as the primary keys are rendered into a large IN
     expression in the SQL statement.  Some databases like Oracle have a
     hard limit on how large an IN expression can be, and overall the
     size of the SQL string shouldn’t be arbitrarily large.

   * As “selectin” loading relies upon IN, for a mapping with composite
     primary keys, it must use the “tuple” form of IN, which looks like
     ‘WHERE (table.column_a, table.column_b) IN ((?, ?), (?, ?), (?,
     ?))’.  This syntax is not currently supported on SQL Server and for
     SQLite requires at least version 3.15.  There is no special logic
     in SQLAlchemy to check ahead of time which platforms support this
     syntax or not; if run against a non-supporting platform, the
     database will return an error immediately.  An advantage to
     SQLAlchemy just running the SQL out for it to fail is that if a
     particular database does start supporting this syntax, it will work
     without any changes to SQLAlchemy (as was the case with SQLite).

In general, “selectin” loading is probably superior to “subquery” eager
loading in most ways, save for the syntax requirement with composite
primary keys and possibly that it may emit many SELECT statements for
larger result sets.  As always, developers should spend time looking at
the statements and results generated by their applications in
development to check that things are working efficiently.

   ---------- Footnotes ----------

   (1) (1) by “simple” we mean that the relationship.primaryjoin
condition expresses an equality comparison between the primary key
of the “one” side and a straight foreign key of the “many” side, without
any additional criteria.

   (2) (1) by “simple” we mean that the relationship.primaryjoin
condition expresses an equality comparison between the primary key
of the “one” side and a straight foreign key of the “many” side, without
any additional criteria.

3.4.3.13 What Kind of Loading to Use ?
......................................

Which type of loading to use typically comes down to optimizing the
tradeoff between number of SQL executions, complexity of SQL emitted,
and amount of data fetched.  Lets take two examples, a
relationship() which references a collection, and a
relationship() that references a scalar many-to-one reference.

   * One to Many Collection

        * When using the default lazy loading, if you load 100 objects,
          and then access a collection on each of them, a total of 101
          SQL statements will be emitted, although each statement will
          typically be a simple SELECT without any joins.

        * When using joined loading, the load of 100 objects and their
          collections will emit only one SQL statement.  However, the
          total number of rows fetched will be equal to the sum of the
          size of all the collections, plus one extra row for each
          parent object that has an empty collection.  Each row will
          also contain the full set of columns represented by the
          parents, repeated for each collection item - SQLAlchemy does
          not re-fetch these columns other than those of the primary
          key, however most DBAPIs (with some exceptions) will transmit
          the full data of each parent over the wire to the client
          connection in any case.  Therefore joined eager loading only
          makes sense when the size of the collections are relatively
          small.  The LEFT OUTER JOIN can also be performance intensive
          compared to an INNER join.

        * When using subquery loading, the load of 100 objects will emit
          two SQL statements.  The second statement will fetch a total
          number of rows equal to the sum of the size of all
          collections.  An INNER JOIN is used, and a minimum of parent
          columns are requested, only the primary keys.  So a subquery
          load makes sense when the collections are larger.

        * When multiple levels of depth are used with joined or subquery
          loading, loading collections-within- collections will multiply
          the total number of rows fetched in a cartesian fashion.  Both
          joined and subquery eager loading always join from the
          original parent class; if loading a collection four levels
          deep, there will be four JOINs out to the parent.  selectin
          loading on the other hand will always have exactly one JOIN to
          the immediate parent table.

        * Using selectin loading, the load of 100 objects will also emit
          two SQL statements, the second of which refers to the 100
          primary keys of the objects loaded.  selectin loading will
          however render at most 500 primary key values into a single
          SELECT statement; so for a lead collection larger than 500,
          there will be a SELECT statement emitted for each batch of 500
          objects selected.

        * Using multiple levels of depth with selectin loading does not
          incur the “cartesian” issue that joined and subquery eager
          loading have; the queries for selectin loading have the best
          performance characteristics and the fewest number of rows.
          The only caveat is that there might be more than one SELECT
          emitted depending on the size of the lead result.

        * selectin loading, unlike joined (when using collections) and
          subquery eager loading (all kinds of relationships), is
          potentially compatible with result set batching provided by
          Query.yield_per() assuming an appropriate database
          driver, so may be able to allow batching for large result
          sets.

   * Many to One Reference

        * When using the default lazy loading, a load of 100 objects
          will like in the case of the collection emit as many as 101
          SQL statements.  However - there is a significant exception to
          this, in that if the many-to-one reference is a simple foreign
          key reference to the target’s primary key, each reference will
          be checked first in the current identity map using
          Query.get().  So here, if the collection of objects
          references a relatively small set of target objects, or the
          full set of possible target objects have already been loaded
          into the session and are strongly referenced, using the
          default of ‘lazy=’select’’ is by far the most efficient way to
          go.

        * When using joined loading, the load of 100 objects will emit
          only one SQL statement.  The join will be a LEFT OUTER JOIN,
          and the total number of rows will be equal to 100 in all
          cases.  If you know that each parent definitely has a child
          (i.e.  the foreign key reference is NOT NULL), the joined load
          can be configured with relationship.innerjoin set
          to ‘True’, which is usually specified within the
          relationship().  For a load of objects where there are
          many possible target references which may have not been loaded
          already, joined loading with an INNER JOIN is extremely
          efficient.

        * Subquery loading will issue a second load for all the child
          objects, so for a load of 100 objects there would be two SQL
          statements emitted.  There’s probably not much advantage here
          over joined loading, however, except perhaps that subquery
          loading can use an INNER JOIN in all cases whereas joined
          loading requires that the foreign key is NOT NULL.

        * Selectin loading will also issue a second load for all the
          child objects (and as stated before, for larger results it
          will emit a SELECT per 500 rows), so for a load of 100 objects
          there would be two SQL statements emitted.  The query itself
          still has to JOIN to the parent table, so again there’s not
          too much advantage to selectin loading for many-to-one vs.
          joined eager loading save for the use of INNER JOIN in all
          cases.

3.4.3.14 Polymorphic Eager Loading
..................................

Specification of polymorphic options on a per-eager-load basis is
supported.  See the section Eager Loading of Specific or Polymorphic Subtypes
for examples of the
PropComparator.of_type() method in conjunction with the
with_polymorphic() function.

3.4.3.15 Wildcard Loading Strategies
....................................

Each of joinedload(), subqueryload(),
lazyload(), selectinload(), noload(), and
raiseload() can be used to set the default style of
relationship() loading for a particular query, affecting all
relationship(). -mapped attributes not otherwise specified in the
Query.  This feature is available by passing the string ‘'*'’
as the argument to any of these options:

     session.query(MyClass).options(lazyload('*'))

Above, the ‘lazyload('*')’ option will supersede the ‘lazy’ setting of
all relationship() constructs in use for that query, except
for those which use the ‘'dynamic'’ style of loading.  If some
relationships specify ‘lazy='joined'’ or ‘lazy='subquery'’, for example,
using ‘lazyload('*')’ will unilaterally cause all those relationships to
use ‘'select'’ loading, e.g.  emit a SELECT statement when each
attribute is accessed.

The option does not supersede loader options stated in the query, such
as eagerload(), subqueryload(), etc.  The query
below will still use joined loading for the ‘widget’ relationship:

     session.query(MyClass).options(
         lazyload('*'),
         joinedload(MyClass.widget)
     )

If multiple ‘'*'’ options are passed, the last one overrides those
previously passed.

3.4.3.16 Per-Entity Wildcard Loading Strategies
...............................................

A variant of the wildcard loader strategy is the ability to set the
strategy on a per-entity basis.  For example, if querying for ‘User’ and
‘Address’, we can instruct all relationships on ‘Address’ only to use
lazy loading by first applying the Load object, then
specifying the ‘*’ as a chained option:

     session.query(User, Address).options(
         Load(Address).lazyload('*'))

Above, all relationships on ‘Address’ will be set to a lazy load.

3.4.3.17 Routing Explicit Joins/Statements into Eagerly Loaded Collections
..........................................................................

The behavior of joinedload() is such that joins are created
automatically, using anonymous aliases as targets, the results of which
are routed into collections and scalar references on loaded objects.  It
is often the case that a query already includes the necessary joins
which represent a particular collection or scalar reference, and the
joins added by the joinedload feature are redundant - yet you’d still
like the collections/references to be populated.

For this SQLAlchemy supplies the contains_eager() option.
This option is used in the same manner as the joinedload()
option except it is assumed that the ‘Query’ will specify the
appropriate joins explicitly.  Below, we specify a join between ‘User’
and ‘Address’ and additionally establish this as the basis for eager
loading of ‘User.addresses’:

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         addresses = relationship("Address")

     class Address(Base):
         __tablename__ = 'address'

         # ...

     q = session.query(User).join(User.addresses).\
                 options(contains_eager(User.addresses))

If the “eager” portion of the statement is “aliased”, the path should be
specified using PropComparator.of_type(), which allows the
specific aliased() construct to be passed:

     # use an alias of the Address entity
     adalias = aliased(Address)

     # construct a Query object which expects the "addresses" results
     query = session.query(User).\
         outerjoin(User.addresses.of_type(adalias)).\
         options(contains_eager(User.addresses.of_type(adalias)))

     # get results normally
     r = query.all()
     {opensql}SELECT
         users.user_id AS users_user_id,
         users.user_name AS users_user_name,
         adalias.address_id AS adalias_address_id,
         adalias.user_id AS adalias_user_id,
         adalias.email_address AS adalias_email_address,
         (...other columns...)
     FROM users
     LEFT OUTER JOIN email_addresses AS email_addresses_1
     ON users.user_id = email_addresses_1.user_id

The path given as the argument to contains_eager() needs to
be a full path from the starting entity.  For example if we were loading
‘Users->orders->Order->items->Item’, the option would be used as:

     query(User).options(
         contains_eager(User.orders).
         contains_eager(Order.items))

3.4.3.18 Using contains_eager() to load a custom-filtered collection result
...........................................................................

When we use contains_eager(), `we' are constructing ourselves
the SQL that will be used to populate collections.  From this, it
naturally follows that we can opt to `modify' what values the collection
is intended to store, by writing our SQL to load a subset of elements
for collections or scalar attributes.

As an example, we can load a ‘User’ object and eagerly load only
particular addresses into its ‘.addresses’ collection by filtering the
joined data, routing it using contains_eager(), also using
Query.populate_existing() to ensure any already-loaded
collections are overwritten:

     q = session.query(User).\
             join(User.addresses).\
             filter(Address.email_address.like('%@aol.com')).\
             options(contains_eager(User.addresses)).\
             populate_existing()

The above query will load only ‘User’ objects which contain at least
‘Address’ object that contains the substring ‘'aol.com'’ in its ‘email’
field; the ‘User.addresses’ collection will contain `only' these
‘Address’ entries, and `not' any other ‘Address’ entries that are in
fact associated with the collection.

     Tip: In all cases, the SQLAlchemy ORM does `not overwrite already
     loaded attributes and collections' unless told to do so.  As there
     is an identity map in use, it is often the case that an ORM query
     is returning objects that were in fact already present and loaded
     in memory.  Therefore, when using contains_eager() to
     populate a collection in an alternate way, it is usually a good
     idea to use Query.populate_existing() as illustrated
     above so that an already-loaded collection is refreshed with the
     new data.  Query.populate_existing() will reset `all'
     attributes that were already present, including pending changes, so
     make sure all data is flushed before using it.  Using the
     Session with its default behavior of autoflush is
     sufficient.

     Note: The customized collection we load using
     contains_eager() is not “sticky”; that is, the next time this
     collection is loaded, it will be loaded with its usual default
     contents.  The collection is subject to being reloaded if the
     object is expired, which occurs whenever the
     Session.commit(), Session.rollback() methods are
     used assuming default session settings, or the
     Session.expire_all() or Session.expire() methods
     are used.

3.4.3.19 Creating Custom Load Rules
...................................

     deepalchemy: This is an advanced technique!  Great care and testing
     should be applied.

The ORM has various edge cases where the value of an attribute is
locally available, however the ORM itself doesn’t have awareness of
this.  There are also cases when a user-defined system of loading
attributes is desirable.  To support the use case of user-defined
loading systems, a key function set_committed_value() is
provided.  This function is basically equivalent to Python’s own
‘setattr()’ function, except that when applied to a target object,
SQLAlchemy’s “attribute history” system which is used to determine
flush-time changes is bypassed; the attribute is assigned in the same
way as if the ORM loaded it that way from the database.

The use of set_committed_value() can be combined with
another key event known as InstanceEvents.load() to produce
attribute-population behaviors when an object is loaded.  One such
example is the bi-directional “one-to-one” case, where loading the
“many-to-one” side of a one-to-one should also imply the value of the
“one-to-many” side.  The SQLAlchemy ORM does not consider backrefs when
loading related objects, and it views a “one-to-one” as just another
“one-to-many”, that just happens to be one row.

Given the following mapping:

     from sqlalchemy import Integer, ForeignKey, Column
     from sqlalchemy.orm import relationship, backref
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)
         b_id = Column(ForeignKey('b.id'))
         b = relationship(
             "B",
             backref=backref("a", uselist=False),
             lazy='joined')

     class B(Base):
         __tablename__ = 'b'
         id = Column(Integer, primary_key=True)

If we query for an ‘A’ row, and then ask it for ‘a.b.a’, we will get an
extra SELECT:

     >>> a1.b.a
     SELECT a.id AS a_id, a.b_id AS a_b_id
     FROM a
     WHERE ? = a.b_id

This SELECT is redundant because ‘b.a’ is the same value as ‘a1’.  We
can create an on-load rule to populate this for us:

     from sqlalchemy import event
     from sqlalchemy.orm import attributes

     @event.listens_for(A, "load")
     def load_b(target, context):
         if 'b' in target.__dict__:
             attributes.set_committed_value(target.b, 'a', target)

Now when we query for ‘A’, we will get ‘A.b’ from the joined eager load,
and ‘A.b.a’ from our event:

     a1 = s.query(A).first()
     {opensql}SELECT
         a.id AS a_id,
         a.b_id AS a_b_id,
         b_1.id AS b_1_id
     FROM a
     LEFT OUTER JOIN b AS b_1 ON b_1.id = a.b_id
      LIMIT ? OFFSET ?
     (1, 0)
     {stop}assert a1.b.a is a1

3.4.3.20 Relationship Loader API
................................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See contains_eager.(*keys,Indicate that the given attribute should be eagerly loaded from columns stated manually in
**kw)          the query.

See defaultload.(*keys)Indicate an attribute should load using its default loader style.

See eagerload.(*args,A synonym for joinedload().
**kwargs)

See immediateload.(*keys)Indicate that the given attribute should be loaded using an immediate load with a
               per-attribute SELECT statement.

See joinedload.(*keys,Indicate that the given attribute should be loaded using joined eager loading.
**kw)

See lazyload.(*keys)Indicate that the given attribute should be loaded using “lazy” loading.

See Load.Represents loader options which modify the state of a Query in order to affect
               how various mapped attributes are loaded.

See noload.(*keys)Indicate that the given relationship attribute should remain unloaded.

See raiseload.(*keys,Indicate that the given attribute should raise an error if accessed.
**kw)

See selectinload.(*keys)Indicate that the given attribute should be loaded using SELECT IN eager loading.

See subqueryload.(*keys)Indicate that the given attribute should be loaded using subquery eager loading.

 -- Function: sqlalchemy.orm.contains_eager (*keys, **kw)

     Indicate that the given attribute should be eagerly loaded from
     columns stated manually in the query.

     This function is part of the Load interface and
     supports both method-chained and standalone operation.

     The option is used in conjunction with an explicit join that loads
     the desired rows, i.e.:

          sess.query(Order).\
                  join(Order.user).\
                  options(contains_eager(Order.user))

     The above query would join from the ‘Order’ entity to its related
     ‘User’ entity, and the returned ‘Order’ objects would have the
     ‘Order.user’ attribute pre-populated.

     It may also be used for customizing the entries in an eagerly
     loaded collection; queries will normally want to use the
     Query.populate_existing() method assuming the primary
     collection of parent objects may already have been loaded:

          sess.query(User).\
              join(User.addresses).\
              filter(Address.email_address.like('%@aol.com')).\
              options(contains_eager(User.addresses)).\
              populate_existing()

     See the section Routing Explicit Joins/Statements into Eagerly Loaded Collections
     for complete usage details.

     See also
     ........

     See Relationship Loading Techniques.

     See Routing Explicit Joins/Statements into Eagerly Loaded Collections.

 -- Function: sqlalchemy.orm.defaultload (*keys)

     Indicate an attribute should load using its default loader style.

     This method is used to link to other loader options further into a
     chain of attributes without altering the loader style of the links
     along the chain.  For example, to set joined eager loading for an
     element of an element:

          session.query(MyClass).options(
              defaultload(MyClass.someattribute).
              joinedload(MyOtherClass.someotherattribute)
          )

     defaultload() is also useful for setting column-level
     options on a related class, namely that of defer() and
     undefer():

          session.query(MyClass).options(
              defaultload(MyClass.someattribute).
              defer("some_column").
              undefer("some_other_column")
          )

     See also
     ........

     See Load.options(). - allows for complex hierarchical loader
     option structures with less verbosity than with individual
     defaultload() directives.

     See Relationship Loading with Loader Options.

     See Deferred Loading across Multiple Entities.

 -- Function: sqlalchemy.orm.eagerload (*args, **kwargs)

     A synonym for joinedload().

     Deprecated since version 1.4: The eagerload construct is considered
     legacy as of the 1.x series of SQLAlchemy and will be removed in
     2.0.  Please use joinedload().  (Background on
     SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

 -- Function: sqlalchemy.orm.immediateload (*keys)

     Indicate that the given attribute should be loaded using an
     immediate load with a per-attribute SELECT statement.

     The immediateload() option is superseded in general by
     the selectinload() option, which performs the same task
     more efficiently by emitting a SELECT for all loaded objects.

     This function is part of the Load interface and
     supports both method-chained and standalone operation.

     See also
     ........

     See Relationship Loading Techniques.

     See Select IN loading.

 -- Function: sqlalchemy.orm.joinedload (*keys, **kw)

     Indicate that the given attribute should be loaded using joined
     eager loading.

     This function is part of the Load interface and
     supports both method-chained and standalone operation.

     examples:

          # joined-load the "orders" collection on "User"
          query(User).options(joinedload(User.orders))

          # joined-load Order.items and then Item.keywords
          query(Order).options(
              joinedload(Order.items).joinedload(Item.keywords))

          # lazily load Order.items, but when Items are loaded,
          # joined-load the keywords collection
          query(Order).options(
              lazyload(Order.items).joinedload(Item.keywords))

     Parameters: ‘innerjoin’ – if ‘True’, indicates that the joined
     eager load should use an inner join instead of the default of left
     outer join:

          query(Order).options(joinedload(Order.user, innerjoin=True))

     In order to chain multiple eager joins together where some may be
     OUTER and others INNER, right-nested joins are used to link them:

          query(A).options(
              joinedload(A.bs, innerjoin=False).
                  joinedload(B.cs, innerjoin=True)
          )

     The above query, linking A.bs via “outer” join and B.cs via “inner”
     join would render the joins as “a LEFT OUTER JOIN (b JOIN c)”.
     When using older versions of SQLite (< 3.7.16), this form of JOIN
     is translated to use full subqueries as this syntax is otherwise
     not directly supported.

     The ‘innerjoin’ flag can also be stated with the term ‘"unnested"’.
     This indicates that an INNER JOIN should be used, `unless' the join
     is linked to a LEFT OUTER JOIN to the left, in which case it will
     render as LEFT OUTER JOIN. For example, supposing ‘A.bs’ is an
     outerjoin:

          query(A).options(
              joinedload(A.bs).
                  joinedload(B.cs, innerjoin="unnested")
          )

     The above join will render as “a LEFT OUTER JOIN b LEFT OUTER JOIN
     c”, rather than as “a LEFT OUTER JOIN (b JOIN c)”.

          Note: The “unnested” flag does `not' affect the JOIN rendered
          from a many-to-many association table, e.g.  a table
          configured as relationship.secondary, to the target
          table; for correctness of results, these joins are always
          INNER and are therefore right-nested if linked to an OUTER
          join.

     Changed in version 1.0.0: ‘innerjoin=True’ now implies
     ‘innerjoin="nested"’, whereas in 0.9 it implied
     ‘innerjoin="unnested"’.  In order to achieve the pre-1.0 “unnested”
     inner join behavior, use the value ‘innerjoin="unnested"’.  See
     Right inner join nesting now the default for joinedload with innerjoin=True.

          Note: The joins produced by joinedload() are
          `anonymously aliased'.  The criteria by which the join
          proceeds cannot be modified, nor can the Query
          refer to these joins in any way, including ordering.  See
          The Zen of Joined Eager Loading for further
          detail.

          To produce a specific SQL JOIN which is explicitly available,
          use Query.join().  To combine explicit JOINs with
          eager loading of collections, use contains_eager();
          see Routing Explicit Joins/Statements into Eagerly Loaded Collections.

     See also
     ........

     See Relationship Loading Techniques.

     See Joined Eager Loading.

 -- Function: sqlalchemy.orm.lazyload (*keys)

     Indicate that the given attribute should be loaded using “lazy”
     loading.

     This function is part of the Load interface and
     supports both method-chained and standalone operation.

     See also
     ........

     See Relationship Loading Techniques.

     See Lazy Loading.

 -- Class: sqlalchemy.orm.Load (entity)

     Represents loader options which modify the state of a Query
     in order to affect how various mapped attributes are loaded.

     The Load object is in most cases used implicitly behind
     the scenes when one makes use of a query option like
     joinedload(), defer(), or similar.  However, the
     Load object can also be used directly, and in some
     cases can be useful.

     To use Load directly, instantiate it with the target
     mapped class as the argument.  This style of usage is useful when
     dealing with a Query that has multiple entities:

          myopt = Load(MyClass).joinedload("widgets")

     The above ‘myopt’ can now be used with Query.options(),
     where it will only take effect for the ‘MyClass’ entity:

          session.query(MyClass, MyOtherClass).options(myopt)

     One case where Load is useful as public API is when
     specifying “wildcard” options that only take effect for a certain
     class:

          session.query(Order).options(Load(Order).lazyload('*'))

     Above, all relationships on ‘Order’ will be lazy-loaded, but other
     attributes on those descendant objects will load using their normal
     loader strategy.

     See also
     ........

     See Deferred Column Loader Query Options.

     See Deferred Loading across Multiple Entities.

     See Relationship Loading with Loader Options.

     `Class signature'

     class sqlalchemy.orm.Load.
     (‘sqlalchemy.sql.expression.Generative’,
     ‘sqlalchemy.orm.LoaderOption’)

      -- Method: sqlalchemy.orm.Load..baked_lazyload (attr)

          Produce a new Load object with the
          ‘baked_lazyload()’ option applied.

          See ‘baked_lazyload()’ for usage examples.

      -- Method: sqlalchemy.orm.Load..contains_eager (attr,
               alias=None)

          Produce a new Load object with the
          contains_eager() option applied.

          See contains_eager() for usage examples.

      -- Method: sqlalchemy.orm.Load..defaultload (attr)

          Produce a new Load object with the
          defaultload() option applied.

          See defaultload() for usage examples.

      -- Method: sqlalchemy.orm.Load..defer (key,
               raiseload=False)

          Produce a new Load object with the defer()
          option applied.

          See defer() for usage examples.

      -- Method: sqlalchemy.orm.Load..immediateload (attr)

          Produce a new Load object with the
          immediateload() option applied.

          See immediateload() for usage examples.

      -- Method: sqlalchemy.orm.Load..joinedload (attr,
               innerjoin=None)

          Produce a new Load object with the
          joinedload() option applied.

          See joinedload() for usage examples.

      -- Method: sqlalchemy.orm.Load..lazyload (attr)

          Produce a new Load object with the
          lazyload() option applied.

          See lazyload() for usage examples.

      -- Method: sqlalchemy.orm.Load..load_only (*attrs)

          Produce a new Load object with the
          load_only() option applied.

          See load_only() for usage examples.

      -- Method: sqlalchemy.orm.Load..noload (attr)

          Produce a new Load object with the noload()
          option applied.

          See noload() for usage examples.

      -- Method: sqlalchemy.orm.Load..options (*opts)

          Apply a series of options as sub-options to this Load
          object.

          E.g.:

               query = session.query(Author)
               query = query.options(
                           joinedload(Author.book).options(
                               load_only("summary", "excerpt"),
                               joinedload(Book.citations).options(
                                   joinedload(Citation.author)
                               )
                           )
                       )

          Parameters: ‘*opts’ – A series of loader option objects
          (ultimately Load objects) which should be applied
          to the path specified by this Load object.

          New in version 1.3.6.

          See also
          ........

          See defaultload().

          See Relationship Loading with Loader Options.

          See Deferred Loading across Multiple Entities.

      -- Method: sqlalchemy.orm.Load..process_compile_state
               (compile_state)

          Apply a modification to a given ‘CompileState’.

      -- Method: sqlalchemy.orm.Load..raiseload (attr,
               sql_only=False)

          Produce a new Load object with the
          raiseload() option applied.

          See raiseload() for usage examples.

      -- Method: sqlalchemy.orm.Load..selectin_polymorphic
               (classes)

          Produce a new Load object with the
          selectin_polymorphic() option applied.

          See selectin_polymorphic() for usage examples.

      -- Method: sqlalchemy.orm.Load..selectinload (attr)

          Produce a new Load object with the
          selectinload() option applied.

          See selectinload() for usage examples.

      -- Method: sqlalchemy.orm.Load..subqueryload (attr)

          Produce a new Load object with the
          subqueryload() option applied.

          See subqueryload() for usage examples.

      -- Method: sqlalchemy.orm.Load..undefer (key)

          Produce a new Load object with the
          undefer() option applied.

          See undefer() for usage examples.

      -- Method: sqlalchemy.orm.Load..undefer_group (name)

          Produce a new Load object with the
          undefer_group() option applied.

          See undefer_group() for usage examples.

      -- Method: sqlalchemy.orm.Load..with_expression (key,
               expression)

          Produce a new Load object with the
          with_expression() option applied.

          See with_expression() for usage examples.

 -- Function: sqlalchemy.orm.noload (*keys)

     Indicate that the given relationship attribute should remain
     unloaded.

     The relationship attribute will return ‘None’ when accessed without
     producing any loading effect.

     This function is part of the Load interface and
     supports both method-chained and standalone operation.

     noload() applies to relationship()
     attributes; for column-based attributes, see defer().

          Note: Setting this loading strategy as the default strategy
          for a relationship using the relationship.lazy
          parameter may cause issues with flushes, such if a delete
          operation needs to load related objects and instead ‘None’ was
          returned.

     See also
     ........

     See Relationship Loading Techniques.

 -- Function: sqlalchemy.orm.raiseload (*keys, **kw)

     Indicate that the given attribute should raise an error if
     accessed.

     A relationship attribute configured with raiseload()
     will raise an InvalidRequestError upon access.  The
     typical way this is useful is when an application is attempting to
     ensure that all relationship attributes that are accessed in a
     particular context would have been already loaded via eager
     loading.  Instead of having to read through SQL logs to ensure lazy
     loads aren’t occurring, this strategy will cause them to raise
     immediately.

     raiseload() applies to relationship()
     attributes only.  In order to apply raise-on-SQL behavior to a
     column-based attribute, use the defer.raiseload
     parameter on the defer() loader option.

     Parameters: ‘sql_only’ – if True, raise only if the lazy load would
     emit SQL, but not if it is only checking the identity map, or
     determining that the related value should just be None due to
     missing keys.  When False, the strategy will raise for all
     varieties of relationship loading.

     This function is part of the Load interface and
     supports both method-chained and standalone operation.

     New in version 1.1.

     See also
     ........

     See Relationship Loading Techniques.

     See Preventing unwanted lazy loads using raiseload.

     See Raiseload for Deferred Columns.

 -- Function: sqlalchemy.orm.selectinload (*keys)

     Indicate that the given attribute should be loaded using SELECT IN
     eager loading.

     This function is part of the Load interface and
     supports both method-chained and standalone operation.

     examples:

          # selectin-load the "orders" collection on "User"
          query(User).options(selectinload(User.orders))

          # selectin-load Order.items and then Item.keywords
          query(Order).options(
              selectinload(Order.items).selectinload(Item.keywords))

          # lazily load Order.items, but when Items are loaded,
          # selectin-load the keywords collection
          query(Order).options(
              lazyload(Order.items).selectinload(Item.keywords))

     New in version 1.2.

     See also
     ........

     See Relationship Loading Techniques.

     See Select IN loading.

 -- Function: sqlalchemy.orm.subqueryload (*keys)

     Indicate that the given attribute should be loaded using subquery
     eager loading.

     This function is part of the Load interface and
     supports both method-chained and standalone operation.

     examples:

          # subquery-load the "orders" collection on "User"
          query(User).options(subqueryload(User.orders))

          # subquery-load Order.items and then Item.keywords
          query(Order).options(
              subqueryload(Order.items).subqueryload(Item.keywords))

          # lazily load Order.items, but when Items are loaded,
          # subquery-load the keywords collection
          query(Order).options(
              lazyload(Order.items).subqueryload(Item.keywords))

     See also
     ........

     See Relationship Loading Techniques.

     See Subquery Eager Loading.

3.4.4 Loading Inheritance Hierarchies
-------------------------------------

When classes are mapped in inheritance hierarchies using the “joined”,
“single”, or “concrete” table inheritance styles as described at
Mapping Class Inheritance Hierarchies, the usual behavior is that a
query for a particular base class will also yield objects corresponding
to subclasses as well.  When a single query is capable of returning a
result with a different class or subclasses per result row, we use the
term “polymorphic loading”.

Within the realm of polymorphic loading, specifically with joined and
single table inheritance, there is an additional problem of which
subclass attributes are to be queried up front, and which are to be
loaded later.  When an attribute of a particular subclass is queried up
front, we can use it in our query as something to filter on, and it also
will be loaded when we get our objects back.  If it’s not queried up
front, it gets loaded later when we first need to access it.  Basic
control of this behavior is provided using the with_polymorphic()
function, as well as two variants, the mapper configuration
mapper.with_polymorphic in conjunction with the
mapper.polymorphic_load option, and the Query. -level
Query.with_polymorphic() method.  The “with_polymorphic”
family each provide a means of specifying which specific subclasses of a
particular base class should be included within a query, which implies
what columns and tables will be available in the SELECT.

3.4.4.1 Using with_polymorphic
..............................

For the following sections, assume the ‘Employee’ / ‘Engineer’ /
‘Manager’ examples introduced in Mapping Class Inheritance Hierarchies.

Normally, when a Query specifies the base class of an
inheritance hierarchy, only the columns that are local to that base
class are queried:

     session.query(Employee).all()

Above, for both single and joined table inheritance, only the columns
local to ‘Employee’ will be present in the SELECT. We may get back
instances of ‘Engineer’ or ‘Manager’, however they will not have the
additional attributes loaded until we first access them, at which point
a lazy load is emitted.

Similarly, if we wanted to refer to columns mapped to ‘Engineer’ or
‘Manager’ in our query that’s against ‘Employee’, these columns aren’t
available directly in either the single or joined table inheritance
case, since the ‘Employee’ entity does not refer to these columns (note
that for single-table inheritance, this is common if Declarative is
used, but not for a classical mapping).

To solve both of these issues, the with_polymorphic()
function provides a special AliasedClass that represents a
range of columns across subclasses.  This object can be used in a
Query like any other alias.  When queried, it represents all the
columns present in the classes given:

     from sqlalchemy.orm import with_polymorphic

     eng_plus_manager = with_polymorphic(Employee, [Engineer, Manager])

     query = session.query(eng_plus_manager)

If the above mapping were using joined table inheritance, the SELECT
statement for the above would be:

     query.all()
     {opensql}
     SELECT employee.id AS employee_id,
         engineer.id AS engineer_id,
         manager.id AS manager_id,
         employee.name AS employee_name,
         employee.type AS employee_type,
         engineer.engineer_info AS engineer_engineer_info,
         manager.manager_data AS manager_manager_data
     FROM employee
         LEFT OUTER JOIN engineer
         ON employee.id = engineer.id
         LEFT OUTER JOIN manager
         ON employee.id = manager.id
     []

Where above, the additional tables / columns for “engineer” and
“manager” are included.  Similar behavior occurs in the case of single
table inheritance.

with_polymorphic() accepts a single class or mapper, a list
of classes/mappers, or the string ‘'*'’ to indicate all subclasses:

     # include columns for Engineer
     entity = with_polymorphic(Employee, Engineer)

     # include columns for Engineer, Manager
     entity = with_polymorphic(Employee, [Engineer, Manager])

     # include columns for all mapped subclasses
     entity = with_polymorphic(Employee, '*')

3.4.4.2 Using aliasing with with_polymorphic
............................................

The with_polymorphic() function also provides “aliasing” of
the polymorphic selectable itself, meaning, two different
with_polymorphic() entities, referring to the same class
hierarchy, can be used together.  This is available using the
with_polymorphic.aliased flag.  For a polymorphic selectable that
is across multiple tables, the default behavior is to wrap the
selectable into a subquery.  Below we emit a query that will select for
“employee or manager” paired with “employee or engineer” on employees
with the same name:

     engineer_employee = with_polymorphic(
         Employee, [Engineer], aliased=True)
     manager_employee = with_polymorphic(
         Employee, [Manager], aliased=True)

     q = s.query(engineer_employee, manager_employee).\
         join(
             manager_employee,
             and_(
                 engineer_employee.id > manager_employee.id,
                 engineer_employee.name == manager_employee.name
             )
     )
     q.all()
     {opensql}
     SELECT
         anon_1.employee_id AS anon_1_employee_id,
         anon_1.employee_name AS anon_1_employee_name,
         anon_1.employee_type AS anon_1_employee_type,
         anon_1.engineer_id AS anon_1_engineer_id,
         anon_1.engineer_engineer_name AS anon_1_engineer_engineer_name,
         anon_2.employee_id AS anon_2_employee_id,
         anon_2.employee_name AS anon_2_employee_name,
         anon_2.employee_type AS anon_2_employee_type,
         anon_2.manager_id AS anon_2_manager_id,
         anon_2.manager_manager_name AS anon_2_manager_manager_name
     FROM (
         SELECT
             employee.id AS employee_id,
             employee.name AS employee_name,
             employee.type AS employee_type,
             engineer.id AS engineer_id,
             engineer.engineer_name AS engineer_engineer_name
         FROM employee
         LEFT OUTER JOIN engineer ON employee.id = engineer.id
     ) AS anon_1
     JOIN (
         SELECT
             employee.id AS employee_id,
             employee.name AS employee_name,
             employee.type AS employee_type,
             manager.id AS manager_id,
              manager.manager_name AS manager_manager_name
         FROM employee
         LEFT OUTER JOIN manager ON employee.id = manager.id
     ) AS anon_2
     ON anon_1.employee_id > anon_2.employee_id
     AND anon_1.employee_name = anon_2.employee_name

The creation of subqueries above is very verbose.  While it creates the
best encapsulation of the two distinct queries, it may be inefficient.
with_polymorphic() includes an additional flag to help with
this situation, see with_polymorphic.flat, which will “flatten”
the subquery / join combination into straight joins, applying aliasing
to the individual tables instead.  Setting with_polymorphic.flat
implies with_polymorphic.aliased, so only one flag is
necessary:

     engineer_employee = with_polymorphic(
         Employee, [Engineer], flat=True)
     manager_employee = with_polymorphic(
         Employee, [Manager], flat=True)

     q = s.query(engineer_employee, manager_employee).\
         join(
             manager_employee,
             and_(
                 engineer_employee.id > manager_employee.id,
                 engineer_employee.name == manager_employee.name
             )
     )
     q.all()
     {opensql}
     SELECT
         employee_1.id AS employee_1_id,
         employee_1.name AS employee_1_name,
         employee_1.type AS employee_1_type,
         engineer_1.id AS engineer_1_id,
         engineer_1.engineer_name AS engineer_1_engineer_name,
         employee_2.id AS employee_2_id,
         employee_2.name AS employee_2_name,
         employee_2.type AS employee_2_type,
         manager_1.id AS manager_1_id,
         manager_1.manager_name AS manager_1_manager_name
     FROM employee AS employee_1
     LEFT OUTER JOIN engineer AS engineer_1
     ON employee_1.id = engineer_1.id
     JOIN (
         employee AS employee_2
         LEFT OUTER JOIN manager AS manager_1
         ON employee_2.id = manager_1.id
     )
     ON employee_1.id > employee_2.id
     AND employee_1.name = employee_2.name

Note above, when using with_polymorphic.flat, it is often the
case when used in conjunction with joined table inheritance that we get
a right-nested JOIN in our statement.  Some older databases, in
particular older versions of SQLite, may have a problem with this
syntax, although virtually all modern database versions now support this
syntax.

     Note: The with_polymorphic.flat flag only applies to
     the use of ‘with_polymorphic’ with `joined table inheritance' and
     when the with_polymorphic.selectable argument is `not'
     used.

3.4.4.3 Referring to Specific Subclass Attributes
.................................................

The entity returned by with_polymorphic() is an
AliasedClass object, which can be used in a Query like
any other alias, including named attributes for those attributes on the
‘Employee’ class.  In our previous example, ‘eng_plus_manager’ becomes
the entity that we use to refer to the three-way outer join above.  It
also includes namespaces for each class named in the list of classes, so
that attributes specific to those subclasses can be called upon as well.
The following example illustrates calling upon attributes specific to
‘Engineer’ as well as ‘Manager’ in terms of ‘eng_plus_manager’:

     eng_plus_manager = with_polymorphic(Employee, [Engineer, Manager])
     query = session.query(eng_plus_manager).filter(
                     or_(
                         eng_plus_manager.Engineer.engineer_info=='x',
                         eng_plus_manager.Manager.manager_data=='y'
                     )
                 )

3.4.4.4 Setting with_polymorphic at mapper configuration time
.............................................................

The with_polymorphic() function serves the purpose of
allowing “eager” loading of attributes from subclass tables, as well as
the ability to refer to the attributes from subclass tables at query
time.  Historically, the “eager loading” of columns has been the more
important part of the equation.  So just as eager loading for
relationships can be specified as a configurational option, the
mapper.with_polymorphic configuration parameter allows an entity
to use a polymorphic load by default.  We can add the parameter to our
‘Employee’ mapping first introduced at Joined Table Inheritance:

     class Employee(Base):
         __tablename__ = 'employee'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         type = Column(String(50))

         __mapper_args__ = {
             'polymorphic_identity':'employee',
             'polymorphic_on':type,
             'with_polymorphic': '*'
         }

Above is a common setting for mapper.with_polymorphic, which
is to indicate an asterisk to load all subclass columns.  In the case of
joined table inheritance, this option should be used sparingly, as it
implies that the mapping will always emit a (often large) series of LEFT
OUTER JOIN to many tables, which is not efficient from a SQL
perspective.  For single table inheritance, specifying the asterisk is
often a good idea as the load is still against a single table only, but
an additional lazy load of subclass-mapped columns will be prevented.

Using with_polymorphic() or Query.with_polymorphic()
will override the mapper-level mapper.with_polymorphic
setting.

The mapper.with_polymorphic option also accepts a list of
classes just like with_polymorphic() to polymorphically load
among a subset of classes.  However, when using Declarative, providing
classes to this list is not directly possible as the subclasses we’d
like to add are not available yet.  Instead, we can specify on each
subclass that they should individually participate in polymorphic
loading by default using the mapper.polymorphic_load
parameter:

     class Engineer(Employee):
         __tablename__ = 'engineer'
         id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
         engineer_info = Column(String(50))
         __mapper_args__ = {
             'polymorphic_identity':'engineer',
             'polymorphic_load': 'inline'
         }

     class Manager(Employee):
         __tablename__ = 'manager'
         id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
         manager_data = Column(String(50))
         __mapper_args__ = {
             'polymorphic_identity':'manager',
             'polymorphic_load': 'inline'
         }

Setting the mapper.polymorphic_load parameter to the value
‘"inline"’ means that the ‘Engineer’ and ‘Manager’ classes above are
part of the “polymorphic load” of the base ‘Employee’ class by default,
exactly as though they had been appended to the
mapper.with_polymorphic list of classes.

3.4.4.5 Setting with_polymorphic against a query
................................................

The with_polymorphic() function evolved from a query-level
method Query.with_polymorphic().  This method has the same
purpose as with_polymorphic(), except is not as flexible in
its usage patterns in that it only applies to the first entity of the
Query.  It then takes effect for all occurrences of that
entity, so that the entity (and its subclasses) can be referred to
directly, rather than using an alias object.  For simple cases it might
be considered to be more succinct:

     session.query(Employee).\
         with_polymorphic([Engineer, Manager]).\
         filter(
             or_(
                 Engineer.engineer_info=='w',
                 Manager.manager_data=='q'
             )
         )

The Query.with_polymorphic() method has a more complicated
job than the with_polymorphic() function, as it needs to
correctly transform entities like ‘Engineer’ and ‘Manager’
appropriately, but not interfere with other entities.  If its
flexibility is lacking, switch to using with_polymorphic().

3.4.4.6 Polymorphic Selectin Loading
....................................

An alternative to using the with_polymorphic() family of
functions to “eagerly” load the additional subclasses on an inheritance
mapping, primarily when using joined table inheritance, is to use
polymorphic “selectin” loading.  This is an eager loading feature which
works similarly to the Select IN loading feature of
relationship loading.  Given our example mapping, we can instruct a load
of ‘Employee’ to emit an extra SELECT per subclass by using the
selectin_polymorphic() loader option:

     from sqlalchemy.orm import selectin_polymorphic

     query = session.query(Employee).options(
         selectin_polymorphic(Employee, [Manager, Engineer])
     )

When the above query is run, two additional SELECT statements will be
emitted:

     {opensql}query.all()
     SELECT
         employee.id AS employee_id,
         employee.name AS employee_name,
         employee.type AS employee_type
     FROM employee
     ()

     SELECT
         engineer.id AS engineer_id,
         employee.id AS employee_id,
         employee.type AS employee_type,
         engineer.engineer_name AS engineer_engineer_name
     FROM employee JOIN engineer ON employee.id = engineer.id
     WHERE employee.id IN (?, ?) ORDER BY employee.id
     (1, 2)

     SELECT
         manager.id AS manager_id,
         employee.id AS employee_id,
         employee.type AS employee_type,
         manager.manager_name AS manager_manager_name
     FROM employee JOIN manager ON employee.id = manager.id
     WHERE employee.id IN (?) ORDER BY employee.id
     (3,)

We can similarly establish the above style of loading to take place by
default by specifying the mapper.polymorphic_load parameter,
using the value ‘"selectin"’ on a per-subclass basis:

     class Employee(Base):
         __tablename__ = 'employee'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         type = Column(String(50))

         __mapper_args__ = {
             'polymorphic_identity': 'employee',
             'polymorphic_on': type
         }

     class Engineer(Employee):
         __tablename__ = 'engineer'
         id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
         engineer_name = Column(String(30))

         __mapper_args__ = {
             'polymorphic_load': 'selectin',
             'polymorphic_identity': 'engineer',
         }

     class Manager(Employee):
         __tablename__ = 'manager'
         id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
         manager_name = Column(String(30))

         __mapper_args__ = {
             'polymorphic_load': 'selectin',
             'polymorphic_identity': 'manager',
         }

Unlike when using with_polymorphic(), when using the
selectin_polymorphic() style of loading, we do `not' have the
ability to refer to the ‘Engineer’ or ‘Manager’ entities within our main
query as filter, order by, or other criteria, as these entities are not
present in the initial query that is used to locate results.  However,
we can apply loader options that apply towards ‘Engineer’ or ‘Manager’,
which will take effect when the secondary SELECT is emitted.  Below we
assume ‘Manager’ has an additional relationship ‘Manager.paperwork’,
that we’d like to eagerly load as well.  We can use any type of eager
loading, such as joined eager loading via the joinedload()
function:

     from sqlalchemy.orm import joinedload
     from sqlalchemy.orm import selectin_polymorphic

     query = session.query(Employee).options(
         selectin_polymorphic(Employee, [Manager, Engineer]),
         joinedload(Manager.paperwork)
     )

Using the query above, we get three SELECT statements emitted, however
the one against ‘Manager’ will be:

     SELECT
         manager.id AS manager_id,
         employee.id AS employee_id,
         employee.type AS employee_type,
         manager.manager_name AS manager_manager_name,
         paperwork_1.id AS paperwork_1_id,
         paperwork_1.manager_id AS paperwork_1_manager_id,
         paperwork_1.data AS paperwork_1_data
     FROM employee JOIN manager ON employee.id = manager.id
     LEFT OUTER JOIN paperwork AS paperwork_1
     ON manager.id = paperwork_1.manager_id
     WHERE employee.id IN (?) ORDER BY employee.id
     (3,)

Note that selectin polymorphic loading has similar caveats as that of
selectin relationship loading; for entities that make use of a composite
primary key, the database in use must support tuples with “IN”,
currently known to work with MySQL and PostgreSQL.

New in version 1.2.

     Warning: The selectin polymorphic loading feature should be
     considered as `experimental' within early releases of the 1.2
     series.

3.4.4.7 Combining selectin and with_polymorphic
...............................................

     Note: works as of 1.2.0b3

With careful planning, selectin loading can be applied against a
hierarchy that itself uses “with_polymorphic”.  A particular use case is
that of using selectin loading to load a joined-inheritance subtable,
which then uses “with_polymorphic” to refer to further sub-classes,
which may be joined- or single-table inheritance.  If we added a class
‘VicePresident’ that extends ‘Manager’ using single-table inheritance,
we could ensure that a load of ‘Manager’ also fully loads
‘VicePresident’ subtypes at the same time:

     # use "Employee" example from the enclosing section

     class Manager(Employee):
         __tablename__ = 'manager'
         id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
         manager_name = Column(String(30))

         __mapper_args__ = {
             'polymorphic_load': 'selectin',
             'polymorphic_identity': 'manager',
         }

     class VicePresident(Manager):
         vp_info = Column(String(30))

         __mapper_args__ = {
             "polymorphic_load": "inline",
             "polymorphic_identity": "vp"
         }

Above, we add a ‘vp_info’ column to the ‘manager’ table, local to the
‘VicePresident’ subclass.  This subclass is linked to the polymorphic
identity ‘"vp"’ which refers to rows which have this data.  By setting
the load style to “inline”, it means that a load of ‘Manager’ objects
will also ensure that the ‘vp_info’ column is queried for in the same
SELECT statement.  A query against ‘Employee’ that encounters a
‘Manager’ row would emit similarly to the following:

     SELECT employee.id AS employee_id, employee.name AS employee_name,
            employee.type AS employee_type
     FROM employee
     )

     SELECT manager.id AS manager_id, employee.id AS employee_id,
            employee.type AS employee_type,
            manager.manager_name AS manager_manager_name,
            manager.vp_info AS manager_vp_info
     FROM employee JOIN manager ON employee.id = manager.id
     WHERE employee.id IN (?) ORDER BY employee.id
     (1,)

Combining “selectin” polymorphic loading with query-time
with_polymorphic() usage is also possible (though this is very
outer-space stuff!); assuming the above mappings had no
‘polymorphic_load’ set up, we could get the same result as follows:

     from sqlalchemy.orm import with_polymorphic, selectin_polymorphic

     manager_poly = with_polymorphic(Manager, [VicePresident])

     s.query(Employee).options(
         selectin_polymorphic(Employee, [manager_poly])).all()

3.4.4.8 Referring to specific subtypes on relationships
.......................................................

Mapped attributes which correspond to a relationship() are
used in querying in order to refer to the linkage between two mappings.
Common uses for this are to refer to a relationship() in
Query.join() as well as in loader options like
joinedload().  When using relationship() where the
target class is an inheritance hierarchy, the API allows that the join,
eager load, or other linkage should target a specific subclass, alias,
or with_polymorphic() alias, of that class hierarchy, rather
than the class directly targeted by the relationship().

The ‘of_type()’ method allows the construction of joins along
relationship() paths while narrowing the criterion to specific
derived aliases or subclasses.  Suppose the ‘employees’ table represents
a collection of employees which are associated with a ‘Company’ object.
We’ll add a ‘company_id’ column to the ‘employees’ table and a new table
‘companies’:

     class Company(Base):
         __tablename__ = 'company'
         id = Column(Integer, primary_key=True)
         name = Column(String(50))
         employees = relationship("Employee",
                         backref='company')

     class Employee(Base):
         __tablename__ = 'employee'
         id = Column(Integer, primary_key=True)
         type = Column(String(20))
         company_id = Column(Integer, ForeignKey('company.id'))
         __mapper_args__ = {
             'polymorphic_on':type,
             'polymorphic_identity':'employee',
         }

     class Engineer(Employee):
         __tablename__ = 'engineer'
         id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
         engineer_info = Column(String(50))
         __mapper_args__ = {'polymorphic_identity':'engineer'}

     class Manager(Employee):
         __tablename__ = 'manager'
         id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
         manager_data = Column(String(50))
         __mapper_args__ = {'polymorphic_identity':'manager'}

When querying from ‘Company’ onto the ‘Employee’ relationship, the
Query.join() method as well as operators like
PropComparator.any() and PropComparator.has() will
create a join from ‘company’ to ‘employee’, without including ‘engineer’
or ‘manager’ in the mix.  If we wish to have criterion which is
specifically against the ‘Engineer’ class, we can tell those methods to
join or subquery against the set of columns representing the subclass
using the ‘PropComparator.of_type()’ operator:

     session.query(Company).\
         join(Company.employees.of_type(Engineer)).\
         filter(Engineer.engineer_info=='someinfo')

Similarly, to join from ‘Company’ to the polymorphic entity that
includes both ‘Engineer’ and ‘Manager’ columns:

     manager_and_engineer = with_polymorphic(
                                 Employee, [Manager, Engineer])

     session.query(Company).\
         join(Company.employees.of_type(manager_and_engineer)).\
         filter(
             or_(
                 manager_and_engineer.Engineer.engineer_info == 'someinfo',
                 manager_and_engineer.Manager.manager_data == 'somedata'
             )
         )

The PropComparator.any() and PropComparator.has()
operators also can be used with ‘of_type()’, such as when the
embedded criterion is in terms of a subclass:

     session.query(Company).\
             filter(
                 Company.employees.of_type(Engineer).
                     any(Engineer.engineer_info=='someinfo')
                 ).all()

3.4.4.9 Eager Loading of Specific or Polymorphic Subtypes
.........................................................

The joinedload(), subqueryload(),
contains_eager() and other eagerloader options support paths which
make use of ‘of_type()’.  Below, we load ‘Company’ rows while eagerly
loading related ‘Engineer’ objects, querying the ‘employee’ and
‘engineer’ tables simultaneously:

     session.query(Company).\
         options(
             subqueryload(Company.employees.of_type(Engineer)).
             subqueryload(Engineer.machines)
             )
         )

As is the case with Query.join(),
PropComparator.of_type() can be used to combine eager loading and
with_polymorphic(), so that all sub-attributes of all
referenced subtypes can be loaded:

     manager_and_engineer = with_polymorphic(
                                 Employee, [Manager, Engineer],
                                 flat=True)

     session.query(Company).\
         options(
             joinedload(
                 Company.employees.of_type(manager_and_engineer)
             )
         )

     Note: When using with_polymorphic() in conjunction with
     joinedload(), the with_polymorphic() object
     must be against an “aliased” object, that is an instance of
     Alias, so that the polymorphic selectable is aliased (an
     informative error message is raised otherwise).

     The typical way to do this is to include the
     with_polymorphic.aliased or ‘flat’ flag, which will apply
     this aliasing automatically.  However, if the
     with_polymorphic.selectable argument is being used to pass an
     object that is already an Alias object then this flag
     should `not' be set.  The “flat” option implies the “aliased”
     option and is an alternate form of aliasing against join objects
     that produces fewer subqueries.

Once PropComparator.of_type() is the target of the eager
load, that’s the entity we would use for subsequent chaining, not the
original class or derived class.  If we wanted to further eager load a
collection on the eager-loaded ‘Engineer’ class, we access this class
from the namespace of the with_polymorphic() object:

     session.query(Company).\
         options(
             joinedload(Company.employees.of_type(manager_and_engineer)).\
             subqueryload(manager_and_engineer.Engineer.computers)
             )
         )

3.4.4.10 Loading objects with joined table inheritance
......................................................

When using joined table inheritance, if we query for a specific subclass
that represents a JOIN of two tables such as our ‘Engineer’ example from
the inheritance section, the SQL emitted is a join:

     session.query(Engineer).all()

The above query will emit SQL like:

     {opensql}
     SELECT employee.id AS employee_id,
         employee.name AS employee_name, employee.type AS employee_type,
         engineer.name AS engineer_name
     FROM employee JOIN engineer
     ON employee.id = engineer.id

We will then get a collection of ‘Engineer’ objects back, which will
contain all columns from ‘employee’ and ‘engineer’ loaded.

However, when emitting a Query against a base class, the
behavior is to load only from the base table:

     session.query(Employee).all()

Above, the default behavior would be to SELECT only from the ‘employee’
table and not from any “sub” tables (‘engineer’ and ‘manager’, in our
previous examples):

     {opensql}
     SELECT employee.id AS employee_id,
         employee.name AS employee_name, employee.type AS employee_type
     FROM employee
     []

After a collection of ‘Employee’ objects has been returned from the
query, and as attributes are requested from those ‘Employee’ objects
which are represented in either the ‘engineer’ or ‘manager’ child
tables, a second load is issued for the columns in that related row, if
the data was not already loaded.  So above, after accessing the objects
you’d see further SQL issued along the lines of:

     {opensql}
     SELECT manager.id AS manager_id,
         manager.manager_data AS manager_manager_data
     FROM manager
     WHERE ? = manager.id
     [5]
     SELECT engineer.id AS engineer_id,
         engineer.engineer_info AS engineer_engineer_info
     FROM engineer
     WHERE ? = engineer.id
     [2]

The with_polymorphic() function and related configuration
options allow us to instead emit a JOIN up front which will
conditionally load against ‘employee’, ‘engineer’, or ‘manager’, very
much like joined eager loading works for relationships, removing the
necessity for a second per-entity load:

     from sqlalchemy.orm import with_polymorphic

     eng_plus_manager = with_polymorphic(Employee, [Engineer, Manager])

     query = session.query(eng_plus_manager)

The above produces a query which joins the ‘employee’ table to both the
‘engineer’ and ‘manager’ tables like the following:

     query.all()
     {opensql}
     SELECT employee.id AS employee_id,
         engineer.id AS engineer_id,
         manager.id AS manager_id,
         employee.name AS employee_name,
         employee.type AS employee_type,
         engineer.engineer_info AS engineer_engineer_info,
         manager.manager_data AS manager_manager_data
     FROM employee
         LEFT OUTER JOIN engineer
         ON employee.id = engineer.id
         LEFT OUTER JOIN manager
         ON employee.id = manager.id
     []

The section Using with_polymorphic discusses the
with_polymorphic() function and its configurational variants.

See also
........

See Using with_polymorphic.

3.4.4.11 Loading objects with single table inheritance
......................................................

In modern Declarative, single inheritance mappings produce Column
objects that are mapped only to a subclass, and not available from
the superclass, even though they are present on the same table.  In our
example from Single Table Inheritance, the ‘Manager’ mapping
for example had a Column specified:

     class Manager(Employee):
         manager_data = Column(String(50))

         __mapper_args__ = {
             'polymorphic_identity':'manager'
         }

Above, there would be no ‘Employee.manager_data’ attribute, even though
the ‘employee’ table has a ‘manager_data’ column.  A query against
‘Manager’ will include this column in the query, as well as an IN clause
to limit rows only to ‘Manager’ objects:

     session.query(Manager).all()
     {opensql}
     SELECT
         employee.id AS employee_id,
         employee.name AS employee_name,
         employee.type AS employee_type,
         employee.manager_data AS employee_manager_data
     FROM employee
     WHERE employee.type IN (?)

     ('manager',)

However, in a similar way to that of joined table inheritance, a query
against ‘Employee’ will only query for columns mapped to ‘Employee’:

     session.query(Employee).all()
     {opensql}
     SELECT employee.id AS employee_id,
         employee.name AS employee_name,
         employee.type AS employee_type
     FROM employee

If we get back an instance of ‘Manager’ from our result, accessing
additional columns only mapped to ‘Manager’ emits a lazy load for those
columns, in a similar way to joined inheritance:

     SELECT employee.manager_data AS employee_manager_data
     FROM employee
     WHERE employee.id = ? AND employee.type IN (?)

The with_polymorphic() function serves a similar role as
joined inheritance in the case of single inheritance; it allows both for
eager loading of subclass attributes as well as specification of
subclasses in a query, just without the overhead of using OUTER JOIN:

     employee_poly = with_polymorphic(Employee, '*')

     q = session.query(employee_poly).filter(
         or_(
             employee_poly.name == 'a',
             employee_poly.Manager.manager_data == 'b'
         )
     )

Above, our query remains against a single table however we can refer to
the columns present in ‘Manager’ or ‘Engineer’ using the “polymorphic”
namespace.  Since we specified ‘"*"’ for the entities, both ‘Engineer’
and ‘Manager’ will be loaded at once.  SQL emitted would be:

     q.all()
     {opensql}
     SELECT
         employee.id AS employee_id, employee.name AS employee_name,
         employee.type AS employee_type,
         employee.manager_data AS employee_manager_data,
         employee.engineer_info AS employee_engineer_info
     FROM employee
     WHERE employee.name = :name_1
     OR employee.manager_data = :manager_data_1

3.4.4.12 Inheritance Loading API
................................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See selectin_polymorphic.(base_cls,Indicate an eager load should take place for all attributes specific to a subclass.
classes)

See with_polymorphic.(base,Produce an AliasedClass construct which specifies columns for descendant mappers
classes[,      of the given base.
selectable,
flat, ...])

 -- Function: sqlalchemy.orm.with_polymorphic (base, classes,
          selectable=False, flat=False, polymorphic_on=None,
          aliased=False, innerjoin=False, _use_mapper_path=False,
          _existing_alias=None)

     Produce an AliasedClass construct which specifies
     columns for descendant mappers of the given base.

     Using this method will ensure that each descendant mapper’s tables
     are included in the FROM clause, and will allow filter() criterion
     to be used against those tables.  The resulting instances will also
     have those columns already loaded so that no “post fetch” of those
     columns will be required.

     See also
     ........

     See Using with_polymorphic. - full discussion of
     with_polymorphic().

     Parameters:

        * ‘base’ – Base class to be aliased.

        * ‘classes’ – a single class or mapper, or list of
          class/mappers, which inherit from the base class.
          Alternatively, it may also be the string ‘'*'’, in which case
          all descending mapped classes will be added to the FROM
          clause.

        * ‘aliased’ – when True, the selectable will be aliased.  For a
          JOIN, this means the JOIN will be SELECTed from inside of a
          subquery unless the with_polymorphic.flat flag is
          set to True, which is recommended for simpler use cases.

        * ‘flat’ – Boolean, will be passed through to the
          FromClause.alias() call so that aliases of Join
          objects will alias the individual tables inside the join,
          rather than creating a subquery.  This is generally supported
          by all modern databases with regards to right-nested joins and
          generally produces more efficient queries.  Setting this flag
          is recommended as long as the resulting SQL is functional.

        * ‘selectable’ – a table or subquery that will be used in place
          of the generated FROM clause.  This argument is required if
          any of the desired classes use concrete table inheritance,
          since SQLAlchemy currently cannot generate UNIONs among tables
          automatically.  If used, the ‘selectable’ argument must
          represent the full set of tables and columns mapped by every
          mapped class.  Otherwise, the unaccounted mapped columns will
          result in their table being appended directly to the FROM
          clause which will usually lead to incorrect results.

        * ‘polymorphic_on’ – a column to be used as the “discriminator”
          column for the given selectable.  If not given, the
          polymorphic_on attribute of the base classes’ mapper will be
          used, if any.  This is useful for mappings that don’t have
          polymorphic loading behavior by default.

        * ‘innerjoin’ – if True, an INNER JOIN will be used.  This
          should only be specified if querying for one specific subtype
          only

 -- Function: sqlalchemy.orm.selectin_polymorphic (base_cls, classes)

     Indicate an eager load should take place for all attributes
     specific to a subclass.

     This uses an additional SELECT with IN against all matched primary
     key values, and is the per-query analogue to the ‘"selectin"’
     setting on the mapper.polymorphic_load parameter.

     New in version 1.2.

     See also
     ........

     See Polymorphic Selectin Loading.

3.4.5 Constructors and Object Initialization
--------------------------------------------

Mapping imposes no restrictions or requirements on the constructor
(‘__init__’) method for the class.  You are free to require any
arguments for the function that you wish, assign attributes to the
instance that are unknown to the ORM, and generally do anything else you
would normally do when writing a constructor for a Python class.

The SQLAlchemy ORM does not call ‘__init__’ when recreating objects from
database rows.  The ORM’s process is somewhat akin to the Python
standard library’s ‘pickle’ module, invoking the low level ‘__new__’
method and then quietly restoring attributes directly on the instance
rather than calling ‘__init__’.

If you need to do some setup on database-loaded instances before they’re
ready to use, there is an event hook known as
InstanceEvents.load() which can achieve this; it is also available
via a class-specific decorator called reconstructor().  When
using reconstructor(), the mapper will invoke the decorated
method with no arguments every time it loads or reconstructs an instance
of the class.  This is useful for recreating transient properties that
are normally assigned in ‘__init__’:

     from sqlalchemy import orm

     class MyMappedClass(object):
         def __init__(self, data):
             self.data = data
             # we need stuff on all instances, but not in the database.
             self.stuff = []

         @orm.reconstructor
         def init_on_load(self):
             self.stuff = []

Above, when ‘obj = MyMappedClass()’ is executed, the ‘__init__’
constructor is invoked normally and the ‘data’ argument is required.
When instances are loaded during a ‘Query’ operation as in
‘query(MyMappedClass).one()’, ‘init_on_load’ is called.

Any method may be tagged as the reconstructor(), even the
‘__init__’ method itself.  It is invoked after all immediate
column-level attributes are loaded as well as after eagerly-loaded
scalar relationships.  Eagerly loaded collections may be only partially
populated or not populated at all, depending on the kind of eager
loading used.

ORM state changes made to objects at this stage will not be recorded for
the next flush operation, so the activity within a reconstructor should
be conservative.

reconstructor() is a shortcut into a larger system of
“instance level” events, which can be subscribed to using the event API
- see InstanceEvents for the full API description of these
events.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See reconstructor.(fn)Decorate a method as the ‘reconstructor’ hook.

 -- Function: sqlalchemy.orm.reconstructor (fn)

     Decorate a method as the ‘reconstructor’ hook.

     Designates a method as the “reconstructor”, an ‘__init__’-like
     method that will be called by the ORM after the instance has been
     loaded from the database or otherwise reconstituted.

     The reconstructor will be invoked with no arguments.  Scalar
     (non-collection) database-mapped attributes of the instance will be
     available for use within the function.  Eagerly-loaded collections
     are generally not yet available and will usually only contain the
     first element.  ORM state changes made to objects at this stage
     will not be recorded for the next flush() operation, so the
     activity within a reconstructor should be conservative.

     See also
     ........

     See Constructors and Object Initialization.

     See InstanceEvents.load().

3.4.6 Query API
---------------

This section presents the API reference for the ORM Query
object.  For a walkthrough of how to use this object, see Object Relational Tutorial (1.x API).

3.4.6.1 The Query Object
........................

Query is produced in terms of a given Session,
using the Session.query() method:

     q = session.query(SomeMappedClass)

Following is the full interface for the Query object.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See Query.ORM-level SQL construction object.

 -- Class: sqlalchemy.orm.Query (entities, session=None)

     ORM-level SQL construction object.

     Query is the source of all SELECT statements generated
     by the ORM, both those formulated by end-user query operations as
     well as by high level internal operations such as related
     collection loading.  It features a generative interface whereby
     successive calls return a new Query object, a copy of
     the former with additional criteria and options associated with it.

     Query objects are normally initially generated using
     the Session.query() method of Session, and in
     less common cases by instantiating the Query directly
     and associating with a Session using the
     Query.with_session() method.

     For a full walk through of Query usage, see the
     Object Relational Tutorial (1.x API).

     `Class signature'

     class sqlalchemy.orm.Query.
     (‘sqlalchemy.sql.expression._SelectFromElements’,
     ‘sqlalchemy.sql.annotation.SupportsCloneAnnotations’, see
     sqlalchemy.sql.expression.HasPrefixes,
     sqlalchemy.sql.expression.HasSuffixes,
     ‘sqlalchemy.sql.expression.HasHints’, see
     sqlalchemy.sql.expression.Executable)

      -- Method: sqlalchemy.orm.Query..prefix_with (*expr,
               **kw)

          `inherited from the' HasPrefixes.prefix_with().
          `method of' HasPrefixes.

          Add one or more expressions following the statement keyword,
          i.e.  SELECT, INSERT, UPDATE, or DELETE. Generative.

          This is used to support backend-specific prefix keywords such
          as those provided by MySQL.

          E.g.:

               stmt = table.insert().prefix_with("LOW_PRIORITY", dialect="mysql")

               # MySQL 5.7 optimizer hints
               stmt = select(table).prefix_with(
                   "/*+ BKA(t1) */", dialect="mysql")

          Multiple prefixes can be specified by multiple calls to
          HasPrefixes.prefix_with().

          Parameters:

             * ‘*expr’ – textual or ClauseElement construct
               which will be rendered following the INSERT, UPDATE, or
               DELETE keyword.

             * ‘**kw’ – A single keyword ‘dialect’ is accepted.  This is
               an optional string dialect name which will limit
               rendering of this prefix to only that dialect.

      -- Method: sqlalchemy.orm.Query..suffix_with (*expr,
               **kw)

          `inherited from the' HasSuffixes.suffix_with().
          `method of' HasSuffixes.

          Add one or more expressions following the statement as a
          whole.

          This is used to support backend-specific suffix keywords on
          certain constructs.

          E.g.:

               stmt = select(col1, col2).cte().suffix_with(
                   "cycle empno set y_cycle to 1 default 0", dialect="oracle")

          Multiple suffixes can be specified by multiple calls to
          HasSuffixes.suffix_with().

          Parameters:

             * ‘*expr’ – textual or ClauseElement construct
               which will be rendered following the target clause.

             * ‘**kw’ – A single keyword ‘dialect’ is accepted.  This is
               an optional string dialect name which will limit
               rendering of this suffix to only that dialect.

      -- Method: sqlalchemy.orm.Query..with_hint (selectable,
               text, dialect_name='*')

          `inherited from the' ‘HasHints.with_hint()’ `method of'
          ‘HasHints’

          Add an indexing or other executional context hint for the
          given selectable to this Select or other selectable
          object.

          The text of the hint is rendered in the appropriate location
          for the database backend in use, relative to the given
          Table or Alias passed as the ‘selectable’
          argument.  The dialect implementation typically uses Python
          string substitution syntax with the token ‘%(name)s’ to render
          the name of the table or alias.  E.g.  when using Oracle, the
          following:

               select(mytable).\
                   with_hint(mytable, "index(%(name)s ix_mytable)")

          Would render SQL as:

               select /*+ index(mytable ix_mytable) */ ... from mytable

          The ‘dialect_name’ option will limit the rendering of a
          particular hint to a particular backend.  Such as, to add
          hints for both Oracle and Sybase simultaneously:

               select(mytable).\
                   with_hint(mytable, "index(%(name)s ix_mytable)", 'oracle').\
                   with_hint(mytable, "WITH INDEX ix_mytable", 'sybase')

          See also
          ........

          See Select.with_statement_hint().

      -- Method: sqlalchemy.orm.Query..with_statement_hint
               (text, dialect_name='*')

          `inherited from the' ‘HasHints.with_statement_hint()’ `method
          of' ‘HasHints’

          Add a statement hint to this Select or other
          selectable object.

          This method is similar to Select.with_hint()
          except that it does not require an individual table, and
          instead applies to the statement as a whole.

          Hints here are specific to the backend database and may
          include directives such as isolation levels, file directives,
          fetch directives, etc.

          New in version 1.0.0.

          See also
          ........

          See Select.with_hint().

          See Select.prefix_with(). - generic SELECT prefixing
          which also can suit some database-specific HINT syntaxes such
          as MySQL optimizer hints

      -- Method: sqlalchemy.orm.Query..__init__ (entities,
               session=None)

          Construct a Query directly.

          E.g.:

               q = Query([User, Address], session=some_session)

          The above is equivalent to:

               q = some_session.query(User, Address)

          Parameters:

             * ‘entities’ – a sequence of entities and/or SQL
               expressions.

             * ‘session’ – a Session with which the
               Query will be associated.  Optional; a Query
               can be associated with a Session
               generatively via the Query.with_session()
               method as well.

          See also
          ........

          See Session.query().

          See Query.with_session().

      -- Method: sqlalchemy.orm.Query..add_column (column)

          Add a column expression to the list of result columns to be
          returned.

          Deprecated since version 1.4: Query.add_column()
          is deprecated and will be removed in a future release.  Please
          use Query.add_columns().

      -- Method: sqlalchemy.orm.Query..add_columns (*column)

          Add one or more column expressions to the list of result
          columns to be returned.

      -- Method: sqlalchemy.orm.Query..add_entity (entity,
               alias=None)

          add a mapped entity to the list of result columns to be
          returned.

      -- Method: sqlalchemy.orm.Query..all ()

          Return the results represented by this Query as a
          list.

          This results in an execution of the underlying SQL statement.

               Warning: The Query object, when asked to
               return either a sequence or iterator that consists of
               full ORM-mapped entities, will `deduplicate entries based
               on primary key'.  See the FAQ for more details.

                    See also
                    ........

                    See My Query does not return the same number of objects as query.count() tells me - why?.

      -- Method: sqlalchemy.orm.Query..apply_labels ()

          Deprecated since version 1.4: The Query.with_labels()
          and Query.apply_labels() method is considered
          legacy as of the 1.x series of SQLAlchemy and will be removed
          in 2.0.  Use set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
          instead.  (Background on SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

      -- Method: sqlalchemy.orm.Query..as_scalar ()

          Return the full SELECT statement represented by this
          Query, converted to a scalar subquery.

          Deprecated since version 1.4: The Query.as_scalar()
          method is deprecated and will be removed in a future
          release.  Please refer to Query.scalar_subquery().

      -- Method: sqlalchemy.orm.Query..autoflush (setting)

          Return a Query with a specific ‘autoflush’ setting.

          As of SQLAlchemy 1.4, the Query.autoflush() method
          is equivalent to using the ‘autoflush’ execution option at the
          ORM level.  See the section Autoflush for further
          background on this option.

      -- Attribute: sqlalchemy.orm.Query..column_descriptions

          Return metadata about the columns which would be returned by
          this Query.

          Format is a list of dictionaries:

               user_alias = aliased(User, name='user2')
               q = sess.query(User, User.id, user_alias)

               # this expression:
               q.column_descriptions

               # would return:
               [
                   {
                       'name':'User',
                       'type':User,
                       'aliased':False,
                       'expr':User,
                       'entity': User
                   },
                   {
                       'name':'id',
                       'type':Integer(),
                       'aliased':False,
                       'expr':User.id,
                       'entity': User
                   },
                   {
                       'name':'user2',
                       'type':User,
                       'aliased':True,
                       'expr':user_alias,
                       'entity': user_alias
                   }
               ]

      -- Method: sqlalchemy.orm.Query..correlate
               (*fromclauses)

          Return a Query construct which will correlate the
          given FROM clauses to that of an enclosing Query
          or select().

          The method here accepts mapped classes, see aliased()
          constructs, and mapper() constructs as arguments,
          which are resolved into expression constructs, in addition to
          appropriate expression constructs.

          The correlation arguments are ultimately passed to
          Select.correlate() after coercion to expression
          constructs.

          The correlation arguments take effect in such cases as when
          Query.from_self() is used, or when a subquery as
          returned by Query.subquery() is embedded in
          another select() construct.

      -- Method: sqlalchemy.orm.Query..count ()

          Return a count of rows this the SQL formed by this
          Query would return.

          This generates the SQL for this Query as follows:

               SELECT count(1) AS count_1 FROM (
                   SELECT <rest of query follows...>
               ) AS anon_1

          The above SQL returns a single row, which is the aggregate
          value of the count function; the Query.count()
          method then returns that single integer value.

               Warning: It is important to note that the value returned
               by count() is `not the same as the number of ORM objects
               that this Query would return from a method such as the
               .all() method'.  The Query object, when asked
               to return full entities, will `deduplicate entries based
               on primary key', meaning if the same primary key value
               would appear in the results more than once, only one
               object of that primary key would be present.  This does
               not apply to a query that is against individual columns.

               See also
               ........

               See My Query does not return the same number of objects as query.count() tells me - why?.

               See Returning Lists and Scalars.

          For fine grained control over specific columns to count, to
          skip the usage of a subquery or otherwise control of the FROM
          clause, or to use other aggregate functions, use
          expression.func expressions in conjunction with
          Session.query(), i.e.:

               from sqlalchemy import func

               # count User records, without
               # using a subquery.
               session.query(func.count(User.id))

               # return count of user "id" grouped
               # by "name"
               session.query(func.count(User.id)).\
                       group_by(User.name)

               from sqlalchemy import distinct

               # count distinct "name" values
               session.query(func.count(distinct(User.name)))

      -- Method: sqlalchemy.orm.Query..cte (name=None,
               recursive=False)

          Return the full SELECT statement represented by this
          Query represented as a common table expression (CTE).

          Parameters and usage are the same as those of the
          SelectBase.cte() method; see that method for further
          details.

          Here is the PostgreSQL WITH RECURSIVE example(1).  Note that,
          in this example, the ‘included_parts’ cte and the ‘incl_alias’
          alias of it are Core selectables, which means the columns are
          accessed via the ‘.c.’ attribute.  The ‘parts_alias’ object is
          an aliased() instance of the ‘Part’ entity, so
          column-mapped attributes are available directly:

               from sqlalchemy.orm import aliased

               class Part(Base):
                   __tablename__ = 'part'
                   part = Column(String, primary_key=True)
                   sub_part = Column(String, primary_key=True)
                   quantity = Column(Integer)

               included_parts = session.query(
                               Part.sub_part,
                               Part.part,
                               Part.quantity).\
                                   filter(Part.part=="our part").\
                                   cte(name="included_parts", recursive=True)

               incl_alias = aliased(included_parts, name="pr")
               parts_alias = aliased(Part, name="p")
               included_parts = included_parts.union_all(
                   session.query(
                       parts_alias.sub_part,
                       parts_alias.part,
                       parts_alias.quantity).\
                           filter(parts_alias.part==incl_alias.c.sub_part)
                   )

               q = session.query(
                       included_parts.c.sub_part,
                       func.sum(included_parts.c.quantity).
                           label('total_quantity')
                   ).\
                   group_by(included_parts.c.sub_part)

          See also
          ........

          See HasCTE.cte().

      -- Method: sqlalchemy.orm.Query..delete
               (synchronize_session='evaluate')

          Perform a DELETE with an arbitrary WHERE clause.

          Deletes rows matched by this query from the database.

          E.g.:

               sess.query(User).filter(User.age == 25).\
                   delete(synchronize_session=False)

               sess.query(User).filter(User.age == 25).\
                   delete(synchronize_session='evaluate')

               Warning: See the section UPDATE and DELETE with arbitrary WHERE clause
               for important caveats and
               warnings, including limitations when using bulk UPDATE
               and DELETE with mapper inheritance configurations.

          Parameters: ‘synchronize_session’ – chooses the strategy to
          update the attributes on objects in the session.  See the
          section UPDATE and DELETE with arbitrary WHERE clause
          for a discussion of these strategies.

          Returns: the count of rows matched as returned by the
          database’s “row count” feature.

          See also
          ........

          See UPDATE and DELETE with arbitrary WHERE clause.

      -- Method: sqlalchemy.orm.Query..distinct (*expr)

          Apply a ‘DISTINCT’ to the query and return the newly resulting
          ‘Query’.

               Note: The ORM-level distinct() call includes
               logic that will automatically add columns from the ORDER
               BY of the query to the columns clause of the SELECT
               statement, to satisfy the common need of the database
               backend that ORDER BY columns be part of the SELECT list
               when DISTINCT is used.  These columns `are not' added to
               the list of columns actually fetched by the Query,
               however, so would not affect results.  The columns
               are passed through when using the Query.statement
               accessor, however.

               Deprecated since version 2.0: This logic is deprecated
               and will be removed in SQLAlchemy 2.0.  See *note Using
               DISTINCT with additional columns, but only select the
               entity: 579. for a description of this use case in 2.0.

          Parameters: ‘*expr’ – optional column expressions.  When
          present, the PostgreSQL dialect will render a ‘DISTINCT ON
          (<expressions>)’ construct.

          Deprecated since version 1.4: Using *expr in other dialects is
          deprecated and will raise CompileError in a future
          version.

      -- Method: sqlalchemy.orm.Query..enable_assertions
               (value)

          Control whether assertions are generated.

          When set to False, the returned Query will not assert its
          state before certain operations, including that LIMIT/OFFSET
          has not been applied when filter() is called, no criterion
          exists when get() is called, and no “from_statement()” exists
          when filter()/order_by()/group_by() etc.  is called.  This
          more permissive mode is used by custom Query subclasses to
          specify criterion or other modifiers outside of the usual
          usage patterns.

          Care should be taken to ensure that the usage pattern is even
          possible.  A statement applied by from_statement() will
          override any criterion set by filter() or order_by(), for
          example.

      -- Method: sqlalchemy.orm.Query..enable_eagerloads
               (value)

          Control whether or not eager joins and subqueries are
          rendered.

          When set to False, the returned Query will not render eager
          joins regardless of joinedload(),
          subqueryload() options or mapper-level
          ‘lazy='joined'’/‘lazy='subquery'’ configurations.

          This is used primarily when nesting the Query’s statement into
          a subquery or other selectable, or when using
          Query.yield_per().

      -- Method: sqlalchemy.orm.Query..except_ (*q)

          Produce an EXCEPT of this Query against one or more queries.

          Works the same way as ‘Query.union()’.  See that method for
          usage examples.

      -- Method: sqlalchemy.orm.Query..except_all (*q)

          Produce an EXCEPT ALL of this Query against one or more
          queries.

          Works the same way as ‘Query.union()’.  See that method for
          usage examples.

      -- Method: sqlalchemy.orm.Query..execution_options
               (**kwargs)

          Set non-SQL options which take effect during execution.

          Options allowed here include all of those accepted by
          Connection.execution_options(), as well as a series of
          ORM specific options:

          ‘populate_existing=True’ - equivalent to using
          Query.populate_existing().

          ‘autoflush=True|False’ - equivalent to using
          Query.autoflush().

          ‘yield_per=<value>’ - equivalent to using
          Query.yield_per().

          Note that the ‘stream_results’ execution option is enabled
          automatically if the ‘Query.yield_per()’ method or execution
          option is used.

          The execution options may also be specified on a per execution
          basis when using 2.0 style queries via the
          Session.execution_options parameter.

          New in version 1.4: - added ORM options to
          Query.execution_options().

          See also
          ........

          See Using Server Side Cursors (a.k.a. stream results).

          See Query.get_execution_options().

      -- Method: sqlalchemy.orm.Query..exists ()

          A convenience method that turns a query into an EXISTS
          subquery of the form EXISTS (SELECT 1 FROM … WHERE …).

          e.g.:

               q = session.query(User).filter(User.name == 'fred')
               session.query(q.exists())

          Producing SQL similar to:

               SELECT EXISTS (
                   SELECT 1 FROM users WHERE users.name = :name_1
               ) AS anon_1

          The EXISTS construct is usually used in the WHERE clause:

               session.query(User.id).filter(q.exists()).scalar()

          Note that some databases such as SQL Server don’t allow an
          EXISTS expression to be present in the columns clause of a
          SELECT. To select a simple boolean value based on the exists
          as a WHERE, use literal():

               from sqlalchemy import literal

               session.query(literal(True)).filter(q.exists()).scalar()

      -- Method: sqlalchemy.orm.Query..filter (*criterion)

          Apply the given filtering criterion to a copy of this
          Query, using SQL expressions.

          e.g.:

               session.query(MyClass).filter(MyClass.name == 'some name')

          Multiple criteria may be specified as comma separated; the
          effect is that they will be joined together using the
          and_() function:

               session.query(MyClass).\
                   filter(MyClass.name == 'some name', MyClass.id > 5)

          The criterion is any SQL expression object applicable to the
          WHERE clause of a select.  String expressions are coerced into
          SQL expression constructs via the text() construct.

          See also
          ........

          See Query.filter_by(). - filter on keyword expressions.

      -- Method: sqlalchemy.orm.Query..filter_by (**kwargs)

          Apply the given filtering criterion to a copy of this
          Query, using keyword expressions.

          e.g.:

               session.query(MyClass).filter_by(name = 'some name')

          Multiple criteria may be specified as comma separated; the
          effect is that they will be joined together using the
          and_() function:

               session.query(MyClass).\
                   filter_by(name = 'some name', id = 5)

          The keyword expressions are extracted from the primary entity
          of the query, or the last entity that was the target of a call
          to Query.join().

          See also
          ........

          See Query.filter(). - filter on SQL expressions.

      -- Method: sqlalchemy.orm.Query..first ()

          Return the first result of this ‘Query’ or None if the result
          doesn’t contain any row.

          first() applies a limit of one within the generated SQL, so
          that only one primary entity row is generated on the server
          side (note this may consist of multiple result rows if
          join-loaded collections are present).

          Calling Query.first() results in an execution of
          the underlying query.

          See also
          ........

          See Query.one().

          See Query.one_or_none().

      -- Method: sqlalchemy.orm.Query..from_self (*entities)

          return a Query that selects from this Query’s SELECT
          statement.

          Deprecated since version 1.4: The Query.from_self()
          method is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  The new approach is to
          use the aliased() construct in conjunction with a
          subquery.  See the section Selecting from the query itself as a subquery
          in the 2.0 migration notes for an
          example.  (Background on SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

          Query.from_self() essentially turns the SELECT
          statement into a SELECT of itself.  Given a query such as:

               q = session.query(User).filter(User.name.like('e%'))

          Given the Query.from_self() version:

               q = session.query(User).filter(User.name.like('e%')).from_self()

          This query renders as:

               SELECT anon_1.user_id AS anon_1_user_id,
                      anon_1.user_name AS anon_1_user_name
               FROM (SELECT "user".id AS user_id, "user".name AS user_name
               FROM "user"
               WHERE "user".name LIKE :name_1) AS anon_1

          There are lots of cases where Query.from_self()
          may be useful.  A simple one is where above, we may want to
          apply a row LIMIT to the set of user objects we query against,
          and then apply additional joins against that row-limited set:

               q = session.query(User).filter(User.name.like('e%')).\
                   limit(5).from_self().\
                   join(User.addresses).filter(Address.email.like('q%'))

          The above query joins to the ‘Address’ entity but only against
          the first five results of the ‘User’ query:

               SELECT anon_1.user_id AS anon_1_user_id,
                      anon_1.user_name AS anon_1_user_name
               FROM (SELECT "user".id AS user_id, "user".name AS user_name
               FROM "user"
               WHERE "user".name LIKE :name_1
                LIMIT :param_1) AS anon_1
               JOIN address ON anon_1.user_id = address.user_id
               WHERE address.email LIKE :email_1

          `Automatic Aliasing'

          Another key behavior of Query.from_self() is that
          it applies `automatic aliasing' to the entities inside the
          subquery, when they are referenced on the outside.  Above, if
          we continue to refer to the ‘User’ entity without any
          additional aliasing applied to it, those references will be in
          terms of the subquery:

               q = session.query(User).filter(User.name.like('e%')).\
                   limit(5).from_self().\
                   join(User.addresses).filter(Address.email.like('q%')).\
                   order_by(User.name)

          The ORDER BY against ‘User.name’ is aliased to be in terms of
          the inner subquery:

               SELECT anon_1.user_id AS anon_1_user_id,
                      anon_1.user_name AS anon_1_user_name
               FROM (SELECT "user".id AS user_id, "user".name AS user_name
               FROM "user"
               WHERE "user".name LIKE :name_1
                LIMIT :param_1) AS anon_1
               JOIN address ON anon_1.user_id = address.user_id
               WHERE address.email LIKE :email_1 ORDER BY anon_1.user_name

          The automatic aliasing feature only works in a `limited' way,
          for simple filters and orderings.  More ambitious
          constructions such as referring to the entity in joins should
          prefer to use explicit subquery objects, typically making use
          of the Query.subquery() method to produce an
          explicit subquery object.  Always test the structure of
          queries by viewing the SQL to ensure a particular structure
          does what’s expected!

          `Changing the Entities'

          Query.from_self() also includes the ability to
          modify what columns are being queried.  In our example, we
          want ‘User.id’ to be queried by the inner query, so that we
          can join to the ‘Address’ entity on the outside, but we only
          wanted the outer query to return the ‘Address.email’ column:

               q = session.query(User).filter(User.name.like('e%')).\
                   limit(5).from_self(Address.email).\
                   join(User.addresses).filter(Address.email.like('q%'))

          yielding:

               SELECT address.email AS address_email
               FROM (SELECT "user".id AS user_id, "user".name AS user_name
               FROM "user"
               WHERE "user".name LIKE :name_1
                LIMIT :param_1) AS anon_1
               JOIN address ON anon_1.user_id = address.user_id
               WHERE address.email LIKE :email_1

          `Looking out for Inner / Outer Columns'

          Keep in mind that when referring to columns that originate
          from inside the subquery, we need to ensure they are present
          in the columns clause of the subquery itself; this is an
          ordinary aspect of SQL. For example, if we wanted to load from
          a joined entity inside the subquery using
          contains_eager(), we need to add those columns.  Below
          illustrates a join of ‘Address’ to ‘User’, then a subquery,
          and then we’d like contains_eager() to access the
          ‘User’ columns:

               q = session.query(Address).join(Address.user).\
                   filter(User.name.like('e%'))

               q = q.add_entity(User).from_self().\
                   options(contains_eager(Address.user))

          We use Query.add_entity() above `before' we call
          Query.from_self() so that the ‘User’ columns are
          present in the inner subquery, so that they are available to
          the contains_eager() modifier we are using on the
          outside, producing:

               SELECT anon_1.address_id AS anon_1_address_id,
                      anon_1.address_email AS anon_1_address_email,
                      anon_1.address_user_id AS anon_1_address_user_id,
                      anon_1.user_id AS anon_1_user_id,
                      anon_1.user_name AS anon_1_user_name
               FROM (
                   SELECT address.id AS address_id,
                   address.email AS address_email,
                   address.user_id AS address_user_id,
                   "user".id AS user_id,
                   "user".name AS user_name
               FROM address JOIN "user" ON "user".id = address.user_id
               WHERE "user".name LIKE :name_1) AS anon_1

          If we didn’t call ‘add_entity(User)’, but still asked
          contains_eager() to load the ‘User’ entity, it would be
          forced to add the table on the outside without the correct
          join criteria - note the ‘anon1, "user"’ phrase at the end:

               -- incorrect query
               SELECT anon_1.address_id AS anon_1_address_id,
                      anon_1.address_email AS anon_1_address_email,
                      anon_1.address_user_id AS anon_1_address_user_id,
                      "user".id AS user_id,
                      "user".name AS user_name
               FROM (
                   SELECT address.id AS address_id,
                   address.email AS address_email,
                   address.user_id AS address_user_id
               FROM address JOIN "user" ON "user".id = address.user_id
               WHERE "user".name LIKE :name_1) AS anon_1, "user"

          Parameters: ‘*entities’ – optional list of entities which will
          replace those being selected.

      -- Method: sqlalchemy.orm.Query..from_statement
               (statement)

          Execute the given SELECT statement and return results.

          This method bypasses all internal statement compilation, and
          the statement is executed without modification.

          The statement is typically either a text() or
          select() construct, and should return the set of columns
          appropriate to the entity class represented by this
          Query.

          See also
          ........

          See Using Textual SQL. - usage examples in the ORM
          tutorial

      -- Method: sqlalchemy.orm.Query..get (ident)

          Return an instance based on the given primary key identifier,
          or ‘None’ if not found.

          Deprecated since version 1.4: The Query.get()
          method is considered legacy as of the 1.x series of SQLAlchemy
          and becomes a legacy construct in 2.0.  The method is now
          available as Session.get(). (Background on
          SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

          E.g.:

               my_user = session.query(User).get(5)

               some_object = session.query(VersionedFoo).get((5, 10))

               some_object = session.query(VersionedFoo).get(
                   {"id": 5, "version_id": 10})

          Query.get() is special in that it provides direct
          access to the identity map of the owning Session.
          If the given primary key identifier is present in the local
          identity map, the object is returned directly from this
          collection and no SQL is emitted, unless the object has been
          marked fully expired.  If not present, a SELECT is performed
          in order to locate the object.

          Query.get() also will perform a check if the
          object is present in the identity map and marked as expired -
          a SELECT is emitted to refresh the object as well as to ensure
          that the row is still present.  If not, see
          ObjectDeletedError is raised.

          Query.get() is only used to return a single mapped
          instance, not multiple instances or individual column
          constructs, and strictly on a single primary key value.  The
          originating Query must be constructed in this way,
          i.e.  against a single mapped entity, with no additional
          filtering criterion.  Loading options via
          Query.options() may be applied however, and will be used
          if the object is not yet locally present.

          Parameters: ‘ident’ – A scalar, tuple, or dictionary
          representing the primary key.  For a composite (e.g.  multiple
          column) primary key, a tuple or dictionary should be passed.

          For a single-column primary key, the scalar calling form is
          typically the most expedient.  If the primary key of a row is
          the value “5”, the call looks like:

               my_object = query.get(5)

          The tuple form contains primary key values typically in the
          order in which they correspond to the mapped Table
          object’s primary key columns, or if the
          Mapper.primary_key configuration parameter were used, in
          the order used for that parameter.  For example, if the
          primary key of a row is represented by the integer digits “5,
          10” the call would look like:

               my_object = query.get((5, 10))

          The dictionary form should include as keys the mapped
          attribute names corresponding to each element of the primary
          key.  If the mapped class has the attributes ‘id’,
          ‘version_id’ as the attributes which store the object’s
          primary key value, the call would look like:

               my_object = query.get({"id": 5, "version_id": 10})

          New in version 1.3: the Query.get() method now
          optionally accepts a dictionary of attribute names to values
          in order to indicate a primary key identifier.

          Returns: The object instance, or ‘None’.

      -- Method: sqlalchemy.orm.Query..get_execution_options
               ()

          Get the non-SQL options which will take effect during
          execution.

          New in version 1.3.

          See also
          ........

          See Query.execution_options().

      -- Attribute: sqlalchemy.orm.Query..get_label_style

          Retrieve the current label style.

          New in version 1.4.

      -- Method: sqlalchemy.orm.Query..group_by (*clauses)

          Apply one or more GROUP BY criterion to the query and return
          the newly resulting Query.

          All existing GROUP BY settings can be suppressed by passing
          ‘None’ - this will suppress any GROUP BY configured on mappers
          as well.

          New in version 1.1: GROUP BY can be cancelled by passing
          ‘None’, in the same way as ORDER BY.

      -- Method: sqlalchemy.orm.Query..having (criterion)

          Apply a HAVING criterion to the query and return the newly
          resulting Query.

          Query.having() is used in conjunction with
          Query.group_by().

          HAVING criterion makes it possible to use filters on aggregate
          functions like COUNT, SUM, AVG, MAX, and MIN, eg.:

               q = session.query(User.id).\
                           join(User.addresses).\
                           group_by(User.id).\
                           having(func.count(Address.id) > 2)

      -- Method: sqlalchemy.orm.Query..instances
               (result_proxy, context=None)

          Return an ORM result given a CursorResult and
          QueryContext.

      -- Method: sqlalchemy.orm.Query..intersect (*q)

          Produce an INTERSECT of this Query against one or more
          queries.

          Works the same way as ‘Query.union()’.  See that method for
          usage examples.

      -- Method: sqlalchemy.orm.Query..intersect_all (*q)

          Produce an INTERSECT ALL of this Query against one or more
          queries.

          Works the same way as ‘Query.union()’.  See that method for
          usage examples.

      -- Attribute: sqlalchemy.orm.Query..is_single_entity

          Indicates if this Query returns tuples or single
          entities.

          Returns True if this query returns a single entity for each
          instance in its result list, and False if this query returns a
          tuple of entities for each result.

          New in version 1.3.11.

          See also
          ........

          See Query.only_return_tuples().

      -- Method: sqlalchemy.orm.Query..join (target, *props,
               **kwargs)

          Create a SQL JOIN against this Query object’s
          criterion and apply generatively, returning the newly
          resulting Query.

          `Simple Relationship Joins'

          Consider a mapping between two classes ‘User’ and ‘Address’,
          with a relationship ‘User.addresses’ representing a collection
          of ‘Address’ objects associated with each ‘User’.  The most
          common usage of Query.join() is to create a JOIN
          along this relationship, using the ‘User.addresses’ attribute
          as an indicator for how this should occur:

               q = session.query(User).join(User.addresses)

          Where above, the call to Query.join() along
          ‘User.addresses’ will result in SQL approximately equivalent
          to:

               SELECT user.id, user.name
               FROM user JOIN address ON user.id = address.user_id

          In the above example we refer to ‘User.addresses’ as passed to
          Query.join() as the “on clause”, that is, it
          indicates how the “ON” portion of the JOIN should be
          constructed.

          To construct a chain of joins, multiple Query.join()
          calls may be used.  The relationship-bound attribute
          implies both the left and right side of the join at once:

               q = session.query(User).\
                       join(User.orders).\
                       join(Order.items).\
                       join(Item.keywords)

               Note: as seen in the above example, `the order in which
               each call to the join() method occurs is important'.
               Query would not, for example, know how to join correctly
               if we were to specify ‘User’, then ‘Item’, then ‘Order’,
               in our chain of joins; in such a case, depending on the
               arguments passed, it may raise an error that it doesn’t
               know how to join, or it may produce invalid SQL in which
               case the database will raise an error.  In correct
               practice, the Query.join() method is invoked
               in such a way that lines up with how we would want the
               JOIN clauses in SQL to be rendered, and each call should
               represent a clear link from what precedes it.

          `Joins to a Target Entity or Selectable'

          A second form of Query.join() allows any mapped
          entity or core selectable construct as a target.  In this
          usage, see Query.join() will attempt to create a JOIN
          along the natural foreign key relationship between two
          entities:

               q = session.query(User).join(Address)

          In the above calling form, see Query.join() is called
          upon to create the “on clause” automatically for us.  This
          calling form will ultimately raise an error if either there
          are no foreign keys between the two entities, or if there are
          multiple foreign key linkages between the target entity and
          the entity or entities already present on the left side such
          that creating a join requires more information.  Note that
          when indicating a join to a target without any ON clause, ORM
          configured relationships are not taken into account.

          `Joins to a Target with an ON Clause'

          The third calling form allows both the target entity as well
          as the ON clause to be passed explicitly.  A example that
          includes a SQL expression as the ON clause is as follows:

               q = session.query(User).join(Address, User.id==Address.user_id)

          The above form may also use a relationship-bound attribute as
          the ON clause as well:

               q = session.query(User).join(Address, User.addresses)

          The above syntax can be useful for the case where we wish to
          join to an alias of a particular target entity.  If we wanted
          to join to ‘Address’ twice, it could be achieved using two
          aliases set up using the aliased() function:

               a1 = aliased(Address)
               a2 = aliased(Address)

               q = session.query(User).\
                       join(a1, User.addresses).\
                       join(a2, User.addresses).\
                       filter(a1.email_address=='ed@foo.com').\
                       filter(a2.email_address=='ed@bar.com')

          The relationship-bound calling form can also specify a target
          entity using the PropComparator.of_type() method;
          a query equivalent to the one above would be:

               a1 = aliased(Address)
               a2 = aliased(Address)

               q = session.query(User).\
                       join(User.addresses.of_type(a1)).\
                       join(User.addresses.of_type(a2)).\
                       filter(a1.email_address == 'ed@foo.com').\
                       filter(a2.email_address == 'ed@bar.com')

          `Augmenting Built-in ON Clauses'

          As a substitute for providing a full custom ON condition for
          an existing relationship, the PropComparator.and_()
          function may be applied to a relationship attribute to
          augment additional criteria into the ON clause; the additional
          criteria will be combined with the default criteria using AND:

               q = session.query(User).join(
                   User.addresses.and_(Address.email_address != 'foo@bar.com')
               )

          New in version 1.4.

          `Joining to Tables and Subqueries'

          The target of a join may also be any table or SELECT
          statement, which may be related to a target entity or not.
          Use the appropriate ‘.subquery()’ method in order to make a
          subquery out of a query:

               subq = session.query(Address).\
                   filter(Address.email_address == 'ed@foo.com').\
                   subquery()

               q = session.query(User).join(
                   subq, User.id == subq.c.user_id
               )

          Joining to a subquery in terms of a specific relationship
          and/or target entity may be achieved by linking the subquery
          to the entity using aliased():

               subq = session.query(Address).\
                   filter(Address.email_address == 'ed@foo.com').\
                   subquery()

               address_subq = aliased(Address, subq)

               q = session.query(User).join(
                   User.addresses.of_type(address_subq)
               )

          `Controlling what to Join From'

          In cases where the left side of the current state of
          Query is not in line with what we want to join from, the
          Query.select_from() method may be used:

               q = session.query(Address).select_from(User).\
                               join(User.addresses).\
                               filter(User.name == 'ed')

          Which will produce SQL similar to:

               SELECT address.* FROM user
                   JOIN address ON user.id=address.user_id
                   WHERE user.name = :name_1

          `Legacy Features of Query.join()'

          Deprecated since version 1.4: The following features are
          deprecated and will be removed in SQLAlchemy 2.0.

          The Query.join() method currently supports several
          usage patterns and arguments that are considered to be legacy
          as of SQLAlchemy 1.3.  A deprecation path will follow in the
          1.4 series for the following features:

             * Joining on relationship names rather than attributes:

                    session.query(User).join("addresses")

               `Why it’s legacy': the string name does not provide
               enough context for Query.join() to always
               know what is desired, notably in that there is no
               indication of what the left side of the join should be.
               This gives rise to flags like ‘from_joinpoint’ as well as
               the ability to place several join clauses in a single
               Query.join() call which don’t solve the
               problem fully while also adding new calling styles that
               are unnecessary and expensive to accommodate internally.

               `Modern calling pattern': Use the actual relationship,
               e.g.  ‘User.addresses’ in the above case:

                    session.query(User).join(User.addresses)

             * Automatic aliasing with the ‘aliased=True’ flag:

                    session.query(Node).join(Node.children, aliased=True).\
                        filter(Node.name == 'some name')

               `Why it’s legacy': the automatic aliasing feature of
               Query is intensely complicated, both in its
               internal implementation as well as in its observed
               behavior, and is almost never used.  It is difficult to
               know upon inspection where and when its aliasing of a
               target entity, ‘Node’ in the above case, will be applied
               and when it won’t, and additionally the feature has to
               use very elaborate heuristics to achieve this implicit
               behavior.

               `Modern calling pattern': Use the aliased()
               construct explicitly:

                    from sqlalchemy.orm import aliased

                    n1 = aliased(Node)

                    session.query(Node).join(Node.children.of_type(n1)).\
                        filter(n1.name == 'some name')

             * Multiple joins in one call:

                    session.query(User).join("orders", "items")

                    session.query(User).join(User.orders, Order.items)

                    session.query(User).join(
                        (Order, User.orders),
                        (Item, Item.order_id == Order.id)
                    )

                    # ... and several more forms actually

               `Why it’s legacy': being able to chain multiple ON
               clauses in one call to Query.join() is yet
               another attempt to solve the problem of being able to
               specify what entity to join from, and is the source of a
               large variety of potential calling patterns that are
               internally expensive and complicated to parse and
               accommodate.

               `Modern calling pattern': Use relationship-bound
               attributes or SQL-oriented ON clauses within separate
               calls, so that each call to Query.join()
               knows what the left side should be:

                    session.query(User).join(User.orders).join(
                        Item, Item.order_id == Order.id)

          Parameters:

             * ‘*props’ – Incoming arguments for Query.join(),
               the props collection in modern use should be
               considered to be a one or two argument form, either as a
               single “target” entity or ORM attribute-bound
               relationship, or as a target entity plus an “on clause”
               which may be a SQL expression or ORM attribute-bound
               relationship.

             * ‘isouter=False’ – If True, the join used will be a left
               outer join, just as if the Query.outerjoin()
               method were called.

             * ‘full=False’ – render FULL OUTER JOIN; implies ‘isouter’.

               New in version 1.1.

             * ‘from_joinpoint=False’ – When using ‘aliased=True’, a
               setting of True here will cause the join to be from the
               most recent joined target, rather than starting back from
               the original FROM clauses of the query.

                    Note: This flag is considered legacy.

             * ‘aliased=False’ – If True, indicate that the JOIN target
               should be anonymously aliased.  Subsequent calls to
               Query.filter() and similar will adapt the incoming
               criterion to the target alias, until
               Query.reset_joinpoint() is called.

                    Note: This flag is considered legacy.

          See also
          ........

          Querying with Joins in the ORM tutorial.

          Mapping Class Inheritance Hierarchies for details
          on how Query.join() is used for inheritance
          relationships.

          See join(). - a standalone ORM-level join function,
          used internally by Query.join(), which in previous
          SQLAlchemy versions was the primary ORM-level joining
          interface.

      -- Method: sqlalchemy.orm.Query..label (name)

          Return the full SELECT statement represented by this
          Query, converted to a scalar subquery with a label of the
          given name.

          Analogous to SelectBase.label().

      -- Attribute: sqlalchemy.orm.Query..lazy_loaded_from

          An InstanceState that is using this Query
          for a lazy load operation.

          Deprecated since version 1.4: This attribute should be viewed
          via the ORMExecuteState.lazy_loaded_from
          attribute, within the context of the
          SessionEvents.do_orm_execute() event.

          See also
          ........

          See ORMExecuteState.lazy_loaded_from.

      -- Method: sqlalchemy.orm.Query..limit (limit)

          Apply a ‘LIMIT’ to the query and return the newly resulting
          ‘Query’.

      -- Attribute: sqlalchemy.orm.Query..load_options

          alias of
          ‘sqlalchemy.orm.context.QueryContext.default_load_options’

      -- Method: sqlalchemy.orm.Query..merge_result
               (iterator, load=True)

          Merge a result into this Query object’s Session.

          Given an iterator returned by a Query of the same
          structure as this one, return an identical iterator of
          results, with all mapped instances merged into the session
          using Session.merge().  This is an optimized method
          which will merge all mapped instances, preserving the
          structure of the result rows and unmapped columns with less
          method overhead than that of calling Session.merge()
          explicitly for each value.

          The structure of the results is determined based on the column
          list of this Query. - if these do not correspond,
          unchecked errors will occur.

          The ‘load’ argument is the same as that of
          Session.merge().

          For an example of how Query.merge_result() is
          used, see the source code for the example Dogpile Caching,
          where Query.merge_result() is used
          to efficiently restore state from a cache back into a target
          Session.

      -- Method: sqlalchemy.orm.Query..offset (offset)

          Apply an ‘OFFSET’ to the query and return the newly resulting
          ‘Query’.

      -- Method: sqlalchemy.orm.Query..one ()

          Return exactly one result or raise an exception.

          Raises ‘sqlalchemy.orm.exc.NoResultFound’ if the query selects
          no rows.  Raises ‘sqlalchemy.orm.exc.MultipleResultsFound’ if
          multiple object identities are returned, or if multiple rows
          are returned for a query that returns only scalar values as
          opposed to full identity-mapped entities.

          Calling one() results in an execution of the
          underlying query.

          See also
          ........

          See Query.first().

          See Query.one_or_none().

      -- Method: sqlalchemy.orm.Query..one_or_none ()

          Return at most one result or raise an exception.

          Returns ‘None’ if the query selects no rows.  Raises
          ‘sqlalchemy.orm.exc.MultipleResultsFound’ if multiple object
          identities are returned, or if multiple rows are returned for
          a query that returns only scalar values as opposed to full
          identity-mapped entities.

          Calling Query.one_or_none() results in an
          execution of the underlying query.

          New in version 1.0.9: Added Query.one_or_none().

          See also
          ........

          See Query.first().

          See Query.one().

      -- Method: sqlalchemy.orm.Query..only_return_tuples
               (value)

          When set to True, the query results will always be a tuple.

          This is specifically for single element queries.  The default
          is False.

          New in version 1.2.5.

          See also
          ........

          See Query.is_single_entity().

      -- Method: sqlalchemy.orm.Query..options (*args)

          Return a new Query object, applying the given list
          of mapper options.

          Most supplied options regard changing how column- and
          relationship-mapped attributes are loaded.

          See also
          ........

          See Deferred Column Loader Query Options.

          See Relationship Loading with Loader Options.

      -- Method: sqlalchemy.orm.Query..order_by (*clauses)

          Apply one or more ORDER BY criterion to the query and return
          the newly resulting Query.

          All existing ORDER BY settings can be suppressed by passing
          ‘None’.

      -- Method: sqlalchemy.orm.Query..outerjoin (target,
               *props, **kwargs)

          Create a left outer join against this ‘Query’ object’s
          criterion and apply generatively, returning the newly
          resulting ‘Query’.

          Usage is the same as the ‘join()’ method.

      -- Method: sqlalchemy.orm.Query..params (*args,
               **kwargs)

          Add values for bind parameters which may have been specified
          in filter().

          Parameters may be specified using **kwargs, or optionally a
          single dictionary as the first positional argument.  The
          reason for both is that **kwargs is convenient, however some
          parameter dictionaries contain unicode keys in which case
          **kwargs cannot be used.

      -- Method: sqlalchemy.orm.Query..populate_existing ()

          Return a Query that will expire and refresh all
          instances as they are loaded, or reused from the current
          Session.

          As of SQLAlchemy 1.4, the Query.populate_existing()
          method is equivalent to using the ‘populate_existing’
          execution option at the ORM level.  See the section
          Populate Existing for further background on this option.

      -- Method: sqlalchemy.orm.Query..reset_joinpoint ()

          Return a new Query, where the “join point” has been
          reset back to the base FROM entities of the query.

          This method is usually used in conjunction with the
          ‘aliased=True’ feature of the Query.join() method.
          See the example in Query.join() for how this is
          used.

      -- Method: sqlalchemy.orm.Query..scalar ()

          Return the first element of the first result or None if no
          rows present.  If multiple rows are returned, raises
          MultipleResultsFound.

               >>> session.query(Item).scalar()
               <Item>
               >>> session.query(Item.id).scalar()
               1
               >>> session.query(Item.id).filter(Item.id < 0).scalar()
               None
               >>> session.query(Item.id, Item.name).scalar()
               1
               >>> session.query(func.count(Parent.id)).scalar()
               20

          This results in an execution of the underlying query.

      -- Method: sqlalchemy.orm.Query..scalar_subquery ()

          Return the full SELECT statement represented by this
          Query, converted to a scalar subquery.

          Analogous to SelectBase.scalar_subquery().

          Changed in version 1.4: The Query.scalar_subquery()
          method replaces the Query.as_scalar() method.

      -- Method: sqlalchemy.orm.Query..select_entity_from
               (from_obj)

          Set the FROM clause of this Query to a core
          selectable, applying it as a replacement FROM clause for
          corresponding mapped entities.

          Deprecated since version 1.4: The
          Query.select_entity_from() method is considered legacy
          as of the 1.x series of SQLAlchemy and will be removed in 2.0.
          Use the aliased() construct instead (Background on
          SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

          The Query.select_entity_from() method supplies an
          alternative approach to the use case of applying an
          aliased() construct explicitly throughout a query.
          Instead of referring to the aliased() construct
          explicitly, see Query.select_entity_from()
          automatically `adapts' all occurrences of the entity to the
          target selectable.

          Given a case for aliased() such as selecting
          ‘User’ objects from a SELECT statement:

               select_stmt = select(User).where(User.id == 7)
               user_alias = aliased(User, select_stmt)

               q = session.query(user_alias).\
                   filter(user_alias.name == 'ed')

          Above, we apply the ‘user_alias’ object explicitly throughout
          the query.  When it’s not feasible for ‘user_alias’ to be
          referenced explicitly in many places, see
          Query.select_entity_from() may be used at the start of
          the query to adapt the existing ‘User’ entity:

               q = session.query(User).\
                   select_entity_from(select_stmt.subquery()).\
                   filter(User.name == 'ed')

          Above, the generated SQL will show that the ‘User’ entity is
          adapted to our statement, even in the case of the WHERE
          clause:

               SELECT anon_1.id AS anon_1_id, anon_1.name AS anon_1_name
               FROM (SELECT "user".id AS id, "user".name AS name
               FROM "user"
               WHERE "user".id = :id_1) AS anon_1
               WHERE anon_1.name = :name_1

          The Query.select_entity_from() method is similar
          to the Query.select_from() method, in that it sets
          the FROM clause of the query.  The difference is that it
          additionally applies adaptation to the other parts of the
          query that refer to the primary entity.  If above we had used
          Query.select_from() instead, the SQL generated
          would have been:

               -- uses plain select_from(), not select_entity_from()
               SELECT "user".id AS user_id, "user".name AS user_name
               FROM "user", (SELECT "user".id AS id, "user".name AS name
               FROM "user"
               WHERE "user".id = :id_1) AS anon_1
               WHERE "user".name = :name_1

          To supply textual SQL to the Query.select_entity_from()
          method, we can make use of the text()
          construct.  However, the text() construct needs to
          be aligned with the columns of our entity, which is achieved
          by making use of the TextClause.columns() method:

               text_stmt = text("select id, name from user").columns(
                   User.id, User.name).subquery()
               q = session.query(User).select_entity_from(text_stmt)

          Query.select_entity_from() itself accepts an
          aliased() object, so that the special options of
          aliased() such as aliased.adapt_on_names may
          be used within the scope of the
          Query.select_entity_from() method’s adaptation services.
          Suppose a view ‘user_view’ also returns rows from ‘user’.  If
          we reflect this view into a Table, this view has no
          relationship to the Table to which we are mapped,
          however we can use name matching to select from it:

               user_view = Table('user_view', metadata,
                                 autoload_with=engine)
               user_view_alias = aliased(
                   User, user_view, adapt_on_names=True)
               q = session.query(User).\
                   select_entity_from(user_view_alias).\
                   order_by(User.name)

          Changed in version 1.1.7: The
          Query.select_entity_from() method now accepts an
          aliased() object as an alternative to a
          FromClause object.

          Parameters: ‘from_obj’ – a FromClause object that
          will replace the FROM clause of this Query.  It
          also may be an instance of aliased().

          See also
          ........

          See Query.select_from().

      -- Method: sqlalchemy.orm.Query..select_from
               (*from_obj)

          Set the FROM clause of this Query explicitly.

          Query.select_from() is often used in conjunction
          with Query.join() in order to control which entity
          is selected from on the “left” side of the join.

          The entity or selectable object here effectively replaces the
          “left edge” of any calls to Query.join(), when no
          joinpoint is otherwise established - usually, the default
          “join point” is the leftmost entity in the Query
          object’s list of entities to be selected.

          A typical example:

               q = session.query(Address).select_from(User).\
                   join(User.addresses).\
                   filter(User.name == 'ed')

          Which produces SQL equivalent to:

               SELECT address.* FROM user
               JOIN address ON user.id=address.user_id
               WHERE user.name = :name_1

          Parameters: ‘*from_obj’ – collection of one or more entities
          to apply to the FROM clause.  Entities can be mapped classes,
          see AliasedClass objects, see Mapper objects
          as well as core FromClause elements like
          subqueries.

          Changed in version 0.9: This method no longer applies the
          given FROM object to be the selectable from which matching
          entities select from; the select_entity_from()
          method now accomplishes this.  See that method for a
          description of this behavior.

          See also
          ........

          See Query.join().

          See Query.select_entity_from().

      -- Attribute: sqlalchemy.orm.Query..selectable

          Return the Select object emitted by this
          Query.

          Used for inspect() compatibility, this is
          equivalent to:

               query.enable_eagerloads(False).with_labels().statement

      -- Method: sqlalchemy.orm.Query..set_label_style
               (style)

          Apply column labels to the return value of Query.statement.

          Indicates that this Query’s ‘statement’ accessor should return
          a SELECT statement that applies labels to all columns in the
          form <tablename>_<columnname>; this is commonly used to
          disambiguate columns from multiple tables which have the same
          name.

          When the ‘Query’ actually issues SQL to load rows, it always
          uses column labeling.

               Note: The Query.set_label_style() method
               `only' applies the output of Query.statement,
               and `not' to any of the result-row invoking systems of
               Query itself, e.g.  see Query.first(),
               Query.all(), etc.  To execute a query using
               Query.set_label_style(), invoke the
               Query.statement using Session.execute():

                    result = session.execute(
                        query
                        .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
                        .statement
                    )

          New in version 1.4.

      -- Method: sqlalchemy.orm.Query..slice (start, stop)

          Computes the “slice” of the Query represented by
          the given indices and returns the resulting Query.

          The start and stop indices behave like the argument to
          Python’s built-in ‘range()’ function.  This method provides an
          alternative to using ‘LIMIT’/‘OFFSET’ to get a slice of the
          query.

          For example,

               session.query(User).order_by(User.id).slice(1, 3)

          renders as

               SELECT users.id AS users_id,
                      users.name AS users_name
               FROM users ORDER BY users.id
               LIMIT ? OFFSET ?
               (2, 1)

          See also
          ........

          See Query.limit().

          See Query.offset().

      -- Attribute: sqlalchemy.orm.Query..statement

          The full SELECT statement represented by this Query.

          The statement by default will not have disambiguating labels
          applied to the construct unless with_labels(True) is called
          first.

      -- Method: sqlalchemy.orm.Query..subquery (name=None,
               with_labels=False, reduce_columns=False)

          Return the full SELECT statement represented by this
          Query, embedded within an Alias.

          Eager JOIN generation within the query is disabled.

          Parameters:

             * ‘name’ – string name to be assigned as the alias; this is
               passed through to FromClause.alias().  If
               ‘None’, a name will be deterministically generated at
               compile time.

             * ‘with_labels’ – if True, see with_labels() will
               be called on the Query first to apply
               table-qualified labels to all columns.

             * ‘reduce_columns’ – if True, see
               Select.reduce_columns() will be called on the
               resulting select() construct, to remove
               same-named columns where one also refers to the other via
               foreign key or WHERE clause equivalence.

      -- Method: sqlalchemy.orm.Query..union (*q)

          Produce a UNION of this Query against one or more queries.

          e.g.:

               q1 = sess.query(SomeClass).filter(SomeClass.foo=='bar')
               q2 = sess.query(SomeClass).filter(SomeClass.bar=='foo')

               q3 = q1.union(q2)

          The method accepts multiple Query objects so as to control the
          level of nesting.  A series of ‘union()’ calls such as:

               x.union(y).union(z).all()

          will nest on each ‘union()’, and produces:

               SELECT * FROM (SELECT * FROM (SELECT * FROM X UNION
                               SELECT * FROM y) UNION SELECT * FROM Z)

          Whereas:

               x.union(y, z).all()

          produces:

               SELECT * FROM (SELECT * FROM X UNION SELECT * FROM y UNION
                               SELECT * FROM Z)

          Note that many database backends do not allow ORDER BY to be
          rendered on a query called within UNION, EXCEPT, etc.  To
          disable all ORDER BY clauses including those configured on
          mappers, issue ‘query.order_by(None)’ - the resulting
          Query object will not render ORDER BY within its SELECT
          statement.

      -- Method: sqlalchemy.orm.Query..union_all (*q)

          Produce a UNION ALL of this Query against one or more queries.

          Works the same way as ‘Query.union()’.  See that method for
          usage examples.

      -- Method: sqlalchemy.orm.Query..update (values,
               synchronize_session='evaluate', update_args=None)

          Perform an UPDATE with an arbitrary WHERE clause.

          Updates rows matched by this query in the database.

          E.g.:

               sess.query(User).filter(User.age == 25).\
                   update({User.age: User.age - 10}, synchronize_session=False)

               sess.query(User).filter(User.age == 25).\
                   update({"age": User.age - 10}, synchronize_session='evaluate')

               Warning: See the section UPDATE and DELETE with arbitrary WHERE clause
               for important caveats and
               warnings, including limitations when using arbitrary
               UPDATE and DELETE with mapper inheritance configurations.

          Parameters:

             * ‘values’ – a dictionary with attributes names, or
               alternatively mapped attributes or SQL expressions, as
               keys, and literal values or sql expressions as values.
               If parameter-ordered mode is desired, the
               values can be passed as a list of 2-tuples; this requires
               that the update.preserve_parameter_order flag
               is passed to the Query.update.update_args
               dictionary as well.

             * ‘synchronize_session’ – chooses the strategy to update
               the attributes on objects in the session.  See the
               section UPDATE and DELETE with arbitrary WHERE clause
               for a discussion of these strategies.

             * ‘update_args’ – Optional dictionary, if present will be
               passed to the underlying update() construct
               as the ‘**kw’ for the object.  May be used to pass
               dialect-specific arguments such as ‘mysql_limit’, as well
               as other special arguments such as
               update.preserve_parameter_order.

          Returns: the count of rows matched as returned by the
          database’s “row count” feature.

          See also
          ........

          See UPDATE and DELETE with arbitrary WHERE clause.

      -- Method: sqlalchemy.orm.Query..value (column)

          Return a scalar result corresponding to the given column
          expression.

          Deprecated since version 1.4: Query.value() is
          deprecated and will be removed in a future release.  Please
          use Query.with_entities() in combination with
          Query.scalar().

      -- Method: sqlalchemy.orm.Query..values (*columns)

          Return an iterator yielding result tuples corresponding to the
          given list of columns

          Deprecated since version 1.4: Query.values() is
          deprecated and will be removed in a future release.  Please
          use Query.with_entities().

      -- Method: sqlalchemy.orm.Query..where (*criterion)

          A synonym for Query.filter().

          New in version 1.4.

      -- Attribute: sqlalchemy.orm.Query..whereclause

          A readonly attribute which returns the current WHERE criterion
          for this Query.

          This returned value is a SQL expression construct, or ‘None’
          if no criterion has been established.

      -- Method: sqlalchemy.orm.Query..with_entities
               (*entities)

          Return a new Query replacing the SELECT list with
          the given entities.

          e.g.:

               # Users, filtered on some arbitrary criterion
               # and then ordered by related email address
               q = session.query(User).\
                           join(User.address).\
                           filter(User.name.like('%ed%')).\
                           order_by(Address.email)

               # given *only* User.id==5, Address.email, and 'q', what
               # would the *next* User in the result be ?
               subq = q.with_entities(Address.email).\
                           order_by(None).\
                           filter(User.id==5).\
                           subquery()
               q = q.join((subq, subq.c.email < Address.email)).\
                           limit(1)

      -- Method: sqlalchemy.orm.Query..with_for_update
               (read=False, nowait=False, of=None, skip_locked=False,
               key_share=False)

          return a new Query with the specified options for
          the ‘FOR UPDATE’ clause.

          The behavior of this method is identical to that of
          GenerativeSelect.with_for_update().  When called with no
          arguments, the resulting ‘SELECT’ statement will have a ‘FOR
          UPDATE’ clause appended.  When additional arguments are
          specified, backend-specific options such as ‘FOR UPDATE
          NOWAIT’ or ‘LOCK IN SHARE MODE’ can take effect.

          E.g.:

               q = sess.query(User).populate_existing().with_for_update(nowait=True, of=User)

          The above query on a PostgreSQL backend will render like:

               SELECT users.id AS users_id FROM users FOR UPDATE OF users NOWAIT

               Note: It is generally a good idea to combine the use of
               the Query.populate_existing() method when
               using the Query.with_for_update() method.
               The purpose of Query.populate_existing() is
               to force all the data read from the SELECT to be
               populated into the ORM objects returned, even if these
               objects are already in the identity map.

          See also
          ........

          See GenerativeSelect.with_for_update(). - Core level
          method with full argument and behavioral description.

          See Query.populate_existing(). - overwrites attributes
          of objects already loaded in the identity map.

      -- Method: sqlalchemy.orm.Query..with_labels ()

          Deprecated since version 1.4: The Query.with_labels()
          and Query.apply_labels() method is considered
          legacy as of the 1.x series of SQLAlchemy and will be removed
          in 2.0.  Use set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
          instead.  (Background on SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

      -- Method: sqlalchemy.orm.Query..with_parent (instance,
               property=None, from_entity=None)

          Add filtering criterion that relates the given instance to a
          child object or collection, using its attribute state as well
          as an established relationship() configuration.

          Deprecated since version 1.4: The Query.with_parent()
          method is considered legacy as of the 1.x series of
          SQLAlchemy and becomes a legacy construct in 2.0.  Use the
          with_parent() standalone construct.  (Background
          on SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

          The method uses the with_parent() function to
          generate the clause, the result of which is passed to
          Query.filter().

          Parameters are the same as with_parent(), with the
          exception that the given property can be None, in which case a
          search is performed against this Query object’s
          target mapper.

          Parameters:

             * ‘instance’ – An instance which has some
               relationship().

             * ‘property’ – String property name, or class-bound
               attribute, which indicates what relationship from the
               instance should be used to reconcile the parent/child
               relationship.

             * ‘from_entity’ – Entity in which to consider as the left
               side.  This defaults to the “zero” entity of the
               Query itself.

      -- Method: sqlalchemy.orm.Query..with_polymorphic
               (cls_or_mappers, selectable=None, polymorphic_on=None)

          Load columns for inheriting classes.

          Deprecated since version 1.4: The
          Query.with_polymorphic() method is considered legacy as
          of the 1.x series of SQLAlchemy and will be removed in 2.0.
          Use the orm.with_polymorphic() standalone function (Background
          on SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

          Query.with_polymorphic() applies transformations
          to the “main” mapped class represented by this Query.
          The “main” mapped class here means the Query
          object’s first argument is a full class, i.e.
          ‘session.query(SomeClass)’.  These transformations allow
          additional tables to be present in the FROM clause so that
          columns for a joined-inheritance subclass are available in the
          query, both for the purposes of load-time efficiency as well
          as the ability to use these columns at query time.

          See the documentation section Using with_polymorphic
          for details on how this method is used.

      -- Method: sqlalchemy.orm.Query..with_session (session)

          Return a Query that will use the given
          Session.

          While the Query object is normally instantiated
          using the Session.query() method, it is legal to
          build the Query directly without necessarily using
          a Session.  Such a Query object, or any
          Query already associated with a different
          Session, can produce a new Query object
          associated with a target session using this method:

               from sqlalchemy.orm import Query

               query = Query([MyClass]).filter(MyClass.id == 5)

               result = query.with_session(my_session).one()

      -- Method: sqlalchemy.orm.Query..with_transformation
               (fn)

          Return a new Query object transformed by the given
          function.

          E.g.:

               def filter_something(criterion):
                   def transform(q):
                       return q.filter(criterion)
                   return transform

               q = q.with_transformation(filter_something(x==5))

          This allows ad-hoc recipes to be created for Query
          objects.  See the example at Building Transformers.

      -- Method: sqlalchemy.orm.Query..yield_per (count)

          Yield only ‘count’ rows at a time.

          The purpose of this method is when fetching very large result
          sets (> 10K rows), to batch results in sub-collections and
          yield them out partially, so that the Python interpreter
          doesn’t need to declare very large areas of memory which is
          both time consuming and leads to excessive memory use.  The
          performance from fetching hundreds of thousands of rows can
          often double when a suitable yield-per setting (e.g.
          approximately 1000) is used, even with DBAPIs that buffer rows
          (which are most).

          As of SQLAlchemy 1.4, the Query.yield_per() method
          is equivalent to using the ‘yield_per’ execution option at the
          ORM level.  See the section Yield Per for further
          background on this option.

   ---------- Footnotes ----------

   (1) http://www.postgresql.org/docs/8.4/static/queries-with.html

3.4.6.2 ORM-Specific Query Constructs
.....................................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See aliased.(element[,Produce an alias of the given element, usually an AliasedClass instance.
alias, name,
flat, ...])

See AliasedClass.Represents an “aliased” form of a mapped class for usage with Query.

See AliasedInsp.Provide an inspection interface for an AliasedClass object.

See Bundle.A grouping of SQL expressions that are returned by a Query under one namespace.

See join.(left,Produce an inner join between left and right clauses.
right[,
onclause,
isouter,
...])

See Load.Represents loader options which modify the state of a Query in order to affect
               how various mapped attributes are loaded.

See outerjoin.(left,Produce a left outer join between left and right clauses.
right[,
onclause,
full, ...])

See with_loader_criteria.(entity_or_base,Add additional WHERE criteria to the load for all occurrences of a particular entity.
where_criteria[,
loader_only,
include_aliases,
...])

See with_parent.(instance,Create filtering criterion that relates this query’s primary entity to the given related
prop[,         instance, using established relationship() configuration.
from_entity])

 -- Function: sqlalchemy.orm.aliased (element, alias=None, name=None,
          flat=False, adapt_on_names=False)

     Produce an alias of the given element, usually an
     AliasedClass instance.

     E.g.:

          my_alias = aliased(MyClass)

          session.query(MyClass, my_alias).filter(MyClass.id > my_alias.id)

     The aliased() function is used to create an ad-hoc
     mapping of a mapped class to a new selectable.  By default, a
     selectable is generated from the normally mapped selectable
     (typically a Table. ) using the FromClause.alias()
     method.  However, see aliased() can also be used to
     link the class to a new select() statement.  Also, the
     with_polymorphic() function is a variant of
     aliased() that is intended to specify a so-called
     “polymorphic selectable”, that corresponds to the union of several
     joined-inheritance subclasses at once.

     For convenience, the aliased() function also accepts
     plain FromClause constructs, such as a Table
     or select() construct.  In those cases, the
     FromClause.alias() method is called on the object and the new
     Alias object returned.  The returned Alias
     is not ORM-mapped in this case.

     Parameters:

        * ‘element’ – element to be aliased.  Is normally a mapped
          class, but for convenience can also be a FromClause
          element.

        * ‘alias’ – Optional selectable unit to map the element to.
          This is usually used to link the object to a subquery, and
          should be an aliased select construct as one would produce
          from the Query.subquery() method or the
          Select.subquery() or Select.alias() methods
          of the select() construct.

        * ‘name’ – optional string name to use for the alias, if not
          specified by the ‘alias’ parameter.  The name, among other
          things, forms the attribute name that will be accessible via
          tuples returned by a Query object.  Not supported
          when creating aliases of Join objects.

        * ‘flat’ – Boolean, will be passed through to the
          FromClause.alias() call so that aliases of Join
          objects will alias the individual tables inside the join,
          rather than creating a subquery.  This is generally supported
          by all modern databases with regards to right-nested joins and
          generally produces more efficient queries.

        * ‘adapt_on_names’ – if True, more liberal “matching” will be
          used when mapping the mapped columns of the ORM entity to
          those of the given selectable - a name-based match will be
          performed if the given selectable doesn’t otherwise have a
          column that corresponds to one on the entity.  The use case
          for this is when associating an entity with some derived
          selectable such as one that uses aggregate functions:

               class UnitPrice(Base):
                   __tablename__ = 'unit_price'
                   ...
                   unit_id = Column(Integer)
                   price = Column(Numeric)

               aggregated_unit_price = Session.query(
                                           func.sum(UnitPrice.price).label('price')
                                       ).group_by(UnitPrice.unit_id).subquery()

               aggregated_unit_price = aliased(UnitPrice,
                           alias=aggregated_unit_price, adapt_on_names=True)

          Above, functions on ‘aggregated_unit_price’ which refer to
          ‘.price’ will return the
          ‘func.sum(UnitPrice.price).label('price')’ column, as it is
          matched on the name “price”.  Ordinarily, the “price” function
          wouldn’t have any “column correspondence” to the actual
          ‘UnitPrice.price’ column as it is not a proxy of the original.

 -- Class: sqlalchemy.orm.util.AliasedClass (mapped_class_or_ac,
          alias=None, name=None, flat=False, adapt_on_names=False,
          with_polymorphic_mappers=(),
          with_polymorphic_discriminator=None, base_alias=None,
          use_mapper_path=False, represents_outer_join=False)

     Represents an “aliased” form of a mapped class for usage with
     Query.

     The ORM equivalent of a alias() construct, this object
     mimics the mapped class using a ‘__getattr__’ scheme and maintains
     a reference to a real Alias object.

     A primary purpose of AliasedClass is to serve as an
     alternate within a SQL statement generated by the ORM, such that an
     existing mapped entity can be used in multiple contexts.  A simple
     example:

          # find all pairs of users with the same name
          user_alias = aliased(User)
          session.query(User, user_alias).\
                          join((user_alias, User.id > user_alias.id)).\
                          filter(User.name == user_alias.name)

     AliasedClass is also capable of mapping an existing
     mapped class to an entirely new selectable, provided this
     selectable is column- compatible with the existing mapped
     selectable, and it can also be configured in a mapping as the
     target of a relationship().  See the links below for
     examples.

     The AliasedClass object is constructed typically using
     the aliased() function.  It also is produced with
     additional configuration when using the with_polymorphic()
     function.

     The resulting object is an instance of AliasedClass.
     This object implements an attribute scheme which produces the same
     attribute and method interface as the original mapped class,
     allowing AliasedClass to be compatible with any
     attribute technique which works on the original class, including
     hybrid attributes (see Hybrid Attributes).

     The AliasedClass can be inspected for its underlying
     Mapper, aliased selectable, and other information using
     inspect():

          from sqlalchemy import inspect
          my_alias = aliased(MyClass)
          insp = inspect(my_alias)

     The resulting inspection object is an instance of
     AliasedInsp.

     See also
     ........

     See aliased().

     See with_polymorphic().

     See Relationship to Aliased Class.

     See Row-Limited Relationships with Window Functions.

 -- Class: sqlalchemy.orm.util.AliasedInsp (entity, inspected,
          selectable, name, with_polymorphic_mappers, polymorphic_on,
          _base_alias, _use_mapper_path, adapt_on_names,
          represents_outer_join)

     Provide an inspection interface for an AliasedClass
     object.

     The AliasedInsp object is returned given an
     AliasedClass using the inspect() function:

          from sqlalchemy import inspect
          from sqlalchemy.orm import aliased

          my_alias = aliased(MyMappedClass)
          insp = inspect(my_alias)

     Attributes on AliasedInsp include:

        * ‘entity’ - the AliasedClass represented.

        * ‘mapper’ - the Mapper mapping the underlying
          class.

        * ‘selectable’ - the Alias construct which
          ultimately represents an aliased Table or
          Select construct.

        * ‘name’ - the name of the alias.  Also is used as the attribute
          name when returned in a result tuple from Query.

        * ‘with_polymorphic_mappers’ - collection of Mapper.
          objects indicating all those mappers expressed in the select
          construct for the AliasedClass.

        * ‘polymorphic_on’ - an alternate column or SQL expression which
          will be used as the “discriminator” for a polymorphic load.

     See also
     ........

     See Runtime Inspection API.

     `Class signature'

     class ‘sqlalchemy.orm.AliasedInsp’
     (‘sqlalchemy.orm.ORMEntityColumnsClauseRole’,
     ‘sqlalchemy.orm.ORMFromClauseRole’,
     ‘sqlalchemy.sql.traversals.MemoizedHasCacheKey’,
     ‘sqlalchemy.orm.base.InspectionAttr’)

 -- Class: sqlalchemy.orm.Bundle (name, *exprs, **kw)

     A grouping of SQL expressions that are returned by a Query
     under one namespace.

     The Bundle essentially allows nesting of the
     tuple-based results returned by a column-oriented Query
     object.  It also is extensible via simple subclassing, where the
     primary capability to override is that of how the set of
     expressions should be returned, allowing post-processing as well as
     custom return types, without involving ORM identity-mapped classes.

     New in version 0.9.0.

     See also
     ........

     See Column Bundles.

     `Class signature'

     class sqlalchemy.orm.Bundle.
     (‘sqlalchemy.orm.ORMColumnsClauseRole’,
     ‘sqlalchemy.sql.annotation.SupportsCloneAnnotations’,
     ‘sqlalchemy.orm.base.InspectionAttr’)

      -- Method: sqlalchemy.orm.Bundle..__init__ (name,
               *exprs, **kw)

          Construct a new Bundle.

          e.g.:

               bn = Bundle("mybundle", MyClass.x, MyClass.y)

               for row in session.query(bn).filter(
                       bn.c.x == 5).filter(bn.c.y == 4):
                   print(row.mybundle.x, row.mybundle.y)

          Parameters:

             * ‘name’ – name of the bundle.

             * ‘*exprs’ – columns or SQL expressions comprising the
               bundle.

             * ‘single_entity=False’ – if True, rows for this
               Bundle can be returned as a “single entity” outside
               of any enclosing tuple in the same manner as a mapped
               entity.

      -- Attribute: sqlalchemy.orm.Bundle..c = None

          An alias for Bundle.columns.

      -- Attribute: sqlalchemy.orm.Bundle..columns = None

          A namespace of SQL expressions referred to by this
          Bundle.

               e.g.:

                    bn = Bundle("mybundle", MyClass.x, MyClass.y)

                    q = sess.query(bn).filter(bn.c.x == 5)

               Nesting of bundles is also supported:

                    b1 = Bundle("b1",
                            Bundle('b2', MyClass.a, MyClass.b),
                            Bundle('b3', MyClass.x, MyClass.y)
                        )

                    q = sess.query(b1).filter(
                        b1.c.b2.c.a == 5).filter(b1.c.b3.c.y == 9)

          See also
          ........

          See Bundle.c.

      -- Method: sqlalchemy.orm.Bundle..create_row_processor
               (query, procs, labels)

          Produce the “row processing” function for this Bundle.

          May be overridden by subclasses.

          See also
          ........

          See Column Bundles. - includes an example of
          subclassing.

      -- Method: sqlalchemy.orm.Bundle..label (name)

          Provide a copy of this Bundle passing a new label.

      -- Attribute: sqlalchemy.orm.Bundle..single_entity =
               False

          If True, queries for a single Bundle will be returned as a
          single entity, rather than an element within a keyed tuple.

 -- Class: sqlalchemy.orm.Load (entity)

     Represents loader options which modify the state of a Query
     in order to affect how various mapped attributes are loaded.

     The Load object is in most cases used implicitly behind
     the scenes when one makes use of a query option like
     joinedload(), defer(), or similar.  However, the
     Load object can also be used directly, and in some
     cases can be useful.

     To use Load directly, instantiate it with the target
     mapped class as the argument.  This style of usage is useful when
     dealing with a Query that has multiple entities:

          myopt = Load(MyClass).joinedload("widgets")

     The above ‘myopt’ can now be used with Query.options(),
     where it will only take effect for the ‘MyClass’ entity:

          session.query(MyClass, MyOtherClass).options(myopt)

     One case where Load is useful as public API is when
     specifying “wildcard” options that only take effect for a certain
     class:

          session.query(Order).options(Load(Order).lazyload('*'))

     Above, all relationships on ‘Order’ will be lazy-loaded, but other
     attributes on those descendant objects will load using their normal
     loader strategy.

     See also
     ........

     See Deferred Column Loader Query Options.

     See Deferred Loading across Multiple Entities.

     See Relationship Loading with Loader Options.

     `Class signature'

     class sqlalchemy.orm.Load.
     (‘sqlalchemy.sql.expression.Generative’,
     ‘sqlalchemy.orm.LoaderOption’)

      -- Method: sqlalchemy.orm.Load..baked_lazyload (attr)

          Produce a new Load object with the
          ‘baked_lazyload()’ option applied.

          See ‘baked_lazyload()’ for usage examples.

      -- Method: sqlalchemy.orm.Load..contains_eager (attr,
               alias=None)

          Produce a new Load object with the
          contains_eager() option applied.

          See contains_eager() for usage examples.

      -- Method: sqlalchemy.orm.Load..defaultload (attr)

          Produce a new Load object with the
          defaultload() option applied.

          See defaultload() for usage examples.

      -- Method: sqlalchemy.orm.Load..defer (key,
               raiseload=False)

          Produce a new Load object with the defer()
          option applied.

          See defer() for usage examples.

      -- Method: sqlalchemy.orm.Load..immediateload (attr)

          Produce a new Load object with the
          immediateload() option applied.

          See immediateload() for usage examples.

      -- Method: sqlalchemy.orm.Load..joinedload (attr,
               innerjoin=None)

          Produce a new Load object with the
          joinedload() option applied.

          See joinedload() for usage examples.

      -- Method: sqlalchemy.orm.Load..lazyload (attr)

          Produce a new Load object with the
          lazyload() option applied.

          See lazyload() for usage examples.

      -- Method: sqlalchemy.orm.Load..load_only (*attrs)

          Produce a new Load object with the
          load_only() option applied.

          See load_only() for usage examples.

      -- Method: sqlalchemy.orm.Load..noload (attr)

          Produce a new Load object with the noload()
          option applied.

          See noload() for usage examples.

      -- Method: sqlalchemy.orm.Load..options (*opts)

          Apply a series of options as sub-options to this Load
          object.

          E.g.:

               query = session.query(Author)
               query = query.options(
                           joinedload(Author.book).options(
                               load_only("summary", "excerpt"),
                               joinedload(Book.citations).options(
                                   joinedload(Citation.author)
                               )
                           )
                       )

          Parameters: ‘*opts’ – A series of loader option objects
          (ultimately Load objects) which should be applied
          to the path specified by this Load object.

          New in version 1.3.6.

          See also
          ........

          See defaultload().

          See Relationship Loading with Loader Options.

          See Deferred Loading across Multiple Entities.

      -- Method: sqlalchemy.orm.Load..process_compile_state
               (compile_state)

          Apply a modification to a given ‘CompileState’.

      -- Method: sqlalchemy.orm.Load..raiseload (attr,
               sql_only=False)

          Produce a new Load object with the
          raiseload() option applied.

          See raiseload() for usage examples.

      -- Method: sqlalchemy.orm.Load..selectin_polymorphic
               (classes)

          Produce a new Load object with the
          selectin_polymorphic() option applied.

          See selectin_polymorphic() for usage examples.

      -- Method: sqlalchemy.orm.Load..selectinload (attr)

          Produce a new Load object with the
          selectinload() option applied.

          See selectinload() for usage examples.

      -- Method: sqlalchemy.orm.Load..subqueryload (attr)

          Produce a new Load object with the
          subqueryload() option applied.

          See subqueryload() for usage examples.

      -- Method: sqlalchemy.orm.Load..undefer (key)

          Produce a new Load object with the
          undefer() option applied.

          See undefer() for usage examples.

      -- Method: sqlalchemy.orm.Load..undefer_group (name)

          Produce a new Load object with the
          undefer_group() option applied.

          See undefer_group() for usage examples.

      -- Method: sqlalchemy.orm.Load..with_expression (key,
               expression)

          Produce a new Load object with the
          with_expression() option applied.

          See with_expression() for usage examples.

 -- Function: sqlalchemy.orm.with_loader_criteria (entity_or_base,
          where_criteria, loader_only=False, include_aliases=False,
          propagate_to_loaders=True, track_closure_variables=True)

     Add additional WHERE criteria to the load for all occurrences of a
     particular entity.

     New in version 1.4.

     The with_loader_criteria() option is intended to add
     limiting criteria to a particular kind of entity in a query,
     `globally', meaning it will apply to the entity as it appears in
     the SELECT query as well as within any subqueries, join conditions,
     and relationship loads, including both eager and lazy loaders,
     without the need for it to be specified in any particular part of
     the query.  The rendering logic uses the same system used by single
     table inheritance to ensure a certain discriminator is applied to a
     table.

     E.g., using 2.0-style queries, we can limit the way the
     ‘User.addresses’ collection is loaded, regardless of the kind of
     loading used:

          from sqlalchemy.orm import with_loader_criteria

          stmt = select(User).options(
              selectinload(User.addresses),
              with_loader_criteria(Address, Address.email_address != 'foo'))
          )

     Above, the “selectinload” for ‘User.addresses’ will apply the given
     filtering criteria to the WHERE clause.

     Another example, where the filtering will be applied to the ON
     clause of the join, in this example using 1.x style queries:

          q = session.query(User).outerjoin(User.addresses).options(
              with_loader_criteria(Address, Address.email_address != 'foo'))
          )

     The primary purpose of with_loader_criteria() is to use
     it in the SessionEvents.do_orm_execute() event handler
     to ensure that all occurrences of a particular entity are filtered
     in a certain way, such as filtering for access control roles.  It
     also can be used to apply criteria to relationship loads.  In the
     example below, we can apply a certain set of rules to all queries
     emitted by a particular Session:

          session = Session(bind=engine)

          @event.listens_for("do_orm_execute", session)
          def _add_filtering_criteria(execute_state):

              if (
                  execute_state.is_select
                  and not execute_state.is_column_load
                  and not execute_state.is_relationship_load
              ):
                  execute_state.statement = execute_state.statement.options(
                      with_loader_criteria(
                          SecurityRole,
                          lambda cls: cls.role.in_(['some_role']),
                          include_aliases=True
                      )
                  )

     In the above example, the SessionEvents.do_orm_execute()
     event will intercept all queries emitted using the
     Session.  For those queries which are SELECT statements and are
     not attribute or relationship loads a custom
     with_loader_criteria() option is added to the query.  The
     with_loader_criteria() option will be used in the given
     statement and will also be automatically propagated to all
     relationship loads that descend from this query.

     The criteria argument given is a ‘lambda’ that accepts a ‘cls’
     argument.  The given class will expand to include all mapped
     subclass and need not itself be a mapped class.

          Warning: The use of a lambda inside of the call to
          with_loader_criteria() is only invoked `once per unique
          class'.  Custom functions should not be invoked within this
          lambda.  See Using Lambdas to add significant speed gains to statement production
          for an overview of the
          “lambda SQL” feature, which is for advanced use only.

     Parameters:

        * ‘entity_or_base’ – a mapped class, or a class that is a super
          class of a particular set of mapped classes, to which the rule
          will apply.

        * ‘where_criteria’ – a Core SQL expression that applies limiting
          criteria.  This may also be a “lambda:” or Python function
          that accepts a target class as an argument, when the given
          class is a base with many different mapped subclasses.

        * ‘include_aliases’ – if True, apply the rule to
          aliased() constructs as well.

        * ‘propagate_to_loaders’ – defaults to True, apply to
          relationship loaders such as lazy loaders.

     See also
     ........

     See ORM Query Events. - includes examples of using
     with_loader_criteria().

     See Adding global WHERE / ON criteria. - basic example on
     how to combine with_loader_criteria() with the
     SessionEvents.do_orm_execute() event.

     Parameters: ‘track_closure_variables’ – when False, closure
     variables inside of a lambda expression will not be used as part of
     any cache key.  This allows more complex expressions to be used
     inside of a lambda expression but requires that the lambda ensures
     it returns the identical SQL every time given a particular class.

     New in version 1.4.0b2.

 -- Function: sqlalchemy.orm.join (left, right, onclause=None,
          isouter=False, full=False, join_to_left=None)

     Produce an inner join between left and right clauses.

     join() is an extension to the core join interface
     provided by join(), where the left and right selectables
     may be not only core selectable objects such as Table,
     but also mapped classes or AliasedClass instances.  The
     “on” clause can be a SQL expression, or an attribute or string name
     referencing a configured relationship().

     join() is not commonly needed in modern usage, as its
     functionality is encapsulated within that of the
     Query.join() method, which features a significant amount of
     automation beyond join() by itself.  Explicit usage of
     join() with Query involves usage of the
     Query.select_from() method, as in:

          from sqlalchemy.orm import join
          session.query(User).\
              select_from(join(User, Address, User.addresses)).\
              filter(Address.email_address=='foo@bar.com')

     In modern SQLAlchemy the above join can be written more succinctly
     as:

          session.query(User).\
                  join(User.addresses).\
                  filter(Address.email_address=='foo@bar.com')

     See Query.join() for information on modern usage of ORM
     level joins.

     Deprecated since version 0.8: the ‘join_to_left’ parameter is
     deprecated, and will be removed in a future release.  The parameter
     has no effect.

 -- Function: sqlalchemy.orm.outerjoin (left, right, onclause=None,
          full=False, join_to_left=None)

     Produce a left outer join between left and right clauses.

     This is the “outer join” version of the join()
     function, featuring the same behavior except that an OUTER JOIN is
     generated.  See that function’s documentation for other usage
     details.

 -- Function: sqlalchemy.orm.with_parent (instance, prop,
          from_entity=None)

     Create filtering criterion that relates this query’s primary entity
     to the given related instance, using established
     relationship() configuration.

     E.g.:

          stmt = select(Address).where(with_parent(some_user, Address.user))

     The SQL rendered is the same as that rendered when a lazy loader
     would fire off from the given parent on that attribute, meaning
     that the appropriate state is taken from the parent object in
     Python without the need to render joins to the parent table in the
     rendered statement.

     The given property may also make use of
     PropComparator.of_type() to indicate the left side of the
     criteria:

          a1 = aliased(Address)
          a2 = aliased(Address)
          stmt = select(a1, a2).where(
              with_parent(u1, User.addresses.of_type(a2))
          )

     The above use is equivalent to using the ‘from_entity()’ argument:

          a1 = aliased(Address)
          a2 = aliased(Address)
          stmt = select(a1, a2).where(
              with_parent(u1, User.addresses, from_entity=a2)
          )

     Parameters:

        * ‘instance’ – An instance which has some relationship().

        * ‘property’ – String property name, or class-bound attribute,
          which indicates what relationship from the instance should be
          used to reconcile the parent/child relationship.

          Deprecated since version 1.4: Using strings is deprecated and
          will be removed in SQLAlchemy 2.0.  Please use the class-bound
          attribute directly.

        * ‘from_entity’ – Entity in which to consider as the left side.
          This defaults to the “zero” entity of the Query
          itself.

          New in version 1.2.

3.5 Using the Session
=====================

The declarative base and ORM mapping functions described at Mapper Configuration
are the primary configurational interface for the
ORM. Once mappings are configured, the primary usage interface for
persistence operations is the Session.

3.5.1 Session Basics
--------------------

3.5.1.1 What does the Session do ?
..................................

In the most general sense, the Session establishes all
conversations with the database and represents a “holding zone” for all
the objects which you’ve loaded or associated with it during its
lifespan.  It provides the interface where SELECT and other queries are
made that will return and modify ORM-mapped objects.  The ORM objects
themselves are maintained inside the Session, inside a
structure called the identity map - a data structure that maintains
unique copies of each object, where “unique” means “only one object with
a particular primary key”.

The Session begins in a mostly stateless form.  Once queries
are issued or other objects are persisted with it, it requests a
connection resource from an Engine that is associated with
the Session, and then establishes a transaction on that
connection.  This transaction remains in effect until the Session
is instructed to commit or roll back the transaction.

The ORM objects maintained by a Session are instrumented such
that whenever an attribute or a collection is modified in the Python
program, a change event is generated which is recorded by the
Session.  Whenever the database is about to be queried, or when the
transaction is about to be committed, the Session first
`flushes' all pending changes stored in memory to the database.  This is
known as the unit of work pattern.

When using a Session, it’s useful to consider the ORM mapped
objects that it maintains as `proxy objects' to database rows, which are
local to the transaction being held by the Session.  In order
to maintain the state on the objects as matching what’s actually in the
database, there are a variety of events that will cause objects to
re-access the database in order to keep synchronized.  It is possible to
“detach” objects from a Session, and to continue using them,
though this practice has its caveats.  It’s intended that usually, you’d
re-associate detached objects with another Session when you
want to work with them again, so that they can resume their normal task
of representing database state.

3.5.1.2 Basics of Using a Session
.................................

The most basic Session use patterns are presented here.

3.5.1.3 Opening and Closing a Session
.....................................

The Session may be constructed on its own or by using the
sessionmaker class.  It typically is passed a single
Engine as a source of connectivity up front.  A typical use may
look like:

     from sqlalchemy import create_engine
     from sqlalchemy.orm import Session

     # an Engine, which the Session will use for connection
     # resources
     engine = create_engine('postgresql://scott:tiger@localhost/')

     # create session and add objects
     with Session(engine) as session:
         session.add(some_object)
         session.add(some_other_object)
         session.commit()

Above, the Session is instantiated with an Engine
associated with a particular database URL. It is then used in a Python
context manager (i.e.  ‘with:’ statement) so that it is automatically
closed at the end of the block; this is equivalent to calling the
Session.close() method.

The call to Session.commit() is optional, and is only needed
if the work we’ve done with the Session includes new data to
be persisted to the database.  If we were only issuing SELECT calls and
did not need to write any changes, then the call to
Session.commit() would be unnecessary.

3.5.1.4 Framing out a begin / commit / rollback block
.....................................................

We may also enclose the Session.commit() call and the overall
“framing” of the transaction within a context manager for those cases
where we will be committing data to the database.  By “framing” we mean
that if all operations succeed, the Session.commit() method
will be called, but if any exceptions are raised, the
Session.rollback() method will be called so that the transaction
is rolled back immediately, before propagating the exception outward.
In Python this is most fundamentally expressed using a ‘try: / except: /
else:’ block such as:

     # verbose version of what a context manager will do
     with Session(engine) as session:
         try:
             session.add(some_object)
             session.add(some_other_object)
         except:
             session.rollback()
             raise
         else:
             session.commit()

The long-form sequence of operations illustrated above can be achieved
more succinctly by making use of the SessionTransaction
object returned by the Session.begin() method, which
provides a context manager interface for the same sequence of
operations:

     # create session and add objects
     with Session(engine) as session:
         with session.begin():
           session.add(some_object)
           session.add(some_other_object)
         # inner context calls session.commit(), if there were no exceptions
     # outer context calls session.close()

More succinctly, the two contexts may be combined:

     # create session and add objects
     with Session(engine) as session, session.begin():
         session.add(some_object)
         session.add(some_other_object)
     # inner context calls session.commit(), if there were no exceptions
     # outer context calls session.close()

3.5.1.5 Using a sessionmaker
............................

The purpose of sessionmaker is to provide a factory for
Session objects with a fixed configuration.  As it is typical
that an application will have an Engine object in module
scope, the sessionmaker can provide a factory for
Session objects that are against this engine:

     from sqlalchemy import create_engine
     from sqlalchemy.orm import sessionmaker

     # an Engine, which the Session will use for connection
     # resources, typically in module scope
     engine = create_engine('postgresql://scott:tiger@localhost/')

     # a sessionmaker(), also in the same scope as the engine
     Session = sessionmaker(engine)

     # we can now construct a Session() without needing to pass the
     # engine each time
     with Session() as session:
         session.add(some_object)
         session.add(some_other_object)
         session.commit()
     # closes the session

The sessionmaker is analogous to the Engine as a
module-level factory for function-level sessions / connections.  As such
it also has its own sessionmaker.begin() method, analogous
to Engine.begin(), which returns a Session object
and also maintains a begin/commit/rollback block:

     from sqlalchemy import create_engine
     from sqlalchemy.orm import sessionmaker

     # an Engine, which the Session will use for connection
     # resources
     engine = create_engine('postgresql://scott:tiger@localhost/')

     # a sessionmaker(), also in the same scope as the engine
     Session = sessionmaker(engine)

     # we can now construct a Session() and include begin()/commit()/rollback()
     # at once
     with Session.begin() as session:
         session.add(some_object)
         session.add(some_other_object)
     # commits the transaction, closes the session

Where above, the Session will both have its transaction
committed as well as that the Session will be closed, when
the above ‘with:’ block ends.

When you write your application, the sessionmaker factory
should be scoped the same as the Engine object created by
create_engine(), which is typically at module-level or global
scope.  As these objects are both factories, they can be used by any
number of functions and threads simultaneously.

See also
........

See sessionmaker.

See Session.

3.5.1.6 Querying (1.x Style)
............................

The Session.query() function takes one or more `entities'
and returns a new ‘Query’ object which will issue mapper queries within
the context of this Session.  By “entity” we refer to a mapped class, an
attribute of a mapped class, or other ORM constructs such as an
aliased() construct:

     # query from a class
     results = session.query(User).filter_by(name='ed').all()

     # query with multiple classes, returns tuples
     results = session.query(User, Address).join('addresses').filter_by(name='ed').all()

     # query using orm-columns, also returns tuples
     results = session.query(User.name, User.fullname).all()

When ORM objects are returned in results, they are also stored in the
identity map.  When an incoming database row has a primary key that
matches an object which is already present, the same object is returned,
and those attributes of the object which already have a value are not
re-populated.

The Session automatically expires all instances along
transaction boundaries (i.e.  when the current transaction is committed
or rolled back) so that with a normally isolated transaction, data will
refresh itself when a new transaction begins.

The Query object is introduced in great detail in
Object Relational Tutorial (1.x API), and further documented in
Query API.

See also
........

See Object Relational Tutorial (1.x API).

See Session.query().

See Query API.

3.5.1.7 Querying (2.0 style)
............................

New in version 1.4.

SQLAlchemy 2.0 will standardize the production of SELECT statements
across both Core and ORM by making direct use of the Select
object within the ORM, removing the need for there to be a separate
Query object.  This mode of operation is available in
SQLAlchemy 1.4 right now to support applications that will be migrating
to 2.0.  The Session must be instantiated with the
Session.future flag set to ‘True’; from that point on the
Session.execute() method will return ORM results via the standard
Result object when invoking select() statements
that use ORM entities:

     from sqlalchemy import select
     from sqlalchemy.orm import Session

     session = Session(engine, future=True)

     # query from a class
     statement = select(User).filter_by(name="ed")

     # list of first element of each row (i.e. User objects)
     result = session.execute(statement).scalars().all()

     # query with multiple classes
     statement = select(User, Address).join('addresses').filter_by(name='ed')

     # list of tuples
     result = session.execute(statement).all()

     # query with ORM columns
     statement = select(User.name, User.fullname)

     # list of tuples
     result = session.execute(statement).all()

It’s important to note that while methods of Query such as
Query.all() and Query.one() will return
instances of ORM mapped objects directly in the case that only a single
complete entity were requested, the Result object returned by
Session.execute() will always deliver rows (named tuples) by
default; this is so that results against single or multiple ORM objects,
columns, tables, etc.  may all be handled identically.

If only one ORM entity was queried, the rows returned will have exactly
one column, consisting of the ORM-mapped object instance for each row.
To convert these rows into object instances without the tuples, the
Result.scalars() method is used to first apply a “scalars”
filter to the result; then the Result can be iterated or
deliver rows via standard methods such as Result.all(),
Result.first(), etc.

See also
........

See Migrating to SQLAlchemy 2.0.

3.5.1.8 Adding New or Existing Items
....................................

Session.add() is used to place instances in the session.
For transient (i.e.  brand new) instances, this will have the effect of
an INSERT taking place for those instances upon the next flush.  For
instances which are persistent (i.e.  were loaded by this session), they
are already present and do not need to be added.  Instances which are
detached (i.e.  have been removed from a session) may be re-associated
with a session using this method:

     user1 = User(name='user1')
     user2 = User(name='user2')
     session.add(user1)
     session.add(user2)

     session.commit()     # write changes to the database

To add a list of items to the session at once, use
Session.add_all():

     session.add_all([item1, item2, item3])

The Session.add() operation `cascades' along the
‘save-update’ cascade.  For more details see the section Cascades.

3.5.1.9 Deleting
................

The Session.delete() method places an instance into the
Session’s list of objects to be marked as deleted:

     # mark two objects to be deleted
     session.delete(obj1)
     session.delete(obj2)

     # commit (or flush)
     session.commit()

Session.delete() marks an object for deletion, which will
result in a DELETE statement emitted for each primary key affected.
Before the pending deletes are flushed, objects marked by “delete” are
present in the Session.deleted collection.  After the
DELETE, they are expunged from the Session, which becomes
permanent after the transaction is committed.

There are various important behaviors related to the
Session.delete() operation, particularly in how relationships to
other objects and collections are handled.  There’s more information on
how this works in the section Cascades, but in general the
rules are:

   * Rows that correspond to mapped objects that are related to a
     deleted object via the relationship() directive are `not
     deleted by default'.  If those objects have a foreign key
     constraint back to the row being deleted, those columns are set to
     NULL. This will cause a constraint violation if the columns are
     non-nullable.

   * To change the “SET NULL” into a DELETE of a related object’s row,
     use the delete cascade on the relationship().

   * Rows that are in tables linked as “many-to-many” tables, via the
     relationship.secondary parameter, `are' deleted in all
     cases when the object they refer to is deleted.

   * When related objects include a foreign key constraint back to the
     object being deleted, and the related collections to which they
     belong are not currently loaded into memory, the unit of work will
     emit a SELECT to fetch all related rows, so that their primary key
     values can be used to emit either UPDATE or DELETE statements on
     those related rows.  In this way, the ORM without further
     instruction will perform the function of ON DELETE CASCADE, even if
     this is configured on Core ForeignKeyConstraint objects.

   * The relationship.passive_deletes parameter can be used
     to tune this behavior and rely upon “ON DELETE CASCADE” more
     naturally; when set to True, this SELECT operation will no longer
     take place, however rows that are locally present will still be
     subject to explicit SET NULL or DELETE. Setting
     relationship.passive_deletes to the string ‘"all"’ will
     disable `all' related object update/delete.

   * When the DELETE occurs for an object marked for deletion, the
     object is not automatically removed from collections or object
     references that refer to it.  When the Session is
     expired, these collections may be loaded again so that the object
     is no longer present.  However, it is preferable that instead of
     using Session.delete() for these objects, the object
     should instead be removed from its collection and then
     delete-orphan should be used so that it is deleted as a
     secondary effect of that collection removal.  See the section
     Notes on Delete - Deleting Objects Referenced from Collections and Scalar Relationships
     for an example of this.

See also
........

See delete. - describes “delete cascade”, which marks related
objects for deletion when a lead object is deleted.

See delete-orphan. - describes “delete orphan cascade”, which
marks related objects for deletion when they are de-associated from
their lead object.

See Notes on Delete - Deleting Objects Referenced from Collections and Scalar Relationships.
- important background on
Session.delete() as involves relationships being refreshed in
memory.

3.5.1.10 Flushing
.................

When the ‘Session’ is used with its default configuration, the flush
step is nearly always done transparently.  Specifically, the flush
occurs before any individual SQL statement is issued as a result of a
Query or a 2.0-style Session.execute() call, as
well as within the Session.commit() call before the
transaction is committed.  It also occurs before a SAVEPOINT is issued
when Session.begin_nested() is used.

Regardless of the autoflush setting, a flush can always be forced by
issuing Session.flush():

     session.flush()

The “flush-on-Query” aspect of the behavior can be disabled by
constructing sessionmaker with the flag ‘autoflush=False’:

     Session = sessionmaker(autoflush=False)

Additionally, autoflush can be temporarily disabled by setting the
‘autoflush’ flag at any time:

     mysession = Session()
     mysession.autoflush = False

More conveniently, it can be turned off within a context managed block
using Session.no_autoflush:

     with mysession.no_autoflush:
         mysession.add(some_object)
         mysession.flush()

The flush process `always' occurs within a transaction, even if the
‘Session’ has been configured with ‘autocommit=True’, a setting that
disables the session’s persistent transactional state.  If no
transaction is present, see Session.flush() creates its own
transaction and commits it.  Any failures during flush will always
result in a rollback of whatever transaction is present.  If the Session
is not in ‘autocommit=True’ mode, an explicit call to
Session.rollback() is required after a flush fails, even though
the underlying transaction will have been rolled back already - this is
so that the overall nesting pattern of so-called “subtransactions” is
consistently maintained.

3.5.1.11 Expiring / Refreshing
..............................

An important consideration that will often come up when using the
Session is that of dealing with the state that is present on
objects that have been loaded from the database, in terms of keeping
them synchronized with the current state of the transaction.  The
SQLAlchemy ORM is based around the concept of an identity map such that
when an object is “loaded” from a SQL query, there will be a unique
Python object instance maintained corresponding to a particular database
identity.  This means if we emit two separate queries, each for the same
row, and get a mapped object back, the two queries will have returned
the same Python object:

     >>> u1 = session.query(User).filter(id=5).first()
     >>> u2 = session.query(User).filter(id=5).first()
     >>> u1 is u2
     True

Following from this, when the ORM gets rows back from a query, it will
`skip the population of attributes' for an object that’s already loaded.
The design assumption here is to assume a transaction that’s perfectly
isolated, and then to the degree that the transaction isn’t isolated,
the application can take steps on an as-needed basis to refresh objects
from the database transaction.  The FAQ entry at *note I’m re-loading
data with my Session but it isn’t seeing changes that I committed
elsewhere: 4c9. discusses this concept in more detail.

When an ORM mapped object is loaded into memory, there are three general
ways to refresh its contents with new data from the current transaction:

   * `the expire() method' - the Session.expire() method
     will erase the contents of selected or all attributes of an object,
     such that they will be loaded from the database when they are next
     accessed, e.g.  using a lazy loading pattern:

          session.expire(u1)
          u1.some_attribute  # <-- lazy loads from the transaction

   * `the refresh() method' - closely related is the
     Session.refresh() method, which does everything the
     Session.expire() method does but also emits one or more SQL
     queries immediately to actually refresh the contents of the object:

          session.refresh(u1)  # <-- emits a SQL query
          u1.some_attribute  # <-- is refreshed from the transaction

   * `the populate_existing() method' - this method is actually on the
     Query object as Query.populate_existing()
     and indicates that it should return objects that are
     unconditionally re-populated from their contents in the database:

          u2 = session.query(User).populate_existing().filter(id=5).first()

Further discussion on the refresh / expire concept can be found at
Refreshing / Expiring.

See also
........

See Refreshing / Expiring.

See I’m re-loading data with my Session but it isn’t seeing changes that I committed elsewhere.

3.5.1.12 UPDATE and DELETE with arbitrary WHERE clause
......................................................

The sections above on Session.flush() and
Session.delete() detail how rows can be inserted, updated and
deleted in the database, based on primary key identities that are
referred towards by mapped Python objets in the application.  The
Session can also emit UPDATE and DELETE statements with arbitrary
WHERE clauses as well, and at the same time refresh locally present
objects which match those rows.

To emit an ORM-enabled UPDATE in 1.x style, the Query.update()
method may be used:

     session.query(User).filter(User.name == "squidward").\
         update({"name": "spongebob"}, synchronize_session="fetch")

Above, an UPDATE will be emitted against all rows that match the name
“squidward” and be updated to the name “spongebob”.  The
Query.update.synchronize_session parameter referring to “fetch”
indicates the list of affected primary keys should be fetched either via
a separate SELECT statement or via RETURNING if the backend database
supports it; objects locally present in memory will be updated in memory
based on these primary key identities.

For ORM-enabled UPDATEs in 2.0 style, see Session.execute() is
used with the Core Update construct:

     from sqlalchemy import update

     stmt = update(User).where(User.name == "squidward").values(name="spongebob").\
         execution_options(synchronize_session="fetch")

     session.execute(stmt)

Above, the ‘Update.execution_options()’ method may be used to establish
execution-time options such as “synchronize_session”.

DELETEs work in the same way as UPDATE except there is no “values / set”
clause established.  When synchronize_session is used, matching objects
within the Session will be marked as deleted and expunged.

ORM-enabled delete, 1.x style:

     session.query(User).filter(User.name == "squidward").\
         delete(synchronize_session="fetch")

ORM-enabled delete, 2.0 style:

     from sqlalchemy import delete

     stmt = delete(User).where(User.name == "squidward").execution_options(synchronize_session="fetch")

     session.execute(stmt)

3.5.1.13 Selecting a Synchronization Strategy
.............................................

With both the 1.x and 2.0 form of ORM-enabled updates and deletes, the
following values for ‘synchronize_session’ are supported:

   * ‘False’ - don’t synchronize the session.  This option is the most
     efficient and is reliable once the session is expired, which
     typically occurs after a commit(), or explicitly using
     expire_all().  Before the expiration, objects that were updated or
     deleted in the database may still remain in the session with stale
     values, which can lead to confusing results.

   * ‘'fetch'’ - Retrieves the primary key identity of affected rows by
     either performing a SELECT before the UPDATE or DELETE, or by using
     RETURNING if the database supports it, so that in-memory objects
     which are affected by the operation can be refreshed with new
     values (updates) or expunged from the Session. (deletes).
     Note that this synchronization strategy is not available if the
     given update() or delete() construct
     specifies columns for UpdateBase.returning()
     explicitly.

   * ‘'evaluate'’ - Evaluate the WHERE criteria given in the UPDATE or
     DELETE statement in Python, to locate matching objects within the
     Session.  This approach does not add any round trips and
     in the absense of RETURNING support is more efficient.  For UPDATE
     or DELETE statements with complex criteria, the ‘'evaluate'’
     strategy may not be able to evaluate the expression in Python and
     will raise an error.  If this occurs, use the ‘'fetch'’ strategy
     for the operation instead.

          Warning: The ‘"evaluate"’ strategy should be avoided if an
          UPDATE operation is to run on a Session that has
          many objects which have been expired, because it will
          necessarily need to refresh those objects as they are located
          which will emit a SELECT for each one.  The Session
          may have expired objects if it is being used across multiple
          Session.commit() calls and the
          Session.expire_on_commit flag is at its default value of
          ‘True’.

     Warning: `Additional Caveats for ORM-enabled updates and deletes'

     The ORM-enabled UPDATE and DELETE features bypass ORM unit-of-work
     automation in favor being able to emit a single UPDATE or DELETE
     statement that matches multiple rows at once without complexity.

        * The operations do not offer in-Python cascading of
          relationships - it is assumed that ON UPDATE CASCADE and/or ON
          DELETE CASCADE is configured for any foreign key references
          which require it, otherwise the database may emit an integrity
          violation if foreign key references are being enforced.

        * After the UPDATE or DELETE, dependent objects in the
          Session which were impacted by an ON UPDATE CASCADE or ON
          DELETE CASCADE on related tables may not contain the current
          state; this issue is resolved once the Session is
          expired, which normally occurs upon Session.commit()
          or can be forced by using Session.expire_all().

        * The ‘'fetch'’ strategy, when run on a database that does not
          support RETURNING such as MySQL or SQLite, results in an
          additional SELECT statement emitted which may reduce
          performance.  Use SQL echoing when developing to evaluate the
          impact of SQL emitted.

        * ORM-enabled UPDATEs and DELETEs do not handle joined table
          inheritance automatically.  If the operation is against
          multiple tables, typically individual UPDATE / DELETE
          statements against the individual tables should be used.  Some
          databases support multiple table UPDATEs.  Similar guidelines
          as those detailed at Multiple Table Updates may be
          applied.

        * The WHERE criteria needed in order to limit the polymorphic
          identity to specific subclasses for single-table-inheritance
          mappings `is included automatically' .  This only applies to a
          subclass mapper that has no table of its own.

          Changed in version 1.4: ORM updates/deletes now automatically
          accommodate for the WHERE criteria added for
          single-inheritance mappings.

        * The with_loader_criteria() option `is supported'
          by ORM update and delete operations; criteria here will be
          added to that of the UPDATE or DELETE statement being emitted,
          as well as taken into account during the “synchronize”
          process.

        * In order to intercept ORM-enabled UPDATE and DELETE operations
          with event handlers, use the
          SessionEvents.do_orm_execute() event.

3.5.1.14 Selecting ORM Objects Inline with UPDATE.. RETURNING or INSERT..RETURNING
..................................................................................

     deepalchemy: The feature of linking ORM objects to RETURNING is a
     new and experimental feature.

New in version 1.4.0b3.

The DML constructs insert(), update(), and
delete() feature a method UpdateBase.returning() which
on database backends that support RETURNING (PostgreSQL, SQL Server,
some MariaDB versions) may be used to return database rows generated or
matched by the statement as though they were SELECTed.  The ORM-enabled
UPDATE and DELETE statements may be combined with this feature, so that
they return rows corresponding to all the rows which were matched by the
criteria:

     from sqlalchemy import update

     stmt = update(User).where(User.name == "squidward").values(name="spongebob").\
         returning(User.id)

     for row in session.execute(stmt):
         print(f"id: {row.id}")

The above example returns the ‘User.id’ attribute for each row matched.
Provided that each row contains at least a primary key value, we may opt
to receive these rows as ORM objects, allowing ORM objects to be loaded
from the database corresponding atomically to an UPDATE statement
against those rows.  To achieve this, we may combine the Update
construct which returns ‘User’ rows with a select()
that’s adapted to run this UPDATE statement in an ORM context using the
Select.from_statement() method:

     stmt = update(User).where(User.name == "squidward").values(name="spongebob").\
         returning(User)

     orm_stmt = select(User).from_statement(stmt).execution_options(populate_existing=True)

     for user in session.execute(orm_stmt).scalars():
         print("updated user: %s" % user)

Above, we produce an update() construct that includes
Update.returning() given the full ‘User’ entity, which will
produce complete rows from the database table as it UPDATEs them; any
arbitrary set of columns to load may be specified as long as the full
primary key is included.  Next, these rows are adapted to an ORM load by
producing a select() for the desired entity, then adapting it
to the UPDATE statement by passing the Update construct to
the Select.from_statement() method; this special ORM method,
introduced at Getting ORM Results from Textual and Core Statements,
produces an ORM-specific adapter that allows the given
statement to act as though it were the SELECT of rows that is first
described.  No SELECT is actually emitted in the database, only the
UPDATE..RETURNING we’ve constructed.

Finally, we make use of Populate Existing on the construct
so that all the data returned by the UPDATE, including the columns we’ve
updated, are populated into the returned objects, replacing any values
which were there already.  This has the same effect as if we had used
the ‘synchronize_session='fetch'’ strategy described previously at
Selecting a Synchronization Strategy.

The above approach can be used with INSERTs as well (and technically
DELETEs too, though this makes less sense as the returned ORM objects by
definition don’t exist in the database anymore), as both of these
constructs support RETURNING as well.

See also
........

See Getting ORM Results from Textual and Core Statements. -
introduces the Select.from_statement() method.

3.5.1.15 Committing
...................

Session.commit() is used to commit the current transaction.
It always issues Session.flush() beforehand to flush any
remaining state to the database; this is independent of the “autoflush”
setting.

If the Session does not currently have a transaction present,
the method will silently pass, unless the legacy “autocommit” mode is
enabled in which it will raise an error.

Another behavior of Session.commit() is that by default it
expires the state of all instances present after the commit is complete.
This is so that when the instances are next accessed, either through
attribute access or by them being present in the result of a SELECT,
they receive the most recent state.  This behavior may be controlled by
the Session.expire_on_commit flag, which may be set to
‘False’ when this behavior is undesirable.

3.5.1.16 Rolling Back
.....................

Session.rollback() rolls back the current transaction.  With
a default configured session, the post-rollback state of the session is
as follows:

        * All transactions are rolled back and all connections returned
          to the connection pool, unless the Session was bound directly
          to a Connection, in which case the connection is still
          maintained (but still rolled back).

        * Objects which were initially in the pending state when they
          were added to the ‘Session’ within the lifespan of the
          transaction are expunged, corresponding to their INSERT
          statement being rolled back.  The state of their attributes
          remains unchanged.

        * Objects which were marked as deleted within the lifespan of
          the transaction are promoted back to the persistent state,
          corresponding to their DELETE statement being rolled back.
          Note that if those objects were first pending within the
          transaction, that operation takes precedence instead.

        * All objects not expunged are fully expired.

With that state understood, the ‘Session’ may safely continue usage
after a rollback occurs.

When a Session.flush() fails, typically for reasons like
primary key, foreign key, or “not nullable” constraint violations, a
ROLLBACK is issued automatically (it’s currently not possible for a
flush to continue after a partial failure).  However, the Session
goes into a state known as “inactive” at this point, and the calling
application must always call the Session.rollback() method
explicitly so that the Session can go back into a useable
state (it can also be simply closed and discarded).  See the FAQ entry
at “This Session’s transaction has been rolled back due to a previous exception during flush.” (or similar)
for further
discussion.

3.5.1.17 Closing
................

The Session.close() method issues a
Session.expunge_all() which removes all ORM-mapped objects from
the session, and releases any transactional/connection resources from
the Engine object(s) to which it is bound.  When connections
are returned to the connection pool, transactional state is rolled back
as well.

When the Session is closed, it is essentially in the original
state as when it was first constructed, and `may be used again'.  In
this sense, the Session.close() method is more like a
“reset” back to the clean state and not as much like a “database close”
method.

It’s recommended that the scope of a Session be limited by a
call to Session.close() at the end, especially if the
Session.commit() or Session.rollback() methods are not
used.  The Session may be used as a context manager to ensure
that Session.close() is called:

     with Session(engine) as session:
         result = session.execute(select(User))

     # closes session automatically

3.5.1.18 Session Frequently Asked Questions
...........................................

By this point, many users already have questions about sessions.  This
section presents a mini-FAQ (note that we have also a real FAQ)
of the most basic issues one is presented with when using a
Session.

3.5.1.19 When do I make a ‘sessionmaker’?
.........................................

Just one time, somewhere in your application’s global scope.  It should
be looked upon as part of your application’s configuration.  If your
application has three .py files in a package, you could, for example,
place the sessionmaker line in your ‘__init__.py’ file; from
that point on your other modules say “from mypackage import Session”.
That way, everyone else just uses Session(), and the
configuration of that session is controlled by that central point.

If your application starts up, does imports, but does not know what
database it’s going to be connecting to, you can bind the Session
at the “class” level to the engine later on, using
sessionmaker.configure().

In the examples in this section, we will frequently show the
sessionmaker being created right above the line where we actually
invoke Session.  But that’s just for example’s sake!  In
reality, the sessionmaker would be somewhere at the module
level.  The calls to instantiate Session would then be placed
at the point in the application where database conversations begin.

3.5.1.20 When do I construct a ‘Session’, when do I commit it, and when do I close it?
......................................................................................

tl;dr;
......

  1. As a general rule, keep the lifecycle of the session `separate and
     external' from functions and objects that access and/or manipulate
     database data.  This will greatly help with achieving a predictable
     and consistent transactional scope.

  2. Make sure you have a clear notion of where transactions begin and
     end, and keep transactions `short', meaning, they end at the series
     of a sequence of operations, instead of being held open
     indefinitely.

A Session is typically constructed at the beginning of a
logical operation where database access is potentially anticipated.

The Session, whenever it is used to talk to the database,
begins a database transaction as soon as it starts communicating.  This
transaction remains in progress until the Session is rolled
back, committed, or closed.  The Session will begin a new
transaction if it is used again, subsequent to the previous transaction
ending; from this it follows that the Session is capable of
having a lifespan across many transactions, though only one at a time.
We refer to these two concepts as `transaction scope' and `session
scope'.

It’s usually not very hard to determine the best points at which to
begin and end the scope of a Session, though the wide variety
of application architectures possible can introduce challenging
situations.

Some sample scenarios include:

   * Web applications.  In this case, it’s best to make use of the
     SQLAlchemy integrations provided by the web framework in use.  Or
     otherwise, the basic pattern is create a Session at the
     start of a web request, call the Session.commit() method
     at the end of web requests that do POST, PUT, or DELETE, and then
     close the session at the end of web request.  It’s also usually a
     good idea to set Session.expire_on_commit to False so
     that subsequent access to objects that came from a Session
     within the view layer do not need to emit new SQL queries to
     refresh the objects, if the transaction has been committed already.

   * A background daemon which spawns off child forks would want to
     create a Session local to each child process, work with
     that Session through the life of the “job” that the fork
     is handling, then tear it down when the job is completed.

   * For a command-line script, the application would create a single,
     global Session that is established when the program
     begins to do its work, and commits it right as the program is
     completing its task.

   * For a GUI interface-driven application, the scope of the
     Session may best be within the scope of a user-generated
     event, such as a button push.  Or, the scope may correspond to
     explicit user interaction, such as the user “opening” a series of
     records, then “saving” them.

As a general rule, the application should manage the lifecycle of the
session `externally' to functions that deal with specific data.  This is
a fundamental separation of concerns which keeps data-specific
operations agnostic of the context in which they access and manipulate
that data.

E.g.  `don’t do this':

     ### this is the **wrong way to do it** ###

     class ThingOne(object):
         def go(self):
             session = Session()
             try:
                 session.query(FooBar).update({"x": 5})
                 session.commit()
             except:
                 session.rollback()
                 raise

     class ThingTwo(object):
         def go(self):
             session = Session()
             try:
                 session.query(Widget).update({"q": 18})
                 session.commit()
             except:
                 session.rollback()
                 raise

     def run_my_program():
         ThingOne().go()
         ThingTwo().go()

Keep the lifecycle of the session (and usually the transaction)
`separate and external'.  The example below illustrates how this might
look, and additionally makes use of a Python context manager (i.e.  the
‘with:’ keyword) in order to manage the scope of the Session
and its transaction automatically:

     ### this is a **better** (but not the only) way to do it ###

     class ThingOne(object):
         def go(self, session):
             session.query(FooBar).update({"x": 5})

     class ThingTwo(object):
         def go(self, session):
             session.query(Widget).update({"q": 18})

     def run_my_program():
         with Session() as session:
             with session.begin():
                 ThingOne().go(session)
                 ThingTwo().go(session)

Changed in version 1.4: The Session may be used as a context
manager without the use of external helper functions.

3.5.1.21 Is the Session a cache?
................................

Yeee…no.  It’s somewhat used as a cache, in that it implements the
identity map pattern, and stores objects keyed to their primary key.
However, it doesn’t do any kind of query caching.  This means, if you
say ‘session.query(Foo).filter_by(name='bar')’, even if
‘Foo(name='bar')’ is right there, in the identity map, the session has
no idea about that.  It has to issue SQL to the database, get the rows
back, and then when it sees the primary key in the row, `then' it can
look in the local identity map and see that the object is already there.
It’s only when you say ‘query.get({some primary key})’ that the
‘Session’ doesn’t have to issue a query.

Additionally, the Session stores object instances using a weak reference
by default.  This also defeats the purpose of using the Session as a
cache.

The Session is not designed to be a global object from which
everyone consults as a “registry” of objects.  That’s more the job of a
`second level cache'.  SQLAlchemy provides a pattern for implementing
second level caching using dogpile.cache(1), via the Dogpile Caching
example.

   ---------- Footnotes ----------

   (1) https://dogpilecache.readthedocs.io/

3.5.1.22 How can I get the ‘Session’ for a certain object?
..........................................................

Use the Session.object_session() classmethod available on
‘Session’:

     session = Session.object_session(someobject)

The newer Runtime Inspection API system can also be used:

     from sqlalchemy import inspect
     session = inspect(someobject).session

3.5.1.23 Is the session thread-safe?
....................................

The Session is very much intended to be used in a
`non-concurrent' fashion, which usually means in only one thread at a
time.

The Session should be used in such a way that one instance
exists for a single series of operations within a single transaction.
One expedient way to get this effect is by associating a Session
with the current thread (see Contextual/Thread-local Sessions
for background).  Another is to use a pattern where the
Session is passed between functions and is otherwise not shared
with other threads.

The bigger point is that you should not `want' to use the session with
multiple concurrent threads.  That would be like having everyone at a
restaurant all eat from the same plate.  The session is a local
“workspace” that you use for a specific set of tasks; you don’t want to,
or need to, share that session with other threads who are doing some
other task.

Making sure the Session is only used in a single concurrent
thread at a time is called a “share nothing” approach to concurrency.
But actually, not sharing the Session implies a more
significant pattern; it means not just the Session object
itself, but also `all objects that are associated with that Session',
must be kept within the scope of a single concurrent thread.  The set of
mapped objects associated with a Session are essentially
proxies for data within database rows accessed over a database
connection, and so just like the Session itself, the whole
set of objects is really just a large-scale proxy for a database
connection (or connections).  Ultimately, it’s mostly the DBAPI
connection itself that we’re keeping away from concurrent access; but
since the Session and all the objects associated with it are
all proxies for that DBAPI connection, the entire graph is essentially
not safe for concurrent access.

If there are in fact multiple threads participating in the same task,
then you may consider sharing the session and its objects between those
threads; however, in this extremely unusual scenario the application
would need to ensure that a proper locking scheme is implemented so that
there isn’t `concurrent' access to the Session or its state.
A more common approach to this situation is to maintain a single
Session per concurrent thread, but to instead `copy' objects from
one Session to another, often using the
Session.merge() method to copy the state of an object into a new
object local to a different Session.

3.5.2 State Management
----------------------

3.5.2.1 Quickie Intro to Object States
......................................

It’s helpful to know the states which an instance can have within a
session:

   * `Transient' - an instance that’s not in a session, and is not saved
     to the database; i.e.  it has no database identity.  The only
     relationship such an object has to the ORM is that its class has a
     Mapper associated with it.

   * `Pending' - when you Session.add() a transient
     instance, it becomes pending.  It still wasn’t actually flushed to
     the database yet, but it will be when the next flush occurs.

   * `Persistent' - An instance which is present in the session and has
     a record in the database.  You get persistent instances by either
     flushing so that the pending instances become persistent, or by
     querying the database for existing instances (or moving persistent
     instances from other sessions into your local session).

   * `Deleted' - An instance which has been deleted within a flush, but
     the transaction has not yet completed.  Objects in this state are
     essentially in the opposite of “pending” state; when the session’s
     transaction is committed, the object will move to the detached
     state.  Alternatively, when the session’s transaction is rolled
     back, a deleted object moves `back' to the persistent state.

     Changed in version 1.1: The ‘deleted’ state is a newly added
     session object state distinct from the ‘persistent’ state.

   * `Detached' - an instance which corresponds, or previously
     corresponded, to a record in the database, but is not currently in
     any session.  The detached object will contain a database identity
     marker, however because it is not associated with a session, it is
     unknown whether or not this database identity actually exists in a
     target database.  Detached objects are safe to use normally, except
     that they have no ability to load unloaded attributes or attributes
     that were previously marked as “expired”.

For a deeper dive into all possible state transitions, see the section
Object Lifecycle Events which describes each transition as
well as how to programmatically track each one.

3.5.2.2 Getting the Current State of an Object
..............................................

The actual state of any mapped object can be viewed at any time using
the inspect() system:

     >>> from sqlalchemy import inspect
     >>> insp = inspect(my_object)
     >>> insp.persistent
     True

See also
........

See InstanceState.transient.

See InstanceState.pending.

See InstanceState.persistent.

See InstanceState.deleted.

See InstanceState.detached.

3.5.2.3 Session Attributes
..........................

The ‘Session’ itself acts somewhat like a set-like collection.  All
items present may be accessed using the iterator interface:

     for obj in session:
         print(obj)

And presence may be tested for using regular “contains” semantics:

     if obj in session:
         print("Object is present")

The session is also keeping track of all newly created (i.e.  pending)
objects, all objects which have had changes since they were last loaded
or saved (i.e.  “dirty”), and everything that’s been marked as deleted:

     # pending objects recently added to the Session
     session.new

     # persistent objects which currently have changes detected
     # (this collection is now created on the fly each time the property is called)
     session.dirty

     # persistent objects that have been marked as deleted via session.delete(obj)
     session.deleted

     # dictionary of all persistent objects, keyed on their
     # identity key
     session.identity_map

(Documentation: Session.new, Session.dirty,
Session.deleted, Session.identity_map).

3.5.2.4 Session Referencing Behavior
....................................

Objects within the session are `weakly referenced'.  This means that
when they are dereferenced in the outside application, they fall out of
scope from within the ‘Session’ as well and are subject to garbage
collection by the Python interpreter.  The exceptions to this include
objects which are pending, objects which are marked as deleted, or
persistent objects which have pending changes on them.  After a full
flush, these collections are all empty, and all objects are again weakly
referenced.

To cause objects in the Session to remain strongly
referenced, usually a simple approach is all that’s needed.  Examples of
externally managed strong-referencing behavior include loading objects
into a local dictionary keyed to their primary key, or into lists or
sets for the span of time that they need to remain referenced.  These
collections can be associated with a Session, if desired, by
placing them into the Session.info dictionary.

An event based approach is also feasible.  A simple recipe that provides
“strong referencing” behavior for all objects as they remain within the
persistent state is as follows:

     from sqlalchemy import event

     def strong_reference_session(session):
         @event.listens_for(session, "pending_to_persistent")
         @event.listens_for(session, "deleted_to_persistent")
         @event.listens_for(session, "detached_to_persistent")
         @event.listens_for(session, "loaded_as_persistent")
         def strong_ref_object(sess, instance):
             if 'refs' not in sess.info:
                 sess.info['refs'] = refs = set()
             else:
                 refs = sess.info['refs']

             refs.add(instance)

         @event.listens_for(session, "persistent_to_detached")
         @event.listens_for(session, "persistent_to_deleted")
         @event.listens_for(session, "persistent_to_transient")
         def deref_object(sess, instance):
             sess.info['refs'].discard(instance)

Above, we intercept the SessionEvents.pending_to_persistent(),
see SessionEvents.detached_to_persistent(),
SessionEvents.deleted_to_persistent() and
SessionEvents.loaded_as_persistent() event hooks in order to
intercept objects as they enter the persistent transition, and the
SessionEvents.persistent_to_detached() and
SessionEvents.persistent_to_deleted() hooks to intercept objects
as they leave the persistent state.

The above function may be called for any Session in order to
provide strong-referencing behavior on a per-see Session basis:

     from sqlalchemy.orm import Session

     my_session = Session()
     strong_reference_session(my_session)

It may also be called for any sessionmaker:

     from sqlalchemy.orm import sessionmaker

     maker = sessionmaker()
     strong_reference_session(maker)

3.5.2.5 Merging
...............

Session.merge() transfers state from an outside object into
a new or already existing instance within a session.  It also reconciles
the incoming data against the state of the database, producing a history
stream which will be applied towards the next flush, or alternatively
can be made to produce a simple “transfer” of state without producing
change history or accessing the database.  Usage is as follows:

     merged_object = session.merge(existing_object)

When given an instance, it follows these steps:

   * It examines the primary key of the instance.  If it’s present, it
     attempts to locate that instance in the local identity map.  If the
     ‘load=True’ flag is left at its default, it also checks the
     database for this primary key if not located locally.

   * If the given instance has no primary key, or if no instance can be
     found with the primary key given, a new instance is created.

   * The state of the given instance is then copied onto the
     located/newly created instance.  For attributes which are present
     on the source instance, the value is transferred to the target
     instance.  For mapped attributes which aren’t present on the
     source, the attribute is expired on the target instance, discarding
     its existing value.

     If the ‘load=True’ flag is left at its default, this copy process
     emits events and will load the target object’s unloaded collections
     for each attribute present on the source object, so that the
     incoming state can be reconciled against what’s present in the
     database.  If ‘load’ is passed as ‘False’, the incoming data is
     “stamped” directly without producing any history.

   * The operation is cascaded to related objects and collections, as
     indicated by the ‘merge’ cascade (see Cascades).

   * The new instance is returned.

With Session.merge(), the given “source” instance is not
modified nor is it associated with the target Session, and
remains available to be merged with any number of other Session
objects.  Session.merge() is useful for taking the state
of any kind of object structure without regard for its origins or
current session associations and copying its state into a new session.
Here’s some examples:

   * An application which reads an object structure from a file and
     wishes to save it to the database might parse the file, build up
     the structure, and then use Session.merge() to save it
     to the database, ensuring that the data within the file is used to
     formulate the primary key of each element of the structure.  Later,
     when the file has changed, the same process can be re-run,
     producing a slightly different object structure, which can then be
     ‘merged’ in again, and the ‘Session’ will automatically update the
     database to reflect those changes, loading each object from the
     database by primary key and then updating its state with the new
     state given.

   * An application is storing objects in an in-memory cache, shared by
     many Session objects simultaneously.
     Session.merge() is used each time an object is retrieved from
     the cache to create a local copy of it in each Session
     which requests it.  The cached object remains detached; only its
     state is moved into copies of itself that are local to individual
     Session objects.

     In the caching use case, it’s common to use the ‘load=False’ flag
     to remove the overhead of reconciling the object’s state with the
     database.  There’s also a “bulk” version of Session.merge()
     called Query.merge_result() that was designed to
     work with cache-extended Query objects - see the
     section Dogpile Caching.

   * An application wants to transfer the state of a series of objects
     into a Session maintained by a worker thread or other
     concurrent system.  Session.merge() makes a copy of
     each object to be placed into this new Session.  At the
     end of the operation, the parent thread/process maintains the
     objects it started with, and the thread/worker can proceed with
     local copies of those objects.

     In the “transfer between threads/processes” use case, the
     application may want to use the ‘load=False’ flag as well to avoid
     overhead and redundant SQL queries as the data is transferred.

3.5.2.6 Merge Tips
..................

Session.merge() is an extremely useful method for many
purposes.  However, it deals with the intricate border between objects
that are transient/detached and those that are persistent, as well as
the automated transference of state.  The wide variety of scenarios that
can present themselves here often require a more careful approach to the
state of objects.  Common problems with merge usually involve some
unexpected state regarding the object being passed to
Session.merge().

Lets use the canonical example of the User and Address objects:

     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         name = Column(String(50), nullable=False)
         addresses = relationship("Address", backref="user")

     class Address(Base):
         __tablename__ = 'address'

         id = Column(Integer, primary_key=True)
         email_address = Column(String(50), nullable=False)
         user_id = Column(Integer, ForeignKey('user.id'), nullable=False)

Assume a ‘User’ object with one ‘Address’, already persistent:

     >>> u1 = User(name='ed', addresses=[Address(email_address='ed@ed.com')])
     >>> session.add(u1)
     >>> session.commit()

We now create ‘a1’, an object outside the session, which we’d like to
merge on top of the existing ‘Address’:

     >>> existing_a1 = u1.addresses[0]
     >>> a1 = Address(id=existing_a1.id)

A surprise would occur if we said this:

     >>> a1.user = u1
     >>> a1 = session.merge(a1)
     >>> session.commit()
     sqlalchemy.orm.exc.FlushError: New instance <Address at 0x1298f50>
     with identity key (<class '__main__.Address'>, (1,)) conflicts with
     persistent instance <Address at 0x12a25d0>

Why is that ?  We weren’t careful with our cascades.  The assignment of
‘a1.user’ to a persistent object cascaded to the backref of
‘User.addresses’ and made our ‘a1’ object pending, as though we had
added it.  Now we have `two' ‘Address’ objects in the session:

     >>> a1 = Address()
     >>> a1.user = u1
     >>> a1 in session
     True
     >>> existing_a1 in session
     True
     >>> a1 is existing_a1
     False

Above, our ‘a1’ is already pending in the session.  The subsequent
Session.merge() operation essentially does nothing.  Cascade can
be configured via the relationship.cascade option on
relationship(), although in this case it would mean removing the
‘save-update’ cascade from the ‘User.addresses’ relationship - and
usually, that behavior is extremely convenient.  The solution here would
usually be to not assign ‘a1.user’ to an object already persistent in
the target session.

The ‘cascade_backrefs=False’ option of relationship() will
also prevent the ‘Address’ from being added to the session via the
‘a1.user = u1’ assignment.

Further detail on cascade operation is at Cascades.

Another example of unexpected state:

     >>> a1 = Address(id=existing_a1.id, user_id=u1.id)
     >>> assert a1.user is None
     True
     >>> a1 = session.merge(a1)
     >>> session.commit()
     sqlalchemy.exc.IntegrityError: (IntegrityError) address.user_id
     may not be NULL

Here, we accessed a1.user, which returned its default value of ‘None’,
which as a result of this access, has been placed in the ‘__dict__’ of
our object ‘a1’.  Normally, this operation creates no change event, so
the ‘user_id’ attribute takes precedence during a flush.  But when we
merge the ‘Address’ object into the session, the operation is equivalent
to:

     >>> existing_a1.id = existing_a1.id
     >>> existing_a1.user_id = u1.id
     >>> existing_a1.user = None

Where above, both ‘user_id’ and ‘user’ are assigned to, and change
events are emitted for both.  The ‘user’ association takes precedence,
and None is applied to ‘user_id’, causing a failure.

Most Session.merge() issues can be examined by first
checking - is the object prematurely in the session ?

     >>> a1 = Address(id=existing_a1, user_id=user.id)
     >>> assert a1 not in session
     >>> a1 = session.merge(a1)

Or is there state on the object that we don’t want ?  Examining
‘__dict__’ is a quick way to check:

     >>> a1 = Address(id=existing_a1, user_id=user.id)
     >>> a1.user
     >>> a1.__dict__
     {'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x1298d10>,
         'user_id': 1,
         'id': 1,
         'user': None}
     >>> # we don't want user=None merged, remove it
     >>> del a1.user
     >>> a1 = session.merge(a1)
     >>> # success
     >>> session.commit()

3.5.2.7 Expunging
.................

Expunge removes an object from the Session, sending persistent instances
to the detached state, and pending instances to the transient state:

     session.expunge(obj1)

To remove all items, call Session.expunge_all(). (this method
was formerly known as ‘clear()’).

3.5.2.8 Refreshing / Expiring
.............................

Expiring means that the database-persisted data held inside a series of
object attributes is erased, in such a way that when those attributes
are next accessed, a SQL query is emitted which will refresh that data
from the database.

When we talk about expiration of data we are usually talking about an
object that is in the persistent state.  For example, if we load an
object as follows:

     user = session.query(User).filter_by(name='user1').first()

The above ‘User’ object is persistent, and has a series of attributes
present; if we were to look inside its ‘__dict__’, we’d see that state
loaded:

     >>> user.__dict__
     {
       'id': 1, 'name': u'user1',
       '_sa_instance_state': <...>,
     }

where ‘id’ and ‘name’ refer to those columns in the database.
‘_sa_instance_state’ is a non-database-persisted value used by
SQLAlchemy internally (it refers to the InstanceState for
the instance.  While not directly relevant to this section, if we want
to get at it, we should use the inspect() function to access
it).

At this point, the state in our ‘User’ object matches that of the loaded
database row.  But upon expiring the object using a method such as
Session.expire(), we see that the state is removed:

     >>> session.expire(user)
     >>> user.__dict__
     {'_sa_instance_state': <...>}

We see that while the internal “state” still hangs around, the values
which correspond to the ‘id’ and ‘name’ columns are gone.  If we were to
access one of these columns and are watching SQL, we’d see this:

     >>> print(user.name)
     {opensql}SELECT user.id AS user_id, user.name AS user_name
     FROM user
     WHERE user.id = ?
     (1,)
     {stop}user1

Above, upon accessing the expired attribute ‘user.name’, the ORM
initiated a lazy load to retrieve the most recent state from the
database, by emitting a SELECT for the user row to which this user
refers.  Afterwards, the ‘__dict__’ is again populated:

     >>> user.__dict__
     {
       'id': 1, 'name': u'user1',
       '_sa_instance_state': <...>,
     }

     Note: While we are peeking inside of ‘__dict__’ in order to see a
     bit of what SQLAlchemy does with object attributes, we `should not
     modify' the contents of ‘__dict__’ directly, at least as far as
     those attributes which the SQLAlchemy ORM is maintaining (other
     attributes outside of SQLA’s realm are fine).  This is because
     SQLAlchemy uses descriptors in order to track the changes we make
     to an object, and when we modify ‘__dict__’ directly, the ORM won’t
     be able to track that we changed something.

Another key behavior of both Session.expire() and
Session.refresh() is that all un-flushed changes on an object are
discarded.  That is, if we were to modify an attribute on our ‘User’:

     >>> user.name = 'user2'

but then we call Session.expire() without first calling
Session.flush(), our pending value of ‘'user2'’ is discarded:

     >>> session.expire(user)
     >>> user.name
     'user1'

The Session.expire() method can be used to mark as “expired”
all ORM-mapped attributes for an instance:

     # expire all ORM-mapped attributes on obj1
     session.expire(obj1)

it can also be passed a list of string attribute names, referring to
specific attributes to be marked as expired:

     # expire only attributes obj1.attr1, obj1.attr2
     session.expire(obj1, ['attr1', 'attr2'])

The Session.expire_all() method allows us to essentially
call Session.expire() on all objects contained within the
Session at once:

     session.expire_all()

The Session.refresh() method has a similar interface, but
instead of expiring, it emits an immediate SELECT for the object’s row
immediately:

     # reload all attributes on obj1
     session.refresh(obj1)

Session.refresh() also accepts a list of string attribute
names, but unlike Session.expire(), expects at least one name
to be that of a column-mapped attribute:

     # reload obj1.attr1, obj1.attr2
     session.refresh(obj1, ['attr1', 'attr2'])

An alternative method of refreshing which is often more flexible is to
use the Query.populate_existing() method of Query.
With this option, all of the ORM objects returned by the
Query will be refreshed with the contents of what was loaded in
the SELECT:

     for user in session.query(User).populate_existing().filter(User.name.in_(['a', 'b', 'c'])):
         print(user)  # will be refreshed for those columns that came back from the query

3.5.2.9 What Actually Loads
...........................

The SELECT statement that’s emitted when an object marked with
Session.expire() or loaded with Session.refresh()
varies based on several factors, including:

   * The load of expired attributes is triggered from `column-mapped
     attributes only'.  While any kind of attribute can be marked as
     expired, including a relationship(). - mapped attribute,
     accessing an expired relationship() attribute will emit
     a load only for that attribute, using standard
     relationship-oriented lazy loading.  Column-oriented attributes,
     even if expired, will not load as part of this operation, and
     instead will load when any column-oriented attribute is accessed.

   * relationship().- mapped attributes will not load in
     response to expired column-based attributes being accessed.

   * Regarding relationships, see Session.refresh() is more
     restrictive than Session.expire() with regards to
     attributes that aren’t column-mapped.  Calling
     Session.refresh() and passing a list of names that only
     includes relationship-mapped attributes will actually raise an
     error.  In any case, non-eager-loading relationship()
     attributes will not be included in any refresh operation.

   * relationship() attributes configured as “eager loading”
     via the relationship.lazy parameter will load in the
     case of Session.refresh(), if either no attribute names
     are specified, or if their names are included in the list of
     attributes to be refreshed.

   * Attributes that are configured as deferred() will not
     normally load, during either the expired-attribute load or during a
     refresh.  An unloaded attribute that’s deferred()
     instead loads on its own when directly accessed, or if part of a
     “group” of deferred attributes where an unloaded attribute in that
     group is accessed.

   * For expired attributes that are loaded on access, a
     joined-inheritance table mapping will emit a SELECT that typically
     only includes those tables for which unloaded attributes are
     present.  The action here is sophisticated enough to load only the
     parent or child table, for example, if the subset of columns that
     were originally expired encompass only one or the other of those
     tables.

   * When Session.refresh() is used on a joined-inheritance
     table mapping, the SELECT emitted will resemble that of when
     Session.query() is used on the target object’s class.  This
     is typically all those tables that are set up as part of the
     mapping.

3.5.2.10 When to Expire or Refresh
..................................

The Session uses the expiration feature automatically
whenever the transaction referred to by the session ends.  Meaning,
whenever Session.commit() or Session.rollback()
is called, all objects within the Session are expired, using
a feature equivalent to that of the Session.expire_all()
method.  The rationale is that the end of a transaction is a demarcating
point at which there is no more context available in order to know what
the current state of the database is, as any number of other
transactions may be affecting it.  Only when a new transaction starts
can we again have access to the current state of the database, at which
point any number of changes may have occurred.

Transaction Isolation
.....................

Of course, most databases are capable of handling multiple transactions
at once, even involving the same rows of data.  When a relational
database handles multiple transactions involving the same tables or
rows, this is when the isolation aspect of the database comes into play.
The isolation behavior of different databases varies considerably and
even on a single database can be configured to behave in different ways
(via the so-called isolation level setting).  In that sense, the
Session can’t fully predict when the same SELECT statement, emitted
a second time, will definitely return the data we already have, or will
return new data.  So as a best guess, it assumes that within the scope
of a transaction, unless it is known that a SQL expression has been
emitted to modify a particular row, there’s no need to refresh a row
unless explicitly told to do so.

The Session.expire() and Session.refresh()
methods are used in those cases when one wants to force an object to
re-load its data from the database, in those cases when it is known that
the current state of data is possibly stale.  Reasons for this might
include:

   * some SQL has been emitted within the transaction outside of the
     scope of the ORM’s object handling, such as if a
     Table.update() construct were emitted using the
     Session.execute() method;

   * if the application is attempting to acquire data that is known to
     have been modified in a concurrent transaction, and it is also
     known that the isolation rules in effect allow this data to be
     visible.

The second bullet has the important caveat that “it is also known that
the isolation rules in effect allow this data to be visible.” This means
that it cannot be assumed that an UPDATE that happened on another
database connection will yet be visible here locally; in many cases, it
will not.  This is why if one wishes to use Session.expire()
or Session.refresh() in order to view data between ongoing
transactions, an understanding of the isolation behavior in effect is
essential.

See also
........

See Session.expire().

See Session.expire_all().

See Session.refresh().

See Query.populate_existing(). - see Query method that
refreshes all matching objects in the identity map against the results
of a SELECT statement.

isolation - glossary explanation of isolation which includes links to
Wikipedia.

The SQLAlchemy Session In-Depth(1) - a video + slides with an in-depth
discussion of the object lifecycle including the role of data
expiration.

   ---------- Footnotes ----------

   (1)
http://techspot.zzzeek.org/2012/11/14/pycon-canada-the-sqlalchemy-session-in-depth/

3.5.3 Cascades
--------------

Mappers support the concept of configurable cascade behavior on
relationship() constructs.  This refers to how operations performed
on a “parent” object relative to a particular Session should
be propagated to items referred to by that relationship (e.g.  “child”
objects), and is affected by the relationship.cascade
option.

The default behavior of cascade is limited to cascades of the so-called
save-update and merge settings.  The typical
“alternative” setting for cascade is to add the delete and
delete-orphan options; these settings are appropriate for
related objects which only exist as long as they are attached to their
parent, and are otherwise deleted.

Cascade behavior is configured using the relationship.cascade
option on relationship():

     class Order(Base):
         __tablename__ = 'order'

         items = relationship("Item", cascade="all, delete-orphan")
         customer = relationship("User", cascade="save-update")

To set cascades on a backref, the same flag can be used with the
backref() function, which ultimately feeds its arguments back into
relationship():

     class Item(Base):
         __tablename__ = 'item'

         order = relationship("Order",
                         backref=backref("items", cascade="all, delete-orphan")
                     )

The Origins of Cascade
......................

SQLAlchemy’s notion of cascading behavior on relationships, as well as
the options to configure them, are primarily derived from the similar
feature in the Hibernate ORM; Hibernate refers to “cascade” in a few
places such as in Example: Parent/Child(1).  If cascades are confusing,
we’ll refer to their conclusion, stating “The sections we have just
covered can be a bit confusing.  However, in practice, it all works out
nicely.”

The default value of relationship.cascade is ‘save-update,
merge’.  The typical alternative setting for this parameter is either
‘all’ or more commonly ‘all, delete-orphan’.  The ‘all’ symbol is a
synonym for ‘save-update, merge, refresh-expire, expunge, delete’, and
using it in conjunction with ‘delete-orphan’ indicates that the child
object should follow along with its parent in all cases, and be deleted
once it is no longer associated with that parent.

The list of available values which can be specified for the
relationship.cascade parameter are described in the following
subsections.

   ---------- Footnotes ----------

   (1)
https://docs.jboss.org/hibernate/orm/3.3/reference/en-US/html/example-parentchild.html

3.5.3.1 save-update
...................

‘save-update’ cascade indicates that when an object is placed into a
Session via Session.add(), all the objects
associated with it via this relationship() should also be
added to that same Session.  Suppose we have an object ‘user1’
with two related objects ‘address1’, ‘address2’:

     >>> user1 = User()
     >>> address1, address2 = Address(), Address()
     >>> user1.addresses = [address1, address2]

If we add ‘user1’ to a Session, it will also add ‘address1’,
‘address2’ implicitly:

     >>> sess = Session()
     >>> sess.add(user1)
     >>> address1 in sess
     True

‘save-update’ cascade also affects attribute operations for objects that
are already present in a Session.  If we add a third object,
‘address3’ to the ‘user1.addresses’ collection, it becomes part of the
state of that Session:

     >>> address3 = Address()
     >>> user1.append(address3)
     >>> address3 in sess
     >>> True

A ‘save-update’ cascade can exhibit surprising behavior when removing an
item from a collection or de-associating an object from a scalar
attribute.  In some cases, the orphaned objects may still be pulled into
the ex-parent’s Session; this is so that the flush process
may handle that related object appropriately.  This case usually only
arises if an object is removed from one Session and added to
another:

     >>> user1 = sess1.query(User).filter_by(id=1).first()
     >>> address1 = user1.addresses[0]
     >>> sess1.close()   # user1, address1 no longer associated with sess1
     >>> user1.addresses.remove(address1)  # address1 no longer associated with user1
     >>> sess2 = Session()
     >>> sess2.add(user1)   # ... but it still gets added to the new session,
     >>> address1 in sess2  # because it's still "pending" for flush
     True

The ‘save-update’ cascade is on by default, and is typically taken for
granted; it simplifies code by allowing a single call to
Session.add() to register an entire structure of objects within
that Session at once.  While it can be disabled, there is
usually not a need to do so.

One case where ‘save-update’ cascade does sometimes get in the way is in
that it takes place in both directions for bi-directional relationships,
e.g.  backrefs, meaning that the association of a child object with a
particular parent can have the effect of the parent object being
implicitly associated with that child object’s Session; this
pattern, as well as how to modify its behavior using the
relationship.cascade_backrefs flag, is discussed in the section
Controlling Cascade on Backrefs.

3.5.3.2 delete
..............

The ‘delete’ cascade indicates that when a “parent” object is marked for
deletion, its related “child” objects should also be marked for
deletion.  If for example we have a relationship ‘User.addresses’ with
‘delete’ cascade configured:

     class User(Base):
         # ...

         addresses = relationship("Address", cascade="all, delete")

If using the above mapping, we have a ‘User’ object and two related
‘Address’ objects:

     >>> user1 = sess.query(User).filter_by(id=1).first()
     >>> address1, address2 = user1.addresses

If we mark ‘user1’ for deletion, after the flush operation proceeds,
‘address1’ and ‘address2’ will also be deleted:

     >>> sess.delete(user1)
     >>> sess.commit()
     {opensql}DELETE FROM address WHERE address.id = ?
     ((1,), (2,))
     DELETE FROM user WHERE user.id = ?
     (1,)
     COMMIT

Alternatively, if our ‘User.addresses’ relationship does `not' have
‘delete’ cascade, SQLAlchemy’s default behavior is to instead
de-associate ‘address1’ and ‘address2’ from ‘user1’ by setting their
foreign key reference to ‘NULL’.  Using a mapping as follows:

     class User(Base):
         # ...

         addresses = relationship("Address")

Upon deletion of a parent ‘User’ object, the rows in ‘address’ are not
deleted, but are instead de-associated:

     >>> sess.delete(user1)
     >>> sess.commit()
     {opensql}UPDATE address SET user_id=? WHERE address.id = ?
     (None, 1)
     UPDATE address SET user_id=? WHERE address.id = ?
     (None, 2)
     DELETE FROM user WHERE user.id = ?
     (1,)
     COMMIT

delete cascade on one-to-many relationships is often
combined with delete-orphan cascade, which will emit a
DELETE for the related row if the “child” object is deassociated from
the parent.  The combination of ‘delete’ and ‘delete-orphan’ cascade
covers both situations where SQLAlchemy has to decide between setting a
foreign key column to NULL versus deleting the row entirely.

The feature by default works completely independently of
database-configured ‘FOREIGN KEY’ constraints that may themselves
configure ‘CASCADE’ behavior.  In order to integrate more efficiently
with this configuration, additional directives described at Using foreign key ON DELETE cascade with ORM relationships
should be
used.

See also
........

See Using foreign key ON DELETE cascade with ORM relationships.

See Using delete cascade with many-to-many relationships.

See delete-orphan.

3.5.3.3 Using delete cascade with many-to-many relationships
............................................................

The ‘cascade="all, delete"’ option works equally well with a
many-to-many relationship, one that uses relationship.secondary
to indicate an association table.  When a parent object is deleted,
and therefore de-associated with its related objects, the unit of work
process will normally delete rows from the association table, but leave
the related objects intact.  When combined with ‘cascade="all, delete"’,
additional ‘DELETE’ statements will take place for the child rows
themselves.

The following example adapts that of Many To Many to
illustrate the ‘cascade="all, delete"’ setting on `one' side of the
association:

     association_table = Table('association', Base.metadata,
         Column('left_id', Integer, ForeignKey('left.id')),
         Column('right_id', Integer, ForeignKey('right.id'))
     )

     class Parent(Base):
         __tablename__ = 'left'
         id = Column(Integer, primary_key=True)
         children = relationship(
             "Child",
             secondary=association_table,
             back_populates="parents",
             cascade="all, delete"
         )

     class Child(Base):
         __tablename__ = 'right'
         id = Column(Integer, primary_key=True)
         parents = relationship(
             "Parent",
             secondary=association_table,
             back_populates="children",
         )

Above, when a ‘Parent’ object is marked for deletion using
Session.delete(), the flush process will as usual delete the
associated rows from the ‘association’ table, however per cascade rules
it will also delete all related ‘Child’ rows.

     Warning: If the above ‘cascade="all, delete"’ setting were
     configured on `both' relationships, then the cascade action would
     continue cascading through all ‘Parent’ and ‘Child’ objects,
     loading each ‘children’ and ‘parents’ collection encountered and
     deleting everything that’s connected.  It is typically not
     desireable for “delete” cascade to be configured bidirectionally.

See also
........

See Deleting Rows from the Many to Many Table.

See Using foreign key ON DELETE with many-to-many relationships.

3.5.3.4 Using foreign key ON DELETE cascade with ORM relationships
..................................................................

The behavior of SQLAlchemy’s “delete” cascade overlaps with the ‘ON
DELETE’ feature of a database ‘FOREIGN KEY’ constraint.  SQLAlchemy
allows configuration of these schema-level DDL behaviors using the
ForeignKey and ForeignKeyConstraint constructs; usage of
these objects in conjunction with Table metadata is described
at ON UPDATE and ON DELETE.

In order to use ‘ON DELETE’ foreign key cascades in conjunction with
relationship(), it’s important to note first and foremost that
the relationship.cascade setting must still be configured to
match the desired “delete” or “set null” behavior (using ‘delete’
cascade or leaving it omitted), so that whether the ORM or the database
level constraints will handle the task of actually modifying the data in
the database, the ORM will still be able to appropriately track the
state of locally present objects that may be affected.

There is then an additional option on relationship() which
indicates the degree to which the ORM should try to run DELETE/UPDATE
operations on related rows itself, vs.  how much it should rely upon
expecting the database-side FOREIGN KEY constraint cascade to handle the
task; this is the relationship.passive_deletes parameter and
it accepts options ‘False’ (the default), ‘True’ and ‘"all"’.

The most typical example is that where child rows are to be deleted when
parent rows are deleted, and that ‘ON DELETE CASCADE’ is configured on
the relevant ‘FOREIGN KEY’ constraint as well:

     class Parent(Base):
         __tablename__ = 'parent'
         id = Column(Integer, primary_key=True)
         children = relationship(
             "Child", back_populates="parent",
             cascade="all, delete",
             passive_deletes=True
         )

     class Child(Base):
         __tablename__ = 'child'
         id = Column(Integer, primary_key=True)
         parent_id = Column(Integer, ForeignKey('parent.id', ondelete="CASCADE"))
         parent = relationship("Parent", back_populates="children")

The behavior of the above configuration when a parent row is deleted is
as follows:

  1. The application calls ‘session.delete(my_parent)’, where
     ‘my_parent’ is an instance of ‘Parent’.

  2. When the Session next flushes changes to the database,
     all of the `currently loaded' items within the ‘my_parent.children’
     collection are deleted by the ORM, meaning a ‘DELETE’ statement is
     emitted for each record.

  3. If the ‘my_parent.children’ collection is `unloaded', then no
     ‘DELETE’ statements are emitted.  If the
     relationship.passive_deletes flag were `not' set on this
     relationship(), then a ‘SELECT’ statement for unloaded
     ‘Child’ objects would have been emitted.

  4. A ‘DELETE’ statement is then emitted for the ‘my_parent’ row
     itself.

  5. The database-level ‘ON DELETE CASCADE’ setting ensures that all
     rows in ‘child’ which refer to the affected row in ‘parent’ are
     also deleted.

  6. The ‘Parent’ instance referred to by ‘my_parent’, as well as all
     instances of ‘Child’ that were related to this object and were
     `loaded' (i.e.  step 2 above took place), are de-associated from
     the Session.

     Note: To use “ON DELETE CASCADE”, the underlying database engine
     must support ‘FOREIGN KEY’ constraints and they must be enforcing:

        * When using MySQL, an appropriate storage engine must be
          selected.  See CREATE TABLE arguments including Storage Engines
          for details.

        * When using SQLite, foreign key support must be enabled
          explicitly.  See Foreign Key Support for details.

Notes on Passive Deletes
........................

It is important to note the differences between the ORM and the
relational database’s notion of “cascade” as well as how they integrate:

   * A database level ‘ON DELETE’ cascade is configured effectively on
     the `many-to-one' side of the relationship; that is, we configure
     it relative to the ‘FOREIGN KEY’ constraint that is the “many” side
     of a relationship.  At the ORM level, `this direction is reversed'.
     SQLAlchemy handles the deletion of “child” objects relative to a
     “parent” from the “parent” side, which means that ‘delete’ and
     ‘delete-orphan’ cascade are configured on the `one-to-many' side.

   * Database level foreign keys with no ‘ON DELETE’ setting are often
     used to `prevent' a parent row from being removed, as it would
     necessarily leave an unhandled related row present.  If this
     behavior is desired in a one-to-many relationship, SQLAlchemy’s
     default behavior of setting a foreign key to ‘NULL’ can be caught
     in one of two ways:

             * The easiest and most common is just to set the
               foreign-key-holding column to ‘NOT NULL’ at the database
               schema level.  An attempt by SQLAlchemy to set the column
               to NULL will fail with a simple NOT NULL constraint
               exception.

             * The other, more special case way is to set the
               relationship.passive_deletes flag to the string
               ‘"all"’.  This has the effect of entirely disabling
               SQLAlchemy’s behavior of setting the foreign key column
               to NULL, and a DELETE will be emitted for the parent row
               without any affect on the child row, even if the child
               row is present in memory.  This may be desirable in the
               case when database-level foreign key triggers, either
               special ‘ON DELETE’ settings or otherwise, need to be
               activated in all cases when a parent row is deleted.

   * Database level ‘ON DELETE’ cascade is generally much more efficient
     than relying upon the “cascade” delete feature of SQLAlchemy.  The
     database can chain a series of cascade operations across many
     relationships at once; e.g.  if row A is deleted, all the related
     rows in table B can be deleted, and all the C rows related to each
     of those B rows, and on and on, all within the scope of a single
     DELETE statement.  SQLAlchemy on the other hand, in order to
     support the cascading delete operation fully, has to individually
     load each related collection in order to target all rows that then
     may have further related collections.  That is, SQLAlchemy isn’t
     sophisticated enough to emit a DELETE for all those related rows at
     once within this context.

   * SQLAlchemy doesn’t `need' to be this sophisticated, as we instead
     provide smooth integration with the database’s own ‘ON DELETE’
     functionality, by using the relationship.passive_deletes
     option in conjunction with properly configured foreign key
     constraints.  Under this behavior, SQLAlchemy only emits DELETE for
     those rows that are already locally present in the Session;
     for any collections that are unloaded, it leaves them to the
     database to handle, rather than emitting a SELECT for them.  The
     section Using foreign key ON DELETE cascade with ORM relationships
     provides an example of this use.

   * While database-level ‘ON DELETE’ functionality works only on the
     “many” side of a relationship, SQLAlchemy’s “delete” cascade has
     `limited' ability to operate in the `reverse' direction as well,
     meaning it can be configured on the “many” side to delete an object
     on the “one” side when the reference on the “many” side is deleted.
     However this can easily result in constraint violations if there
     are other objects referring to this “one” side from the “many”, so
     it typically is only useful when a relationship is in fact a “one
     to one”.  The relationship.single_parent flag should be
     used to establish an in-Python assertion for this case.

3.5.3.5 Using foreign key ON DELETE with many-to-many relationships
...................................................................

As described at Using delete cascade with many-to-many relationships,
“delete” cascade works for many-to-many
relationships as well.  To make use of ‘ON DELETE CASCADE’ foreign keys
in conjunction with many to many, ‘FOREIGN KEY’ directives are
configured on the association table.  These directives can handle the
task of automatically deleting from the association table, but cannot
accommodate the automatic deletion of the related objects themselves.

In this case, the relationship.passive_deletes directive can
save us some additional ‘SELECT’ statements during a delete operation
but there are still some collections that the ORM will continue to load,
in order to locate affected child objects and handle them correctly.

     Note: Hypothetical optimizations to this could include a single
     ‘DELETE’ statement against all parent-associated rows of the
     association table at once, then use ‘RETURNING’ to locate affected
     related child rows, however this is not currently part of the ORM
     unit of work implementation.

In this configuration, we configure ‘ON DELETE CASCADE’ on both foreign
key constraints of the association table.  We configure ‘cascade="all,
delete"’ on the parent->child side of the relationship, and we can then
configure ‘passive_deletes=True’ on the `other' side of the
bidirectional relationship as illustrated below:

     association_table = Table('association', Base.metadata,
         Column('left_id', Integer, ForeignKey('left.id', ondelete="CASCADE")),
         Column('right_id', Integer, ForeignKey('right.id', ondelete="CASCADE"))
     )

     class Parent(Base):
         __tablename__ = 'left'
         id = Column(Integer, primary_key=True)
         children = relationship(
             "Child",
             secondary=association_table,
             back_populates="parents",
             cascade="all, delete",
         )

     class Child(Base):
         __tablename__ = 'right'
         id = Column(Integer, primary_key=True)
         parents = relationship(
             "Parent",
             secondary=association_table,
             back_populates="children",
             passive_deletes=True
         )

Using the above configuration, the deletion of a ‘Parent’ object
proceeds as follows:

  1. A ‘Parent’ object is marked for deletion using
     Session.delete().

  2. When the flush occurs, if the ‘Parent.children’ collection is not
     loaded, the ORM will first emit a SELECT statement in order to load
     the ‘Child’ objects that correspond to ‘Parent.children’.

  3. It will then then emit ‘DELETE’ statements for the rows in
     ‘association’ which correspond to that parent row.

  4. for each ‘Child’ object affected by this immediate deletion,
     because ‘passive_deletes=True’ is configured, the unit of work will
     not need to try to emit SELECT statements for each ‘Child.parents’
     collection as it is assumed the corresponding rows in ‘association’
     will be deleted.

  5. ‘DELETE’ statements are then emitted for each ‘Child’ object that
     was loaded from ‘Parent.children’.

3.5.3.6 delete-orphan
.....................

‘delete-orphan’ cascade adds behavior to the ‘delete’ cascade, such that
a child object will be marked for deletion when it is de-associated from
the parent, not just when the parent is marked for deletion.  This is a
common feature when dealing with a related object that is “owned” by its
parent, with a NOT NULL foreign key, so that removal of the item from
the parent collection results in its deletion.

‘delete-orphan’ cascade implies that each child object can only have one
parent at a time, and in the `vast majority of cases is configured only
on a one-to-many relationship.'  For the much less common case of
setting it on a many-to-one or many-to-many relationship, the “many”
side can be forced to allow only a single object at a time by
configuring the relationship.single_parent argument, which
establishes Python-side validation that ensures the object is associated
with only one parent at a time, however this greatly limits the
functionality of the “many” relationship and is usually not what’s
desired.

See also
........

*note For relationship <relationship>, delete-orphan cascade is normally
configured only on the “one” side of a one-to-many relationship, and not
on the “many” side of a many-to-one or many-to-many relationship.: 647.
- background on a common error scenario involving delete-orphan cascade.

3.5.3.7 merge
.............

‘merge’ cascade indicates that the Session.merge() operation
should be propagated from a parent that’s the subject of the
Session.merge() call down to referred objects.  This cascade is
also on by default.

3.5.3.8 refresh-expire
......................

‘refresh-expire’ is an uncommon option, indicating that the
Session.expire() operation should be propagated from a parent down
to referred objects.  When using Session.refresh(), the
referred objects are expired only, but not actually refreshed.

3.5.3.9 expunge
...............

‘expunge’ cascade indicates that when the parent object is removed from
the Session using Session.expunge(), the operation
should be propagated down to referred objects.

3.5.3.10 Controlling Cascade on Backrefs
........................................

     Note: This section applies to a behavior that is removed in
     SQLAlchemy 2.0.  By setting the Session.future flag on
     a given Session, the 2.0 behavior will be achieved which
     is essentially that the relationship.cascade_backrefs
     flag is ignored.  See the section cascade_backrefs behavior deprecated for removal in 2.0
     for notes.

In 1.x style ORM usage, the save-update cascade by default
takes place on attribute change events emitted from backrefs.  This is
probably a confusing statement more easily described through
demonstration; it means that, given a mapping such as this:

     mapper_registry.map_imperatively(Order, order_table, properties={
         'items' : relationship(Item, backref='order')
     })

If an ‘Order’ is already in the session, and is assigned to the ‘order’
attribute of an ‘Item’, the backref appends the ‘Item’ to the ‘items’
collection of that ‘Order’, resulting in the ‘save-update’ cascade
taking place:

     >>> o1 = Order()
     >>> session.add(o1)
     >>> o1 in session
     True

     >>> i1 = Item()
     >>> i1.order = o1
     >>> i1 in o1.items
     True
     >>> i1 in session
     True

This behavior can be disabled using the
relationship.cascade_backrefs flag:

     mapper_registry.map_imperatively(Order, order_table, properties={
         'items' : relationship(Item, backref='order', cascade_backrefs=False)
     })

So above, the assignment of ‘i1.order = o1’ will append ‘i1’ to the
‘items’ collection of ‘o1’, but will not add ‘i1’ to the session.  You
can, of course, see Session.add(). ‘i1’ to the session at a later
point.  This option may be helpful for situations where an object needs
to be kept out of a session until it’s construction is completed, but
still needs to be given associations to objects which are already
persistent in the target session.

3.5.3.11 Notes on Delete - Deleting Objects Referenced from Collections and Scalar Relationships
................................................................................................

The ORM in general never modifies the contents of a collection or scalar
relationship during the flush process.  This means, if your class has a
relationship() that refers to a collection of objects, or a
reference to a single object such as many-to-one, the contents of this
attribute will not be modified when the flush process occurs.  Instead,
it is expected that the Session would eventually be expired,
either through the expire-on-commit behavior of Session.commit()
or through explicit use of Session.expire().  At that
point, any referenced object or collection associated with that
Session will be cleared and will re-load itself upon next access.

A common confusion that arises regarding this behavior involves the use
of the Session.delete() method.  When
Session.delete() is invoked upon an object and the Session
is flushed, the row is deleted from the database.  Rows that refer
to the target row via foreign key, assuming they are tracked using a
relationship() between the two mapped object types, will also
see their foreign key attributes UPDATED to null, or if delete cascade
is set up, the related rows will be deleted as well.  However, even
though rows related to the deleted object might be themselves modified
as well, `no changes occur to relationship-bound collections or object
references on the objects' involved in the operation within the scope of
the flush itself.  This means if the object was a member of a related
collection, it will still be present on the Python side until that
collection is expired.  Similarly, if the object were referenced via
many-to-one or one-to-one from another object, that reference will
remain present on that object until the object is expired as well.

Below, we illustrate that after an ‘Address’ object is marked for
deletion, it’s still present in the collection associated with the
parent ‘User’, even after a flush:

     >>> address = user.addresses[1]
     >>> session.delete(address)
     >>> session.flush()
     >>> address in user.addresses
     True

When the above session is committed, all attributes are expired.  The
next access of ‘user.addresses’ will re-load the collection, revealing
the desired state:

     >>> session.commit()
     >>> address in user.addresses
     False

There is a recipe for intercepting Session.delete() and
invoking this expiration automatically; see
ExpireRelationshipOnFKChange(1) for this.  However, the usual practice
of deleting items within collections is to forego the usage of
Session.delete() directly, and instead use cascade behavior to
automatically invoke the deletion as a result of removing the object
from the parent collection.  The ‘delete-orphan’ cascade accomplishes
this, as illustrated in the example below:

     class User(Base):
         __tablename__ = 'user'

         # ...

         addresses = relationship(
             "Address", cascade="all, delete-orphan")

     # ...

     del user.addresses[1]
     session.flush()

Where above, upon removing the ‘Address’ object from the
‘User.addresses’ collection, the ‘delete-orphan’ cascade has the effect
of marking the ‘Address’ object for deletion in the same way as passing
it to Session.delete().

The ‘delete-orphan’ cascade can also be applied to a many-to-one or
one-to-one relationship, so that when an object is de-associated from
its parent, it is also automatically marked for deletion.  Using
‘delete-orphan’ cascade on a many-to-one or one-to-one requires an
additional flag relationship.single_parent which invokes an
assertion that this related object is not to shared with any other
parent simultaneously:

     class User(Base):
         # ...

         preference = relationship(
             "Preference", cascade="all, delete-orphan",
             single_parent=True)

Above, if a hypothetical ‘Preference’ object is removed from a ‘User’,
it will be deleted on flush:

     some_user.preference = None
     session.flush()  # will delete the Preference object

See also
........

Cascades for detail on cascades.

   ---------- Footnotes ----------

   (1)
http://www.sqlalchemy.org/trac/wiki/UsageRecipes/ExpireRelationshipOnFKChange

3.5.4 Transactions and Connection Management
--------------------------------------------

3.5.4.1 Managing Transactions
.............................

Changed in version 1.4: Session transaction management has been revised
to be clearer and easier to use.  In particular, it now features
“autobegin” operation, which means the point at which a transaction
begins may be controlled, without using the legacy “autocommit” mode.

The Session tracks the state of a single “virtual”
transaction at a time, using an object called SessionTransaction.
This object then makes use of the underyling Engine or
engines to which the Session object is bound in order to
start real connection-level transactions using the Connection
object as needed.

This “virtual” transaction is created automatically when needed, or can
alternatively be started using the Session.begin() method.
To as great a degree as possible, Python context manager use is
supported both at the level of creating Session objects as
well as to maintain the scope of the SessionTransaction.

Below, assume we start with a Session:

     from sqlalchemy.orm import Session
     session = Session(engine)

We can now run operations within a demarcated transaction using a
context manager:

     with session.begin():
         session.add(some_object())
         session.add(some_other_object())
     # commits transaction at the end, or rolls back if there
     # was an exception raised

At the end of the above context, assuming no exceptions were raised, any
pending objects will be flushed to the database and the database
transaction will be committed.  If an exception was raised within the
above block, then the transaction would be rolled back.  In both cases,
the above Session subsequent to exiting the block is ready to
be used in subsequent transactions.

The Session.begin() method is optional, and the
Session may also be used in a commit-as-you-go approach, where it
will begin transactions automatically as needed; these only need be
committed or rolled back:

     session = Session(engine)

     session.add(some_object())
     session.add(some_other_object())

     session.commit()  # commits

     # will automatically begin again
     result = session.execute(< some select statment >)
     session.add_all([more_objects, ...])
     session.commit()  # commits

     session.add(still_another_object)
     session.flush()  # flush still_another_object
     session.rollback()   # rolls back still_another_object

The Session itself features a Session.close()
method.  If the Session is begun within a transaction that
has not yet been committed or rolled back, this method will cancel (i.e.
rollback) that transaction, and also expunge all objects contained
within the Session object’s state.  If the Session
is being used in such a way that a call to Session.commit()
or Session.rollback() is not guaranteed (e.g.  not within a
context manager or similar), the close method may be used to
ensure all resources are released:

     # expunges all objects, releases all transactions unconditionally
     # (with rollback), releases all database connections back to their
     # engines
     session.close()

Finally, the session construction / close process can itself be run via
context manager.  This is the best way to ensure that the scope of a
Session object’s use is scoped within a fixed block.
Illustrated via the Session constructor first:

     with Session(engine) as session:
         session.add(some_object())
         session.add(some_other_object())

         session.commit()  # commits

         session.add(still_another_object)
         session.flush()  # flush still_another_object

         session.commit()  # commits

         result = session.execute(<some SELECT statement>)

     # remaining transactional state from the .execute() call is
     # discarded

Similarly, the sessionmaker can be used in the same way:

     Session = sesssionmaker(engine)

     with Session() as session:
         with session.begin():
             session.add(some_object)
         # commits

     # closes the Session

sessionmaker itself includes a sessionmaker.begin()
method to allow both operations to take place at once:

     with Session.begin() as session:
         session.add(some_object):

3.5.4.2 Using SAVEPOINT
.......................

SAVEPOINT transactions, if supported by the underlying engine, may be
delineated using the Session.begin_nested() method:

     Session = sessionmaker()

     with Session.begin() as session:
         session.add(u1)
         session.add(u2)

         nested = session.begin_nested() # establish a savepoint
         session.add(u3)
         nested.rollback()  # rolls back u3, keeps u1 and u2

     # commits u1 and u2

Each time Session.begin_nested() is called, a new “BEGIN
SAVEPOINT” command is emitted to the database wih a unique identifier.
When ‘SessionTransaction.commit()’ is called, “RELEASE SAVEPOINT” is
emitted on the database, and if instead ‘SessionTransaction.rollback()’
is called, “ROLLBACK TO SAVEPOINT” is emitted.

Session.begin_nested() may also be used as a context manager
in the same manner as that of the Session.begin() method:

     for record in records:
         try:
             with session.begin_nested():
                 session.merge(record)
         except:
             print("Skipped record %s" % record)
     session.commit()

When Session.begin_nested() is called, a
Session.flush() is unconditionally issued (regardless of the
‘autoflush’ setting).  This is so that when a rollback on this nested
transaction occurs, the full state of the session is expired, thus
causing all subsequent attribute/instance access to reference the full
state of the ‘Session’ right before Session.begin_nested()
was called.

See also
........

See NestedTransaction. - the NestedTransaction class
is the Core-level construct that is used by the Session
internally to produce SAVEPOINT blocks.

3.5.4.3 Session-level vs. Engine level transaction control
..........................................................

As of SQLAlchemy 1.4, the sessionmaker and Core
Engine objects both support 2.0 style operation, by making use of
the Session.future flag as well as the
‘create_engine.future’ flag so that these two objects assume 2.0-style
semantics.

When using future mode, there should be equivalent semantics between the
two packages, at the level of the sessionmaker vs.  the
Engine, as well as the Session vs.  the
Connection.  The following sections detail these scenarios based on
the following scheme:

     ORM (using future Session)                    Core (using future engine)
     -----------------------------------------     -----------------------------------
     sessionmaker                                  Engine
     Session                                       Connection
     sessionmaker.begin()                          Engine.begin()
     some_session.commit()                         some_connection.commit()
     with some_sessionmaker() as session:          with some_engine.connect() as conn:
     with some_sessionmaker.begin() as session:    with some_engine.begin() as conn:
     with some_session.begin_nested() as sp:       with some_connection.begin_nested() as sp:

3.5.4.4 Commit as you go
........................

Both Session and Connection feature
Connection.commit() and Connection.rollback() methods.
Using SQLAlchemy 2.0-style operation, these methods affect the
`outermost' transaction in all cases.

Engine:

     engine = create_engine("postgresql://user:pass@host/dbname", future=True)

     with engine.connect() as conn:
         conn.execute(
             some_table.insert(),
             [
                 {"data": "some data one"},
                 {"data": "some data two"},
                 {"data": "some data three"}
             ]
         )
         conn.commit()

Session:

     Session = sessionmaker(engine, future=True)

     with Session() as session:
         session.add_all([
             SomeClass(data="some data one"),
             SomeClass(data="some data two"),
             SomeClass(data="some data three")
         ])
         session.commit()

3.5.4.5 Begin Once
..................

Both sessionmaker and Engine feature a
Engine.begin() method that will both procure a new object with
which to execute SQL statements (the Session and
Connection, respectively) and then return a context manager that
will maintain a begin/commit/rollback context for that object.

Engine:

     engine = create_engine("postgresql://user:pass@host/dbname", future=True)

     with engine.begin() as conn:
         conn.execute(
             some_table.insert(),
             [
                 {"data": "some data one"},
                 {"data": "some data two"},
                 {"data": "some data three"}
             ]
         )
     # commits and closes automatically

Session:

     Session = sessionmaker(engine, future=True)

     with Session.begin() as session:
         session.add_all([
             SomeClass(data="some data one"),
             SomeClass(data="some data two"),
             SomeClass(data="some data three")
         ])
     # commits and closes automatically

3.5.4.6 Nested Transaction
..........................

When using a SAVEPOINT via the Session.begin_nested() or
Connection.begin_nested() methods, the transaction object
returned must be used to commit or rollback the SAVEPOINT. Calling the
Session.commit() or Connection.commit() methods
will always commit the `outermost' transaction; this is a SQLAlchemy 2.0
specific behavior that is reversed from the 1.x series.

Engine:

     engine = create_engine("postgresql://user:pass@host/dbname", future=True)

     with engine.begin() as conn:
         savepoint = conn.begin_nested()
         conn.execute(
             some_table.insert(),
             [
                 {"data": "some data one"},
                 {"data": "some data two"},
                 {"data": "some data three"}
             ]
         )
         savepoint.commit()  # or rollback

     # commits automatically

Session:

     Session = sessionmaker(engine, future=True)

     with Session.begin() as session:
         savepoint = session.begin_nested()
         session.add_all([
             SomeClass(data="some data one"),
             SomeClass(data="some data two"),
             SomeClass(data="some data three")
         ])
         savepoint.commit()  # or rollback
     # commits automatically

3.5.4.7 Explicit Begin
......................

Changed in version 1.4: SQLAlchemy 1.4 deprecates “autocommit mode”,
which is historically enabled by using the Session.autocommit
flag.  Going forward, a new approach to allowing usage of the
Session.begin() method is new “autobegin” behavior so that the
method may now be called when a Session is first constructed,
or after the previous transaction has ended and before it begins a new
one.

For background on migrating away from the “subtransaction” pattern for
frameworks that rely upon nesting of begin()/commit() pairs, see the
next section Migrating from the “subtransaction” pattern.

The Session features “autobegin” behavior, meaning that as
soon as operations begin to take place, it ensures a
SessionTransaction is present to track ongoing operations.  This
transaction is completed when Session.commit() is called.

It is often desirable, particularly in framework integrations, to
control the point at which the “begin” operation occurs.  To suit this,
the Session uses an “autobegin” strategy, such that the
Session.begin() method may be called directly for a Session
that has not already had a transaction begun:

     Session = sessionmaker(bind=engine)
     session = Session()
     session.begin()
     try:
         item1 = session.query(Item).get(1)
         item2 = session.query(Item).get(2)
         item1.foo = 'bar'
         item2.bar = 'foo'
         session.commit()
     except:
         session.rollback()
         raise

The above pattern is more idiomatically invoked using a context manager:

     Session = sessionmaker(bind=engine)
     session = Session()
     with session.begin():
         item1 = session.query(Item).get(1)
         item2 = session.query(Item).get(2)
         item1.foo = 'bar'
         item2.bar = 'foo'

The Session.begin() method and the session’s “autobegin”
process use the same sequence of steps to begin the transaction.  This
includes that the SessionEvents.after_transaction_create()
event is invoked when it occurs; this hook is used by frameworks in
order to integrate their own transactional processes with that of the
ORM Session.

3.5.4.8 Migrating from the “subtransaction” pattern
...................................................

Deprecated since version 1.4: The Session.begin.subtransactions
flag is deprecated.  While the Session still uses the
“subtransactions” pattern internally, it is not suitable for end-user
use as it leads to confusion, and additionally it may be removed from
the Session itself in version 2.0 once “autocommit” mode is
removed.

The “subtransaction” pattern that was often used with autocommit mode is
also deprecated in 1.4.  This pattern allowed the use of the
Session.begin() method when a transaction were already begun,
resulting in a construct called a “subtransaction”, which was
essentially a block that would prevent the Session.commit()
method from actually committing.

This pattern has been shown to be confusing in real world applications,
and it is preferable for an application to ensure that the top-most
level of database operations are performed with a single begin/commit
pair.

To provide backwards compatibility for applications that make use of
this pattern, the following context manager or a similar implementation
based on a decorator may be used:

     import contextlib

     @contextlib.contextmanager
     def transaction(session):
         if not session.in_transaction():
             with session.begin():
                 yield
         else:
             yield

The above context manager may be used in the same way the
“subtransaction” flag works, such as in the following example:

     # method_a starts a transaction and calls method_b
     def method_a(session):
         with transaction(session):
             method_b(session)

     # method_b also starts a transaction, but when
     # called from method_a participates in the ongoing
     # transaction.
     def method_b(session):
         with transaction(session):
             session.add(SomeObject('bat', 'lala'))

     Session = sessionmaker(engine)

     # create a Session and call method_a
     with Session() as session:
         method_a(session)

To compare towards the preferred idiomatic pattern, the begin block
should be at the outermost level.  This removes the need for individual
functions or methods to be concerned with the details of transaction
demarcation:

     def method_a(session):
         method_b(session)

     def method_b(session):
         session.add(SomeObject('bat', 'lala'))

     Session = sessionmaker(engine)

     # create a Session and call method_a
     with Session() as session:
         with session.begin():
             method_a(session)

See also
........

See Migrating from the “nesting” pattern. - similar pattern based
on Core only

3.5.4.9 Enabling Two-Phase Commit
.................................

For backends which support two-phase operation (currently MySQL and
PostgreSQL), the session can be instructed to use two-phase commit
semantics.  This will coordinate the committing of transactions across
databases so that the transaction is either committed or rolled back in
all databases.  You can also Session.prepare() the session
for interacting with transactions not managed by SQLAlchemy.  To use two
phase transactions set the flag ‘twophase=True’ on the session:

     engine1 = create_engine('postgresql://db1')
     engine2 = create_engine('postgresql://db2')

     Session = sessionmaker(twophase=True)

     # bind User operations to engine 1, Account operations to engine 2
     Session.configure(binds={User:engine1, Account:engine2})

     session = Session()

     # .... work with accounts and users

     # commit.  session will issue a flush to all DBs, and a prepare step to all DBs,
     # before committing both transactions
     session.commit()

3.5.4.10 Setting Transaction Isolation Levels / DBAPI AUTOCOMMIT
................................................................

Most DBAPIs support the concept of configurable transaction isolation
levels.  These are traditionally the four levels “READ UNCOMMITTED”,
“READ COMMITTED”, “REPEATABLE READ” and “SERIALIZABLE”.  These are
usually applied to a DBAPI connection before it begins a new
transaction, noting that most DBAPIs will begin this transaction
implicitly when SQL statements are first emitted.

DBAPIs that support isolation levels also usually support the concept of
true “autocommit”, which means that the DBAPI connection itself will be
placed into a non-transactional autocommit mode.  This usually means
that the typical DBAPI behavior of emitting “BEGIN” to the database
automatically no longer occurs, but it may also include other
directives.  When using this mode, `the DBAPI does not use a transaction
under any circumstances'.  SQLAlchemy methods like ‘.begin()’,
‘.commit()’ and ‘.rollback()’ pass silently.

SQLAlchemy’s dialects support settable isolation modes on a per-see
Engine or per-see Connection basis, using flags at both
the create_engine() level as well as at the
Connection.execution_options() level.

When using the ORM Session, it acts as a `facade' for engines
and connections, but does not expose transaction isolation directly.  So
in order to affect transaction isolation level, we need to act upon the
Engine or Connection as appropriate.

3.5.4.11 Setting Isolation For A Sessionmaker / Engine Wide
...........................................................

To set up a Session or sessionmaker with a
specific isolation level globally, the first technique is that an
Engine can be constructed against a specific isolation level in
all cases, which is then used as the source of connectivity for a
Session and/or sessionmaker:

     from sqlalchemy import create_engine
     from sqlalchemy.orm import sessionmaker

     eng = create_engine(
         "postgresql://scott:tiger@localhost/test",
         isolation_level='REPEATABLE READ'
     )

     Session = sessionmaker(eng)

Another option, useful if there are to be two engines with different
isolation levels at once, is to use the
Engine.execution_options() method, which will produce a shallow
copy of the original Engine which shares the same connection
pool as the parent engine.  This is often preferable when operations
will be separated into “transactional” and “autocommit” operations:

     from sqlalchemy import create_engine
     from sqlalchemy.orm import sessionmaker

     eng = create_engine("postgresql://scott:tiger@localhost/test")

     autocommit_engine = eng.execution_options(isolation_level="AUTOCOMMIT")

     transactional_session = sessionmaker(eng)
     autocommit_session = sessionmaker(autocommit_engine)

Above, both “‘eng’” and ‘"autocommit_engine"’ share the same dialect and
connection pool.  However the “AUTOCOMMIT” mode will be set upon
connections when they are acquired from the ‘autocommit_engine’.  The
two sessionmaker objects “‘transactional_session’” and
“‘autocommit_session"’ then inherit these characteristics when they work
with database connections.

The “‘autocommit_session’” `continues to have transactional semantics',
including that Session.commit() and Session.rollback()
still consider themselves to be “committing” and “rolling back”
objects, however the transaction will be silently absent.  For this
reason, `it is typical, though not strictly required, that a Session
with AUTOCOMMIT isolation be used in a read-only fashion', that is:

     with autocommit_session() as session:
         some_objects = session.execute(<statement>)
         some_other_objects = session.execute(<statement>)

     # closes connection

3.5.4.12 Setting Isolation for Individual Sessions
..................................................

When we make a new Session, either using the constructor
directly or when we call upon the callable produced by a
sessionmaker, we can pass the ‘bind’ argument directly, overriding
the pre-existing bind.  We can for example create our Session
from the “‘transactional_session’” and pass the “‘autocommit_engine’”:

     with transactional_session(bind=autocommit_engine) as session:
         # work with session

For the case where the Session or sessionmaker is
configured with multiple “binds”, we can either re-specify the ‘binds’
argument fully, or if we want to only replace specific binds, we can use
the Session.bind_mapper() or Session.bind_table()
methods:

     session = maker()
     session.bind_mapper(User, autocommit_engine)

We can also use the individual transaction method that follows.

3.5.4.13 Setting Isolation for Individual Transactions
......................................................

A key caveat regarding isolation level is that the setting cannot be
safely modified on a Connection where a transaction has
already started.  Databases cannot change the isolation level of a
transaction in progress, and some DBAPIs and SQLAlchemy dialects have
inconsistent behaviors in this area.

Therefore it is preferable to use a Session that is up front
bound to an engine with the desired isolation level.  However, the
isolation level on a per-connection basis can be affected by using the
Session.connection() method at the start of a transaction:

     from sqlalchemy.orm import Session

     sess = Session(bind=engine)
     with sess.begin():
         sess.connection(execution_options={'isolation_level': 'SERIALIZABLE'})

     # commits transaction.  the connection is released
     # and reverted to its previous isolation level.

Above, we first produce a Session using either the
constructor or a sessionmaker.  Then we explicitly set up the
start of a transaction by calling upon Session.connection(),
which provides for execution options that will be passed to the
connection before the transaction is begun.

3.5.4.14 Tracking Transaction State with Events
...............................................

See the section Transaction Events for an overview of the
available event hooks for session transaction state changes.

3.5.4.15 Joining a Session into an External Transaction (such as for test suites)
.................................................................................

If a Connection is being used which is already in a
transactional state (i.e.  has a Transaction established), a
Session can be made to participate within that transaction by
just binding the Session to that Connection.  The
usual rationale for this is a test suite that allows ORM code to work
freely with a Session, including the ability to call
Session.commit(), where afterwards the entire database interaction
is rolled back.

Changed in version 1.4: This section introduces a new version of the
“join into an external transaction” recipe that will work equally well
for both 2.0 style and 1.x style engines and sessions.  The recipe here
from previous versions such as 1.3 will also continue to work for 1.x
engines and sessions.

The recipe works by establishing a Connection within a
transaction and optionally a SAVEPOINT, then passing it to a
Session as the “bind”.  The Session detects that the
given Connection is already in a transaction and will not
run COMMIT on it if the transaction is in fact an outermost transaction.
Then when the test tears down, the transaction is rolled back so that
any data changes throughout the test are reverted:

     from sqlalchemy.orm import sessionmaker
     from sqlalchemy import create_engine
     from unittest import TestCase

     # global application scope.  create Session class, engine
     Session = sessionmaker()

     engine = create_engine('postgresql://...')

     class SomeTest(TestCase):
         def setUp(self):
             # connect to the database
             self.connection = engine.connect()

             # begin a non-ORM transaction
             self.trans = self.connection.begin()

             # bind an individual Session to the connection
             self.session = Session(bind=self.connection)

             ###    optional     ###

             # if the database supports SAVEPOINT (SQLite needs special
             # config for this to work), starting a savepoint
             # will allow tests to also use rollback within tests

             self.nested = self.connection.begin_nested()

             @event.listens_for(self.session, "after_transaction_end")
             def end_savepoint(session, transaction):
                 if not self.nested.is_active:
                     self.nested = self.connection.begin_nested()

             ### ^^^ optional ^^^ ###

         def test_something(self):
             # use the session in tests.

             self.session.add(Foo())
             self.session.commit()

         def test_something_with_rollbacks(self):
             # if the SAVEPOINT steps are taken, then a test can also
             # use session.rollback() and continue working with the database

             self.session.add(Bar())
             self.session.flush()
             self.session.rollback()

             self.session.add(Foo())
             self.session.commit()

         def tearDown(self):
             self.session.close()

             # rollback - everything that happened with the
             # Session above (including calls to commit())
             # is rolled back.
             self.trans.rollback()

             # return connection to the Engine
             self.connection.close()

The above recipe is part of SQLAlchemy’s own CI to ensure that it
remains working as expected.

3.5.5 Additional Persistence Techniques
---------------------------------------

3.5.5.1 Embedding SQL Insert/Update Expressions into a Flush
............................................................

This feature allows the value of a database column to be set to a SQL
expression instead of a literal value.  It’s especially useful for
atomic updates, calling stored procedures, etc.  All you do is assign an
expression to an attribute:

     class SomeClass(Base):
         __tablename__ = "some_table"

         # ...

         value = Column(Integer)

     someobject = session.query(SomeClass).get(5)

     # set 'value' attribute to a SQL expression adding one
     someobject.value = SomeClass.value + 1

     # issues "UPDATE some_table SET value=value+1"
     session.commit()

This technique works both for INSERT and UPDATE statements.  After the
flush/commit operation, the ‘value’ attribute on ‘someobject’ above is
expired, so that when next accessed the newly generated value will be
loaded from the database.

The feature also has conditional support to work in conjunction with
primary key columns.  A database that supports RETURNING, e.g.
PostgreSQL, Oracle, or SQL Server, or as a special case when using
SQLite with the pysqlite driver and a single auto-increment column, a
SQL expression may be assigned to a primary key column as well.  This
allows both the SQL expression to be evaluated, as well as allows any
server side triggers that modify the primary key value on INSERT, to be
successfully retrieved by the ORM as part of the object’s primary key:

     class Foo(Base):
         __tablename__ = 'foo'
         pk = Column(Integer, primary_key=True)
         bar = Column(Integer)

     e = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
     Base.metadata.create_all(e)

     session = Session(e)

     foo = Foo(pk=sql.select(sql.func.coalesce(sql.func.max(Foo.pk) + 1, 1))
     session.add(foo)
     session.commit()

On PostgreSQL, the above Session will emit the following
INSERT:

     INSERT INTO foo (foopk, bar) VALUES
     ((SELECT coalesce(max(foo.foopk) + %(max_1)s, %(coalesce_2)s) AS coalesce_1
     FROM foo), %(bar)s) RETURNING foo.foopk

New in version 1.3: SQL expressions can now be passed to a primary key
column during an ORM flush; if the database supports RETURNING, or if
pysqlite is in use, the ORM will be able to retrieve the
server-generated value as the value of the primary key attribute.

3.5.5.2 Using SQL Expressions with Sessions
...........................................

SQL expressions and strings can be executed via the ‘Session’ within its
transactional context.  This is most easily accomplished using the
Session.execute() method, which returns a CursorResult
in the same manner as an Engine or Connection:

     Session = sessionmaker(bind=engine)
     session = Session()

     # execute a string statement
     result = session.execute("select * from table where id=:id", {'id':7})

     # execute a SQL expression construct
     result = session.execute(select(mytable).where(mytable.c.id==7))

The current Connection held by the ‘Session’ is accessible
using the Session.connection() method:

     connection = session.connection()

The examples above deal with a Session that’s bound to a
single Engine or Connection.  To execute
statements using a Session which is bound either to multiple
engines, or none at all (i.e.  relies upon bound metadata), both
Session.execute() and Session.connection() accept a
dictionary of bind arguments Session.execute.bind_arguments
which may include “mapper” which is passed a mapped class or
Mapper instance, which is used to locate the proper context for
the desired engine:

     Session = sessionmaker()
     session = Session()

     # need to specify mapper or class when executing
     result = session.execute(
         text("select * from table where id=:id"),
         {'id':7},
         bind_arguments={'mapper': MyMappedClass}
     )

     result = session.execute(
         select(mytable).where(mytable.c.id==7),
         bind_arguments={'mapper': MyMappedClass}
     )

     connection = session.connection(MyMappedClass)

Changed in version 1.4: the ‘mapper’ and ‘clause’ arguments to
Session.execute() are now passed as part of a dictionary sent as
the Session.execute.bind_arguments parameter.  The previous
arguments are still accepted however this usage is deprecated.

3.5.5.3 Forcing NULL on a column with a default
...............................................

The ORM considers any attribute that was never set on an object as a
“default” case; the attribute will be omitted from the INSERT statement:

     class MyObject(Base):
         __tablename__ = 'my_table'
         id = Column(Integer, primary_key=True)
         data = Column(String(50), nullable=True)

     obj = MyObject(id=1)
     session.add(obj)
     session.commit()  # INSERT with the 'data' column omitted; the database
                       # itself will persist this as the NULL value

Omitting a column from the INSERT means that the column will have the
NULL value set, `unless' the column has a default set up, in which case
the default value will be persisted.  This holds true both from a pure
SQL perspective with server-side defaults, as well as the behavior of
SQLAlchemy’s insert behavior with both client-side and server-side
defaults:

     class MyObject(Base):
         __tablename__ = 'my_table'
         id = Column(Integer, primary_key=True)
         data = Column(String(50), nullable=True, server_default="default")

     obj = MyObject(id=1)
     session.add(obj)
     session.commit()  # INSERT with the 'data' column omitted; the database
                       # itself will persist this as the value 'default'

However, in the ORM, even if one assigns the Python value ‘None’
explicitly to the object, this is treated the `same' as though the value
were never assigned:

     class MyObject(Base):
         __tablename__ = 'my_table'
         id = Column(Integer, primary_key=True)
         data = Column(String(50), nullable=True, server_default="default")

     obj = MyObject(id=1, data=None)
     session.add(obj)
     session.commit()  # INSERT with the 'data' column explicitly set to None;
                       # the ORM still omits it from the statement and the
                       # database will still persist this as the value 'default'

The above operation will persist into the ‘data’ column the server
default value of ‘"default"’ and not SQL NULL, even though ‘None’ was
passed; this is a long-standing behavior of the ORM that many
applications hold as an assumption.

So what if we want to actually put NULL into this column, even though
the column has a default value?  There are two approaches.  One is that
on a per-instance level, we assign the attribute using the null.
SQL construct:

     from sqlalchemy import null

     obj = MyObject(id=1, data=null())
     session.add(obj)
     session.commit()  # INSERT with the 'data' column explicitly set as null();
                       # the ORM uses this directly, bypassing all client-
                       # and server-side defaults, and the database will
                       # persist this as the NULL value

The null. SQL construct always translates into the SQL NULL
value being directly present in the target INSERT statement.

If we’d like to be able to use the Python value ‘None’ and have this
also be persisted as NULL despite the presence of column defaults, we
can configure this for the ORM using a Core-level modifier
TypeEngine.evaluates_none(), which indicates a type where the ORM
should treat the value ‘None’ the same as any other value and pass it
through, rather than omitting it as a “missing” value:

     class MyObject(Base):
         __tablename__ = 'my_table'
         id = Column(Integer, primary_key=True)
         data = Column(
           String(50).evaluates_none(),  # indicate that None should always be passed
           nullable=True, server_default="default")

     obj = MyObject(id=1, data=None)
     session.add(obj)
     session.commit()  # INSERT with the 'data' column explicitly set to None;
                       # the ORM uses this directly, bypassing all client-
                       # and server-side defaults, and the database will
                       # persist this as the NULL value

Evaluating None
...............

The TypeEngine.evaluates_none() modifier is primarily
intended to signal a type where the Python value “None” is significant,
the primary example being a JSON type which may want to persist the JSON
‘null’ value rather than SQL NULL. We are slightly repurposing it here
in order to signal to the ORM that we’d like ‘None’ to be passed into
the type whenever present, even though no special type-level behaviors
are assigned to it.

New in version 1.1: added the TypeEngine.evaluates_none()
method in order to indicate that a “None” value should be treated as
significant.

3.5.5.4 Fetching Server-Generated Defaults
..........................................

As introduced in the sections Server-invoked DDL-Explicit Default Expressions
and Marking Implicitly Generated Values, timestamps, and Triggered Columns,
the Core supports the notion of
database columns for which the database itself generates a value upon
INSERT and in less common cases upon UPDATE statements.  The ORM
features support for such columns regarding being able to fetch these
newly generated values upon flush.  This behavior is required in the
case of primary key columns that are generated by the server, since the
ORM has to know the primary key of an object once it is persisted.

In the vast majority of cases, primary key columns that have their value
generated automatically by the database are simple integer columns,
which are implemented by the database as either a so-called
“autoincrement” column, or from a sequence associated with the column.
Every database dialect within SQLAlchemy Core supports a method of
retrieving these primary key values which is often native to the Python
DBAPI, and in general this process is automatic, with the exception of a
database like Oracle that requires us to specify a Sequence
explicitly.  There is more documentation regarding this at
Column.autoincrement.

For server-generating columns that are not primary key columns or that
are not simple autoincrementing integer columns, the ORM requires that
these columns are marked with an appropriate ‘server_default’ directive
that allows the ORM to retrieve this value.  Not all methods are
supported on all backends, however, so care must be taken to use the
appropriate method.  The two questions to be answered are, 1.  is this
column part of the primary key or not, and 2.  does the database support
RETURNING or an equivalent, such as “OUTPUT inserted”; these are SQL
phrases which return a server-generated value at the same time as the
INSERT or UPDATE statement is invoked.  Databases that support RETURNING
or equivalent include PostgreSQL, Oracle, and SQL Server.  Databases
that do not include SQLite and MySQL.

3.5.5.5 Case 1: non primary key, RETURNING or equivalent is supported
.....................................................................

In this case, columns should be marked as FetchedValue or
with an explicit Column.server_default.  The
mapper.eager_defaults flag may be used to indicate that these
columns should be fetched immediately upon INSERT and sometimes UPDATE:

     class MyModel(Base):
         __tablename__ = 'my_table'

         id = Column(Integer, primary_key=True)
         timestamp = Column(DateTime(), server_default=func.now())

         # assume a database trigger populates a value into this column
         # during INSERT
         special_identifier = Column(String(50), server_default=FetchedValue())

         __mapper_args__ = {"eager_defaults": True}

Above, an INSERT statement that does not specify explicit values for
“timestamp” or “special_identifier” from the client side will include
the “timestamp” and “special_identifier” columns within the RETURNING
clause so they are available immediately.  On the PostgreSQL database,
an INSERT for the above table will look like:

     INSERT INTO my_table DEFAULT VALUES RETURNING my_table.id, my_table.timestamp, my_table.special_identifier

3.5.5.6 Case 2: non primary key, RETURNING or equivalent is not supported or not needed
.......................................................................................

This case is the same as case 1 above, except we don’t specify
mapper.eager_defaults:

     class MyModel(Base):
         __tablename__ = 'my_table'

         id = Column(Integer, primary_key=True)
         timestamp = Column(DateTime(), server_default=func.now())

         # assume a database trigger populates a value into this column
         # during INSERT
         special_identifier = Column(String(50), server_default=FetchedValue())

After a record with the above mapping is INSERTed, the “timestamp” and
“special_identifier” columns will remain empty, and will be fetched via
a second SELECT statement when they are first accessed after the flush,
e.g.  they are marked as “expired”.

If the mapper.eager_defaults is still used, and the backend
database does not support RETURNING or an equivalent, the ORM will emit
this SELECT statement immediately following the INSERT statement.  This
is often undesirable as it adds additional SELECT statements to the
flush process that may not be needed.  Using the above mapping with the
mapper.eager_defaults flag set to True against MySQL results
in SQL like this upon flush (minus the comment, which is for
clarification only):

     INSERT INTO my_table () VALUES ()

     -- when eager_defaults **is** used, but RETURNING is not supported
     SELECT my_table.timestamp AS my_table_timestamp, my_table.special_identifier AS my_table_special_identifier
     FROM my_table WHERE my_table.id = %s

3.5.5.7 Case 3: primary key, RETURNING or equivalent is supported
.................................................................

A primary key column with a server-generated value must be fetched
immediately upon INSERT; the ORM can only access rows for which it has a
primary key value, so if the primary key is generated by the server, the
ORM needs a way for the database to give us that new value immediately
upon INSERT.

As mentioned above, for integer “autoincrement” columns as well as
PostgreSQL SERIAL, these types are handled automatically by the Core;
databases include functions for fetching the “last inserted id” where
RETURNING is not supported, and where RETURNING is supported SQLAlchemy
will use that.

However, for non-integer values, as well as for integer values that must
be explicitly linked to a sequence or other triggered routine, the
server default generation must be marked in the table metadata.

For an explicit sequence as we use with Oracle, this just means we are
using the Sequence construct:

     class MyOracleModel(Base):
         __tablename__ = 'my_table'

         id = Column(Integer, Sequence("my_sequence"), primary_key=True)
         data = Column(String(50))

The INSERT for a model as above on Oracle looks like:

     INSERT INTO my_table (id, data) VALUES (my_sequence.nextval, :data) RETURNING my_table.id INTO :ret_0

Where above, SQLAlchemy renders ‘my_sequence.nextval’ for the primary
key column and also uses RETURNING to get the new value back
immediately.

For datatypes that generate values automatically, or columns that are
populated by a trigger, we use FetchedValue.  Below is a
model that uses a SQL Server TIMESTAMP column as the primary key, which
generates values automatically:

     class MyModel(Base):
         __tablename__ = 'my_table'

         timestamp = Column(TIMESTAMP(), server_default=FetchedValue(), primary_key=True)

An INSERT for the above table on SQL Server looks like:

     INSERT INTO my_table OUTPUT inserted.timestamp DEFAULT VALUES

3.5.5.8 Case 4: primary key, RETURNING or equivalent is not supported
.....................................................................

In this area we are generating rows for a database such as SQLite or
MySQL where some means of generating a default is occurring on the
server, but is outside of the database’s usual autoincrement routine.
In this case, we have to make sure SQLAlchemy can “pre-execute” the
default, which means it has to be an explicit SQL expression.

     Note: This section will illustrate multiple recipes involving
     datetime values for MySQL and SQLite, since the datetime datatypes
     on these two backends have additional idiosyncratic requirements
     that are useful to illustrate.  Keep in mind however that SQLite
     and MySQL require an explicit “pre-executed” default generator for
     `any' auto-generated datatype used as the primary key other than
     the usual single-column autoincrementing integer value.

3.5.5.9 MySQL with DateTime primary key
.......................................

Using the example of a DateTime column for MySQL, we add an
explicit pre-execute-supported default using the “NOW()” SQL function:

     class MyModel(Base):
         __tablename__ = 'my_table'

         timestamp = Column(DateTime(), default=func.now(), primary_key=True)

Where above, we select the “NOW()” function to deliver a datetime value
to the column.  The SQL generated by the above is:

     SELECT now() AS anon_1
     INSERT INTO my_table (timestamp) VALUES (%s)
     ('2018-08-09 13:08:46',)

3.5.5.10 MySQL with TIMESTAMP primary key
.........................................

When using the TIMESTAMP datatype with MySQL, MySQL
ordinarily associates a server-side default with this datatype
automatically.  However when we use one as a primary key, the Core
cannot retrieve the newly generated value unless we execute the function
ourselves.  As TIMESTAMP on MySQL actually stores a binary
value, we need to add an additional “CAST” to our usage of “NOW()” so
that we retrieve a binary value that can be persisted into the column:

     from sqlalchemy import cast, Binary

     class MyModel(Base):
         __tablename__ = 'my_table'

         timestamp = Column(
             TIMESTAMP(),
             default=cast(func.now(), Binary),
             primary_key=True)

Above, in addition to selecting the “NOW()” function, we additionally
make use of the ‘Binary’ datatype in conjunction with cast()
so that the returned value is binary.  SQL rendered from the above
within an INSERT looks like:

     SELECT CAST(now() AS BINARY) AS anon_1
     INSERT INTO my_table (timestamp) VALUES (%s)
     (b'2018-08-09 13:08:46',)

3.5.5.11 SQLite with DateTime primary key
.........................................

For SQLite, new timestamps can be generated using the SQL function
‘datetime('now', 'localtime')’ (or specify ‘'utc'’ for UTC), however
making things more complicated is that this returns a string value,
which is then incompatible with SQLAlchemy’s DateTime
datatype (even though the datatype converts the information back into a
string for the SQLite backend, it must be passed through as a Python
datetime).  We therefore must also specify that we’d like to coerce the
return value to DateTime when it is returned from the
function, which we achieve by passing this as the ‘type_’ parameter:

     class MyModel(Base):
         __tablename__ = 'my_table'

         timestamp = Column(
             DateTime,
             default=func.datetime('now', 'localtime', type_=DateTime),
             primary_key=True)

The above mapping upon INSERT will look like:

     SELECT datetime(?, ?) AS datetime_1
     ('now', 'localtime')
     INSERT INTO my_table (timestamp) VALUES (?)
     ('2018-10-02 13:37:33.000000',)

See also
........

See Column INSERT/UPDATE Defaults.

3.5.5.12 Partitioning Strategies (e.g. multiple database backends per Session)
..............................................................................

3.5.5.13 Simple Vertical Partitioning
.....................................

Vertical partitioning places different classes, class hierarchies, or
mapped tables, across multiple databases, by configuring the
Session with the Session.binds argument.  This argument
receives a dictionary that contains any combination of ORM-mapped
classes, arbitrary classes within a mapped hierarchy (such as
declarative base classes or mixins), see Table objects, and
Mapper objects as keys, which then refer typically to
Engine or less typically Connection objects as
targets.  The dictionary is consulted whenever the Session
needs to emit SQL on behalf of a particular kind of mapped class in
order to locate the appropriate source of database connectivity:

     engine1 = create_engine('postgresql://db1')
     engine2 = create_engine('postgresql://db2')

     Session = sessionmaker()

     # bind User operations to engine 1, Account operations to engine 2
     Session.configure(binds={User:engine1, Account:engine2})

     session = Session()

Above, SQL operations against either class will make usage of the
Engine linked to that class.  The functionality is comprehensive
across both read and write operations; a Query that is
against entities mapped to ‘engine1’ (determined by looking at the first
entity in the list of items requested) will make use of ‘engine1’ to run
the query.  A flush operation will make use of `both' engines on a
per-class basis as it flushes objects of type ‘User’ and ‘Account’.

In the more common case, there are typically base or mixin classes that
can be used to distinguish between operations that are destined for
different database connections.  The Session.binds argument
can accommodate any arbitrary Python class as a key, which will be used
if it is found to be in the ‘__mro__’ (Python method resolution order)
for a particular mapped class.  Supposing two declarative bases are
representing two different database connections:

     BaseA = declarative_base()

     BaseB = declarative_base()

     class User(BaseA):
         # ...

     class Address(BaseA):
         # ...

     class GameInfo(BaseB):
         # ...

     class GameStats(BaseB):
         # ...

     Session = sessionmaker()

     # all User/Address operations will be on engine 1, all
     # Game operations will be on engine 2
     Session.configure(binds={BaseA:engine1, BaseB:engine2})

Above, classes which descend from ‘BaseA’ and ‘BaseB’ will have their
SQL operations routed to one of two engines based on which superclass
they descend from, if any.  In the case of a class that descends from
more than one “bound” superclass, the superclass that is highest in the
target class’ hierarchy will be chosen to represent which engine should
be used.

See also
........

See Session.binds.

3.5.5.14 Coordination of Transactions for a multiple-engine Session
...................................................................

One caveat to using multiple bound engines is in the case where a commit
operation may fail on one backend after the commit has succeeded on
another.  This is an inconsistency problem that in relational databases
is solved using a “two phase transaction”, which adds an additional
“prepare” step to the commit sequence that allows for multiple databases
to agree to commit before actually completing the transaction.

Due to limited support within DBAPIs, SQLAlchemy has limited support for
two- phase transactions across backends.  Most typically, it is known to
work well with the PostgreSQL backend and to a lesser extent with the
MySQL backend.  However, the Session is fully capable of
taking advantage of the two phase transaction feature when the backend
supports it, by setting the Session.use_twophase flag within
sessionmaker or Session.  See Enabling Two-Phase Commit
for an example.

3.5.5.15 Custom Vertical Partitioning
.....................................

More comprehensive rule-based class-level partitioning can be built by
overriding the Session.get_bind() method.  Below we
illustrate a custom Session which delivers the following
rules:

  1. Flush operations, as well as bulk “update” and “delete” operations,
     are delivered to the engine named ‘leader’.

  2. Operations on objects that subclass ‘MyOtherClass’ all occur on the
     ‘other’ engine.

  3. Read operations for all other classes occur on a random choice of
     the ‘follower1’ or ‘follower2’ database.

     engines = {
         'leader':create_engine("sqlite:///leader.db"),
         'other':create_engine("sqlite:///other.db"),
         'follower1':create_engine("sqlite:///follower1.db"),
         'follower2':create_engine("sqlite:///follower2.db"),
     }

     from sqlalchemy.sql import Update, Delete
     from sqlalchemy.orm import Session, sessionmaker
     import random

     class RoutingSession(Session):
         def get_bind(self, mapper=None, clause=None):
             if mapper and issubclass(mapper.class_, MyOtherClass):
                 return engines['other']
             elif self._flushing or isinstance(clause, (Update, Delete)):
                 return engines['leader']
             else:
                 return engines[
                     random.choice(['follower1','follower2'])
                 ]

The above Session class is plugged in using the ‘class_’
argument to sessionmaker:

     Session = sessionmaker(class_=RoutingSession)

This approach can be combined with multiple MetaData objects,
using an approach such as that of using the declarative ‘__abstract__’
keyword, described at __abstract__.

See also
........

Django-style Database Routers in SQLAlchemy(1) - blog post on a more
comprehensive example of Session.get_bind().

   ---------- Footnotes ----------

   (1)
http://techspot.zzzeek.org/2012/01/11/django-style-database-routers-in-sqlalchemy/

3.5.5.16 Horizontal Partitioning
................................

Horizontal partitioning partitions the rows of a single table (or a set
of tables) across multiple databases.  The SQLAlchemy Session
contains support for this concept, however to use it fully requires that
Session and Query subclasses are used.  A basic
version of these subclasses are available in the Horizontal Sharding.
ORM extension.  An example of use is at: Horizontal Sharding.

3.5.5.17 Bulk Operations
........................

     deepalchemy: Bulk operations are essentially lower-functionality
     versions of the Unit of Work’s facilities for emitting INSERT and
     UPDATE statements on primary key targeted rows.  These routines
     were added to suit some cases where many rows being inserted or
     updated could be run into the database without as much of the usual
     unit of work overhead, in that most unit of work features are
     `disabled'.

     There is `usually no need to use these routines, and they are not
     easy to use as there are many missing behaviors that are usually
     expected when using ORM objects'; for efficient bulk inserts, it’s
     better to use the Core Insert construct directly.
     Please read all caveats at ORM Compatibility / Caveats.

     Note: Bulk INSERT and UPDATE should not be confused with the more
     common feature known as UPDATE and DELETE with arbitrary WHERE clause.
     This feature allows a single UPDATE or DELETE
     statement with arbitrary WHERE criteria to be emitted.

New in version 1.0.0.

Bulk INSERT/per-row UPDATE operations on the Session include
Session.bulk_save_objects(),
Session.bulk_insert_mappings(), and
Session.bulk_update_mappings().  The purpose of these methods is to
directly expose internal elements of the unit of work system, such that
facilities for emitting INSERT and UPDATE statements given dictionaries
or object states can be utilized alone, bypassing the normal unit of
work mechanics of state, relationship and attribute management.  The
advantages to this approach is strictly one of reduced Python overhead:

   * The flush() process, including the survey of all objects, their
     state, their cascade status, the status of all objects associated
     with them via relationship(), and the topological sort of
     all operations to be performed is completely bypassed.  This
     reduces a great amount of Python overhead.

   * The objects as given have no defined relationship to the target
     Session, even when the operation is complete, meaning
     there’s no overhead in attaching them or managing their state in
     terms of the identity map or session.

   * The Session.bulk_insert_mappings() and
     Session.bulk_update_mappings() methods accept lists of plain
     Python dictionaries, not objects; this further reduces a large
     amount of overhead associated with instantiating mapped objects and
     assigning state to them, which normally is also subject to
     expensive tracking of history on a per-attribute basis.

   * The set of objects passed to all bulk methods are processed in the
     order they are received.  In the case of
     Session.bulk_save_objects(), when objects of different types
     are passed, the INSERT and UPDATE statements are necessarily broken
     up into per-type groups.  In order to reduce the number of batch
     INSERT or UPDATE statements passed to the DBAPI, ensure that the
     incoming list of objects are grouped by type.

   * The process of fetching primary keys after an INSERT also is
     disabled by default.  When performed correctly, INSERT statements
     can now more readily be batched by the unit of work process into
     ‘executemany()’ blocks, which perform vastly better than individual
     statement invocations.

   * UPDATE statements can similarly be tailored such that all
     attributes are subject to the SET clause unconditionally, again
     making it much more likely that ‘executemany()’ blocks can be used.

The performance behavior of the bulk routines should be studied using
the Performance example suite.  This is a series of example
scripts which illustrate Python call-counts across a variety of
scenarios, including bulk insert and update scenarios.

See also
........

See Performance. - includes detailed examples of bulk operations
contrasted against traditional Core and ORM methods, including
performance metrics.

3.5.5.18 Usage
..............

The methods each work in the context of the Session object’s
transaction, like any other:

     s = Session()
     objects = [
         User(name="u1"),
         User(name="u2"),
         User(name="u3")
     ]
     s.bulk_save_objects(objects)

For Session.bulk_insert_mappings(), and
Session.bulk_update_mappings(), dictionaries are passed:

     s.bulk_insert_mappings(User,
       [dict(name="u1"), dict(name="u2"), dict(name="u3")]
     )

See also
........

See Session.bulk_save_objects().

See Session.bulk_insert_mappings().

See Session.bulk_update_mappings().

3.5.5.19 Comparison to Core Insert / Update Constructs
......................................................

The bulk methods offer performance that under particular circumstances
can be close to that of using the core Insert and
Update constructs in an “executemany” context (for a description of
“executemany”, see Executing Multiple Statements in the Core
tutorial).  In order to achieve this, the
Session.bulk_insert_mappings.return_defaults flag should be
disabled so that rows can be batched together.  The example suite in
Performance should be carefully studied in order to gain
familiarity with how fast bulk performance can be achieved.

3.5.5.20 ORM Compatibility / Caveats
....................................

     Warning: Be sure to familiarize with these limitations before using
     the bulk routines.

The bulk insert / update methods lose a significant amount of
functionality versus traditional ORM use.  The following is a listing of
features that are `not available' when using these methods:

   * persistence along relationship() linkages

   * sorting of rows within order of dependency; rows are inserted or
     updated directly in the order in which they are passed to the
     methods

   * Session-management on the given objects, including attachment to
     the session, identity map management.

   * Functionality related to primary key mutation, ON UPDATE cascade -
     `mutation of primary key columns will not work' - as the original
     PK value of each row is not available, so the WHERE criteria cannot
     be generated.

   * SQL expression inserts / updates (e.g.  see Embedding SQL Insert/Update Expressions into a Flush)
     - having to evaluate
     these would prevent INSERT and UPDATE statements from being batched
     together in a straightforward way for a single executemany() call
     as they alter the SQL compilation of the statement itself.

   * ORM events such as MapperEvents.before_insert(), etc.
     The bulk session methods have no event support.

Features that `are available' include:

   * INSERTs and UPDATEs of mapped objects

   * Version identifier support

   * Multi-table mappings, such as joined-inheritance - however, an
     object to be inserted across multiple tables either needs to have
     primary key identifiers fully populated ahead of time, else the
     Session.bulk_save_objects.return_defaults flag must be
     used, which will greatly reduce the performance benefits

3.5.6 Contextual/Thread-local Sessions
--------------------------------------

Recall from the section When do I construct a Session, when do I commit it, and when do I close it?,
the concept of “session scopes”
was introduced, with an emphasis on web applications and the practice of
linking the scope of a Session with that of a web request.
Most modern web frameworks include integration tools so that the scope
of the Session can be managed automatically, and these tools
should be used as they are available.

SQLAlchemy includes its own helper object, which helps with the
establishment of user-defined Session scopes.  It is also
used by third-party integration systems to help construct their
integration schemes.

The object is the scoped_session object, and it represents a
`registry' of Session objects.  If you’re not familiar with
the registry pattern, a good introduction can be found in Patterns of
Enterprise Architecture(1).

     Note: The scoped_session object is a very popular and
     useful object used by many SQLAlchemy applications.  However, it is
     important to note that it presents `only one approach' to the issue
     of Session management.  If you’re new to SQLAlchemy, and
     especially if the term “thread-local variable” seems strange to
     you, we recommend that if possible you familiarize first with an
     off-the-shelf integration system such as Flask-SQLAlchemy(2) or
     zope.sqlalchemy(3).

A scoped_session is constructed by calling it, passing it a
`factory' which can create new Session objects.  A factory is
just something that produces a new object when called, and in the case
of Session, the most common factory is the sessionmaker,
introduced earlier in this section.  Below we illustrate this
usage:

     >>> from sqlalchemy.orm import scoped_session
     >>> from sqlalchemy.orm import sessionmaker

     >>> session_factory = sessionmaker(bind=some_engine)
     >>> Session = scoped_session(session_factory)

The scoped_session object we’ve created will now call upon
the sessionmaker when we “call” the registry:

     >>> some_session = Session()

Above, ‘some_session’ is an instance of Session, which we can
now use to talk to the database.  This same Session is also
present within the scoped_session registry we’ve created.
If we call upon the registry a second time, we get back the `same'
Session:

     >>> some_other_session = Session()
     >>> some_session is some_other_session
     True

This pattern allows disparate sections of the application to call upon a
global scoped_session, so that all those areas may share the
same session without the need to pass it explicitly.  The Session
we’ve established in our registry will remain, until we explicitly
tell our registry to dispose of it, by calling
scoped_session.remove():

     >>> Session.remove()

The scoped_session.remove() method first calls
Session.close() on the current Session, which has the
effect of releasing any connection/transactional resources owned by the
Session first, then discarding the Session itself.
“Releasing” here means that connections are returned to their connection
pool and any transactional state is rolled back, ultimately using the
‘rollback()’ method of the underlying DBAPI connection.

At this point, the scoped_session object is “empty”, and
will create a `new' Session when called again.  As
illustrated below, this is not the same Session we had
before:

     >>> new_session = Session()
     >>> new_session is some_session
     False

The above series of steps illustrates the idea of the “registry” pattern
in a nutshell.  With that basic idea in hand, we can discuss some of the
details of how this pattern proceeds.

   ---------- Footnotes ----------

   (1) http://martinfowler.com/eaaCatalog/registry.html

   (2) http://packages.python.org/Flask-SQLAlchemy/

   (3) http://pypi.python.org/pypi/zope.sqlalchemy

3.5.6.1 Implicit Method Access
..............................

The job of the scoped_session is simple; hold onto a
Session for all who ask for it.  As a means of producing more
transparent access to this Session, the scoped_session
also includes `proxy behavior', meaning that the registry itself
can be treated just like a Session directly; when methods are
called on this object, they are `proxied' to the underlying
Session being maintained by the registry:

     Session = scoped_session(some_factory)

     # equivalent to:
     #
     # session = Session()
     # print(session.query(MyClass).all())
     #
     print(Session.query(MyClass).all())

The above code accomplishes the same task as that of acquiring the
current Session by calling upon the registry, then using that
Session.

3.5.6.2 Thread-Local Scope
..........................

Users who are familiar with multithreaded programming will note that
representing anything as a global variable is usually a bad idea, as it
implies that the global object will be accessed by many threads
concurrently.  The Session object is entirely designed to be
used in a `non-concurrent' fashion, which in terms of multithreading
means “only in one thread at a time”.  So our above example of
scoped_session usage, where the same Session object is
maintained across multiple calls, suggests that some process needs to be
in place such that multiple calls across many threads don’t actually get
a handle to the same session.  We call this notion `thread local
storage', which means, a special object is used that will maintain a
distinct object per each application thread.  Python provides this via
the threading.local()(1) construct.  The scoped_session
object by default uses this object as storage, so that a single
Session is maintained for all who call upon the
scoped_session registry, but only within the scope of a single
thread.  Callers who call upon the registry in a different thread get a
Session instance that is local to that other thread.

Using this technique, the scoped_session provides a quick
and relatively simple (if one is familiar with thread-local storage) way
of providing a single, global object in an application that is safe to
be called upon from multiple threads.

The scoped_session.remove() method, as always, removes the
current Session associated with the thread, if any.  However,
one advantage of the ‘threading.local()’ object is that if the
application thread itself ends, the “storage” for that thread is also
garbage collected.  So it is in fact “safe” to use thread local scope
with an application that spawns and tears down threads, without the need
to call scoped_session.remove().  However, the scope of
transactions themselves, i.e.  ending them via Session.commit()
or Session.rollback(), will usually still be something
that must be explicitly arranged for at the appropriate time, unless the
application actually ties the lifespan of a thread to the lifespan of a
transaction.

   ---------- Footnotes ----------

   (1) http://docs.python.org/library/threading.html#threading.local

3.5.6.3 Using Thread-Local Scope with Web Applications
......................................................

As discussed in the section When do I construct a Session, when do I commit it, and when do I close it?,
a web application is
architected around the concept of a `web request', and integrating such
an application with the Session usually implies that the
Session will be associated with that request.  As it turns
out, most Python web frameworks, with notable exceptions such as the
asynchronous frameworks Twisted and Tornado, use threads in a simple
way, such that a particular web request is received, processed, and
completed within the scope of a single `worker thread'.  When the
request ends, the worker thread is released to a pool of workers where
it is available to handle another request.

This simple correspondence of web request and thread means that to
associate a Session with a thread implies it is also
associated with the web request running within that thread, and vice
versa, provided that the Session is created only after the
web request begins and torn down just before the web request ends.  So
it is a common practice to use scoped_session as a quick way
to integrate the Session with a web application.  The
sequence diagram below illustrates this flow:

     Web Server          Web Framework        SQLAlchemy ORM Code
     --------------      --------------       ------------------------------
     startup        ->   Web framework        # Session registry is established
                         initializes          Session = scoped_session(sessionmaker())

     incoming
     web request    ->   web request     ->   # The registry is *optionally*
                         starts               # called upon explicitly to create
                                              # a Session local to the thread and/or request
                                              Session()

                                              # the Session registry can otherwise
                                              # be used at any time, creating the
                                              # request-local Session() if not present,
                                              # or returning the existing one
                                              Session.query(MyClass) # ...

                                              Session.add(some_object) # ...

                                              # if data was modified, commit the
                                              # transaction
                                              Session.commit()

                         web request ends  -> # the registry is instructed to
                                              # remove the Session
                                              Session.remove()

                         sends output      <-
     outgoing web    <-
     response

Using the above flow, the process of integrating the Session
with the web application has exactly two requirements:

  1. Create a single scoped_session registry when the web
     application first starts, ensuring that this object is accessible
     by the rest of the application.

  2. Ensure that scoped_session.remove() is called when the
     web request ends, usually by integrating with the web framework’s
     event system to establish an “on request end” event.

As noted earlier, the above pattern is `just one potential way' to
integrate a Session with a web framework, one which in
particular makes the significant assumption that the `web framework
associates web requests with application threads'.  It is however
`strongly recommended that the integration tools provided with the web
framework itself be used, if available', instead of
scoped_session.

In particular, while using a thread local can be convenient, it is
preferable that the Session be associated `directly with the
request', rather than with the current thread.  The next section on
custom scopes details a more advanced configuration which can combine
the usage of scoped_session with direct request based scope,
or any kind of scope.

3.5.6.4 Using Custom Created Scopes
...................................

The scoped_session object’s default behavior of “thread
local” scope is only one of many options on how to “scope” a
Session.  A custom scope can be defined based on any existing system
of getting at “the current thing we are working with”.

Suppose a web framework defines a library function
‘get_current_request()’.  An application built using this framework can
call this function at any time, and the result will be some kind of
‘Request’ object that represents the current request being processed.
If the ‘Request’ object is hashable, then this function can be easily
integrated with scoped_session to associate the
Session with the request.  Below we illustrate this in conjunction
with a hypothetical event marker provided by the web framework
‘on_request_end’, which allows code to be invoked whenever a request
ends:

     from my_web_framework import get_current_request, on_request_end
     from sqlalchemy.orm import scoped_session, sessionmaker

     Session = scoped_session(sessionmaker(bind=some_engine), scopefunc=get_current_request)

     @on_request_end
     def remove_session(req):
         Session.remove()

Above, we instantiate scoped_session in the usual way,
except that we pass our request-returning function as the “scopefunc”.
This instructs scoped_session to use this function to
generate a dictionary key whenever the registry is called upon to return
the current Session.  In this case it is particularly
important that we ensure a reliable “remove” system is implemented, as
this dictionary is not otherwise self-managed.

3.5.6.5 Contextual Session API
..............................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See scoped_session.Provides scoped management of Session objects.

See ScopedRegistry.A Registry that can store one or multiple instances of a single class on the basis of a
               “scope” function.

See ThreadLocalRegistry.A ScopedRegistry that uses a ‘threading.local()’ variable for storage.

 -- Class: sqlalchemy.orm.scoping.scoped_session (session_factory,
          scopefunc=None)

     Provides scoped management of Session objects.

     See Contextual/Thread-local Sessions for a tutorial.

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               __call__ (**kw)

          Return the current Session, creating it using the
          scoped_session.session_factory if not present.

          Parameters: ‘**kw’ – Keyword arguments will be passed to the
          scoped_session.session_factory callable, if an
          existing Session is not present.  If the
          Session is present and keyword arguments have been
          passed, see InvalidRequestError is raised.

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               __init__ (session_factory, scopefunc=None)

          Construct a new scoped_session.

          Parameters:

             * ‘session_factory’ – a factory to create new
               Session instances.  This is usually, but not
               necessarily, an instance of sessionmaker.

             * ‘scopefunc’ – optional function which defines the current
               scope.  If not passed, the scoped_session
               object assumes “thread-local” scope, and will use a
               Python ‘threading.local()’ in order to maintain the
               current Session.  If passed, the function
               should return a hashable token; this token will be used
               as the key in a dictionary in order to store and retrieve
               the current Session.

      -- Method: sqlalchemy.orm.scoping.scoped_session..add
               (instance, _warn=True)

          Place an object in the ‘Session’.

          Proxied for the Session class on behalf of the
          scoped_session class.

          Its state will be persisted to the database on the next flush
          operation.

          Repeated calls to ‘add()’ will be ignored.  The opposite of
          ‘add()’ is ‘expunge()’.

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               add_all (instances)

          Add the given collection of instances to this ‘Session’.

          Proxied for the Session class on behalf of the
          scoped_session class.

      -- Method: sqlalchemy.orm.scoping.scoped_session..begin
               (subtransactions=False, nested=False, _subtrans=False)

          Begin a transaction, or nested transaction, on this
          Session.

          Proxied for the Session class on behalf of the
          scoped_session class.

          When used to begin the outermost transaction, an error is
          raised if this Session is already inside of a
          transaction.

          Parameters:

             * ‘nested’ – if True, begins a SAVEPOINT transaction and is
               equivalent to calling Session.begin_nested().
               For documentation on SAVEPOINT transactions, please see
               Using SAVEPOINT.

             * ‘subtransactions’ – if True, indicates that this
               Session.begin() can create a “subtransaction”.

               Deprecated since version 1.4: The
               Session.begin.subtransactions flag is deprecated
               and will be removed in SQLAlchemy version 2.0.  See the
               documentation at Migrating from the “subtransaction” pattern
               for background on a
               compatible alternative pattern.

          Returns: the SessionTransaction object.  Note that
          SessionTransaction acts as a Python context
          manager, allowing Session.begin() to be used in a
          “with” block.  See Explicit Begin for an example.

          See also
          ........

          See Managing Transactions.

          See Session.begin_nested().

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               begin_nested ()

          Begin a “nested” transaction on this Session, e.g.  SAVEPOINT.

          Proxied for the Session class on behalf of the
          scoped_session class.

          The target database(s) and associated drivers must support SQL
          SAVEPOINT for this method to function correctly.

          For documentation on SAVEPOINT transactions, please see
          Using SAVEPOINT.

          Returns: the SessionTransaction object.  Note that
          SessionTransaction acts as a context manager,
          allowing Session.begin_nested() to be used in a
          “with” block.  See Using SAVEPOINT for a usage
          example.

          See also
          ........

          See Using SAVEPOINT.

          See Serializable isolation / Savepoints / Transactional DDL.
          - special workarounds required with the SQLite driver in
          order for SAVEPOINT to work correctly.

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               bulk_insert_mappings (mapper, mappings,
               return_defaults=False, render_nulls=False)

          Perform a bulk insert of the given list of mapping
          dictionaries.

          Proxied for the Session class on behalf of the
          scoped_session class.

          The bulk insert feature allows plain Python dictionaries to be
          used as the source of simple INSERT operations which can be
          more easily grouped together into higher performing
          “executemany” operations.  Using dictionaries, there is no
          “history” or session state management features in use,
          reducing latency when inserting large numbers of simple rows.

          The values within the dictionaries as given are typically
          passed without modification into Core
          sqlalchemy.sql.expression.Insert() constructs, after
          organizing the values within them across the tables to which
          the given mapper is mapped.

          New in version 1.0.0.

               Warning: The bulk insert feature allows for a
               lower-latency INSERT of rows at the expense of most other
               unit-of-work features.  Features such as object
               management, relationship handling, and SQL clause support
               are `silently omitted' in favor of raw INSERT of records.

               `Please read the list of caveats at' ORM Compatibility / Caveats.
               `before using this method,
               and fully test and confirm the functionality of all code
               developed using these systems.'

          Parameters:

             * ‘mapper’ – a mapped class, or the actual Mapper
               object, representing the single kind of object
               represented within the mapping list.

             * ‘mappings’ – a sequence of dictionaries, each one
               containing the state of the mapped row to be inserted, in
               terms of the attribute names on the mapped class.  If the
               mapping refers to multiple tables, such as a
               joined-inheritance mapping, each dictionary must contain
               all keys to be populated into all tables.

             * ‘return_defaults’ – when True, rows that are missing
               values which generate defaults, namely integer primary
               key defaults and sequences, will be inserted `one at a
               time', so that the primary key value is available.  In
               particular this will allow joined-inheritance and other
               multi-table mappings to insert correctly without the need
               to provide primary key values ahead of time; however,
               see Session.bulk_insert_mappings.return_defaults.
               `greatly reduces the performance gains' of the method
               overall.  If the rows to be inserted only refer to a
               single table, then there is no reason this flag should be
               set as the returned default information is not used.

             * ‘render_nulls’ – When True, a value of ‘None’ will result
               in a NULL value being included in the INSERT statement,
               rather than the column being omitted from the INSERT.
               This allows all the rows being INSERTed to have the
               identical set of columns which allows the full set of
               rows to be batched to the DBAPI. Normally, each
               column-set that contains a different combination of NULL
               values than the previous row must omit a different series
               of columns from the rendered INSERT statement, which
               means it must be emitted as a separate statement.  By
               passing this flag, the full set of rows are guaranteed to
               be batchable into one batch; the cost however is that
               server-side defaults which are invoked by an omitted
               column will be skipped, so care must be taken to ensure
               that these are not necessary.

                    Warning: When this flag is set, `server side default
                    SQL values will not be invoked' for those columns
                    that are inserted as NULL; the NULL value will be
                    sent explicitly.  Care must be taken to ensure that
                    no server-side default functions need to be invoked
                    for the operation as a whole.

               New in version 1.1.

          See also
          ........

          See Bulk Operations.

          See Session.bulk_save_objects().

          See Session.bulk_update_mappings().

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               bulk_save_objects (objects, return_defaults=False,
               update_changed_only=True, preserve_order=True)

          Perform a bulk save of the given list of objects.

          Proxied for the Session class on behalf of the
          scoped_session class.

          The bulk save feature allows mapped objects to be used as the
          source of simple INSERT and UPDATE operations which can be
          more easily grouped together into higher performing
          “executemany” operations; the extraction of data from the
          objects is also performed using a lower-latency process that
          ignores whether or not attributes have actually been modified
          in the case of UPDATEs, and also ignores SQL expressions.

          The objects as given are not added to the session and no
          additional state is established on them, unless the
          ‘return_defaults’ flag is also set, in which case primary key
          attributes and server-side default values will be populated.

          New in version 1.0.0.

               Warning: The bulk save feature allows for a lower-latency
               INSERT/UPDATE of rows at the expense of most other
               unit-of-work features.  Features such as object
               management, relationship handling, and SQL clause support
               are `silently omitted' in favor of raw INSERT/UPDATES of
               records.

               `Please read the list of caveats at' ORM Compatibility / Caveats.
               `before using this method,
               and fully test and confirm the functionality of all code
               developed using these systems.'

          Parameters:

             * ‘objects’ – a sequence of mapped object instances.  The
               mapped objects are persisted as is, and are `not'
               associated with the Session afterwards.

               For each object, whether the object is sent as an INSERT
               or an UPDATE is dependent on the same rules used by the
               Session in traditional operation; if the
               object has the ‘InstanceState.key’ attribute set, then
               the object is assumed to be “detached” and will result in
               an UPDATE. Otherwise, an INSERT is used.

               In the case of an UPDATE, statements are grouped based on
               which attributes have changed, and are thus to be the
               subject of each SET clause.  If ‘update_changed_only’ is
               False, then all attributes present within each object are
               applied to the UPDATE statement, which may help in
               allowing the statements to be grouped together into a
               larger executemany(), and will also reduce the overhead
               of checking history on attributes.

             * ‘return_defaults’ – when True, rows that are missing
               values which generate defaults, namely integer primary
               key defaults and sequences, will be inserted `one at a
               time', so that the primary key value is available.  In
               particular this will allow joined-inheritance and other
               multi-table mappings to insert correctly without the need
               to provide primary key values ahead of time; however,
               see Session.bulk_save_objects.return_defaults.
               `greatly reduces the performance gains' of the method
               overall.

             * ‘update_changed_only’ – when True, UPDATE statements are
               rendered based on those attributes in each state that
               have logged changes.  When False, all attributes present
               are rendered into the SET clause with the exception of
               primary key attributes.

             * ‘preserve_order’ – when True, the order of inserts and
               updates matches exactly the order in which the objects
               are given.  When False, common types of objects are
               grouped into inserts and updates, to allow for more
               batching opportunities.

               New in version 1.3.

          See also
          ........

          See Bulk Operations.

          See Session.bulk_insert_mappings().

          See Session.bulk_update_mappings().

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               bulk_update_mappings (mapper, mappings)

          Perform a bulk update of the given list of mapping
          dictionaries.

          Proxied for the Session class on behalf of the
          scoped_session class.

          The bulk update feature allows plain Python dictionaries to be
          used as the source of simple UPDATE operations which can be
          more easily grouped together into higher performing
          “executemany” operations.  Using dictionaries, there is no
          “history” or session state management features in use,
          reducing latency when updating large numbers of simple rows.

          New in version 1.0.0.

               Warning: The bulk update feature allows for a
               lower-latency UPDATE of rows at the expense of most other
               unit-of-work features.  Features such as object
               management, relationship handling, and SQL clause support
               are `silently omitted' in favor of raw UPDATES of
               records.

               `Please read the list of caveats at' ORM Compatibility / Caveats.
               `before using this method,
               and fully test and confirm the functionality of all code
               developed using these systems.'

          Parameters:

             * ‘mapper’ – a mapped class, or the actual Mapper
               object, representing the single kind of object
               represented within the mapping list.

             * ‘mappings’ – a sequence of dictionaries, each one
               containing the state of the mapped row to be updated, in
               terms of the attribute names on the mapped class.  If the
               mapping refers to multiple tables, such as a
               joined-inheritance mapping, each dictionary may contain
               keys corresponding to all tables.  All those keys which
               are present and are not part of the primary key are
               applied to the SET clause of the UPDATE statement; the
               primary key values, which are required, are applied to
               the WHERE clause.

          See also
          ........

          See Bulk Operations.

          See Session.bulk_insert_mappings().

          See Session.bulk_save_objects().

      -- Method: sqlalchemy.orm.scoping.scoped_session..close
               ()

          Close this Session.

          Proxied for the Session class on behalf of the
          scoped_session class.

          This clears all items and ends any transaction in progress.

          If this Session was created with ‘autocommit=False’, a new
          transaction will be begun when the Session is next
          asked to procure a database connection.

          Changed in version 1.4: The Session.close() method
          does not immediately create a new SessionTransaction
          object; instead, the new SessionTransaction
          is created only if the Session is used again for a
          database operation.

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               classmethod close_all ()

          Close `all' sessions in memory.

          Proxied for the Session class on behalf of the
          scoped_session class.

          Deprecated since version 1.3: The Session.close_all()
          method is deprecated and will be removed in a future
          release.  Please refer to ‘close_all_sessions()’.

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               commit ()

          Flush pending changes and commit the current transaction.

          Proxied for the Session class on behalf of the
          scoped_session class.

          If no transaction is in progress, the method will first
          “autobegin” a new transaction and commit.

          If 1.x-style use is in effect and there are currently
          SAVEPOINTs in progress via Session.begin_nested(),
          the operation will release the current SAVEPOINT but not
          commit the outermost database transaction.

          If 2.0-style use is in effect via the Session.future
          flag, the outermost database transaction is committed
          unconditionally, automatically releasing any SAVEPOINTs in
          effect.

          When using legacy “autocommit” mode, this method is only valid
          to call if a transaction is actually in progress, else an
          error is raised.  Similarly, when using legacy
          “subtransactions”, the method will instead close out the
          current “subtransaction”, rather than the actual database
          transaction, if a transaction is in progress.

          See also
          ........

          See Committing.

          See Managing Transactions.

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               configure (**kwargs)

          reconfigure the sessionmaker used by this
          scoped_session.

          See sessionmaker.configure().

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               connection (bind_arguments=None,
               close_with_result=False, execution_options=None, **kw)

          Return a Connection object corresponding to this
          Session object’s transactional state.

          Proxied for the Session class on behalf of the
          scoped_session class.

          If this Session is configured with
          ‘autocommit=False’, either the Connection
          corresponding to the current transaction is returned, or if no
          transaction is in progress, a new one is begun and the
          Connection returned (note that no transactional state is
          established with the DBAPI until the first SQL statement is
          emitted).

          Alternatively, if this Session is configured with
          ‘autocommit=True’, an ad-hoc Connection is
          returned using Engine.connect() on the underlying
          Engine.

          Ambiguity in multi-bind or unbound Session objects
          can be resolved through any of the optional keyword arguments.
          This ultimately makes usage of the get_bind()
          method for resolution.

          Parameters:

             * ‘bind_arguments’ – dictionary of bind arguments.  May
               include “mapper”, “bind”, “clause”, other custom
               arguments that are passed to Session.get_bind().

             * ‘bind’ – deprecated; use bind_arguments

             * ‘mapper’ – deprecated; use bind_arguments

             * ‘clause’ – deprecated; use bind_arguments

             * ‘close_with_result’ – Passed to Engine.connect(),
               indicating the Connection should be
               considered “single use”, automatically closing when the
               first result set is closed.  This flag only has an effect
               if this Session is configured with
               ‘autocommit=True’ and does not already have a transaction
               in progress.

             * ‘execution_options’ – a dictionary of execution options
               that will be passed to
               Connection.execution_options(), `when the connection
               is first procured only'.  If the connection is already
               present within the Session, a warning is
               emitted and the arguments are ignored.

               See also
               ........

               See Setting Transaction Isolation Levels / DBAPI AUTOCOMMIT.

             * ‘**kw’ – deprecated; use bind_arguments

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               delete (instance)

          Mark an instance as deleted.

          Proxied for the Session class on behalf of the
          scoped_session class.

          The database delete operation occurs upon ‘flush()’.

      -- Attribute: sqlalchemy.orm.scoping.scoped_session..
               deleted

          The set of all instances marked as ‘deleted’ within this
          ‘Session’

          Proxied for the Session class on behalf of the
          scoped_session class.

      -- Attribute: sqlalchemy.orm.scoping.scoped_session..
               dirty

          The set of all persistent instances considered dirty.

          Proxied for the Session class on behalf of the
          scoped_session class.

          E.g.:

               some_mapped_object in session.dirty

          Instances are considered dirty when they were modified but not
          deleted.

          Note that this ‘dirty’ calculation is ‘optimistic’; most
          attribute-setting or collection modification operations will
          mark an instance as ‘dirty’ and place it in this set, even if
          there is no net change to the attribute’s value.  At flush
          time, the value of each attribute is compared to its
          previously saved value, and if there’s no net change, no SQL
          operation will occur (this is a more expensive operation so
          it’s only done at flush time).

          To check if an instance has actionable net changes to its
          attributes, use the Session.is_modified() method.

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               execute (statement, params=None,
               execution_options={}, bind_arguments=None,
               _parent_execute_state=None, _add_event=None, **kw)

          Execute a SQL expression construct.

          Proxied for the Session class on behalf of the
          scoped_session class.

          Returns a Result object representing results of the
          statement execution.

          E.g.:

               from sqlalchemy import select
               result = session.execute(
                   select(User).where(User.id == 5)
               )

          The API contract of Session.execute() is similar to
          that of Connection.execute(), the 2.0 style version
          of Connection.

          Changed in version 1.4: the Session.execute()
          method is now the primary point of ORM statement execution
          when using 2.0 style ORM usage.

          Parameters:

             * ‘statement’ – An executable statement (i.e.  an
               Executable expression such as select()).

             * ‘params’ – Optional dictionary, or list of dictionaries,
               containing bound parameter values.  If a single
               dictionary, single-row execution occurs; if a list of
               dictionaries, an “executemany” will be invoked.  The keys
               in each dictionary must correspond to parameter names
               present in the statement.

             * ‘execution_options’ – optional dictionary of execution
               options, which will be associated with the statement
               execution.  This dictionary can provide a subset of the
               options that are accepted by
               ‘Connection.execution_options()’, and may also provide
               additional options understood only in an ORM context.

             * ‘bind_arguments’ – dictionary of additional arguments to
               determine the bind.  May include “mapper”, “bind”, or
               other custom arguments.  Contents of this dictionary are
               passed to the Session.get_bind() method.

             * ‘mapper’ – deprecated; use the bind_arguments dictionary

             * ‘bind’ – deprecated; use the bind_arguments dictionary

             * ‘**kw’ – deprecated; use the bind_arguments dictionary

          Returns: a Result object.

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               expire (instance, attribute_names=None)

          Expire the attributes on an instance.

          Proxied for the Session class on behalf of the
          scoped_session class.

          Marks the attributes of an instance as out of date.  When an
          expired attribute is next accessed, a query will be issued to
          the Session object’s current transactional context
          in order to load all expired attributes for the given
          instance.  Note that a highly isolated transaction will return
          the same values as were previously read in that same
          transaction, regardless of changes in database state outside
          of that transaction.

          To expire all objects in the Session
          simultaneously, use ‘Session.expire_all()’.

          The Session object’s default behavior is to expire
          all state whenever the ‘Session.rollback()’ or
          ‘Session.commit()’ methods are called, so that new state can
          be loaded for the new transaction.  For this reason, calling
          ‘Session.expire()’ only makes sense for the specific case that
          a non-ORM SQL statement was emitted in the current
          transaction.

          Parameters:

             * ‘instance’ – The instance to be refreshed.

             * ‘attribute_names’ – optional list of string attribute
               names indicating a subset of attributes to be expired.

          See also
          ........

          See Refreshing / Expiring. - introductory material

          See Session.expire().

          See Session.refresh().

          See Query.populate_existing().

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               expire_all ()

          Expires all persistent instances within this Session.

          Proxied for the Session class on behalf of the
          scoped_session class.

          When any attributes on a persistent instance is next accessed,
          a query will be issued using the Session object’s
          current transactional context in order to load all expired
          attributes for the given instance.  Note that a highly
          isolated transaction will return the same values as were
          previously read in that same transaction, regardless of
          changes in database state outside of that transaction.

          To expire individual objects and individual attributes on
          those objects, use ‘Session.expire()’.

          The Session object’s default behavior is to expire
          all state whenever the ‘Session.rollback()’ or
          ‘Session.commit()’ methods are called, so that new state can
          be loaded for the new transaction.  For this reason, calling
          ‘Session.expire_all()’ should not be needed when autocommit is
          ‘False’, assuming the transaction is isolated.

          See also
          ........

          See Refreshing / Expiring. - introductory material

          See Session.expire().

          See Session.refresh().

          See Query.populate_existing().

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               expunge (instance)

          Remove the ‘instance’ from this ‘Session’.

          Proxied for the Session class on behalf of the
          scoped_session class.

          This will free all internal references to the instance.
          Cascading will be applied according to the `expunge' cascade
          rule.

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               expunge_all ()

          Remove all object instances from this ‘Session’.

          Proxied for the Session class on behalf of the
          scoped_session class.

          This is equivalent to calling ‘expunge(obj)’ on all objects in
          this ‘Session’.

      -- Method: sqlalchemy.orm.scoping.scoped_session..flush
               (objects=None)

          Flush all the object changes to the database.

          Proxied for the Session class on behalf of the
          scoped_session class.

          Writes out all pending object creations, deletions and
          modifications to the database as INSERTs, DELETEs, UPDATEs,
          etc.  Operations are automatically ordered by the Session’s
          unit of work dependency solver.

          Database operations will be issued in the current
          transactional context and do not affect the state of the
          transaction, unless an error occurs, in which case the entire
          transaction is rolled back.  You may flush() as often as you
          like within a transaction to move changes from Python to the
          database’s transaction buffer.

          For ‘autocommit’ Sessions with no active manual transaction,
          flush() will create a transaction on the fly that surrounds
          the entire set of operations into the flush.

          Parameters: ‘objects’ – Optional; restricts the flush
          operation to operate only on elements that are in the given
          collection.

          This feature is for an extremely narrow set of use cases where
          particular objects may need to be operated upon before the
          full flush() occurs.  It is not intended for general use.

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               get_bind (mapper=None, clause=None, bind=None,
               _sa_skip_events=None,
               _sa_skip_for_implicit_returning=False)

          Return a “bind” to which this Session is bound.

          Proxied for the Session class on behalf of the
          scoped_session class.

          The “bind” is usually an instance of Engine, except
          in the case where the Session has been explicitly
          bound directly to a Connection.

          For a multiply-bound or unbound Session, the
          ‘mapper’ or ‘clause’ arguments are used to determine the
          appropriate bind to return.

          Note that the “mapper” argument is usually present when
          Session.get_bind() is called via an ORM operation such
          as a Session.query(), each individual
          INSERT/UPDATE/DELETE operation within a Session.flush(),
          call, etc.

          The order of resolution is:

            1. if mapper given and Session.binds is present,
               locate a bind based first on the mapper in use, then on
               the mapped class in use, then on any base classes that
               are present in the ‘__mro__’ of the mapped class, from
               more specific superclasses to more general.

            2. if clause given and ‘Session.binds’ is present, locate a
               bind based on Table objects found in the given
               clause present in ‘Session.binds’.

            3. if ‘Session.binds’ is present, return that.

            4. if clause given, attempt to return a bind linked to the
               MetaData ultimately associated with the
               clause.

            5. if mapper given, attempt to return a bind linked to the
               MetaData ultimately associated with the
               Table or other selectable to which the mapper is
               mapped.

            6. No bind can be found, see UnboundExecutionError.
               is raised.

          Note that the Session.get_bind() method can be
          overridden on a user-defined subclass of Session to
          provide any kind of bind resolution scheme.  See the example
          at Custom Vertical Partitioning.

          Parameters:

             * ‘mapper’ – Optional mapper() mapped class or
               instance of Mapper.  The bind can be derived
               from a Mapper first by consulting the “binds”
               map associated with this Session, and secondly
               by consulting the MetaData associated with the
               Table to which the Mapper is
               mapped for a bind.

             * ‘clause’ – A ClauseElement. (i.e.  see
               select(), text(), etc.).  If the ‘mapper’
               argument is not present or could not produce a bind, the
               given expression construct will be searched for a bound
               element, typically a Table associated with
               bound MetaData.

          See also
          ........

          See Partitioning Strategies (e.g. multiple database backends per Session).

          See Session.binds.

          See Session.bind_mapper().

          See Session.bind_table().

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               classmethod identity_key (*args, **kwargs)

          Return an identity key.

          Proxied for the Session class on behalf of the
          scoped_session class.

          This is an alias of identity_key().

      -- Attribute: sqlalchemy.orm.scoping.scoped_session..
               info

          A user-modifiable dictionary.

          Proxied for the Session class on behalf of the
          scoped_session class.

          The initial value of this dictionary can be populated using
          the ‘info’ argument to the Session constructor or
          sessionmaker constructor or factory methods.  The
          dictionary here is always local to this Session and
          can be modified independently of all other Session
          objects.

      -- Attribute: sqlalchemy.orm.scoping.scoped_session..
               is_active

          True if this Session not in “partial rollback”
          state.

          Proxied for the Session class on behalf of the
          scoped_session class.

          Changed in version 1.4: The Session no longer
          begins a new transaction immediately, so this attribute will
          be False when the Session is first instantiated.

          “partial rollback” state typically indicates that the flush
          process of the Session has failed, and that the
          Session.rollback() method must be emitted in order
          to fully roll back the transaction.

          If this Session is not in a transaction at all, the
          Session will autobegin when it is first used, so in
          this case Session.is_active will return True.

          Otherwise, if this Session is within a transaction,
          and that transaction has not been rolled back internally, the
          Session.is_active will also return True.

          See also
          ........

          See “This Session’s transaction has been rolled back due to a previous exception during flush.” (or similar).

          See Session.in_transaction().

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               is_modified (instance, include_collections=True)

          Return ‘True’ if the given instance has locally modified
          attributes.

          Proxied for the Session class on behalf of the
          scoped_session class.

          This method retrieves the history for each instrumented
          attribute on the instance and performs a comparison of the
          current value to its previously committed value, if any.

          It is in effect a more expensive and accurate version of
          checking for the given instance in the Session.dirty
          collection; a full test for each attribute’s net “dirty”
          status is performed.

          E.g.:

               return session.is_modified(someobject)

          A few caveats to this method apply:

             * Instances present in the Session.dirty.
               collection may report ‘False’ when tested with this
               method.  This is because the object may have received
               change events via attribute mutation, thus placing it in
               Session.dirty, but ultimately the state is the
               same as that loaded from the database, resulting in no
               net change here.

             * Scalar attributes may not have recorded the previously
               set value when a new value was applied, if the attribute
               was not loaded, or was expired, at the time the new value
               was received - in these cases, the attribute is assumed
               to have a change, even if there is ultimately no net
               change against its database value.  SQLAlchemy in most
               cases does not need the “old” value when a set event
               occurs, so it skips the expense of a SQL call if the old
               value isn’t present, based on the assumption that an
               UPDATE of the scalar value is usually needed, and in
               those few cases where it isn’t, is less expensive on
               average than issuing a defensive SELECT.

               The “old” value is fetched unconditionally upon set only
               if the attribute container has the ‘active_history’ flag
               set to ‘True’.  This flag is set typically for primary
               key attributes and scalar object references that are not
               a simple many-to-one.  To set this flag for any arbitrary
               mapped column, use the ‘active_history’ argument with
               column_property().

          Parameters:

             * ‘instance’ – mapped instance to be tested for pending
               changes.

             * ‘include_collections’ – Indicates if multivalued
               collections should be included in the operation.  Setting
               this to ‘False’ is a way to detect only local-column
               based properties (i.e.  scalar columns or many-to-one
               foreign keys) that would result in an UPDATE for this
               instance upon flush.

      -- Method: sqlalchemy.orm.scoping.scoped_session..merge
               (instance, load=True)

          Copy the state of a given instance into a corresponding
          instance within this Session.

          Proxied for the Session class on behalf of the
          scoped_session class.

          Session.merge() examines the primary key
          attributes of the source instance, and attempts to reconcile
          it with an instance of the same primary key in the session.
          If not found locally, it attempts to load the object from the
          database based on primary key, and if none can be located,
          creates a new instance.  The state of each attribute on the
          source instance is then copied to the target instance.  The
          resulting target instance is then returned by the method; the
          original source instance is left unmodified, and un-associated
          with the Session if not already.

          This operation cascades to associated instances if the
          association is mapped with ‘cascade="merge"’.

          See Merging for a detailed discussion of merging.

          Changed in version 1.1: - see Session.merge() will now
          reconcile pending objects with overlapping primary keys in the
          same way as persistent.  See Session.merge resolves pending conflicts the same as persistent
          for discussion.

          Parameters:

             * ‘instance’ – Instance to be merged.

             * ‘load’ – Boolean, when False, see merge().
               switches into a “high performance” mode which causes it
               to forego emitting history events as well as all database
               access.  This flag is used for cases such as transferring
               graphs of objects into a Session from a second
               level cache, or to transfer just-loaded objects into the
               Session owned by a worker thread or process
               without re-querying the database.

               The ‘load=False’ use case adds the caveat that the given
               object has to be in a “clean” state, that is, has no
               pending changes to be flushed - even if the incoming
               object is detached from any Session.  This is
               so that when the merge operation populates local
               attributes and cascades to related objects and
               collections, the values can be “stamped” onto the target
               object as is, without generating any history or attribute
               events, and without the need to reconcile the incoming
               data with any existing related objects or collections
               that might not be loaded.  The resulting objects from
               ‘load=False’ are always produced as “clean”, so it is
               only appropriate that the given objects should be “clean”
               as well, else this suggests a mis-use of the method.

          See also
          ........

          See make_transient_to_detached(). - provides for an
          alternative means of “merging” a single object into the
          Session.

      -- Attribute: sqlalchemy.orm.scoping.scoped_session..
               new

          The set of all instances marked as ‘new’ within this
          ‘Session’.

          Proxied for the Session class on behalf of the
          scoped_session class.

      -- Attribute: sqlalchemy.orm.scoping.scoped_session..
               no_autoflush

          Return a context manager that disables autoflush.

          Proxied for the Session class on behalf of the
          scoped_session class.

          e.g.:

               with session.no_autoflush:

                   some_object = SomeClass()
                   session.add(some_object)
                   # won't autoflush
                   some_object.related_thing = session.query(SomeRelated).first()

          Operations that proceed within the ‘with:’ block will not be
          subject to flushes occurring upon query access.  This is
          useful when initializing a series of objects which involve
          existing database queries, where the uncompleted object should
          not yet be flushed.

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               classmethod object_session (instance)

          Return the Session to which an object belongs.

          Proxied for the Session class on behalf of the
          scoped_session class.

          This is an alias of object_session().

      -- Method: sqlalchemy.orm.scoping.scoped_session..query
               (*entities, **kwargs)

          Return a new Query object corresponding to this
          Session.

          Proxied for the Session class on behalf of the
          scoped_session class.

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               query_property (query_cls=None)

          return a class property which produces a Query
          object against the class and the current Session
          when called.

          e.g.:

               Session = scoped_session(sessionmaker())

               class MyClass(object):
                   query = Session.query_property()

               # after mappers are defined
               result = MyClass.query.filter(MyClass.name=='foo').all()

          Produces instances of the session’s configured query class by
          default.  To override and use a custom implementation, provide
          a ‘query_cls’ callable.  The callable will be invoked with the
          class’s mapper as a positional argument and a session keyword
          argument.

          There is no limit to the number of query properties placed on
          a class.

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               refresh (instance, attribute_names=None,
               with_for_update=None)

          Expire and refresh the attributes on the given instance.

          Proxied for the Session class on behalf of the
          scoped_session class.

          A query will be issued to the database and all attributes will
          be refreshed with their current database value.

          Lazy-loaded relational attributes will remain lazily loaded,
          so that the instance-wide refresh operation will be followed
          immediately by the lazy load of that attribute.

          Eagerly-loaded relational attributes will eagerly load within
          the single refresh operation.

          Note that a highly isolated transaction will return the same
          values as were previously read in that same transaction,
          regardless of changes in database state outside of that
          transaction - usage of ‘Session.refresh()’ usually only makes
          sense if non-ORM SQL statement were emitted in the ongoing
          transaction, or if autocommit mode is turned on.

          Parameters:

             * ‘attribute_names’ – optional.  An iterable collection of
               string attribute names indicating a subset of attributes
               to be refreshed.

             * ‘with_for_update’ – optional boolean ‘True’ indicating
               FOR UPDATE should be used, or may be a dictionary
               containing flags to indicate a more specific set of FOR
               UPDATE flags for the SELECT; flags should match the
               parameters of Query.with_for_update().
               Supersedes the Session.refresh.lockmode
               parameter.

               New in version 1.2.

          See also
          ........

          See Refreshing / Expiring. - introductory material

          See Session.expire().

          See Session.expire_all().

          See Query.populate_existing().

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               remove ()

          Dispose of the current Session, if present.

          This will first call Session.close() method on the
          current Session, which releases any existing
          transactional/connection resources still being held;
          transactions specifically are rolled back.  The Session
          is then discarded.  Upon next usage within the same scope,
          the scoped_session will produce a new
          Session object.

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               rollback ()

          Rollback the current transaction in progress.

          Proxied for the Session class on behalf of the
          scoped_session class.

          If no transaction is in progress, this method is a
          pass-through.

          In 1.x-style use, this method rolls back the topmost database
          transaction if no nested transactions are in effect, or to the
          current nested transaction if one is in effect.

          When 2.0-style use is in effect via the Session.future
          flag, the method always rolls back the topmost database
          transaction, discarding any nested transactions that may be in
          progress.

          See also
          ........

          See Rolling Back.

          See Managing Transactions.

      -- Method: sqlalchemy.orm.scoping.scoped_session..
               scalar (statement, params=None, execution_options={},
               bind_arguments=None, **kw)

          Execute a statement and return a scalar result.

          Proxied for the Session class on behalf of the
          scoped_session class.

          Usage and parameters are the same as that of
          Session.execute(); the return result is a scalar Python
          value.

      -- Attribute: sqlalchemy.orm.scoping.scoped_session..
               session_factory = None

          The ‘session_factory’ provided to ‘__init__’ is stored in this
          attribute and may be accessed at a later time.  This can be
          useful when a new non-scoped Session or
          Connection to the database is needed.

 -- Class: sqlalchemy.util.ScopedRegistry (createfunc, scopefunc)

     A Registry that can store one or multiple instances of a single
     class on the basis of a “scope” function.

     The object implements ‘__call__’ as the “getter”, so by calling
     ‘myregistry()’ the contained object is returned for the current
     scope.

     Parameters:

        * ‘createfunc’ – a callable that returns a new object to be
          placed in the registry

        * ‘scopefunc’ – a callable that will return a key to
          store/retrieve an object.

      -- Method: sqlalchemy.util.ScopedRegistry..__init__
               (createfunc, scopefunc)

          Construct a new ScopedRegistry.

          Parameters:

             * ‘createfunc’ – A creation function that will generate a
               new value for the current scope, if none is present.

             * ‘scopefunc’ – A function that returns a hashable token
               representing the current scope (such as, current thread
               identifier).

      -- Method: sqlalchemy.util.ScopedRegistry..clear ()

          Clear the current scope, if any.

      -- Method: sqlalchemy.util.ScopedRegistry..has ()

          Return True if an object is present in the current scope.

      -- Method: sqlalchemy.util.ScopedRegistry..set (obj)

          Set the value for the current scope.

 -- Class: sqlalchemy.util.ThreadLocalRegistry (createfunc)

     A ScopedRegistry that uses a ‘threading.local()’
     variable for storage.

     `Class signature'

     class sqlalchemy.util.ThreadLocalRegistry. (see
     sqlalchemy.util.ScopedRegistry)

3.5.7 Tracking queries, object and Session Changes with Events
--------------------------------------------------------------

SQLAlchemy features an extensive Event Listening system used
throughout the Core and ORM. Within the ORM, there are a wide variety of
event listener hooks, which are documented at an API level at ORM Events.
This collection of events has grown over the years to
include lots of very useful new events as well as some older events that
aren’t as relevant as they once were.  This section will attempt to
introduce the major event hooks and when they might be used.

3.5.7.1 Execute Events
......................

New in version 1.4: The Session now features a single
comprehensive hook designed to intercept all SELECT statements made on
behalf of the ORM as well as bulk UPDATE and DELETE statements.  This
hook supersedes the previous QueryEvents.before_compile()
event as well QueryEvents.before_compile_update() and
QueryEvents.before_compile_delete().

Session features a comprehensive system by which all queries
invoked via the Session.execute() method, which includes all
SELECT statements emitted by Query as well as all SELECT
statements emitted on behalf of column and relationship loaders, may be
intercepted and modified.  The system makes use of the
SessionEvents.do_orm_execute() event hook as well as the
ORMExecuteState object to represent the event state.

3.5.7.2 Basic Query Interception
................................

SessionEvents.do_orm_execute() is firstly useful for any
kind of interception of a query, which includes those emitted by
Query with 1.x style as well as when an ORM-enabled 2.0 style
select(), update() or delete()
construct is delivered to Session.execute().  The
ORMExecuteState construct provides accessors to allow
modifications to statements, parameters, and options:

     Session = sessionmaker(engine, future=True)

     @event.listens_for(Session, "do_orm_execute")
     def _do_orm_execute(orm_execute_state):
         if orm_execute_state.is_select:
             # add populate_existing for all SELECT statements

             orm_execute_state.update_execution_options(populate_existing=True)

             # check if the SELECT is against a certain entity and add an
             # ORDER BY if so
             col_descriptions = orm_execute_state.statement.column_descriptions

             if col_descriptions[0]['entity'] is MyEntity:
                 orm_execute_state.statement = statement.order_by(MyEntity.name)

The above example illustrates some simple modifications to SELECT
statements.  At this level, the SessionEvents.do_orm_execute()
event hook intends to replace the previous use of the
QueryEvents.before_compile() event, which was not fired off
consistently for various kinds of loaders; additionally, the
QueryEvents.before_compile() only applies to 1.x style use with
Query and not with 2.0 style use of Session.execute().

3.5.7.3 Adding global WHERE / ON criteria
.........................................

One of the most requested query-extension features is the ability to add
WHERE criteria to all occurrences of an entity in all queries.  This is
achievable by making use of the with_loader_criteria() query
option, which may be used on its own, or is ideally suited to be used
within the SessionEvents.do_orm_execute() event:

     from sqlalchemy.orm import with_loader_criteria

     Session = sessionmaker(engine, future=True)

     @event.listens_for(Session, "do_orm_execute")
     def _do_orm_execute(orm_execute_state):

         if (
             orm_execute_state.is_select and
             not orm_execute_state.is_column_load and
             not orm_execute_state.is_relationship_load
         ):
             orm_execute_state.statement = orm_execute_state.statement.options(
                 with_loader_criteria(MyEntity.public == True)
             )

Above, an option is added to all SELECT statements that will limit all
queries against ‘MyEntity’ to filter on ‘public == True’.  The criteria
will be applied to `all' loads of that class within the scope of the
immediate query.  The with_loader_criteria() option by
default will automatically propagate to relationship loaders as well,
which will apply to subsequent relationship loads, which includes lazy
loads, selectinloads, etc.

For a series of classes that all feature some common column structure,
if the classes are composed using a declarative mixin, the
mixin class itself may be used in conjunction with the
with_loader_criteria() option by making use of a Python lambda.
The Python lambda will be invoked at query compilation time against the
specific entities which match the criteria.  Given a series of classes
based on a mixin called ‘HasTimestamp’:

     import datetime

     class HasTimestamp(object):
         timestamp = Column(DateTime, default=datetime.datetime.now)

     class SomeEntity(HasTimestamp, Base):
         __tablename__ = "some_entity"
         id = Column(Integer, primary_key=True)

     class SomeOtherEntity(HasTimestamp, Base):
         __tablename__ = "some_entity"
         id = Column(Integer, primary_key=True)

The above classes ‘SomeEntity’ and ‘SomeOtherEntity’ will each have a
column ‘timestamp’ that defaults to the current date and time.  An event
may be used to intercept all objects that extend from ‘HasTimestamp’ and
filter their ‘timestamp’ column on a date that is no older than one
month ago:

     @event.listens_for(Session, "do_orm_execute")
     def _do_orm_execute(orm_execute_state):
         if (
                 orm_execute_state.is_select
                 and not orm_execute_state.is_column_load
                 and not orm_execute_state.is_relationship_load
         ):
             one_month_ago = datetime.datetime.today() - datetime.timedelta(months=1)

             orm_execute_state.statement = orm_execute_state.statement.options(
                 with_loader_criteria(
                     HasTimestamp,
                     lambda cls: cls.timestamp >= one_month_ago,
                     include_aliases=True
                 )
             )

     Warning: The use of a lambda inside of the call to
     with_loader_criteria() is only invoked `once per unique
     class'.  Custom functions should not be invoked within this lambda.
     See Using Lambdas to add significant speed gains to statement production
     for an overview of the “lambda SQL” feature, which
     is for advanced use only.

See also
........

See ORM Query Events. - includes working examples of the above
with_loader_criteria() recipes.

3.5.7.4 Re-Executing Statements
...............................

     deepalchemy: the statement re-execution feature involves a slightly
     intricate recursive sequence, and is intended to solve the fairly
     hard problem of being able to re-route the execution of a SQL
     statement into various non-SQL contexts.  The twin examples of
     “dogpile caching” and “horizontal sharding”, linked below, should
     be used as a guide for when this rather advanced feature is
     appropriate to be used.

The ORMExecuteState is capable of controlling the execution
of the given statement; this includes the ability to either not invoke
the statement at all, allowing a pre-constructed result set retrieved
from a cache to be returned instead, as well as the ability to invoke
the same statement repeatedly with different state, such as invoking it
against multiple database connections and then merging the results
together in memory.  Both of these advanced patterns are demonstrated in
SQLAlchemy’s example suite as detailed below.

When inside the SessionEvents.do_orm_execute() event hook,
the ORMExecuteState.invoke_statement() method may be used to
invoke the statement using a new nested invocation of
Session.execute(), which will then preempt the subsequent handling
of the current execution in progress and instead return the
Result returned by the inner execution.  The event handlers thus
far invoked for the SessionEvents.do_orm_execute() hook
within this process will be skipped within this nested call as well.

The ORMExecuteState.invoke_statement() method returns a
Result object; this object then features the ability for it
to be “frozen” into a cacheable format and “unfrozen” into a new
Result object, as well as for its data to be merged with that of
other Result objects.

E.g., using SessionEvents.do_orm_execute() to implement a
cache:

     from sqlalchemy.orm import loading

     cache = {}

     @event.listens_for(Session, "do_orm_execute")
     def _do_orm_execute(orm_execute_state):
         if "my_cache_key" in orm_execute_state.execution_options:
             cache_key = orm_execute_state.execution_options["my_cache_key"]

             if cache_key in cache:
                 frozen_result = cache[cache_key]
             else:
                 frozen_result = orm_execute_state.invoke_statement().freeze()
                 cache[cache_key] = frozen_result

             return loading.merge_frozen_result(
                 orm_execute_state.session,
                 orm_execute_state.statement,
                 frozen_result,
                 load=False,
             )

With the above hook in place, an example of using the cache would look
like:

     stmt = select(User).where(User.name == 'sandy').execution_options(my_cache_key="key_sandy")

     result = session.execute(stmt)

Above, a custom execution option is passed to
Select.execution_options() in order to establish a “cache key”
that will then be intercepted by the
SessionEvents.do_orm_execute() hook.  This cache key is then
matched to a FrozenResult object that may be present in the
cache, and if present, the object is re-used.  The recipe makes use of
the Result.freeze() method to “freeze” a Result
object, which above will contain ORM results, such that it can be stored
in a cache and used multiple times.  In order to return a live result
from the “frozen” result, the ‘merge_frozen_result()’ function is used
to merge the “frozen” data from the result object into the current
session.

The above example is implemented as a complete example in Dogpile Caching.

The ORMExecuteState.invoke_statement() method may also be
called multiple times, passing along different information to the
ORMExecuteState.invoke_statement.bind_arguments parameter such
that the Session will make use of different Engine
objects each time.  This will return a different Result
object each time; these results can be merged together using the
Result.merge() method.  This is the technique employed by the
Horizontal Sharding extension; see the source code to
familiarize.

See also
........

See Dogpile Caching.

See Horizontal Sharding.

3.5.7.5 Persistence Events
..........................

Probably the most widely used series of events are the “persistence”
events, which correspond to the flush process.  The flush is
where all the decisions are made about pending changes to objects and
are then emitted out to the database in the form of INSERT, UPDATE, and
DELETE statements.

3.5.7.6 ‘before_flush()’
........................

The SessionEvents.before_flush() hook is by far the most
generally useful event to use when an application wants to ensure that
additional persistence changes to the database are made when a flush
proceeds.  Use SessionEvents.before_flush() in order to
operate upon objects to validate their state as well as to compose
additional objects and references before they are persisted.  Within
this event, it is `safe to manipulate the Session’s state', that is, new
objects can be attached to it, objects can be deleted, and individual
attributes on objects can be changed freely, and these changes will be
pulled into the flush process when the event hook completes.

The typical SessionEvents.before_flush() hook will be tasked
with scanning the collections Session.new,
Session.dirty and Session.deleted in order to look for
objects where something will be happening.

For illustrations of SessionEvents.before_flush(), see
examples such as Versioning with a History Table and
Versioning using Temporal Rows.

3.5.7.7 ‘after_flush()’
.......................

The SessionEvents.after_flush() hook is called after the SQL
has been emitted for a flush process, but `before' the state of the
objects that were flushed has been altered.  That is, you can still
inspect the Session.new, Session.dirty and
Session.deleted collections to see what was just flushed, and you
can also use history tracking features like the ones provided by
AttributeState to see what changes were just persisted.  In the
SessionEvents.after_flush() event, additional SQL can be
emitted to the database based on what’s observed to have changed.

3.5.7.8 ‘after_flush_postexec()’
................................

SessionEvents.after_flush_postexec() is called soon after
SessionEvents.after_flush(), but is invoked `after' the state
of the objects has been modified to account for the flush that just took
place.  The Session.new, Session.dirty and
Session.deleted collections are normally completely empty here.
Use SessionEvents.after_flush_postexec() to inspect the
identity map for finalized objects and possibly emit additional SQL. In
this hook, there is the ability to make new changes on objects, which
means the Session will again go into a “dirty” state; the
mechanics of the Session here will cause it to flush `again'
if new changes are detected in this hook if the flush were invoked in
the context of Session.commit(); otherwise, the pending
changes will be bundled as part of the next normal flush.  When the hook
detects new changes within a Session.commit(), a counter
ensures that an endless loop in this regard is stopped after 100
iterations, in the case that an
SessionEvents.after_flush_postexec() hook continually adds new
state to be flushed each time it is called.

3.5.7.9 Mapper-level Events
...........................

In addition to the flush-level hooks, there is also a suite of hooks
that are more fine-grained, in that they are called on a per-object
basis and are broken out based on INSERT, UPDATE or DELETE. These are
the mapper persistence hooks, and they too are very popular, however
these events need to be approached more cautiously, as they proceed
within the context of the flush process that is already ongoing; many
operations are not safe to proceed here.

The events are:

   * MapperEvents.before_insert().

   * MapperEvents.after_insert().

   * MapperEvents.before_update().

   * MapperEvents.after_update().

   * MapperEvents.before_delete().

   * MapperEvents.after_delete().

Each event is passed the Mapper, the mapped object itself,
and the Connection which is being used to emit an INSERT,
UPDATE or DELETE statement.  The appeal of these events is clear, in
that if an application wants to tie some activity to when a specific
type of object is persisted with an INSERT, the hook is very specific;
unlike the SessionEvents.before_flush() event, there’s no
need to search through collections like Session.new in order
to find targets.  However, the flush plan which represents the full list
of every single INSERT, UPDATE, DELETE statement to be emitted has
`already been decided' when these events are called, and no changes may
be made at this stage.  Therefore the only changes that are even
possible to the given objects are upon attributes `local' to the
object’s row.  Any other change to the object or other objects will
impact the state of the Session, which will fail to function
properly.

Operations that are not supported within these mapper-level persistence
events include:

   * Session.add().

   * Session.delete().

   * Mapped collection append, add, remove, delete, discard, etc.

   * Mapped relationship attribute set/del events, i.e.
     ‘someobject.related = someotherobject’

The reason the Connection is passed is that it is encouraged
that `simple SQL operations take place here', directly on the
Connection, such as incrementing counters or inserting extra rows
within log tables.  When dealing with the Connection, it is
expected that Core-level SQL operations will be used; e.g.  those
described in SQL Expression Language Tutorial (1.x API).

There are also many per-object operations that don’t need to be handled
within a flush event at all.  The most common alternative is to simply
establish additional state along with an object inside its ‘__init__()’
method, such as creating additional objects that are to be associated
with the new object.  Using validators as described in Simple Validators
is another approach; these functions can intercept
changes to attributes and establish additional state changes on the
target object in response to the attribute change.  With both of these
approaches, the object is in the correct state before it ever gets to
the flush step.

3.5.7.10 Object Lifecycle Events
................................

Another use case for events is to track the lifecycle of objects.  This
refers to the states first introduced at Quickie Intro to Object States.

New in version 1.1: added a system of events that intercept all possible
state transitions of an object within the Session.

All the states above can be tracked fully with events.  Each event
represents a distinct state transition, meaning, the starting state and
the destination state are both part of what are tracked.  With the
exception of the initial transient event, all the events are in terms of
the Session object or class, meaning they can be associated
either with a specific Session object:

     from sqlalchemy import event
     from sqlalchemy.orm import Session

     session = Session()

     @event.listens_for(session, 'transient_to_pending')
     def object_is_pending(session, obj):
         print("new pending: %s" % obj)

Or with the Session class itself, as well as with a specific
sessionmaker, which is likely the most useful form:

     from sqlalchemy import event
     from sqlalchemy.orm import sessionmaker

     maker = sessionmaker()

     @event.listens_for(maker, 'transient_to_pending')
     def object_is_pending(session, obj):
         print("new pending: %s" % obj)

The listeners can of course be stacked on top of one function, as is
likely to be common.  For example, to track all objects that are
entering the persistent state:

     @event.listens_for(maker, "pending_to_persistent")
     @event.listens_for(maker, "deleted_to_persistent")
     @event.listens_for(maker, "detached_to_persistent")
     @event.listens_for(maker, "loaded_as_persistent")
     def detect_all_persistent(session, instance):
         print("object is now persistent: %s" % instance)

3.5.7.11 Transient
..................

All mapped objects when first constructed start out as transient.  In
this state, the object exists alone and doesn’t have an association with
any Session.  For this initial state, there’s no specific
“transition” event since there is no Session, however if one
wanted to intercept when any transient object is created, the
InstanceEvents.init() method is probably the best event.  This
event is applied to a specific class or superclass.  For example, to
intercept all new objects for a particular declarative base:

     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy import event

     Base = declarative_base()

     @event.listens_for(Base, "init", propagate=True)
     def intercept_init(instance, args, kwargs):
         print("new transient: %s" % instance)

3.5.7.12 Transient to Pending
.............................

The transient object becomes pending when it is first associated with a
Session via the Session.add() or
Session.add_all() method.  An object may also become part of a
Session as a result of a “cascade” from a
referencing object that was explicitly added.  The transient to pending
transition is detectable using the
SessionEvents.transient_to_pending() event:

     @event.listens_for(sessionmaker, "transient_to_pending")
     def intercept_transient_to_pending(session, object_):
         print("transient to pending: %s" % object_)

3.5.7.13 Pending to Persistent
..............................

The pending object becomes persistent when a flush proceeds and an
INSERT statement takes place for the instance.  The object now has an
identity key.  Track pending to persistent with the
SessionEvents.pending_to_persistent() event:

     @event.listens_for(sessionmaker, "pending_to_persistent")
     def intercept_pending_to_persistent(session, object_):
         print("pending to persistent: %s" % object_)

3.5.7.14 Pending to Transient
.............................

The pending object can revert back to transient if the
Session.rollback() method is called before the pending object has
been flushed, or if the Session.expunge() method is called
for the object before it is flushed.  Track pending to transient with
the SessionEvents.pending_to_transient() event:

     @event.listens_for(sessionmaker, "pending_to_transient")
     def intercept_pending_to_transient(session, object_):
         print("transient to pending: %s" % object_)

3.5.7.15 Loaded as Persistent
.............................

Objects can appear in the Session directly in the persistent
state when they are loaded from the database.  Tracking this state
transition is synonymous with tracking objects as they are loaded, and
is synonymous with using the InstanceEvents.load()
instance-level event.  However, the
SessionEvents.loaded_as_persistent() event is provided as a
session-centric hook for intercepting objects as they enter the
persistent state via this particular avenue:

     @event.listens_for(sessionmaker, "loaded_as_persistent")
     def intercept_loaded_as_persistent(session, object_):
         print("object loaded into persistent state: %s" % object_)

3.5.7.16 Persistent to Transient
................................

The persistent object can revert to the transient state if the
Session.rollback() method is called for a transaction where the
object was first added as pending.  In the case of the ROLLBACK, the
INSERT statement that made this object persistent is rolled back, and
the object is evicted from the Session to again become
transient.  Track objects that were reverted to transient from
persistent using the SessionEvents.persistent_to_transient()
event hook:

     @event.listens_for(sessionmaker, "persistent_to_transient")
     def intercept_persistent_to_transient(session, object_):
         print("persistent to transient: %s" % object_)

3.5.7.17 Persistent to Deleted
..............................

The persistent object enters the deleted state when an object marked for
deletion is deleted from the database within the flush process.  Note
that this is `not the same' as when the Session.delete()
method is called for a target object.  The Session.delete()
method only `marks' the object for deletion; the actual DELETE statement
is not emitted until the flush proceeds.  It is subsequent to the flush
that the “deleted” state is present for the target object.

Within the “deleted” state, the object is only marginally associated
with the Session.  It is not present in the identity map nor
is it present in the Session.deleted collection that refers
to when it was pending for deletion.

From the “deleted” state, the object can go either to the detached state
when the transaction is committed, or back to the persistent state if
the transaction is instead rolled back.

Track the persistent to deleted transition with
SessionEvents.persistent_to_deleted():

     @event.listens_for(sessionmaker, "persistent_to_deleted")
     def intercept_persistent_to_deleted(session, object_):
         print("object was DELETEd, is now in deleted state: %s" % object_)

3.5.7.18 Deleted to Detached
............................

The deleted object becomes detached when the session’s transaction is
committed.  After the Session.commit() method is called, the
database transaction is final and the Session now fully
discards the deleted object and removes all associations to it.  Track
the deleted to detached transition using
SessionEvents.deleted_to_detached():

     @event.listens_for(sessionmaker, "deleted_to_detached")
     def intercept_deleted_to_detached(session, object_):
         print("deleted to detached: %s" % object_)

     Note: While the object is in the deleted state, the
     InstanceState.deleted attribute, accessible using
     ‘inspect(object).deleted’, returns True.  However when the object
     is detached, see InstanceState.deleted will again return
     False.  To detect that an object was deleted, regardless of whether
     or not it is detached, use the InstanceState.was_deleted
     accessor.

3.5.7.19 Persistent to Detached
...............................

The persistent object becomes detached when the object is de-associated
with the Session, via the Session.expunge(),
Session.expunge_all(), or Session.close() methods.

     Note: An object may also become `implicitly detached' if its owning
     Session is dereferenced by the application and discarded
     due to garbage collection.  In this case, `no event is emitted'.

Track objects as they move from persistent to detached using the
SessionEvents.persistent_to_detached() event:

     @event.listens_for(sessionmaker, "persistent_to_detached")
     def intercept_persistent_to_detached(session, object_):
         print("object became detached: %s" % object_)

3.5.7.20 Detached to Persistent
...............................

The detached object becomes persistent when it is re-associated with a
session using the Session.add() or equivalent method.  Track
objects moving back to persistent from detached using the
SessionEvents.detached_to_persistent() event:

     @event.listens_for(sessionmaker, "detached_to_persistent")
     def intercept_detached_to_persistent(session, object_):
         print("object became persistent again: %s" % object_)

3.5.7.21 Deleted to Persistent
..............................

The deleted object can be reverted to the persistent state when the
transaction in which it was DELETEd was rolled back using the
Session.rollback() method.  Track deleted objects moving back to
the persistent state using the
SessionEvents.deleted_to_persistent() event:

     @event.listens_for(sessionmaker, "deleted_to_persistent")
     def intercept_deleted_to_persistent(session, object_):
         print("deleted to persistent: %s" % object_)

3.5.7.22 Transaction Events
...........................

Transaction events allow an application to be notified when transaction
boundaries occur at the Session level as well as when the
Session changes the transactional state on Connection
objects.

   * SessionEvents.after_transaction_create(),
     SessionEvents.after_transaction_end(). - these events track
     the logical transaction scopes of the Session in a way
     that is not specific to individual database connections.  These
     events are intended to help with integration of
     transaction-tracking systems such as ‘zope.sqlalchemy’.  Use these
     events when the application needs to align some external scope with
     the transactional scope of the Session.  These hooks
     mirror the “nested” transactional behavior of the Session,
     in that they track logical “subtransactions” as well as
     “nested” (e.g.  SAVEPOINT) transactions.

   * SessionEvents.before_commit(),
     SessionEvents.after_commit(),
     SessionEvents.after_begin(),
     SessionEvents.after_rollback(),
     SessionEvents.after_soft_rollback(). - These events allow
     tracking of transaction events from the perspective of database
     connections.  SessionEvents.after_begin() in particular
     is a per-connection event; a Session that maintains more
     than one connection will emit this event for each connection
     individually as those connections become used within the current
     transaction.  The rollback and commit events then refer to when the
     DBAPI connections themselves have received rollback or commit
     instructions directly.

3.5.7.23 Attribute Change Events
................................

The attribute change events allow interception of when specific
attributes on an object are modified.  These events include
AttributeEvents.set(), AttributeEvents.append(), and
AttributeEvents.remove().  These events are extremely useful,
particularly for per-object validation operations; however, it is often
much more convenient to use a “validator” hook, which uses these hooks
behind the scenes; see Simple Validators for background on
this.  The attribute events are also behind the mechanics of
backreferences.  An example illustrating use of attribute events is in
Attribute Instrumentation.

3.5.8 Session API
-----------------

3.5.8.1 Session and sessionmaker()
..................................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See ORMExecuteState.Represents a call to the Session.execute() method, as passed to the
               SessionEvents.do_orm_execute() event hook.

See Session.Manages persistence operations for ORM-mapped objects.

See sessionmaker.A configurable Session factory.

See SessionTransaction.A Session.-level transaction.

 -- Class: sqlalchemy.orm.sessionmaker (bind=None, class_=<class
          'sqlalchemy.orm.session.Session'>, autoflush=True,
          autocommit=False, expire_on_commit=True, info=None, **kw)

     A configurable Session factory.

     The sessionmaker factory generates new Session
     objects when called, creating them given the configurational
     arguments established here.

     e.g.:

          from sqlalchemy import create_engine
          from sqlalchemy.orm import sessionmaker

          # an Engine, which the Session will use for connection
          # resources
          engine = create_engine('postgresql://scott:tiger@localhost/')

          Session = sessionmaker(engine)

          with Session() as session:
              session.add(some_object)
              session.add(some_other_object)
              session.commit()

     Context manager use is optional; otherwise, the returned
     Session object may be closed explicitly via the
     Session.close() method.  Using a ‘try:/finally:’ block is
     optional, however will ensure that the close takes place even if
     there are database errors:

          session = Session()
          try:
              session.add(some_object)
              session.add(some_other_object)
              session.commit()
          finally:
              session.close()

     sessionmaker acts as a factory for Session
     objects in the same way as an Engine acts as a factory
     for Connection objects.  In this way it also includes a
     sessionmaker.begin() method, that provides a context
     manager which both begins and commits a transaction, as well as
     closes out the Session when complete, rolling back the
     transaction if any errors occur:

          Session = sessionmaker(engine)

          with Session.begin() as session:
              session.add(some_object)
              session.add(some_other_object)
          # commits transaction, closes session

     New in version 1.4.

     When calling upon sessionmaker to construct a
     Session, keyword arguments may also be passed to the method;
     these arguments will override that of the globally configured
     parameters.  Below we use a sessionmaker bound to a
     certain Engine to produce a Session that is
     instead bound to a specific Connection procured from
     that engine:

          Session = sessionmaker(engine)

          # bind an individual session to a connection

          with engine.connect() as connection:
              with Session(bind=connection) as session:
                  # work with session

     The class also includes a method sessionmaker.configure(),
     which can be used to specify additional keyword arguments to
     the factory, which will take effect for subsequent Session
     objects generated.  This is usually used to associate one or
     more Engine objects with an existing
     sessionmaker factory before it is first used:

          # application starts, sessionmaker does not have
          # an engine bound yet
          Session = sessionmaker()

          # ... later, when an engine URL is read from a configuration
          # file or other events allow the engine to be created
          engine = create_engine('sqlite:///foo.db')
          Session.configure(bind=engine)

          sess = Session()
          # work with session

     See also
     ........

     See Opening and Closing a Session. - introductory text on
     creating sessions using sessionmaker.

     `Class signature'

     class sqlalchemy.orm.sessionmaker.
     (‘sqlalchemy.orm.session._SessionClassMethods’)

      -- Method: sqlalchemy.orm.sessionmaker..__call__
               (**local_kw)

          Produce a new Session object using the
          configuration established in this sessionmaker.

          In Python, the ‘__call__’ method is invoked on an object when
          it is “called” in the same way as a function:

               Session = sessionmaker()
               session = Session()  # invokes sessionmaker.__call__()

      -- Method: sqlalchemy.orm.sessionmaker..__init__
               (bind=None, class_=<class
               'sqlalchemy.orm.session.Session'>, autoflush=True,
               autocommit=False, expire_on_commit=True, info=None, **kw)

          Construct a new sessionmaker.

          All arguments here except for ‘class_’ correspond to arguments
          accepted by Session directly.  See the
          Session.__init__() docstring for more details on
          parameters.

          Parameters:

             * ‘bind’ – a Engine or other ‘Connectable’ with
               which newly created Session objects will be
               associated.

             * ‘class_’ – class to use in order to create new
               Session objects.  Defaults to Session.

             * ‘autoflush’ – The autoflush setting to use with newly
               created Session objects.

             * ‘autocommit’ – The autocommit setting to use with newly
               created Session objects.

             * ‘expire_on_commit=True’ – the
               Session.expire_on_commit setting to use with newly
               created Session objects.

             * ‘info’ – optional dictionary of information that will be
               available via Session.info.  Note this
               dictionary is `updated', not replaced, when the ‘info’
               parameter is specified to the specific Session
               construction operation.

             * ‘**kw’ – all other keyword arguments are passed to the
               constructor of newly created Session objects.

      -- Method: sqlalchemy.orm.sessionmaker..begin ()

          Produce a context manager that both provides a new
          Session as well as a transaction that commits.

          e.g.:

               Session = sessionmaker(some_engine)

               with Session.begin() as session:
                   session.add(some_object)

               # commits transaction, closes session

          New in version 1.4.

      -- Method: sqlalchemy.orm.sessionmaker..classmethod
               close_all ()

          `inherited from the'
          ‘sqlalchemy.orm.session._SessionClassMethods.close_all’
          `method of' ‘sqlalchemy.orm.session._SessionClassMethods’

          Close `all' sessions in memory.

          Deprecated since version 1.3: The Session.close_all()
          method is deprecated and will be removed in a future
          release.  Please refer to ‘close_all_sessions()’.

      -- Method: sqlalchemy.orm.sessionmaker..configure
               (**new_kw)

          (Re)configure the arguments for this sessionmaker.

          e.g.:

               Session = sessionmaker()

               Session.configure(bind=create_engine('sqlite://'))

      -- Method: sqlalchemy.orm.sessionmaker..classmethod
               identity_key (*args, **kwargs)

          `inherited from the'
          ‘sqlalchemy.orm.session._SessionClassMethods.identity_key’
          `method of' ‘sqlalchemy.orm.session._SessionClassMethods’

          Return an identity key.

          This is an alias of identity_key().

      -- Method: sqlalchemy.orm.sessionmaker..classmethod
               object_session (instance)

          `inherited from the'
          ‘sqlalchemy.orm.session._SessionClassMethods.object_session’
          `method of' ‘sqlalchemy.orm.session._SessionClassMethods’

          Return the Session to which an object belongs.

          This is an alias of object_session().

 -- Class: sqlalchemy.orm.ORMExecuteState (session, statement,
          parameters, execution_options, bind_arguments,
          compile_state_cls, events_todo)

     Represents a call to the Session.execute() method, as
     passed to the SessionEvents.do_orm_execute() event
     hook.

     New in version 1.4.

     See also
     ........

     See Execute Events. - top level documentation on how to use
     SessionEvents.do_orm_execute().

     `Class signature'

     class sqlalchemy.orm.ORMExecuteState.
     (‘sqlalchemy.util.langhelpers.MemoizedSlots’)

      -- Attribute: sqlalchemy.orm.ORMExecuteState..session

          The Session in use.

      -- Attribute: sqlalchemy.orm.ORMExecuteState..statement

          The SQL statement being invoked.  For an ORM selection as
          would be retrieved from Query, this is an instance
          of select that was generated from the ORM query.

      -- Attribute: sqlalchemy.orm.ORMExecuteState..
               parameters

          Dictionary of parameters that was passed to
          Session.execute().

      -- Attribute: sqlalchemy.orm.ORMExecuteState..
               bind_arguments

          The dictionary passed as the
          Session.execute.bind_arguments dictionary.  This
          dictionary may be used by extensions to Session to
          pass arguments that will assist in determining amongst a set
          of database connections which one should be used to invoke
          this statement.

      -- Attribute: sqlalchemy.orm.ORMExecuteState..
               local_execution_options

          Dictionary view of the execution options passed to the
          Session.execute() method.  This does not include options
          that may be associated with the statement being invoked.

          See also
          ........

          See ORMExecuteState.execution_options.

      -- Attribute: sqlalchemy.orm.ORMExecuteState..
               execution_options

      -- Attribute: The complete dictionary of current execution
               options.

          This is a merge of the statement level options with the
          locally passed execution options.

      -- Attribute: sqlalchemy.orm.ORMExecuteState..
               all_mappers

          Return a sequence of all Mapper objects that are
          involved at the top level of this statement.

          By “top level” we mean those Mapper objects that
          would be represented in the result set rows for a
          select() query, or for a update() or
          delete() query, the mapper that is the main subject of
          the UPDATE or DELETE.

          New in version 1.4.0b2.

          See also
          ........

          See ORMExecuteState.bind_mapper.

      -- Attribute: sqlalchemy.orm.ORMExecuteState..
               bind_mapper

          Return the Mapper that is the primary “bind”
          mapper.

          For an ORMExecuteState object invoking an ORM
          statement, that is, the
          ORMExecuteState.is_orm_statement attribute is ‘True’,
          this attribute will return the Mapper that is
          considered to be the “primary” mapper of the statement.  The
          term “bind mapper” refers to the fact that a Session
          object may be “bound” to multiple Engine
          objects keyed to mapped classes, and the “bind mapper”
          determines which of those Engine objects would be
          selected.

          For a statement that is invoked against a single mapped class,
          see ORMExecuteState.bind_mapper is intended to be a
          reliable way of getting this mapper.

          New in version 1.4.0b2.

          See also
          ........

          See ORMExecuteState.all_mappers.

      -- Method: sqlalchemy.orm.ORMExecuteState..
               invoke_statement (statement=None, params=None,
               execution_options=None, bind_arguments=None)

          Execute the statement represented by this
          ORMExecuteState, without re-invoking events that have
          already proceeded.

          This method essentially performs a re-entrant execution of the
          current statement for which the
          SessionEvents.do_orm_execute() event is being currently
          invoked.  The use case for this is for event handlers that
          want to override how the ultimate Result object is
          returned, such as for schemes that retrieve results from an
          offline cache or which concatenate results from multiple
          executions.

          When the Result object is returned by the actual
          handler function within SessionEvents.do_orm_execute()
          and is propagated to the calling Session.execute()
          method, the remainder of the Session.execute()
          method is preempted and the Result object is
          returned to the caller of Session.execute()
          immediately.

          Parameters:

             * ‘statement’ – optional statement to be invoked, in place
               of the statement currently represented by
               ORMExecuteState.statement.

             * ‘params’ – optional dictionary of parameters which will
               be merged into the existing
               ORMExecuteState.parameters of this
               ORMExecuteState.

             * ‘execution_options’ – optional dictionary of execution
               options will be merged into the existing
               ORMExecuteState.execution_options of this
               ORMExecuteState.

             * ‘bind_arguments’ – optional dictionary of bind_arguments
               which will be merged amongst the current
               ORMExecuteState.bind_arguments of this
               ORMExecuteState.

          Returns: a Result object with ORM-level results.

          See also
          ........

          See Re-Executing Statements. - background and examples
          on the appropriate usage of
          ORMExecuteState.invoke_statement().

      -- Attribute: sqlalchemy.orm.ORMExecuteState..
               is_column_load

          Return True if the operation is refreshing column-oriented
          attributes on an existing ORM object.

          This occurs during operations such as Session.refresh(),
          as well as when an attribute deferred by defer()
          is being loaded, or an attribute that was expired either
          directly by Session.expire() or via a commit
          operation is being loaded.

          Handlers will very likely not want to add any options to
          queries when such an operation is occurring as the query
          should be a straight primary key fetch which should not have
          any additional WHERE criteria, and loader options travelling
          with the instance will have already been added to the query.

          New in version 1.4.0b2.

          See also
          ........

          See ORMExecuteState.is_relationship_load.

      -- Attribute: sqlalchemy.orm.ORMExecuteState..is_delete

          return True if this is a DELETE operation.

      -- Attribute: sqlalchemy.orm.ORMExecuteState..is_insert

          return True if this is an INSERT operation.

      -- Attribute: sqlalchemy.orm.ORMExecuteState..
               is_orm_statement

          return True if the operation is an ORM statement.

          This indicates that the select(), update(), or delete() being
          invoked contains ORM entities as subjects.  For a statement
          that does not have ORM entities and instead refers only to
          Table metadata, it is invoked as a Core SQL
          statement and no ORM-level automation takes place.

      -- Attribute: sqlalchemy.orm.ORMExecuteState..
               is_relationship_load

          Return True if this load is loading objects on behalf of a
          relationship.

          This means, the loader in effect is either a LazyLoader,
          SelectInLoader, SubqueryLoader, or similar, and the entire
          SELECT statement being emitted is on behalf of a relationship
          load.

          Handlers will very likely not want to add any options to
          queries when such an operation is occurring, as loader options
          are already capable of being propagated to relationship
          loaders and should be already present.

          See also
          ........

          See ORMExecuteState.is_column_load.

      -- Attribute: sqlalchemy.orm.ORMExecuteState..is_select

          return True if this is a SELECT operation.

      -- Attribute: sqlalchemy.orm.ORMExecuteState..is_update

          return True if this is an UPDATE operation.

      -- Attribute: sqlalchemy.orm.ORMExecuteState..
               lazy_loaded_from

          An InstanceState that is using this statement
          execution for a lazy load operation.

          The primary rationale for this attribute is to support the
          horizontal sharding extension, where it is available within
          specific query execution time hooks created by this extension.
          To that end, the attribute is only intended to be meaningful
          at `query execution time', and importantly not any time prior
          to that, including query compilation time.

      -- Attribute: sqlalchemy.orm.ORMExecuteState..
               load_options

          Return the load_options that will be used for this execution.

      -- Attribute: sqlalchemy.orm.ORMExecuteState..
               loader_strategy_path

          Return the ‘PathRegistry’ for the current load path.

          This object represents the “path” in a query along
          relationships when a particular object or collection is being
          loaded.

      -- Attribute: sqlalchemy.orm.ORMExecuteState..
               update_delete_options

          Return the update_delete_options that will be used for this
          execution.

      -- Attribute: sqlalchemy.orm.ORMExecuteState..
               user_defined_options

          The sequence of ‘UserDefinedOptions’ that have been associated
          with the statement being invoked.

 -- Class: sqlalchemy.orm.Session (bind=None, autoflush=True,
          future=False, expire_on_commit=True, autocommit=False,
          twophase=False, binds=None, enable_baked_queries=True,
          info=None, query_cls=None)

     Manages persistence operations for ORM-mapped objects.

     The Session’s usage paradigm is described at Using the Session.

     `Class signature'

     class sqlalchemy.orm.Session.
     (‘sqlalchemy.orm.session._SessionClassMethods’)

      -- Method: sqlalchemy.orm.Session..__init__ (bind=None,
               autoflush=True, future=False, expire_on_commit=True,
               autocommit=False, twophase=False, binds=None,
               enable_baked_queries=True, info=None, query_cls=None)

          Construct a new Session.

          See also the sessionmaker function which is used
          to generate a Session.-producing callable with a
          given set of arguments.

          Parameters:

             * ‘autocommit’ – Defaults to ‘False’.  When ‘True’, the
               Session does not automatically begin
               transactions for individual statement executions, will
               acquire connections from the engine on an as-needed
               basis, releasing to the connection pool after each
               statement.  Flushes will begin and commit (or possibly
               rollback) their own transaction if no transaction is
               present.  When using this mode, the
               Session.begin() method may be used to explicitly
               start transactions, but the usual “autobegin” behavior is
               not present.

               Deprecated since version 1.4: The
               Session.autocommit parameter is deprecated and will
               be removed in SQLAlchemy version 2.0.  The Session
               now features “autobegin” behavior such that the
               Session.begin() method may be called if a
               transaction has not yet been started yet.  See the
               section Explicit Begin for background.

             * ‘autoflush’ – When ‘True’, all query operations will
               issue a Session.flush() call to this
               ‘Session’ before proceeding.  This is a convenience
               feature so that Session.flush() need not be
               called repeatedly in order for database queries to
               retrieve results.  It’s typical that ‘autoflush’ is used
               in conjunction with ‘autocommit=False’.  In this
               scenario, explicit calls to Session.flush()
               are rarely needed; you usually only need to call
               Session.commit(). (which flushes) to finalize
               changes.

             * ‘bind’ – An optional Engine or
               Connection to which this ‘Session’ should be bound.
               When specified, all SQL operations performed by this
               session will execute via this connectable.

             * ‘binds’ – A dictionary which may specify any number of
               Engine or Connection objects as
               the source of connectivity for SQL operations on a
               per-entity basis.  The keys of the dictionary consist of
               any series of mapped classes, arbitrary Python classes
               that are bases for mapped classes, see Table
               objects and Mapper objects.  The values of
               the dictionary are then instances of Engine
               or less commonly Connection objects.
               Operations which proceed relative to a particular mapped
               class will consult this dictionary for the closest
               matching entity in order to determine which Engine
               should be used for a particular SQL operation.  The
               complete heuristics for resolution are described at
               Session.get_bind().  Usage looks like:

                    Session = sessionmaker(binds={
                        SomeMappedClass: create_engine('postgresql://engine1'),
                        SomeDeclarativeBase: create_engine('postgresql://engine2'),
                        some_mapper: create_engine('postgresql://engine3'),
                        some_table: create_engine('postgresql://engine4'),
                        })

               See also
               ........

               See Partitioning Strategies (e.g. multiple database backends per Session).

               See Session.bind_mapper().

               See Session.bind_table().

               See Session.get_bind().

             * ‘class_’ – Specify an alternate class other than
               ‘sqlalchemy.orm.session.Session’ which should be used by
               the returned class.  This is the only argument that is
               local to the sessionmaker function, and is
               not sent directly to the constructor for ‘Session’.

             * ‘enable_baked_queries’ – defaults to ‘True’.  A flag
               consumed by the sqlalchemy.ext.baked extension
               to determine if “baked queries” should be cached, as is
               the normal operation of this extension.  When set to
               ‘False’, all caching is disabled, including baked queries
               defined by the calling application as well as those used
               internally.  Setting this flag to ‘False’ can
               significantly reduce memory use, however will also
               degrade performance for those areas that make use of
               baked queries (such as relationship loaders).
               Additionally, baked query logic in the calling
               application or potentially within the ORM that may be
               malfunctioning due to cache key collisions or similar can
               be flagged by observing if this flag resolves the issue.

               New in version 1.2.

             * ‘expire_on_commit’ – Defaults to ‘True’.  When ‘True’,
               all instances will be fully expired after each
               commit(), so that all attribute/object access
               subsequent to a completed transaction will load from the
               most recent database state.

                    See also
                    ........

                    See Committing.

             * ‘future’ – if True, use 2.0 style transactional and
               engine behavior.  Future mode includes the following
               behaviors:

                  * The Session will not use “bound” metadata
                    in order to locate an Engine; the engine
                    or engines in use must be specified to the
                    constructor of Session or otherwise be
                    configured against the sessionmaker in
                    use

                  * The “subtransactions” feature of
                    Session.begin() is removed in version 2.0 and
                    is disabled when the future flag is set.

                  * The behavior of the
                    relationship.cascade_backrefs flag on a
                    relationship() will always assume “False”
                    behavior.

               New in version 1.4.

               See also
               ........

               See Migrating to SQLAlchemy 2.0.

             * ‘info’ – optional dictionary of arbitrary data to be
               associated with this Session.  Is available via
               the Session.info attribute.  Note the
               dictionary is copied at construction time so that
               modifications to the per- see Session dictionary
               will be local to that Session.

             * ‘query_cls’ – Class which should be used to create new
               Query objects, as returned by the Session.query()
               method.  Defaults to Query.

             * ‘twophase’ – When ‘True’, all transactions will be
               started as a “two phase” transaction, i.e.  using the
               “two phase” semantics of the database in use along with
               an XID. During a commit(), after flush()
               has been issued for all attached databases, the
               TwoPhaseTransaction.prepare() method on each
               database’s TwoPhaseTransaction will be
               called.  This allows each database to roll back the
               entire transaction, before each transaction is committed.

      -- Method: sqlalchemy.orm.Session..add (instance,
               _warn=True)

          Place an object in the ‘Session’.

          Its state will be persisted to the database on the next flush
          operation.

          Repeated calls to ‘add()’ will be ignored.  The opposite of
          ‘add()’ is ‘expunge()’.

      -- Method: sqlalchemy.orm.Session..add_all (instances)

          Add the given collection of instances to this ‘Session’.

      -- Method: sqlalchemy.orm.Session..begin
               (subtransactions=False, nested=False, _subtrans=False)

          Begin a transaction, or nested transaction, on this
          Session.

          When used to begin the outermost transaction, an error is
          raised if this Session is already inside of a
          transaction.

          Parameters:

             * ‘nested’ – if True, begins a SAVEPOINT transaction and is
               equivalent to calling Session.begin_nested().
               For documentation on SAVEPOINT transactions, please see
               Using SAVEPOINT.

             * ‘subtransactions’ – if True, indicates that this
               Session.begin() can create a “subtransaction”.

               Deprecated since version 1.4: The
               Session.begin.subtransactions flag is deprecated
               and will be removed in SQLAlchemy version 2.0.  See the
               documentation at Migrating from the “subtransaction” pattern
               for background on a
               compatible alternative pattern.

          Returns: the SessionTransaction object.  Note that
          SessionTransaction acts as a Python context
          manager, allowing Session.begin() to be used in a
          “with” block.  See Explicit Begin for an example.

          See also
          ........

          See Managing Transactions.

          See Session.begin_nested().

      -- Method: sqlalchemy.orm.Session..begin_nested ()

          Begin a “nested” transaction on this Session, e.g.  SAVEPOINT.

          The target database(s) and associated drivers must support SQL
          SAVEPOINT for this method to function correctly.

          For documentation on SAVEPOINT transactions, please see
          Using SAVEPOINT.

          Returns: the SessionTransaction object.  Note that
          SessionTransaction acts as a context manager,
          allowing Session.begin_nested() to be used in a
          “with” block.  See Using SAVEPOINT for a usage
          example.

          See also
          ........

          See Using SAVEPOINT.

          See Serializable isolation / Savepoints / Transactional DDL.
          - special workarounds required with the SQLite driver in
          order for SAVEPOINT to work correctly.

      -- Method: sqlalchemy.orm.Session..bind_mapper (mapper,
               bind)

          Associate a Mapper or arbitrary Python class with
          a “bind”, e.g.  an Engine or Connection.

          The given entity is added to a lookup used by the
          Session.get_bind() method.

          Parameters:

             * ‘mapper’ – a Mapper object, or an instance of
               a mapped class, or any Python class that is the base of a
               set of mapped classes.

             * ‘bind’ – an Engine or Connection.
               object.

          See also
          ........

          See Partitioning Strategies (e.g. multiple database backends per Session).

          See Session.binds.

          See Session.bind_table().

      -- Method: sqlalchemy.orm.Session..bind_table (table,
               bind)

          Associate a Table with a “bind”, e.g.  an
          Engine or Connection.

          The given Table is added to a lookup used by the
          Session.get_bind() method.

          Parameters:

             * ‘table’ – a Table object, which is typically
               the target of an ORM mapping, or is present within a
               selectable that is mapped.

             * ‘bind’ – an Engine or Connection.
               object.

          See also
          ........

          See Partitioning Strategies (e.g. multiple database backends per Session).

          See Session.binds.

          See Session.bind_mapper().

      -- Method: sqlalchemy.orm.Session..bulk_insert_mappings
               (mapper, mappings, return_defaults=False,
               render_nulls=False)

          Perform a bulk insert of the given list of mapping
          dictionaries.

          The bulk insert feature allows plain Python dictionaries to be
          used as the source of simple INSERT operations which can be
          more easily grouped together into higher performing
          “executemany” operations.  Using dictionaries, there is no
          “history” or session state management features in use,
          reducing latency when inserting large numbers of simple rows.

          The values within the dictionaries as given are typically
          passed without modification into Core
          sqlalchemy.sql.expression.Insert() constructs, after
          organizing the values within them across the tables to which
          the given mapper is mapped.

          New in version 1.0.0.

               Warning: The bulk insert feature allows for a
               lower-latency INSERT of rows at the expense of most other
               unit-of-work features.  Features such as object
               management, relationship handling, and SQL clause support
               are `silently omitted' in favor of raw INSERT of records.

               `Please read the list of caveats at' ORM Compatibility / Caveats.
               `before using this method,
               and fully test and confirm the functionality of all code
               developed using these systems.'

          Parameters:

             * ‘mapper’ – a mapped class, or the actual Mapper
               object, representing the single kind of object
               represented within the mapping list.

             * ‘mappings’ – a sequence of dictionaries, each one
               containing the state of the mapped row to be inserted, in
               terms of the attribute names on the mapped class.  If the
               mapping refers to multiple tables, such as a
               joined-inheritance mapping, each dictionary must contain
               all keys to be populated into all tables.

             * ‘return_defaults’ – when True, rows that are missing
               values which generate defaults, namely integer primary
               key defaults and sequences, will be inserted `one at a
               time', so that the primary key value is available.  In
               particular this will allow joined-inheritance and other
               multi-table mappings to insert correctly without the need
               to provide primary key values ahead of time; however,
               see Session.bulk_insert_mappings.return_defaults.
               `greatly reduces the performance gains' of the method
               overall.  If the rows to be inserted only refer to a
               single table, then there is no reason this flag should be
               set as the returned default information is not used.

             * ‘render_nulls’ – When True, a value of ‘None’ will result
               in a NULL value being included in the INSERT statement,
               rather than the column being omitted from the INSERT.
               This allows all the rows being INSERTed to have the
               identical set of columns which allows the full set of
               rows to be batched to the DBAPI. Normally, each
               column-set that contains a different combination of NULL
               values than the previous row must omit a different series
               of columns from the rendered INSERT statement, which
               means it must be emitted as a separate statement.  By
               passing this flag, the full set of rows are guaranteed to
               be batchable into one batch; the cost however is that
               server-side defaults which are invoked by an omitted
               column will be skipped, so care must be taken to ensure
               that these are not necessary.

                    Warning: When this flag is set, `server side default
                    SQL values will not be invoked' for those columns
                    that are inserted as NULL; the NULL value will be
                    sent explicitly.  Care must be taken to ensure that
                    no server-side default functions need to be invoked
                    for the operation as a whole.

               New in version 1.1.

          See also
          ........

          See Bulk Operations.

          See Session.bulk_save_objects().

          See Session.bulk_update_mappings().

      -- Method: sqlalchemy.orm.Session..bulk_save_objects
               (objects, return_defaults=False,
               update_changed_only=True, preserve_order=True)

          Perform a bulk save of the given list of objects.

          The bulk save feature allows mapped objects to be used as the
          source of simple INSERT and UPDATE operations which can be
          more easily grouped together into higher performing
          “executemany” operations; the extraction of data from the
          objects is also performed using a lower-latency process that
          ignores whether or not attributes have actually been modified
          in the case of UPDATEs, and also ignores SQL expressions.

          The objects as given are not added to the session and no
          additional state is established on them, unless the
          ‘return_defaults’ flag is also set, in which case primary key
          attributes and server-side default values will be populated.

          New in version 1.0.0.

               Warning: The bulk save feature allows for a lower-latency
               INSERT/UPDATE of rows at the expense of most other
               unit-of-work features.  Features such as object
               management, relationship handling, and SQL clause support
               are `silently omitted' in favor of raw INSERT/UPDATES of
               records.

               `Please read the list of caveats at' ORM Compatibility / Caveats.
               `before using this method,
               and fully test and confirm the functionality of all code
               developed using these systems.'

          Parameters:

             * ‘objects’ – a sequence of mapped object instances.  The
               mapped objects are persisted as is, and are `not'
               associated with the Session afterwards.

               For each object, whether the object is sent as an INSERT
               or an UPDATE is dependent on the same rules used by the
               Session in traditional operation; if the
               object has the ‘InstanceState.key’ attribute set, then
               the object is assumed to be “detached” and will result in
               an UPDATE. Otherwise, an INSERT is used.

               In the case of an UPDATE, statements are grouped based on
               which attributes have changed, and are thus to be the
               subject of each SET clause.  If ‘update_changed_only’ is
               False, then all attributes present within each object are
               applied to the UPDATE statement, which may help in
               allowing the statements to be grouped together into a
               larger executemany(), and will also reduce the overhead
               of checking history on attributes.

             * ‘return_defaults’ – when True, rows that are missing
               values which generate defaults, namely integer primary
               key defaults and sequences, will be inserted `one at a
               time', so that the primary key value is available.  In
               particular this will allow joined-inheritance and other
               multi-table mappings to insert correctly without the need
               to provide primary key values ahead of time; however,
               see Session.bulk_save_objects.return_defaults.
               `greatly reduces the performance gains' of the method
               overall.

             * ‘update_changed_only’ – when True, UPDATE statements are
               rendered based on those attributes in each state that
               have logged changes.  When False, all attributes present
               are rendered into the SET clause with the exception of
               primary key attributes.

             * ‘preserve_order’ – when True, the order of inserts and
               updates matches exactly the order in which the objects
               are given.  When False, common types of objects are
               grouped into inserts and updates, to allow for more
               batching opportunities.

               New in version 1.3.

          See also
          ........

          See Bulk Operations.

          See Session.bulk_insert_mappings().

          See Session.bulk_update_mappings().

      -- Method: sqlalchemy.orm.Session..bulk_update_mappings
               (mapper, mappings)

          Perform a bulk update of the given list of mapping
          dictionaries.

          The bulk update feature allows plain Python dictionaries to be
          used as the source of simple UPDATE operations which can be
          more easily grouped together into higher performing
          “executemany” operations.  Using dictionaries, there is no
          “history” or session state management features in use,
          reducing latency when updating large numbers of simple rows.

          New in version 1.0.0.

               Warning: The bulk update feature allows for a
               lower-latency UPDATE of rows at the expense of most other
               unit-of-work features.  Features such as object
               management, relationship handling, and SQL clause support
               are `silently omitted' in favor of raw UPDATES of
               records.

               `Please read the list of caveats at' ORM Compatibility / Caveats.
               `before using this method,
               and fully test and confirm the functionality of all code
               developed using these systems.'

          Parameters:

             * ‘mapper’ – a mapped class, or the actual Mapper
               object, representing the single kind of object
               represented within the mapping list.

             * ‘mappings’ – a sequence of dictionaries, each one
               containing the state of the mapped row to be updated, in
               terms of the attribute names on the mapped class.  If the
               mapping refers to multiple tables, such as a
               joined-inheritance mapping, each dictionary may contain
               keys corresponding to all tables.  All those keys which
               are present and are not part of the primary key are
               applied to the SET clause of the UPDATE statement; the
               primary key values, which are required, are applied to
               the WHERE clause.

          See also
          ........

          See Bulk Operations.

          See Session.bulk_insert_mappings().

          See Session.bulk_save_objects().

      -- Method: sqlalchemy.orm.Session..close ()

          Close this Session.

          This clears all items and ends any transaction in progress.

          If this Session was created with ‘autocommit=False’, a new
          transaction will be begun when the Session is next
          asked to procure a database connection.

          Changed in version 1.4: The Session.close() method
          does not immediately create a new SessionTransaction
          object; instead, the new SessionTransaction
          is created only if the Session is used again for a
          database operation.

      -- Method: sqlalchemy.orm.Session..classmethod close_all
               ()

          `inherited from the'
          ‘sqlalchemy.orm.session._SessionClassMethods.close_all’
          `method of' ‘sqlalchemy.orm.session._SessionClassMethods’

          Close `all' sessions in memory.

          Deprecated since version 1.3: The Session.close_all()
          method is deprecated and will be removed in a future
          release.  Please refer to ‘close_all_sessions()’.

      -- Method: sqlalchemy.orm.Session..commit ()

          Flush pending changes and commit the current transaction.

          If no transaction is in progress, the method will first
          “autobegin” a new transaction and commit.

          If 1.x-style use is in effect and there are currently
          SAVEPOINTs in progress via Session.begin_nested(),
          the operation will release the current SAVEPOINT but not
          commit the outermost database transaction.

          If 2.0-style use is in effect via the Session.future
          flag, the outermost database transaction is committed
          unconditionally, automatically releasing any SAVEPOINTs in
          effect.

          When using legacy “autocommit” mode, this method is only valid
          to call if a transaction is actually in progress, else an
          error is raised.  Similarly, when using legacy
          “subtransactions”, the method will instead close out the
          current “subtransaction”, rather than the actual database
          transaction, if a transaction is in progress.

          See also
          ........

          See Committing.

          See Managing Transactions.

      -- Method: sqlalchemy.orm.Session..connection
               (bind_arguments=None, close_with_result=False,
               execution_options=None, **kw)

          Return a Connection object corresponding to this
          Session object’s transactional state.

          If this Session is configured with
          ‘autocommit=False’, either the Connection
          corresponding to the current transaction is returned, or if no
          transaction is in progress, a new one is begun and the
          Connection returned (note that no transactional state is
          established with the DBAPI until the first SQL statement is
          emitted).

          Alternatively, if this Session is configured with
          ‘autocommit=True’, an ad-hoc Connection is
          returned using Engine.connect() on the underlying
          Engine.

          Ambiguity in multi-bind or unbound Session objects
          can be resolved through any of the optional keyword arguments.
          This ultimately makes usage of the get_bind()
          method for resolution.

          Parameters:

             * ‘bind_arguments’ – dictionary of bind arguments.  May
               include “mapper”, “bind”, “clause”, other custom
               arguments that are passed to Session.get_bind().

             * ‘bind’ – deprecated; use bind_arguments

             * ‘mapper’ – deprecated; use bind_arguments

             * ‘clause’ – deprecated; use bind_arguments

             * ‘close_with_result’ – Passed to Engine.connect(),
               indicating the Connection should be
               considered “single use”, automatically closing when the
               first result set is closed.  This flag only has an effect
               if this Session is configured with
               ‘autocommit=True’ and does not already have a transaction
               in progress.

             * ‘execution_options’ – a dictionary of execution options
               that will be passed to
               Connection.execution_options(), `when the connection
               is first procured only'.  If the connection is already
               present within the Session, a warning is
               emitted and the arguments are ignored.

               See also
               ........

               See Setting Transaction Isolation Levels / DBAPI AUTOCOMMIT.

             * ‘**kw’ – deprecated; use bind_arguments

      -- Method: sqlalchemy.orm.Session..delete (instance)

          Mark an instance as deleted.

          The database delete operation occurs upon ‘flush()’.

      -- Attribute: sqlalchemy.orm.Session..deleted

          The set of all instances marked as ‘deleted’ within this
          ‘Session’

      -- Attribute: sqlalchemy.orm.Session..dirty

          The set of all persistent instances considered dirty.

          E.g.:

               some_mapped_object in session.dirty

          Instances are considered dirty when they were modified but not
          deleted.

          Note that this ‘dirty’ calculation is ‘optimistic’; most
          attribute-setting or collection modification operations will
          mark an instance as ‘dirty’ and place it in this set, even if
          there is no net change to the attribute’s value.  At flush
          time, the value of each attribute is compared to its
          previously saved value, and if there’s no net change, no SQL
          operation will occur (this is a more expensive operation so
          it’s only done at flush time).

          To check if an instance has actionable net changes to its
          attributes, use the Session.is_modified() method.

      -- Method: sqlalchemy.orm.Session..
               enable_relationship_loading (obj)

          Associate an object with this Session for related
          object loading.

               Warning: enable_relationship_loading() exists
               to serve special use cases and is not recommended for
               general use.

          Accesses of attributes mapped with relationship()
          will attempt to load a value from the database using this
          Session as the source of connectivity.  The values
          will be loaded based on foreign key and primary key values
          present on this object - if not present, then those
          relationships will be unavailable.

          The object will be attached to this session, but will `not'
          participate in any persistence operations; its state for
          almost all purposes will remain either “transient” or
          “detached”, except for the case of relationship loading.

          Also note that backrefs will often not work as expected.
          Altering a relationship-bound attribute on the target object
          may not fire off a backref event, if the effective value is
          what was already loaded from a foreign-key-holding value.

          The Session.enable_relationship_loading() method
          is similar to the ‘load_on_pending’ flag on
          relationship().  Unlike that flag, see
          Session.enable_relationship_loading() allows an object
          to remain transient while still being able to load related
          items.

          To make a transient object associated with a Session
          via Session.enable_relationship_loading()
          pending, add it to the Session using
          Session.add() normally.  If the object instead
          represents an existing identity in the database, it should be
          merged using Session.merge().

          Session.enable_relationship_loading() does not
          improve behavior when the ORM is used normally - object
          references should be constructed at the object level, not at
          the foreign key level, so that they are present in an ordinary
          way before flush() proceeds.  This method is not intended for
          general use.

          See also
          ........

          See relationship.load_on_pending. - this flag allows
          per-relationship loading of many-to-ones on items that are
          pending.

          See make_transient_to_detached(). - allows for an
          object to be added to a Session without SQL
          emitted, which then will unexpire attributes on access.

      -- Method: sqlalchemy.orm.Session..execute (statement,
               params=None, execution_options={}, bind_arguments=None,
               _parent_execute_state=None, _add_event=None, **kw)

          Execute a SQL expression construct.

          Returns a Result object representing results of the
          statement execution.

          E.g.:

               from sqlalchemy import select
               result = session.execute(
                   select(User).where(User.id == 5)
               )

          The API contract of Session.execute() is similar to
          that of Connection.execute(), the 2.0 style version
          of Connection.

          Changed in version 1.4: the Session.execute()
          method is now the primary point of ORM statement execution
          when using 2.0 style ORM usage.

          Parameters:

             * ‘statement’ – An executable statement (i.e.  an
               Executable expression such as select()).

             * ‘params’ – Optional dictionary, or list of dictionaries,
               containing bound parameter values.  If a single
               dictionary, single-row execution occurs; if a list of
               dictionaries, an “executemany” will be invoked.  The keys
               in each dictionary must correspond to parameter names
               present in the statement.

             * ‘execution_options’ – optional dictionary of execution
               options, which will be associated with the statement
               execution.  This dictionary can provide a subset of the
               options that are accepted by
               ‘Connection.execution_options()’, and may also provide
               additional options understood only in an ORM context.

             * ‘bind_arguments’ – dictionary of additional arguments to
               determine the bind.  May include “mapper”, “bind”, or
               other custom arguments.  Contents of this dictionary are
               passed to the Session.get_bind() method.

             * ‘mapper’ – deprecated; use the bind_arguments dictionary

             * ‘bind’ – deprecated; use the bind_arguments dictionary

             * ‘**kw’ – deprecated; use the bind_arguments dictionary

          Returns: a Result object.

      -- Method: sqlalchemy.orm.Session..expire (instance,
               attribute_names=None)

          Expire the attributes on an instance.

          Marks the attributes of an instance as out of date.  When an
          expired attribute is next accessed, a query will be issued to
          the Session object’s current transactional context
          in order to load all expired attributes for the given
          instance.  Note that a highly isolated transaction will return
          the same values as were previously read in that same
          transaction, regardless of changes in database state outside
          of that transaction.

          To expire all objects in the Session
          simultaneously, use Session.expire_all().

          The Session object’s default behavior is to expire
          all state whenever the Session.rollback() or
          Session.commit() methods are called, so that new state
          can be loaded for the new transaction.  For this reason,
          calling Session.expire() only makes sense for the
          specific case that a non-ORM SQL statement was emitted in the
          current transaction.

          Parameters:

             * ‘instance’ – The instance to be refreshed.

             * ‘attribute_names’ – optional list of string attribute
               names indicating a subset of attributes to be expired.

          See also
          ........

          See Refreshing / Expiring. - introductory material

          See Session.expire().

          See Session.refresh().

          See Query.populate_existing().

      -- Method: sqlalchemy.orm.Session..expire_all ()

          Expires all persistent instances within this Session.

          When any attributes on a persistent instance is next accessed,
          a query will be issued using the Session object’s
          current transactional context in order to load all expired
          attributes for the given instance.  Note that a highly
          isolated transaction will return the same values as were
          previously read in that same transaction, regardless of
          changes in database state outside of that transaction.

          To expire individual objects and individual attributes on
          those objects, use Session.expire().

          The Session object’s default behavior is to expire
          all state whenever the Session.rollback() or
          Session.commit() methods are called, so that new state
          can be loaded for the new transaction.  For this reason,
          calling Session.expire_all() should not be needed
          when autocommit is ‘False’, assuming the transaction is
          isolated.

          See also
          ........

          See Refreshing / Expiring. - introductory material

          See Session.expire().

          See Session.refresh().

          See Query.populate_existing().

      -- Method: sqlalchemy.orm.Session..expunge (instance)

          Remove the ‘instance’ from this ‘Session’.

          This will free all internal references to the instance.
          Cascading will be applied according to the `expunge' cascade
          rule.

      -- Method: sqlalchemy.orm.Session..expunge_all ()

          Remove all object instances from this ‘Session’.

          This is equivalent to calling ‘expunge(obj)’ on all objects in
          this ‘Session’.

      -- Method: sqlalchemy.orm.Session..flush (objects=None)

          Flush all the object changes to the database.

          Writes out all pending object creations, deletions and
          modifications to the database as INSERTs, DELETEs, UPDATEs,
          etc.  Operations are automatically ordered by the Session’s
          unit of work dependency solver.

          Database operations will be issued in the current
          transactional context and do not affect the state of the
          transaction, unless an error occurs, in which case the entire
          transaction is rolled back.  You may flush() as often as you
          like within a transaction to move changes from Python to the
          database’s transaction buffer.

          For ‘autocommit’ Sessions with no active manual transaction,
          flush() will create a transaction on the fly that surrounds
          the entire set of operations into the flush.

          Parameters: ‘objects’ – Optional; restricts the flush
          operation to operate only on elements that are in the given
          collection.

          This feature is for an extremely narrow set of use cases where
          particular objects may need to be operated upon before the
          full flush() occurs.  It is not intended for general use.

      -- Method: sqlalchemy.orm.Session..get (entity, ident,
               options=None, populate_existing=False,
               with_for_update=None, identity_token=None)

          Return an instance based on the given primary key identifier,
          or ‘None’ if not found.

          E.g.:

               my_user = session.get(User, 5)

               some_object = session.get(VersionedFoo, (5, 10))

               some_object = session.get(
                   VersionedFoo,
                   {"id": 5, "version_id": 10}
               )

          New in version 1.4: Added Session.get(), which is
          moved from the now deprecated Query.get() method.

          Session.get() is special in that it provides
          direct access to the identity map of the Session.
          If the given primary key identifier is present in the local
          identity map, the object is returned directly from this
          collection and no SQL is emitted, unless the object has been
          marked fully expired.  If not present, a SELECT is performed
          in order to locate the object.

          Session.get() also will perform a check if the
          object is present in the identity map and marked as expired -
          a SELECT is emitted to refresh the object as well as to ensure
          that the row is still present.  If not, see
          ObjectDeletedError is raised.

          Parameters:

             * ‘entity’ – a mapped class or Mapper.
               indicating the type of entity to be loaded.

             * ‘ident’ – A scalar, tuple, or dictionary representing the
               primary key.  For a composite (e.g.  multiple column)
               primary key, a tuple or dictionary should be passed.

               For a single-column primary key, the scalar calling form
               is typically the most expedient.  If the primary key of a
               row is the value “5”, the call looks like:

                    my_object = session.get(SomeClass, 5)

               The tuple form contains primary key values typically in
               the order in which they correspond to the mapped
               Table object’s primary key columns, or if the
               Mapper.primary_key configuration parameter were
               used, in the order used for that parameter.  For example,
               if the primary key of a row is represented by the integer
               digits “5, 10” the call would look like:

                    my_object = session.get(SomeClass, (5, 10))

               The dictionary form should include as keys the mapped
               attribute names corresponding to each element of the
               primary key.  If the mapped class has the attributes
               ‘id’, ‘version_id’ as the attributes which store the
               object’s primary key value, the call would look like:

                    my_object = session.get(SomeClass, {"id": 5, "version_id": 10})

             * ‘options’ – optional sequence of loader options which
               will be applied to the query, if one is emitted.

             * ‘populate_existing’ – causes the method to
               unconditionally emit a SQL query and refresh the object
               with the newly loaded data, regardless of whether or not
               the object is already present.

             * ‘with_for_update’ – optional boolean ‘True’ indicating
               FOR UPDATE should be used, or may be a dictionary
               containing flags to indicate a more specific set of FOR
               UPDATE flags for the SELECT; flags should match the
               parameters of Query.with_for_update().
               Supersedes the Session.refresh.lockmode
               parameter.

          Returns: The object instance, or ‘None’.

      -- Method: sqlalchemy.orm.Session..get_bind
               (mapper=None, clause=None, bind=None,
               _sa_skip_events=None,
               _sa_skip_for_implicit_returning=False)

          Return a “bind” to which this Session is bound.

          The “bind” is usually an instance of Engine, except
          in the case where the Session has been explicitly
          bound directly to a Connection.

          For a multiply-bound or unbound Session, the
          ‘mapper’ or ‘clause’ arguments are used to determine the
          appropriate bind to return.

          Note that the “mapper” argument is usually present when
          Session.get_bind() is called via an ORM operation such
          as a Session.query(), each individual
          INSERT/UPDATE/DELETE operation within a Session.flush(),
          call, etc.

          The order of resolution is:

            1. if mapper given and Session.binds is present,
               locate a bind based first on the mapper in use, then on
               the mapped class in use, then on any base classes that
               are present in the ‘__mro__’ of the mapped class, from
               more specific superclasses to more general.

            2. if clause given and ‘Session.binds’ is present, locate a
               bind based on Table objects found in the given
               clause present in ‘Session.binds’.

            3. if ‘Session.binds’ is present, return that.

            4. if clause given, attempt to return a bind linked to the
               MetaData ultimately associated with the
               clause.

            5. if mapper given, attempt to return a bind linked to the
               MetaData ultimately associated with the
               Table or other selectable to which the mapper is
               mapped.

            6. No bind can be found, see UnboundExecutionError.
               is raised.

          Note that the Session.get_bind() method can be
          overridden on a user-defined subclass of Session to
          provide any kind of bind resolution scheme.  See the example
          at Custom Vertical Partitioning.

          Parameters:

             * ‘mapper’ – Optional mapper() mapped class or
               instance of Mapper.  The bind can be derived
               from a Mapper first by consulting the “binds”
               map associated with this Session, and secondly
               by consulting the MetaData associated with the
               Table to which the Mapper is
               mapped for a bind.

             * ‘clause’ – A ClauseElement. (i.e.  see
               select(), text(), etc.).  If the ‘mapper’
               argument is not present or could not produce a bind, the
               given expression construct will be searched for a bound
               element, typically a Table associated with
               bound MetaData.

          See also
          ........

          See Partitioning Strategies (e.g. multiple database backends per Session).

          See Session.binds.

          See Session.bind_mapper().

          See Session.bind_table().

      -- Method: sqlalchemy.orm.Session..
               get_nested_transaction ()

          Return the current nested transaction in progress, if any.

          New in version 1.4.

      -- Method: sqlalchemy.orm.Session..get_transaction ()

          Return the current root transaction in progress, if any.

          New in version 1.4.

      -- Method: sqlalchemy.orm.Session..classmethod
               identity_key (*args, **kwargs)

          `inherited from the'
          ‘sqlalchemy.orm.session._SessionClassMethods.identity_key’
          `method of' ‘sqlalchemy.orm.session._SessionClassMethods’

          Return an identity key.

          This is an alias of identity_key().

      -- Attribute: sqlalchemy.orm.Session..identity_map =
               None

          A mapping of object identities to objects themselves.

          Iterating through ‘Session.identity_map.values()’ provides
          access to the full set of persistent objects (i.e., those that
          have row identity) currently in the session.

          See also
          ........

          See identity_key(). - helper function to produce the
          keys used in this dictionary.

      -- Method: sqlalchemy.orm.Session..in_nested_transaction
               ()

          Return True if this Session has begun a nested
          transaction, e.g.  SAVEPOINT.

          New in version 1.4.

      -- Method: sqlalchemy.orm.Session..in_transaction ()

          Return True if this Session has begun a
          transaction.

          New in version 1.4.

          See also
          ........

          See Session.is_active.

      -- Attribute: sqlalchemy.orm.Session..info

          A user-modifiable dictionary.

          The initial value of this dictionary can be populated using
          the ‘info’ argument to the Session constructor or
          sessionmaker constructor or factory methods.  The
          dictionary here is always local to this Session and
          can be modified independently of all other Session
          objects.

      -- Method: sqlalchemy.orm.Session..invalidate ()

          Close this Session, using connection invalidation.

          This is a variant of Session.close() that will
          additionally ensure that the Connection.invalidate()
          method will be called on each Connection
          object that is currently in use for a transaction (typically
          there is only one connection unless the Session is
          used with multiple engines).

          This can be called when the database is known to be in a state
          where the connections are no longer safe to be used.

          Below illustrates a scenario when using gevent(1), which can
          produce ‘Timeout’ exceptions that may mean the underlying
          connection should be discarded:

               import gevent

               try:
                   sess = Session()
                   sess.add(User())
                   sess.commit()
               except gevent.Timeout:
                   sess.invalidate()
                   raise
               except:
                   sess.rollback()
                   raise

          The method additionally does everything that
          Session.close() does, including that all ORM objects are
          expunged.

      -- Attribute: sqlalchemy.orm.Session..is_active

          True if this Session not in “partial rollback”
          state.

          Changed in version 1.4: The Session no longer
          begins a new transaction immediately, so this attribute will
          be False when the Session is first instantiated.

          “partial rollback” state typically indicates that the flush
          process of the Session has failed, and that the
          Session.rollback() method must be emitted in order
          to fully roll back the transaction.

          If this Session is not in a transaction at all, the
          Session will autobegin when it is first used, so in
          this case Session.is_active will return True.

          Otherwise, if this Session is within a transaction,
          and that transaction has not been rolled back internally, the
          Session.is_active will also return True.

          See also
          ........

          See “This Session’s transaction has been rolled back due to a previous exception during flush.” (or similar).

          See Session.in_transaction().

      -- Method: sqlalchemy.orm.Session..is_modified
               (instance, include_collections=True)

          Return ‘True’ if the given instance has locally modified
          attributes.

          This method retrieves the history for each instrumented
          attribute on the instance and performs a comparison of the
          current value to its previously committed value, if any.

          It is in effect a more expensive and accurate version of
          checking for the given instance in the Session.dirty
          collection; a full test for each attribute’s net “dirty”
          status is performed.

          E.g.:

               return session.is_modified(someobject)

          A few caveats to this method apply:

             * Instances present in the Session.dirty.
               collection may report ‘False’ when tested with this
               method.  This is because the object may have received
               change events via attribute mutation, thus placing it in
               Session.dirty, but ultimately the state is the
               same as that loaded from the database, resulting in no
               net change here.

             * Scalar attributes may not have recorded the previously
               set value when a new value was applied, if the attribute
               was not loaded, or was expired, at the time the new value
               was received - in these cases, the attribute is assumed
               to have a change, even if there is ultimately no net
               change against its database value.  SQLAlchemy in most
               cases does not need the “old” value when a set event
               occurs, so it skips the expense of a SQL call if the old
               value isn’t present, based on the assumption that an
               UPDATE of the scalar value is usually needed, and in
               those few cases where it isn’t, is less expensive on
               average than issuing a defensive SELECT.

               The “old” value is fetched unconditionally upon set only
               if the attribute container has the ‘active_history’ flag
               set to ‘True’.  This flag is set typically for primary
               key attributes and scalar object references that are not
               a simple many-to-one.  To set this flag for any arbitrary
               mapped column, use the ‘active_history’ argument with
               column_property().

          Parameters:

             * ‘instance’ – mapped instance to be tested for pending
               changes.

             * ‘include_collections’ – Indicates if multivalued
               collections should be included in the operation.  Setting
               this to ‘False’ is a way to detect only local-column
               based properties (i.e.  scalar columns or many-to-one
               foreign keys) that would result in an UPDATE for this
               instance upon flush.

      -- Method: sqlalchemy.orm.Session..merge (instance,
               load=True)

          Copy the state of a given instance into a corresponding
          instance within this Session.

          Session.merge() examines the primary key
          attributes of the source instance, and attempts to reconcile
          it with an instance of the same primary key in the session.
          If not found locally, it attempts to load the object from the
          database based on primary key, and if none can be located,
          creates a new instance.  The state of each attribute on the
          source instance is then copied to the target instance.  The
          resulting target instance is then returned by the method; the
          original source instance is left unmodified, and un-associated
          with the Session if not already.

          This operation cascades to associated instances if the
          association is mapped with ‘cascade="merge"’.

          See Merging for a detailed discussion of merging.

          Changed in version 1.1: - see Session.merge() will now
          reconcile pending objects with overlapping primary keys in the
          same way as persistent.  See Session.merge resolves pending conflicts the same as persistent
          for discussion.

          Parameters:

             * ‘instance’ – Instance to be merged.

             * ‘load’ – Boolean, when False, see merge().
               switches into a “high performance” mode which causes it
               to forego emitting history events as well as all database
               access.  This flag is used for cases such as transferring
               graphs of objects into a Session from a second
               level cache, or to transfer just-loaded objects into the
               Session owned by a worker thread or process
               without re-querying the database.

               The ‘load=False’ use case adds the caveat that the given
               object has to be in a “clean” state, that is, has no
               pending changes to be flushed - even if the incoming
               object is detached from any Session.  This is
               so that when the merge operation populates local
               attributes and cascades to related objects and
               collections, the values can be “stamped” onto the target
               object as is, without generating any history or attribute
               events, and without the need to reconcile the incoming
               data with any existing related objects or collections
               that might not be loaded.  The resulting objects from
               ‘load=False’ are always produced as “clean”, so it is
               only appropriate that the given objects should be “clean”
               as well, else this suggests a mis-use of the method.

          See also
          ........

          See make_transient_to_detached(). - provides for an
          alternative means of “merging” a single object into the
          Session.

      -- Attribute: sqlalchemy.orm.Session..new

          The set of all instances marked as ‘new’ within this
          ‘Session’.

      -- Attribute: sqlalchemy.orm.Session..no_autoflush

          Return a context manager that disables autoflush.

          e.g.:

               with session.no_autoflush:

                   some_object = SomeClass()
                   session.add(some_object)
                   # won't autoflush
                   some_object.related_thing = session.query(SomeRelated).first()

          Operations that proceed within the ‘with:’ block will not be
          subject to flushes occurring upon query access.  This is
          useful when initializing a series of objects which involve
          existing database queries, where the uncompleted object should
          not yet be flushed.

      -- Method: sqlalchemy.orm.Session..classmethod
               object_session (instance)

          `inherited from the'
          ‘sqlalchemy.orm.session._SessionClassMethods.object_session’
          `method of' ‘sqlalchemy.orm.session._SessionClassMethods’

          Return the Session to which an object belongs.

          This is an alias of object_session().

      -- Method: sqlalchemy.orm.Session..prepare ()

          Prepare the current transaction in progress for two phase
          commit.

          If no transaction is in progress, this method raises an
          InvalidRequestError.

          Only root transactions of two phase sessions can be prepared.
          If the current transaction is not such, an
          InvalidRequestError is raised.

      -- Method: sqlalchemy.orm.Session..query (*entities,
               **kwargs)

          Return a new Query object corresponding to this
          Session.

      -- Method: sqlalchemy.orm.Session..refresh (instance,
               attribute_names=None, with_for_update=None)

          Expire and refresh the attributes on the given instance.

          A query will be issued to the database and all attributes will
          be refreshed with their current database value.

          Lazy-loaded relational attributes will remain lazily loaded,
          so that the instance-wide refresh operation will be followed
          immediately by the lazy load of that attribute.

          Eagerly-loaded relational attributes will eagerly load within
          the single refresh operation.

          Note that a highly isolated transaction will return the same
          values as were previously read in that same transaction,
          regardless of changes in database state outside of that
          transaction - usage of Session.refresh() usually
          only makes sense if non-ORM SQL statement were emitted in the
          ongoing transaction, or if autocommit mode is turned on.

          Parameters:

             * ‘attribute_names’ – optional.  An iterable collection of
               string attribute names indicating a subset of attributes
               to be refreshed.

             * ‘with_for_update’ – optional boolean ‘True’ indicating
               FOR UPDATE should be used, or may be a dictionary
               containing flags to indicate a more specific set of FOR
               UPDATE flags for the SELECT; flags should match the
               parameters of Query.with_for_update().
               Supersedes the Session.refresh.lockmode
               parameter.

               New in version 1.2.

          See also
          ........

          See Refreshing / Expiring. - introductory material

          See Session.expire().

          See Session.expire_all().

          See Query.populate_existing().

      -- Method: sqlalchemy.orm.Session..rollback ()

          Rollback the current transaction in progress.

          If no transaction is in progress, this method is a
          pass-through.

          In 1.x-style use, this method rolls back the topmost database
          transaction if no nested transactions are in effect, or to the
          current nested transaction if one is in effect.

          When 2.0-style use is in effect via the Session.future
          flag, the method always rolls back the topmost database
          transaction, discarding any nested transactions that may be in
          progress.

          See also
          ........

          See Rolling Back.

          See Managing Transactions.

      -- Method: sqlalchemy.orm.Session..scalar (statement,
               params=None, execution_options={}, bind_arguments=None,
               **kw)

          Execute a statement and return a scalar result.

          Usage and parameters are the same as that of
          Session.execute(); the return result is a scalar Python
          value.

      -- Attribute: sqlalchemy.orm.Session..transaction

          The current active or inactive SessionTransaction.

          Deprecated since version 1.4: The Session.transaction
          attribute is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  For context manager
          use, use Session.begin().  To access the current
          root transaction, use Session.get_transaction().
          (Background on SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

          May be None if no transaction has begun yet.

          Changed in version 1.4: the Session.transaction
          attribute is now a read-only descriptor that also may return
          None if no transaction has begun yet.

 -- Class: sqlalchemy.orm.SessionTransaction (session, parent=None,
          nested=False, autobegin=False)

     A Session.-level transaction.

     SessionTransaction is produced from the
     Session.begin() and Session.begin_nested()
     methods.  It’s largely an internal object that in modern use
     provides a context manager for session transactions.

     Documentation on interacting with SessionTransaction is
     at: Managing Transactions.

     Changed in version 1.4: The scoping and API methods to work with
     the SessionTransaction object directly have been
     simplified.

     See also
     ........

     See Managing Transactions.

     See Session.begin().

     See Session.begin_nested().

     See Session.rollback().

     See Session.commit().

     See Session.in_transaction().

     See Session.in_nested_transaction().

     See Session.get_transaction().

     See Session.get_nested_transaction().

      -- Attribute: sqlalchemy.orm.SessionTransaction..nested
               = False

          Indicates if this is a nested, or SAVEPOINT, transaction.

          When SessionTransaction.nested is True, it is
          expected that SessionTransaction.parent will be
          True as well.

      -- Attribute: sqlalchemy.orm.SessionTransaction..parent

          The parent SessionTransaction of this
          SessionTransaction.

          If this attribute is ‘None’, indicates this
          SessionTransaction is at the top of the stack, and
          corresponds to a real “COMMIT”/”ROLLBACK” block.  If
          non-‘None’, then this is either a “subtransaction” or a
          “nested” / SAVEPOINT transaction.  If the
          SessionTransaction.nested attribute is ‘True’, then this
          is a SAVEPOINT, and if ‘False’, indicates this a
          subtransaction.

          New in version 1.0.16: - use ._parent for previous versions

   ---------- Footnotes ----------

   (1) http://www.gevent.org/

3.5.8.2 Session Utilities
.........................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See close_all_sessions.()Close all sessions in memory.

See make_transient.(instance)Alter the state of the given instance so that it is transient.

See make_transient_to_detached.(instance)Make the given transient instance detached.

See object_session.(instance)Return the Session to which the given instance belongs.

See was_deleted.(object_)Return True if the given object was deleted within a session flush.

 -- Function: sqlalchemy.orm.close_all_sessions ()

     Close all sessions in memory.

     This function consults a global registry of all Session
     objects and calls Session.close() on them, which resets
     them to a clean state.

     This function is not for general use but may be useful for test
     suites within the teardown scheme.

     New in version 1.3.

 -- Function: sqlalchemy.orm.make_transient (instance)

     Alter the state of the given instance so that it is transient.

          Note: make_transient() is a special-case function
          for advanced use cases only.

     The given mapped instance is assumed to be in the persistent or
     detached state.  The function will remove its association with any
     Session as well as its InstanceState.identity.
     The effect is that the object will behave as though it were
     newly constructed, except retaining any attribute / collection
     values that were loaded at the time of the call.  The
     InstanceState.deleted flag is also reset if this object had
     been deleted as a result of using Session.delete().

          Warning: make_transient() does `not' “unexpire” or
          otherwise eagerly load ORM-mapped attributes that are not
          currently loaded at the time the function is called.  This
          includes attributes which:

             * were expired via Session.expire().

             * were expired as the natural effect of committing a
               session transaction, e.g.  see Session.commit().

             * are normally lazy loaded but are not currently loaded

             * are “deferred” via Deferred Column Loading.
               and are not yet loaded

             * were not present in the query which loaded this object,
               such as that which is common in joined table inheritance
               and other scenarios.

          After make_transient() is called, unloaded
          attributes such as those above will normally resolve to the
          value ‘None’ when accessed, or an empty collection for a
          collection-oriented attribute.  As the object is transient and
          un-associated with any database identity, it will no longer
          retrieve these values.

     See also
     ........

     See make_transient_to_detached().

 -- Function: sqlalchemy.orm.make_transient_to_detached (instance)

     Make the given transient instance detached.

          Note: make_transient_to_detached() is a
          special-case function for advanced use cases only.

     All attribute history on the given instance will be reset as though
     the instance were freshly loaded from a query.  Missing attributes
     will be marked as expired.  The primary key attributes of the
     object, which are required, will be made into the “key” of the
     instance.

     The object can then be added to a session, or merged possibly with
     the load=False flag, at which point it will look as if it were
     loaded that way, without emitting SQL.

     This is a special use case function that differs from a normal call
     to Session.merge() in that a given persistent state can
     be manufactured without any SQL calls.

     See also
     ........

     See make_transient().

     See Session.enable_relationship_loading().

 -- Function: sqlalchemy.orm.object_session (instance)

     Return the Session to which the given instance belongs.

     This is essentially the same as the InstanceState.session
     accessor.  See that attribute for details.

 -- Function: sqlalchemy.orm.util.was_deleted (object_)

     Return True if the given object was deleted within a session flush.

     This is regardless of whether or not the object is persistent or
     detached.

     See also
     ........

     See InstanceState.was_deleted.

3.5.8.3 Attribute and State Management Utilities
................................................

These functions are provided by the SQLAlchemy attribute instrumentation
API to provide a detailed interface for dealing with instances,
attribute values, and history.  Some of them are useful when
constructing event listener functions, such as those described in
ORM Events.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See del_attribute.(instance,Delete the value of an attribute, firing history events.
key)

See flag_dirty.(instance)Mark an instance as ‘dirty’ without any specific attribute mentioned.

See flag_modified.(instance,Mark an attribute on an instance as ‘modified’.
key)

See get_attribute.(instance,Get the value of an attribute, firing any callables required.
key)

See get_history.(obj,Return a History record for the given object and attribute key.
key[,
passive])

See History.A 3-tuple of added, unchanged and deleted values, representing the changes which have
               occurred on an instrumented attribute.

See init_collection.(obj,Initialize a collection attribute and return the collection adapter.
key)

See instance_state.Return the InstanceState for a given mapped object.

See is_instrumented.(instance,Return True if the given attribute on the given instance is instrumented by the attributes
key)           package.

See object_state.(instance)Given an object, return the InstanceState associated with the object.

See set_attribute.(instance,Set the value of an attribute, firing history events.
key, value[,
initiator])

See set_committed_value.(instance,Set the value of an attribute with no history events.
key, value)

 -- Function: sqlalchemy.orm.util.object_state (instance)

     Given an object, return the InstanceState associated
     with the object.

     Raises sqlalchemy.orm.exc.UnmappedInstanceError if no
     mapping is configured.

     Equivalent functionality is available via the inspect()
     function as:

          inspect(instance)

     Using the inspection system will raise
     sqlalchemy.exc.NoInspectionAvailable if the instance is not
     part of a mapping.

 -- Function: sqlalchemy.orm.attributes.del_attribute (instance, key)

     Delete the value of an attribute, firing history events.

     This function may be used regardless of instrumentation applied
     directly to the class, i.e.  no descriptors are required.  Custom
     attribute management schemes will need to make usage of this method
     to establish attribute state as understood by SQLAlchemy.

 -- Function: sqlalchemy.orm.attributes.get_attribute (instance, key)

     Get the value of an attribute, firing any callables required.

     This function may be used regardless of instrumentation applied
     directly to the class, i.e.  no descriptors are required.  Custom
     attribute management schemes will need to make usage of this method
     to make usage of attribute state as understood by SQLAlchemy.

 -- Function: sqlalchemy.orm.attributes.get_history (obj, key,
          passive=symbol('PASSIVE_OFF'))

     Return a History record for the given object and
     attribute key.

     This is the `pre-flush' history for a given attribute, which is
     reset each time the Session flushes changes to the
     current database transaction.

          Note: Prefer to use the AttributeState.history and
          AttributeState.load_history() accessors to
          retrieve the History for instance attributes.

     Parameters:

        * ‘obj’ – an object whose class is instrumented by the
          attributes package.

        * ‘key’ – string attribute name.

        * ‘passive’ – indicates loading behavior for the attribute if
          the value is not already present.  This is a bitflag
          attribute, which defaults to the symbol ‘PASSIVE_OFF’
          indicating all necessary SQL should be emitted.

     See also
     ........

     See AttributeState.history.

     See AttributeState.load_history(). - retrieve history using
     loader callables if the value is not locally present.

 -- Function: sqlalchemy.orm.attributes.init_collection (obj, key)

     Initialize a collection attribute and return the collection
     adapter.

     This function is used to provide direct access to collection
     internals for a previously unloaded attribute.  e.g.:

          collection_adapter = init_collection(someobject, 'elements')
          for elem in values:
              collection_adapter.append_without_event(elem)

     For an easier way to do the above, see set_committed_value().

     Parameters:

        * ‘obj’ – a mapped object

        * ‘key’ – string attribute name where the collection is located.

 -- Function: sqlalchemy.orm.attributes.flag_modified (instance, key)

     Mark an attribute on an instance as ‘modified’.

     This sets the ‘modified’ flag on the instance and establishes an
     unconditional change event for the given attribute.  The attribute
     must have a value present, else an InvalidRequestError
     is raised.

     To mark an object “dirty” without referring to any specific
     attribute so that it is considered within a flush, use the
     flag_dirty() call.

     See also
     ........

     See flag_dirty().

 -- Function: sqlalchemy.orm.attributes.flag_dirty (instance)

     Mark an instance as ‘dirty’ without any specific attribute
     mentioned.

     This is a special operation that will allow the object to travel
     through the flush process for interception by events such as
     SessionEvents.before_flush().  Note that no SQL will be
     emitted in the flush process for an object that has no changes,
     even if marked dirty via this method.  However, a
     SessionEvents.before_flush() handler will be able to see the
     object in the Session.dirty collection and may
     establish changes on it, which will then be included in the SQL
     emitted.

     New in version 1.2.

     See also
     ........

     See flag_modified().

 -- Function: sqlalchemy.orm.attributes.instance_state ()

     Return the InstanceState for a given mapped object.

     This function is the internal version of object_state().
     The object_state() and/or the inspect()
     function is preferred here as they each emit an informative
     exception if the given object is not mapped.

 -- Function: sqlalchemy.orm.instrumentation.is_instrumented (instance,
          key)

     Return True if the given attribute on the given instance is
     instrumented by the attributes package.

     This function may be used regardless of instrumentation applied
     directly to the class, i.e.  no descriptors are required.

 -- Function: sqlalchemy.orm.attributes.set_attribute (instance, key,
          value, initiator=None)

     Set the value of an attribute, firing history events.

     This function may be used regardless of instrumentation applied
     directly to the class, i.e.  no descriptors are required.  Custom
     attribute management schemes will need to make usage of this method
     to establish attribute state as understood by SQLAlchemy.

     Parameters:

        * ‘instance’ – the object that will be modified

        * ‘key’ – string name of the attribute

        * ‘value’ – value to assign

        * ‘initiator’ – an instance of ‘Event’ that would have been
          propagated from a previous event listener.  This argument is
          used when the set_attribute() function is being
          used within an existing event listening function where an
          ‘Event’ object is being supplied; the object may be used to
          track the origin of the chain of events.

          New in version 1.2.3.

 -- Function: sqlalchemy.orm.attributes.set_committed_value (instance,
          key, value)

     Set the value of an attribute with no history events.

     Cancels any previous history present.  The value should be a scalar
     value for scalar-holding attributes, or an iterable for any
     collection-holding attribute.

     This is the same underlying method used when a lazy loader fires
     off and loads additional data from the database.  In particular,
     this method can be used by application code which has loaded
     additional attributes or collections through separate queries,
     which can then be attached to an instance as though it were part of
     its original loaded state.

 -- Class: sqlalchemy.orm.attributes.History (added, unchanged, deleted)

     A 3-tuple of added, unchanged and deleted values, representing the
     changes which have occurred on an instrumented attribute.

     The easiest way to get a History object for a
     particular attribute on an object is to use the inspect()
     function:

          from sqlalchemy import inspect

          hist = inspect(myobject).attrs.myattribute.history

     Each tuple member is an iterable sequence:

        * ‘added’ - the collection of items added to the attribute (the
          first tuple element).

        * ‘unchanged’ - the collection of items that have not changed on
          the attribute (the second tuple element).

        * ‘deleted’ - the collection of items that have been removed
          from the attribute (the third tuple element).

     `Class signature'

     class ‘sqlalchemy.orm.History’ (‘sqlalchemy.orm.History’)

      -- Method: sqlalchemy.orm.attributes.History..empty ()

          Return True if this History has no changes and no
          existing, unchanged state.

      -- Method: sqlalchemy.orm.attributes.History..
               has_changes ()

          Return True if this History has changes.

      -- Method: sqlalchemy.orm.attributes.History..non_added
               ()

          Return a collection of unchanged + deleted.

      -- Method: sqlalchemy.orm.attributes.History..
               non_deleted ()

          Return a collection of added + unchanged.

      -- Method: sqlalchemy.orm.attributes.History..sum ()

          Return a collection of added + unchanged + deleted.

3.6 Events and Internals
========================

The SQLAlchemy ORM as well as Core are extended generally through the
use of event hooks.  Be sure to review the use of the event system in
general at Events.

3.6.1 ORM Events
----------------

The ORM includes a wide variety of hooks available for subscription.

For an introduction to the most commonly used ORM events, see the
section Tracking queries, object and Session Changes with Events.
The event system in general is discussed at Events.
Non-ORM events such as those regarding connections and low-level
statement execution are described in Core Events.

3.6.1.1 Session Events
......................

The most basic event hooks are available at the level of the ORM
Session object.  The types of things that are intercepted here
include:

   * `Persistence Operations' - the ORM flush process that sends changes
     to the database can be extended using events that fire off at
     different parts of the flush, to augment or modify the data being
     sent to the database or to allow other things to happen when
     persistence occurs.  Read more about persistence events at
     Persistence Events.

   * `Object lifecycle events' - hooks when objects are added,
     persisted, deleted from sessions.  Read more about these at
     Object Lifecycle Events.

   * `Execution Events' - Part of the 2.0 style execution model, all
     SELECT statements against ORM entities emitted, as well as bulk
     UPDATE and DELETE statements outside of the flush process, are
     intercepted from the Session.execute() method using the
     SessionEvents.do_orm_execute() method.  Read more about
     this event at Execute Events.

Be sure to read the Tracking queries, object and Session Changes with Events
chapter for context on these events.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See SessionEvents.Define events specific to Session lifecycle.

 -- Class: sqlalchemy.orm.SessionEvents

     Define events specific to Session lifecycle.

     e.g.:

          from sqlalchemy import event
          from sqlalchemy.orm import sessionmaker

          def my_before_commit(session):
              print("before commit!")

          Session = sessionmaker()

          event.listen(Session, "before_commit", my_before_commit)

     The listen() function will accept Session
     objects as well as the return result of sessionmaker()
     and scoped_session().

     Additionally, it accepts the Session class which will
     apply listeners to all Session instances globally.

     Parameters:

        * ‘raw=False’ – When True, the “target” argument passed to
          applicable event listener functions that work on individual
          objects will be the instance’s InstanceState
          management object, rather than the mapped instance itself.

          New in version 1.3.14.

        * ‘restore_load_context=False’ – Applies to the
          SessionEvents.loaded_as_persistent() event.  Restores
          the loader context of the object when the event hook is
          complete, so that ongoing eager load operations continue to
          target the object appropriately.  A warning is emitted if the
          object is moved to a new loader context from within this event
          if this flag is not set.

          New in version 1.3.14.

     `Class signature'

     class sqlalchemy.orm.SessionEvents.
     (‘sqlalchemy.event.Events’)

      -- Method: sqlalchemy.orm.SessionEvents..after_attach
               (session, instance)

          Execute after an instance is attached to a session.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'after_attach')
               def receive_after_attach(session, instance):
                   "listen for the 'after_attach' event"

                   # ... (event handling logic) ...

          This is called after an add, delete or merge.

               Note: As of 0.8, this event fires off `after' the item
               has been fully associated with the session, which is
               different than previous releases.  For event handlers
               that require the object not yet be part of session state
               (such as handlers which may autoflush while the target
               object is not yet complete) consider the new
               before_attach() event.

          See also
          ........

          See SessionEvents.before_attach().

          See Object Lifecycle Events.

      -- Method: sqlalchemy.orm.SessionEvents..after_begin
               (session, transaction, connection)

          Execute after a transaction is begun on a connection

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'after_begin')
               def receive_after_begin(session, transaction, connection):
                   "listen for the 'after_begin' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘session’ – The target Session.

             * ‘transaction’ – The SessionTransaction.

             * ‘connection’ – The Connection object which
               will be used for SQL statements.

          See also
          ........

          See SessionEvents.before_commit().

          See SessionEvents.after_commit().

          See SessionEvents.after_transaction_create().

          See SessionEvents.after_transaction_end().

      -- Method: sqlalchemy.orm.SessionEvents..
               after_bulk_delete (delete_context)

          Execute after ORM DELETE against a WHERE expression has been
          invoked.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'after_bulk_delete')
               def receive_after_bulk_delete(delete_context):
                   "listen for the 'after_bulk_delete' event"

                   # ... (event handling logic) ...

               # DEPRECATED calling style (pre-0.9, will be removed in a future release)
               @event.listens_for(SomeSessionOrFactory, 'after_bulk_delete')
               def receive_after_bulk_delete(session, query, query_context, result):
                   "listen for the 'after_bulk_delete' event"

                   # ... (event handling logic) ...

          Deprecated since version 0.9: The ‘after_bulk_delete’ event
          now accepts the arguments ‘delete_context’.  Support for
          listener functions which accept the previous argument
          signature(s) listed above as “deprecated” will be removed in a
          future release.

          This is called as a result of the Query.delete()
          method.

          Parameters: ‘delete_context’ – a “delete context” object which
          contains details about the update, including these attributes:

                  * ‘session’ - the Session involved

                  * ‘query’ -the Query object that this
                    update operation was called upon.

                  * ‘result’ the CursorResult returned as a
                    result of the bulk DELETE operation.

          Changed in version 1.4: the update_context no longer has a
          ‘QueryContext’ object associated with it.

          See also
          ........

          See QueryEvents.before_compile_delete().

          See SessionEvents.after_bulk_update().

      -- Method: sqlalchemy.orm.SessionEvents..
               after_bulk_update (update_context)

          Execute after an ORM UPDATE against a WHERE expression has
          been invoked.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'after_bulk_update')
               def receive_after_bulk_update(update_context):
                   "listen for the 'after_bulk_update' event"

                   # ... (event handling logic) ...

               # DEPRECATED calling style (pre-0.9, will be removed in a future release)
               @event.listens_for(SomeSessionOrFactory, 'after_bulk_update')
               def receive_after_bulk_update(session, query, query_context, result):
                   "listen for the 'after_bulk_update' event"

                   # ... (event handling logic) ...

          Deprecated since version 0.9: The ‘after_bulk_update’ event
          now accepts the arguments ‘update_context’.  Support for
          listener functions which accept the previous argument
          signature(s) listed above as “deprecated” will be removed in a
          future release.

          This is called as a result of the Query.update()
          method.

          Parameters: ‘update_context’ – an “update context” object
          which contains details about the update, including these
          attributes:

                  * ‘session’ - the Session involved

                  * ‘query’ -the Query object that this
                    update operation was called upon.

                  * ‘values’ The “values” dictionary that was passed to
                    Query.update().

                  * ‘result’ the CursorResult returned as a
                    result of the bulk UPDATE operation.

          Changed in version 1.4: the update_context no longer has a
          ‘QueryContext’ object associated with it.

          See also
          ........

          See QueryEvents.before_compile_update().

          See SessionEvents.after_bulk_delete().

      -- Method: sqlalchemy.orm.SessionEvents..after_commit
               (session)

          Execute after a commit has occurred.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'after_commit')
               def receive_after_commit(session):
                   "listen for the 'after_commit' event"

                   # ... (event handling logic) ...

               Note: The SessionEvents.after_commit() hook
               is `not' per-flush, that is, the Session can
               emit SQL to the database many times within the scope of a
               transaction.  For interception of these events, use the
               SessionEvents.before_flush(),
               SessionEvents.after_flush(), or
               SessionEvents.after_flush_postexec() events.

               Note: The Session is not in an active
               transaction when the SessionEvents.after_commit()
               event is invoked, and therefore can not emit SQL. To
               emit SQL corresponding to every transaction, use the
               SessionEvents.before_commit() event.

          Parameters: ‘session’ – The target Session.

          See also
          ........

          See SessionEvents.before_commit().

          See SessionEvents.after_begin().

          See SessionEvents.after_transaction_create().

          See SessionEvents.after_transaction_end().

      -- Method: sqlalchemy.orm.SessionEvents..after_flush
               (session, flush_context)

          Execute after flush has completed, but before commit has been
          called.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'after_flush')
               def receive_after_flush(session, flush_context):
                   "listen for the 'after_flush' event"

                   # ... (event handling logic) ...

          Note that the session’s state is still in pre-flush, i.e.
          ‘new’, ‘dirty’, and ‘deleted’ lists still show pre-flush state
          as well as the history settings on instance attributes.

               Warning: This event runs after the Session has
               emitted SQL to modify the database, but `before' it has
               altered its internal state to reflect those changes,
               including that newly inserted objects are placed into the
               identity map.  ORM operations emitted within this event
               such as loads of related items may produce new identity
               map entries that will immediately be replaced, sometimes
               causing confusing results.  SQLAlchemy will emit a
               warning for this condition as of version 1.3.9.

          Parameters:

             * ‘session’ – The target Session.

             * ‘flush_context’ – Internal UOWTransaction.
               object which handles the details of the flush.

          See also
          ........

          See SessionEvents.before_flush().

          See SessionEvents.after_flush_postexec().

          See Persistence Events.

      -- Method: sqlalchemy.orm.SessionEvents..
               after_flush_postexec (session, flush_context)

          Execute after flush has completed, and after the post-exec
          state occurs.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'after_flush_postexec')
               def receive_after_flush_postexec(session, flush_context):
                   "listen for the 'after_flush_postexec' event"

                   # ... (event handling logic) ...

          This will be when the ‘new’, ‘dirty’, and ‘deleted’ lists are
          in their final state.  An actual commit() may or may not have
          occurred, depending on whether or not the flush started its
          own transaction or participated in a larger transaction.

          Parameters:

             * ‘session’ – The target Session.

             * ‘flush_context’ – Internal UOWTransaction.
               object which handles the details of the flush.

          See also
          ........

          See SessionEvents.before_flush().

          See SessionEvents.after_flush().

          See Persistence Events.

      -- Method: sqlalchemy.orm.SessionEvents..after_rollback
               (session)

          Execute after a real DBAPI rollback has occurred.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'after_rollback')
               def receive_after_rollback(session):
                   "listen for the 'after_rollback' event"

                   # ... (event handling logic) ...

          Note that this event only fires when the `actual' rollback
          against the database occurs - it does `not' fire each time the
          Session.rollback() method is called, if the
          underlying DBAPI transaction has already been rolled back.  In
          many cases, the Session will not be in an “active”
          state during this event, as the current transaction is not
          valid.  To acquire a Session which is active after
          the outermost rollback has proceeded, use the
          SessionEvents.after_soft_rollback() event, checking the
          Session.is_active flag.

          Parameters: ‘session’ – The target Session.

      -- Method: sqlalchemy.orm.SessionEvents..
               after_soft_rollback (session, previous_transaction)

          Execute after any rollback has occurred, including “soft”
          rollbacks that don’t actually emit at the DBAPI level.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'after_soft_rollback')
               def receive_after_soft_rollback(session, previous_transaction):
                   "listen for the 'after_soft_rollback' event"

                   # ... (event handling logic) ...

          This corresponds to both nested and outer rollbacks, i.e.  the
          innermost rollback that calls the DBAPI’s rollback() method,
          as well as the enclosing rollback calls that only pop
          themselves from the transaction stack.

          The given Session can be used to invoke SQL and
          Session.query() operations after an outermost
          rollback by first checking the Session.is_active
          flag:

               @event.listens_for(Session, "after_soft_rollback")
               def do_something(session, previous_transaction):
                   if session.is_active:
                       session.execute("select * from some_table")

          Parameters:

             * ‘session’ – The target Session.

             * ‘previous_transaction’ – The SessionTransaction
               transactional marker object which was just closed.
               The current SessionTransaction for the given
               Session is available via the
               Session.transaction attribute.

      -- Method: sqlalchemy.orm.SessionEvents..
               after_transaction_create (session, transaction)

          Execute when a new SessionTransaction is created.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'after_transaction_create')
               def receive_after_transaction_create(session, transaction):
                   "listen for the 'after_transaction_create' event"

                   # ... (event handling logic) ...

          This event differs from SessionEvents.after_begin()
          in that it occurs for each SessionTransaction
          overall, as opposed to when transactions are begun on
          individual database connections.  It is also invoked for
          nested transactions and subtransactions, and is always matched
          by a corresponding
          SessionEvents.after_transaction_end() event (assuming
          normal operation of the Session).

          Parameters:

             * ‘session’ – the target Session.

             * ‘transaction’ – the target SessionTransaction.

               To detect if this is the outermost
               SessionTransaction, as opposed to a “subtransaction”
               or a SAVEPOINT, test that the
               SessionTransaction.parent attribute is ‘None’:

                    @event.listens_for(session, "after_transaction_create")
                    def after_transaction_create(session, transaction):
                        if transaction.parent is None:
                            # work with top-level transaction

               To detect if the SessionTransaction is a
               SAVEPOINT, use the SessionTransaction.nested
               attribute:

                    @event.listens_for(session, "after_transaction_create")
                    def after_transaction_create(session, transaction):
                        if transaction.nested:
                            # work with SAVEPOINT transaction

          See also
          ........

          See SessionTransaction.

          See SessionEvents.after_transaction_end().

      -- Method: sqlalchemy.orm.SessionEvents..
               after_transaction_end (session, transaction)

          Execute when the span of a SessionTransaction
          ends.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'after_transaction_end')
               def receive_after_transaction_end(session, transaction):
                   "listen for the 'after_transaction_end' event"

                   # ... (event handling logic) ...

          This event differs from SessionEvents.after_commit()
          in that it corresponds to all SessionTransaction
          objects in use, including those for nested transactions
          and subtransactions, and is always matched by a corresponding
          SessionEvents.after_transaction_create() event.

          Parameters:

             * ‘session’ – the target Session.

             * ‘transaction’ – the target SessionTransaction.

               To detect if this is the outermost
               SessionTransaction, as opposed to a “subtransaction”
               or a SAVEPOINT, test that the
               SessionTransaction.parent attribute is ‘None’:

                    @event.listens_for(session, "after_transaction_create")
                    def after_transaction_end(session, transaction):
                        if transaction.parent is None:
                            # work with top-level transaction

               To detect if the SessionTransaction is a
               SAVEPOINT, use the SessionTransaction.nested
               attribute:

                    @event.listens_for(session, "after_transaction_create")
                    def after_transaction_end(session, transaction):
                        if transaction.nested:
                            # work with SAVEPOINT transaction

          See also
          ........

          See SessionTransaction.

          See SessionEvents.after_transaction_create().

      -- Method: sqlalchemy.orm.SessionEvents..before_attach
               (session, instance)

          Execute before an instance is attached to a session.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'before_attach')
               def receive_before_attach(session, instance):
                   "listen for the 'before_attach' event"

                   # ... (event handling logic) ...

          This is called before an add, delete or merge causes the
          object to be part of the session.

          See also
          ........

          See SessionEvents.after_attach().

          See Object Lifecycle Events.

      -- Method: sqlalchemy.orm.SessionEvents..before_commit
               (session)

          Execute before commit is called.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'before_commit')
               def receive_before_commit(session):
                   "listen for the 'before_commit' event"

                   # ... (event handling logic) ...

               Note: The SessionEvents.before_commit() hook
               is `not' per-flush, that is, the Session can
               emit SQL to the database many times within the scope of a
               transaction.  For interception of these events, use the
               SessionEvents.before_flush(),
               SessionEvents.after_flush(), or
               SessionEvents.after_flush_postexec() events.

          Parameters: ‘session’ – The target Session.

          See also
          ........

          See SessionEvents.after_commit().

          See SessionEvents.after_begin().

          See SessionEvents.after_transaction_create().

          See SessionEvents.after_transaction_end().

      -- Method: sqlalchemy.orm.SessionEvents..before_flush
               (session, flush_context, instances)

          Execute before flush process has started.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'before_flush')
               def receive_before_flush(session, flush_context, instances):
                   "listen for the 'before_flush' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘session’ – The target Session.

             * ‘flush_context’ – Internal UOWTransaction.
               object which handles the details of the flush.

             * ‘instances’ – Usually ‘None’, this is the collection of
               objects which can be passed to the Session.flush()
               method (note this usage is deprecated).

          See also
          ........

          See SessionEvents.after_flush().

          See SessionEvents.after_flush_postexec().

          See Persistence Events.

      -- Method: sqlalchemy.orm.SessionEvents..
               deleted_to_detached (session, instance)

          Intercept the “deleted to detached” transition for a specific
          object.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'deleted_to_detached')
               def receive_deleted_to_detached(session, instance):
                   "listen for the 'deleted_to_detached' event"

                   # ... (event handling logic) ...

          This event is invoked when a deleted object is evicted from
          the session.  The typical case when this occurs is when the
          transaction for a Session in which the object was
          deleted is committed; the object moves from the deleted state
          to the detached state.

          It is also invoked for objects that were deleted in a flush
          when the Session.expunge_all() or
          Session.close() events are called, as well as if the
          object is individually expunged from its deleted state via
          Session.expunge().

          New in version 1.1.

          See also
          ........

          See Object Lifecycle Events.

      -- Method: sqlalchemy.orm.SessionEvents..
               deleted_to_persistent (session, instance)

          Intercept the “deleted to persistent” transition for a
          specific object.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'deleted_to_persistent')
               def receive_deleted_to_persistent(session, instance):
                   "listen for the 'deleted_to_persistent' event"

                   # ... (event handling logic) ...

          This transition occurs only when an object that’s been deleted
          successfully in a flush is restored due to a call to
          Session.rollback().  The event is not called under any
          other circumstances.

          New in version 1.1.

          See also
          ........

          See Object Lifecycle Events.

      -- Method: sqlalchemy.orm.SessionEvents..
               detached_to_persistent (session, instance)

          Intercept the “detached to persistent” transition for a
          specific object.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'detached_to_persistent')
               def receive_detached_to_persistent(session, instance):
                   "listen for the 'detached_to_persistent' event"

                   # ... (event handling logic) ...

          This event is a specialization of the
          SessionEvents.after_attach() event which is only invoked
          for this specific transition.  It is invoked typically during
          the Session.add() call, as well as during the
          Session.delete() call if the object was not
          previously associated with the Session. (note that
          an object marked as “deleted” remains in the “persistent”
          state until the flush proceeds).

               Note: If the object becomes persistent as part of a call
               to Session.delete(), the object is `not' yet
               marked as deleted when this event is called.  To detect
               deleted objects, check the ‘deleted’ flag sent to the
               SessionEvents.persistent_to_detached() to
               event after the flush proceeds, or check the
               Session.deleted collection within the
               SessionEvents.before_flush() event if deleted
               objects need to be intercepted before the flush.

          Parameters:

             * ‘session’ – target Session.

             * ‘instance’ – the ORM-mapped instance being operated upon.

          New in version 1.1.

          See also
          ........

          See Object Lifecycle Events.

      -- Method: sqlalchemy.orm.SessionEvents..do_orm_execute
               (orm_execute_state)

          Intercept statement executions that occur in terms of a
          Session.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'do_orm_execute')
               def receive_do_orm_execute(orm_execute_state):
                   "listen for the 'do_orm_execute' event"

                   # ... (event handling logic) ...

          This event is invoked for all top-level SQL statements invoked
          from the Session.execute() method.  As of
          SQLAlchemy 1.4, all ORM queries emitted on behalf of a
          Session will flow through this method, so this event hook
          provides the single point at which ORM queries of all types
          may be intercepted before they are invoked, and additionally
          to replace their execution with a different process.

          This event is a ‘do_’ event, meaning it has the capability to
          replace the operation that the Session.execute()
          method normally performs.  The intended use for this includes
          sharding and result-caching schemes which may seek to invoke
          the same statement across multiple database connections,
          returning a result that is merged from each of them, or which
          don’t invoke the statement at all, instead returning data from
          a cache.

          The hook intends to replace the use of the
          ‘Query._execute_and_instances’ method that could be subclassed
          prior to SQLAlchemy 1.4.

          Parameters: ‘orm_execute_state’ – an instance of
          ORMExecuteState which contains all information about the
          current execution, as well as helper functions used to derive
          other commonly required information.  See that object for
          details.

          See also
          ........

          See Execute Events. - top level documentation on how to
          use SessionEvents.do_orm_execute().

          See ORMExecuteState. - the object passed to the
          SessionEvents.do_orm_execute() event which contains all
          information about the statement to be invoked.  It also
          provides an interface to extend the current statement,
          options, and parameters as well as an option that allows
          programmatic invocation of the statement at any point.

          See ORM Query Events. - includes examples of using
          SessionEvents.do_orm_execute().

          See Dogpile Caching. - an example of how to integrate
          Dogpile caching with the ORM Session making use of
          the SessionEvents.do_orm_execute() event hook.

          See Horizontal Sharding. - the Horizontal Sharding
          example / extension relies upon the
          SessionEvents.do_orm_execute() event hook to invoke a
          SQL statement on multiple backends and return a merged result.

          New in version 1.4.

      -- Method: sqlalchemy.orm.SessionEvents..
               loaded_as_persistent (session, instance)

          Intercept the “loaded as persistent” transition for a specific
          object.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'loaded_as_persistent')
               def receive_loaded_as_persistent(session, instance):
                   "listen for the 'loaded_as_persistent' event"

                   # ... (event handling logic) ...

          This event is invoked within the ORM loading process, and is
          invoked very similarly to the InstanceEvents.load()
          event.  However, the event here is linkable to a
          Session class or instance, rather than to a mapper or
          class hierarchy, and integrates with the other session
          lifecycle events smoothly.  The object is guaranteed to be
          present in the session’s identity map when this event is
          called.

               Note: This event is invoked within the loader process
               before eager loaders may have been completed, and the
               object’s state may not be complete.  Additionally,
               invoking row-level refresh operations on the object will
               place the object into a new loader context, interfering
               with the existing load context.  See the note on
               InstanceEvents.load() for background on making use
               of the SessionEvents.restore_load_context
               parameter, which works in the same manner as that of
               InstanceEvents.restore_load_context, in order
               to resolve this scenario.

          Parameters:

             * ‘session’ – target Session.

             * ‘instance’ – the ORM-mapped instance being operated upon.

          New in version 1.1.

          See also
          ........

          See Object Lifecycle Events.

      -- Method: sqlalchemy.orm.SessionEvents..
               pending_to_persistent (session, instance)

          Intercept the “pending to persistent”” transition for a
          specific object.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'pending_to_persistent')
               def receive_pending_to_persistent(session, instance):
                   "listen for the 'pending_to_persistent' event"

                   # ... (event handling logic) ...

          This event is invoked within the flush process, and is similar
          to scanning the Session.new collection within the
          SessionEvents.after_flush() event.  However, in
          this case the object has already been moved to the persistent
          state when the event is called.

          Parameters:

             * ‘session’ – target Session.

             * ‘instance’ – the ORM-mapped instance being operated upon.

          New in version 1.1.

          See also
          ........

          See Object Lifecycle Events.

      -- Method: sqlalchemy.orm.SessionEvents..
               pending_to_transient (session, instance)

          Intercept the “pending to transient” transition for a specific
          object.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'pending_to_transient')
               def receive_pending_to_transient(session, instance):
                   "listen for the 'pending_to_transient' event"

                   # ... (event handling logic) ...

          This less common transition occurs when an pending object that
          has not been flushed is evicted from the session; this can
          occur when the Session.rollback() method rolls
          back the transaction, or when the Session.expunge()
          method is used.

          Parameters:

             * ‘session’ – target Session.

             * ‘instance’ – the ORM-mapped instance being operated upon.

          New in version 1.1.

          See also
          ........

          See Object Lifecycle Events.

      -- Method: sqlalchemy.orm.SessionEvents..
               persistent_to_deleted (session, instance)

          Intercept the “persistent to deleted” transition for a
          specific object.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'persistent_to_deleted')
               def receive_persistent_to_deleted(session, instance):
                   "listen for the 'persistent_to_deleted' event"

                   # ... (event handling logic) ...

          This event is invoked when a persistent object’s identity is
          deleted from the database within a flush, however the object
          still remains associated with the Session until the
          transaction completes.

          If the transaction is rolled back, the object moves again to
          the persistent state, and the
          SessionEvents.deleted_to_persistent() event is called.
          If the transaction is committed, the object becomes detached,
          which will emit the SessionEvents.deleted_to_detached()
          event.

          Note that while the Session.delete() method is the
          primary public interface to mark an object as deleted, many
          objects get deleted due to cascade rules, which are not always
          determined until flush time.  Therefore, there’s no way to
          catch every object that will be deleted until the flush has
          proceeded.  the SessionEvents.persistent_to_deleted()
          event is therefore invoked at the end of a flush.

          New in version 1.1.

          See also
          ........

          See Object Lifecycle Events.

      -- Method: sqlalchemy.orm.SessionEvents..
               persistent_to_detached (session, instance)

          Intercept the “persistent to detached” transition for a
          specific object.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'persistent_to_detached')
               def receive_persistent_to_detached(session, instance):
                   "listen for the 'persistent_to_detached' event"

                   # ... (event handling logic) ...

          This event is invoked when a persistent object is evicted from
          the session.  There are many conditions that cause this to
          happen, including:

             * using a method such as Session.expunge() or
               Session.close().

             * Calling the Session.rollback() method, when
               the object was part of an INSERT statement for that
               session’s transaction

          Parameters:

             * ‘session’ – target Session.

             * ‘instance’ – the ORM-mapped instance being operated upon.

             * ‘deleted’ – boolean.  If True, indicates this object
               moved to the detached state because it was marked as
               deleted and flushed.

          New in version 1.1.

          See also
          ........

          See Object Lifecycle Events.

      -- Method: sqlalchemy.orm.SessionEvents..
               persistent_to_transient (session, instance)

          Intercept the “persistent to transient” transition for a
          specific object.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'persistent_to_transient')
               def receive_persistent_to_transient(session, instance):
                   "listen for the 'persistent_to_transient' event"

                   # ... (event handling logic) ...

          This less common transition occurs when an pending object that
          has has been flushed is evicted from the session; this can
          occur when the Session.rollback() method rolls
          back the transaction.

          Parameters:

             * ‘session’ – target Session.

             * ‘instance’ – the ORM-mapped instance being operated upon.

          New in version 1.1.

          See also
          ........

          See Object Lifecycle Events.

      -- Method: sqlalchemy.orm.SessionEvents..
               transient_to_pending (session, instance)

          Intercept the “transient to pending” transition for a specific
          object.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSessionOrFactory, 'transient_to_pending')
               def receive_transient_to_pending(session, instance):
                   "listen for the 'transient_to_pending' event"

                   # ... (event handling logic) ...

          This event is a specialization of the
          SessionEvents.after_attach() event which is only invoked
          for this specific transition.  It is invoked typically during
          the Session.add() call.

          Parameters:

             * ‘session’ – target Session.

             * ‘instance’ – the ORM-mapped instance being operated upon.

          New in version 1.1.

          See also
          ........

          See Object Lifecycle Events.

3.6.1.2 Mapper Events
.....................

Mapper event hooks encompass things that happen as related to individual
or multiple Mapper objects, which are the central
configurational object that maps a user-defined class to a Table
object.  Types of things which occur at the Mapper level
include:

   * `Per-object persistence operations' - the most popular mapper hooks
     are the unit-of-work hooks such as
     MapperEvents.before_insert(),
     MapperEvents.after_update(), etc.  These events are contrasted
     to the more coarse grained session-level events such as
     SessionEvents.before_flush() in that they occur within the
     flush process on a per-object basis; while finer grained activity
     on an object is more straightforward, availability of
     Session features is limited.

   * `Mapper configuration events' - the other major class of mapper
     hooks are those which occur as a class is mapped, as a mapper is
     finalized, and when sets of mappers are configured to refer to each
     other.  These events include MapperEvents.instrument_class(),
     see MapperEvents.before_mapper_configured() and
     MapperEvents.mapper_configured() at the individual
     Mapper level, and MapperEvents.before_configured()
     and MapperEvents.after_configured() at the level
     of collections of Mapper objects.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See MapperEvents.Define events specific to mappings.

 -- Class: sqlalchemy.orm.MapperEvents

     Define events specific to mappings.

     e.g.:

          from sqlalchemy import event

          def my_before_insert_listener(mapper, connection, target):
              # execute a stored procedure upon INSERT,
              # apply the value to the row to be inserted
              target.calculated_value = connection.execute(
                  text("select my_special_function(%d)" % target.special_number)
              ).scalar()

          # associate the listener function with SomeClass,
          # to execute during the "before_insert" hook
          event.listen(
              SomeClass, 'before_insert', my_before_insert_listener)

     Available targets include:

        * mapped classes

        * unmapped superclasses of mapped or to-be-mapped classes (using
          the ‘propagate=True’ flag)

        * Mapper objects

        * the Mapper class itself and the mapper()
          function indicate listening for all mappers.

     Mapper events provide hooks into critical sections of the mapper,
     including those related to object instrumentation, object loading,
     and object persistence.  In particular, the persistence methods
     MapperEvents.before_insert(), and
     MapperEvents.before_update() are popular places to augment
     the state being persisted - however, these methods operate with
     several significant restrictions.  The user is encouraged to
     evaluate the SessionEvents.before_flush() and
     SessionEvents.after_flush() methods as more flexible and
     user-friendly hooks in which to apply additional database state
     during a flush.

     When using MapperEvents, several modifiers are available
     to the listen() function.

     Parameters:

        * ‘propagate=False’ – When True, the event listener should be
          applied to all inheriting mappers and/or the mappers of
          inheriting classes, as well as any mapper which is the target
          of this listener.

        * ‘raw=False’ – When True, the “target” argument passed to
          applicable event listener functions will be the instance’s
          InstanceState management object, rather than the
          mapped instance itself.

        * ‘retval=False’ – when True, the user-defined event function
          must have a return value, the purpose of which is either to
          control subsequent event propagation, or to otherwise alter
          the operation in progress by the mapper.  Possible return
          values are:

             * ‘sqlalchemy.orm.interfaces.EXT_CONTINUE’ - continue event
               processing normally.

             * ‘sqlalchemy.orm.interfaces.EXT_STOP’ - cancel all
               subsequent event handlers in the chain.

             * other values - the return value specified by specific
               listeners.

     `Class signature'

     class sqlalchemy.orm.MapperEvents.
     (‘sqlalchemy.event.Events’)

      -- Method: sqlalchemy.orm.MapperEvents..
               after_configured ()

          Called after a series of mappers have been configured.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'after_configured')
               def receive_after_configured():
                   "listen for the 'after_configured' event"

                   # ... (event handling logic) ...

          The MapperEvents.after_configured() event is
          invoked each time the configure_mappers() function
          is invoked, after the function has completed its work.
          configure_mappers() is typically invoked automatically
          as mappings are first used, as well as each time new mappers
          have been made available and new mapper use is detected.

          Contrast this event to the
          MapperEvents.mapper_configured() event, which is called
          on a per-mapper basis while the configuration operation
          proceeds; unlike that event, when this event is invoked, all
          cross-configurations (e.g.  backrefs) will also have been made
          available for any mappers that were pending.  Also contrast to
          MapperEvents.before_configured(), which is invoked
          before the series of mappers has been configured.

          This event can `only' be applied to the Mapper
          class or mapper() function, and not to individual
          mappings or mapped classes.  It is only invoked for all
          mappings as a whole:

               from sqlalchemy.orm import mapper

               @event.listens_for(mapper, "after_configured")
               def go():
                   # ...

          Theoretically this event is called once per application, but
          is actually called any time new mappers have been affected by
          a configure_mappers() call.  If new mappings are
          constructed after existing ones have already been used, this
          event will likely be called again.  To ensure that a
          particular event is only called once and no further, the
          ‘once=True’ argument (new in 0.9.4) can be applied:

               from sqlalchemy.orm import mapper

               @event.listens_for(mapper, "after_configured", once=True)
               def go():
                   # ...

          See also
          ........

          See MapperEvents.before_mapper_configured().

          See MapperEvents.mapper_configured().

          See MapperEvents.before_configured().

      -- Method: sqlalchemy.orm.MapperEvents..after_delete
               (mapper, connection, target)

          Receive an object instance after a DELETE statement has been
          emitted corresponding to that instance.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'after_delete')
               def receive_after_delete(mapper, connection, target):
                   "listen for the 'after_delete' event"

                   # ... (event handling logic) ...

          This event is used to emit additional SQL statements on the
          given connection as well as to perform application specific
          bookkeeping related to a deletion event.

          The event is often called for a batch of objects of the same
          class after their DELETE statements have been emitted at once
          in a previous step.

               Warning: Mapper-level flush events only allow `very
               limited operations', on attributes local to the row being
               operated upon only, as well as allowing any SQL to be
               emitted on the given Connection.  `Please read
               fully' the notes at Mapper-level Events for
               guidelines on using these methods; generally, the
               SessionEvents.before_flush() method should be
               preferred for general on-flush changes.

          Parameters:

             * ‘mapper’ – the Mapper which is the target of
               this event.

             * ‘connection’ – the Connection being used to
               emit DELETE statements for this instance.  This provides
               a handle into the current transaction on the target
               database specific to this instance.

             * ‘target’ – the mapped instance being deleted.  If the
               event is configured with ‘raw=True’, this will instead be
               the InstanceState state-management object
               associated with the instance.

          Returns: No return value is supported by this event.

          See also
          ........

          See Persistence Events.

      -- Method: sqlalchemy.orm.MapperEvents..after_insert
               (mapper, connection, target)

          Receive an object instance after an INSERT statement is
          emitted corresponding to that instance.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'after_insert')
               def receive_after_insert(mapper, connection, target):
                   "listen for the 'after_insert' event"

                   # ... (event handling logic) ...

          This event is used to modify in-Python-only state on the
          instance after an INSERT occurs, as well as to emit additional
          SQL statements on the given connection.

          The event is often called for a batch of objects of the same
          class after their INSERT statements have been emitted at once
          in a previous step.  In the extremely rare case that this is
          not desirable, the mapper() can be configured with
          ‘batch=False’, which will cause batches of instances to be
          broken up into individual (and more poorly performing)
          event->persist->event steps.

               Warning: Mapper-level flush events only allow `very
               limited operations', on attributes local to the row being
               operated upon only, as well as allowing any SQL to be
               emitted on the given Connection.  `Please read
               fully' the notes at Mapper-level Events for
               guidelines on using these methods; generally, the
               SessionEvents.before_flush() method should be
               preferred for general on-flush changes.

          Parameters:

             * ‘mapper’ – the Mapper which is the target of
               this event.

             * ‘connection’ – the Connection being used to
               emit INSERT statements for this instance.  This provides
               a handle into the current transaction on the target
               database specific to this instance.

             * ‘target’ – the mapped instance being persisted.  If the
               event is configured with ‘raw=True’, this will instead be
               the InstanceState state-management object
               associated with the instance.

          Returns: No return value is supported by this event.

          See also
          ........

          See Persistence Events.

      -- Method: sqlalchemy.orm.MapperEvents..after_update
               (mapper, connection, target)

          Receive an object instance after an UPDATE statement is
          emitted corresponding to that instance.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'after_update')
               def receive_after_update(mapper, connection, target):
                   "listen for the 'after_update' event"

                   # ... (event handling logic) ...

          This event is used to modify in-Python-only state on the
          instance after an UPDATE occurs, as well as to emit additional
          SQL statements on the given connection.

          This method is called for all instances that are marked as
          “dirty”, `even those which have no net changes to their
          column-based attributes', and for which no UPDATE statement
          has proceeded.  An object is marked as dirty when any of its
          column-based attributes have a “set attribute” operation
          called or when any of its collections are modified.  If, at
          update time, no column-based attributes have any net changes,
          no UPDATE statement will be issued.  This means that an
          instance being sent to MapperEvents.after_update()
          is `not' a guarantee that an UPDATE statement has been issued.

          To detect if the column-based attributes on the object have
          net changes, and therefore resulted in an UPDATE statement,
          use ‘object_session(instance).is_modified(instance,
          include_collections=False)’.

          The event is often called for a batch of objects of the same
          class after their UPDATE statements have been emitted at once
          in a previous step.  In the extremely rare case that this is
          not desirable, the mapper() can be configured with
          ‘batch=False’, which will cause batches of instances to be
          broken up into individual (and more poorly performing)
          event->persist->event steps.

               Warning: Mapper-level flush events only allow `very
               limited operations', on attributes local to the row being
               operated upon only, as well as allowing any SQL to be
               emitted on the given Connection.  `Please read
               fully' the notes at Mapper-level Events for
               guidelines on using these methods; generally, the
               SessionEvents.before_flush() method should be
               preferred for general on-flush changes.

          Parameters:

             * ‘mapper’ – the Mapper which is the target of
               this event.

             * ‘connection’ – the Connection being used to
               emit UPDATE statements for this instance.  This provides
               a handle into the current transaction on the target
               database specific to this instance.

             * ‘target’ – the mapped instance being persisted.  If the
               event is configured with ‘raw=True’, this will instead be
               the InstanceState state-management object
               associated with the instance.

          Returns: No return value is supported by this event.

          See also
          ........

          See Persistence Events.

      -- Method: sqlalchemy.orm.MapperEvents..
               before_configured ()

          Called before a series of mappers have been configured.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'before_configured')
               def receive_before_configured():
                   "listen for the 'before_configured' event"

                   # ... (event handling logic) ...

          The MapperEvents.before_configured() event is
          invoked each time the configure_mappers() function
          is invoked, before the function has done any of its work.
          configure_mappers() is typically invoked
          automatically as mappings are first used, as well as each time
          new mappers have been made available and new mapper use is
          detected.

          This event can `only' be applied to the Mapper
          class or mapper() function, and not to individual
          mappings or mapped classes.  It is only invoked for all
          mappings as a whole:

               from sqlalchemy.orm import mapper

               @event.listens_for(mapper, "before_configured")
               def go():
                   # ...

          Contrast this event to MapperEvents.after_configured(),
          which is invoked after the series of mappers has been
          configured, as well as
          MapperEvents.before_mapper_configured() and
          MapperEvents.mapper_configured(), which are both invoked
          on a per-mapper basis.

          Theoretically this event is called once per application, but
          is actually called any time new mappers are to be affected by
          a configure_mappers() call.  If new mappings are
          constructed after existing ones have already been used, this
          event will likely be called again.  To ensure that a
          particular event is only called once and no further, the
          ‘once=True’ argument (new in 0.9.4) can be applied:

               from sqlalchemy.orm import mapper

               @event.listens_for(mapper, "before_configured", once=True)
               def go():
                   # ...

          New in version 0.9.3.

          See also
          ........

          See MapperEvents.before_mapper_configured().

          See MapperEvents.mapper_configured().

          See MapperEvents.after_configured().

      -- Method: sqlalchemy.orm.MapperEvents..before_delete
               (mapper, connection, target)

          Receive an object instance before a DELETE statement is
          emitted corresponding to that instance.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'before_delete')
               def receive_before_delete(mapper, connection, target):
                   "listen for the 'before_delete' event"

                   # ... (event handling logic) ...

          This event is used to emit additional SQL statements on the
          given connection as well as to perform application specific
          bookkeeping related to a deletion event.

          The event is often called for a batch of objects of the same
          class before their DELETE statements are emitted at once in a
          later step.

               Warning: Mapper-level flush events only allow `very
               limited operations', on attributes local to the row being
               operated upon only, as well as allowing any SQL to be
               emitted on the given Connection.  `Please read
               fully' the notes at Mapper-level Events for
               guidelines on using these methods; generally, the
               SessionEvents.before_flush() method should be
               preferred for general on-flush changes.

          Parameters:

             * ‘mapper’ – the Mapper which is the target of
               this event.

             * ‘connection’ – the Connection being used to
               emit DELETE statements for this instance.  This provides
               a handle into the current transaction on the target
               database specific to this instance.

             * ‘target’ – the mapped instance being deleted.  If the
               event is configured with ‘raw=True’, this will instead be
               the InstanceState state-management object
               associated with the instance.

          Returns: No return value is supported by this event.

          See also
          ........

          See Persistence Events.

      -- Method: sqlalchemy.orm.MapperEvents..before_insert
               (mapper, connection, target)

          Receive an object instance before an INSERT statement is
          emitted corresponding to that instance.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'before_insert')
               def receive_before_insert(mapper, connection, target):
                   "listen for the 'before_insert' event"

                   # ... (event handling logic) ...

          This event is used to modify local, non-object related
          attributes on the instance before an INSERT occurs, as well as
          to emit additional SQL statements on the given connection.

          The event is often called for a batch of objects of the same
          class before their INSERT statements are emitted at once in a
          later step.  In the extremely rare case that this is not
          desirable, the mapper() can be configured with
          ‘batch=False’, which will cause batches of instances to be
          broken up into individual (and more poorly performing)
          event->persist->event steps.

               Warning: Mapper-level flush events only allow `very
               limited operations', on attributes local to the row being
               operated upon only, as well as allowing any SQL to be
               emitted on the given Connection.  `Please read
               fully' the notes at Mapper-level Events for
               guidelines on using these methods; generally, the
               SessionEvents.before_flush() method should be
               preferred for general on-flush changes.

          Parameters:

             * ‘mapper’ – the Mapper which is the target of
               this event.

             * ‘connection’ – the Connection being used to
               emit INSERT statements for this instance.  This provides
               a handle into the current transaction on the target
               database specific to this instance.

             * ‘target’ – the mapped instance being persisted.  If the
               event is configured with ‘raw=True’, this will instead be
               the InstanceState state-management object
               associated with the instance.

          Returns: No return value is supported by this event.

          See also
          ........

          See Persistence Events.

      -- Method: sqlalchemy.orm.MapperEvents..
               before_mapper_configured (mapper, class_)

          Called right before a specific mapper is to be configured.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'before_mapper_configured')
               def receive_before_mapper_configured(mapper, class_):
                   "listen for the 'before_mapper_configured' event"

                   # ... (event handling logic) ...

          This event is intended to allow a specific mapper to be
          skipped during the configure step, by returning the
          ‘interfaces.EXT_SKIP’ symbol which indicates to the
          configure_mappers() call that this particular mapper (or
          hierarchy of mappers, if ‘propagate=True’ is used) should be
          skipped in the current configuration run.  When one or more
          mappers are skipped, the he “new mappers” flag will remain
          set, meaning the configure_mappers() function will
          continue to be called when mappers are used, to continue to
          try to configure all available mappers.

          In comparison to the other configure-level events, see
          MapperEvents.before_configured(),
          MapperEvents.after_configured(), and
          MapperEvents.mapper_configured(), the
          :meth;‘.MapperEvents.before_mapper_configured‘ event provides
          for a meaningful return value when it is registered with the
          ‘retval=True’ parameter.

          New in version 1.3.

          e.g.:

               from sqlalchemy.orm import EXT_SKIP

               Base = declarative_base()

               DontConfigureBase = declarative_base()

               @event.listens_for(
                   DontConfigureBase,
                   "before_mapper_configured", retval=True, propagate=True)
               def dont_configure(mapper, cls):
                   return EXT_SKIP

          See also
          ........

          See MapperEvents.before_configured().

          See MapperEvents.after_configured().

          See MapperEvents.mapper_configured().

      -- Method: sqlalchemy.orm.MapperEvents..before_update
               (mapper, connection, target)

          Receive an object instance before an UPDATE statement is
          emitted corresponding to that instance.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'before_update')
               def receive_before_update(mapper, connection, target):
                   "listen for the 'before_update' event"

                   # ... (event handling logic) ...

          This event is used to modify local, non-object related
          attributes on the instance before an UPDATE occurs, as well as
          to emit additional SQL statements on the given connection.

          This method is called for all instances that are marked as
          “dirty”, `even those which have no net changes to their
          column-based attributes'.  An object is marked as dirty when
          any of its column-based attributes have a “set attribute”
          operation called or when any of its collections are modified.
          If, at update time, no column-based attributes have any net
          changes, no UPDATE statement will be issued.  This means that
          an instance being sent to MapperEvents.before_update()
          is `not' a guarantee that an UPDATE statement will be
          issued, although you can affect the outcome here by modifying
          attributes so that a net change in value does exist.

          To detect if the column-based attributes on the object have
          net changes, and will therefore generate an UPDATE statement,
          use ‘object_session(instance).is_modified(instance,
          include_collections=False)’.

          The event is often called for a batch of objects of the same
          class before their UPDATE statements are emitted at once in a
          later step.  In the extremely rare case that this is not
          desirable, the mapper() can be configured with
          ‘batch=False’, which will cause batches of instances to be
          broken up into individual (and more poorly performing)
          event->persist->event steps.

               Warning: Mapper-level flush events only allow `very
               limited operations', on attributes local to the row being
               operated upon only, as well as allowing any SQL to be
               emitted on the given Connection.  `Please read
               fully' the notes at Mapper-level Events for
               guidelines on using these methods; generally, the
               SessionEvents.before_flush() method should be
               preferred for general on-flush changes.

          Parameters:

             * ‘mapper’ – the Mapper which is the target of
               this event.

             * ‘connection’ – the Connection being used to
               emit UPDATE statements for this instance.  This provides
               a handle into the current transaction on the target
               database specific to this instance.

             * ‘target’ – the mapped instance being persisted.  If the
               event is configured with ‘raw=True’, this will instead be
               the InstanceState state-management object
               associated with the instance.

          Returns: No return value is supported by this event.

          See also
          ........

          See Persistence Events.

      -- Method: sqlalchemy.orm.MapperEvents..
               instrument_class (mapper, class_)

          Receive a class when the mapper is first constructed, before
          instrumentation is applied to the mapped class.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'instrument_class')
               def receive_instrument_class(mapper, class_):
                   "listen for the 'instrument_class' event"

                   # ... (event handling logic) ...

          This event is the earliest phase of mapper construction.  Most
          attributes of the mapper are not yet initialized.

          This listener can either be applied to the Mapper
          class overall, or to any un-mapped class which serves as a
          base for classes that will be mapped (using the
          ‘propagate=True’ flag):

               Base = declarative_base()

               @event.listens_for(Base, "instrument_class", propagate=True)
               def on_new_class(mapper, cls_):
                   " ... "

          Parameters:

             * ‘mapper’ – the Mapper which is the target of
               this event.

             * ‘class_’ – the mapped class.

      -- Method: sqlalchemy.orm.MapperEvents..
               mapper_configured (mapper, class_)

          Called when a specific mapper has completed its own
          configuration within the scope of the
          configure_mappers() call.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'mapper_configured')
               def receive_mapper_configured(mapper, class_):
                   "listen for the 'mapper_configured' event"

                   # ... (event handling logic) ...

          The MapperEvents.mapper_configured() event is
          invoked for each mapper that is encountered when the
          configure_mappers() function proceeds through the
          current list of not-yet-configured mappers.
          configure_mappers() is typically invoked automatically
          as mappings are first used, as well as each time new mappers
          have been made available and new mapper use is detected.

          When the event is called, the mapper should be in its final
          state, but `not including backrefs' that may be invoked from
          other mappers; they might still be pending within the
          configuration operation.  Bidirectional relationships that are
          instead configured via the relationship.back_populates
          argument `will' be fully available, since this style of
          relationship does not rely upon other possibly-not-configured
          mappers to know that they exist.

          For an event that is guaranteed to have `all' mappers ready to
          go including backrefs that are defined only on other mappings,
          use the MapperEvents.after_configured() event;
          this event invokes only after all known mappings have been
          fully configured.

          The MapperEvents.mapper_configured() event, unlike
          MapperEvents.before_configured() or
          MapperEvents.after_configured(), is called for each
          mapper/class individually, and the mapper is passed to the
          event itself.  It also is called exactly once for a particular
          mapper.  The event is therefore useful for configurational
          steps that benefit from being invoked just once on a specific
          mapper basis, which don’t require that “backref”
          configurations are necessarily ready yet.

          Parameters:

             * ‘mapper’ – the Mapper which is the target of
               this event.

             * ‘class_’ – the mapped class.

          See also
          ........

          See MapperEvents.before_configured().

          See MapperEvents.after_configured().

          See MapperEvents.before_mapper_configured().

3.6.1.3 Instance Events
.......................

Instance events are focused on the construction of ORM mapped instances,
including when they are instantiated as transient objects, when they are
loaded from the database and become persistent objects, as well as when
database refresh or expiration operations occur on the object.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See InstanceEvents.Define events specific to object lifecycle.

 -- Class: sqlalchemy.orm.InstanceEvents

     Define events specific to object lifecycle.

     e.g.:

          from sqlalchemy import event

          def my_load_listener(target, context):
              print("on load!")

          event.listen(SomeClass, 'load', my_load_listener)

     Available targets include:

        * mapped classes

        * unmapped superclasses of mapped or to-be-mapped classes (using
          the ‘propagate=True’ flag)

        * Mapper objects

        * the Mapper class itself and the mapper()
          function indicate listening for all mappers.

     Instance events are closely related to mapper events, but are more
     specific to the instance and its instrumentation, rather than its
     system of persistence.

     When using InstanceEvents, several modifiers are
     available to the listen() function.

     Parameters:

        * ‘propagate=False’ – When True, the event listener should be
          applied to all inheriting classes as well as the class which
          is the target of this listener.

        * ‘raw=False’ – When True, the “target” argument passed to
          applicable event listener functions will be the instance’s
          InstanceState management object, rather than the
          mapped instance itself.

        * ‘restore_load_context=False’ – Applies to the
          InstanceEvents.load() and
          InstanceEvents.refresh() events.  Restores the loader
          context of the object when the event hook is complete, so that
          ongoing eager load operations continue to target the object
          appropriately.  A warning is emitted if the object is moved to
          a new loader context from within one of these events if this
          flag is not set.

          New in version 1.3.14.

     `Class signature'

     class sqlalchemy.orm.InstanceEvents.
     (‘sqlalchemy.event.Events’)

      -- Method: sqlalchemy.orm.InstanceEvents..expire
               (target, attrs)

          Receive an object instance after its attributes or some subset
          have been expired.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'expire')
               def receive_expire(target, attrs):
                   "listen for the 'expire' event"

                   # ... (event handling logic) ...

          ‘keys’ is a list of attribute names.  If None, the entire
          state was expired.

          Parameters:

             * ‘target’ – the mapped instance.  If the event is
               configured with ‘raw=True’, this will instead be the
               InstanceState state-management object
               associated with the instance.

             * ‘attrs’ – sequence of attribute names which were expired,
               or None if all attributes were expired.

      -- Method: sqlalchemy.orm.InstanceEvents..first_init
               (manager, cls)

          Called when the first instance of a particular mapping is
          called.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'first_init')
               def receive_first_init(manager, cls):
                   "listen for the 'first_init' event"

                   # ... (event handling logic) ...

          This event is called when the ‘__init__’ method of a class is
          called the first time for that particular class.  The event
          invokes before ‘__init__’ actually proceeds as well as before
          the InstanceEvents.init() event is invoked.

      -- Method: sqlalchemy.orm.InstanceEvents..init (target,
               args, kwargs)

          Receive an instance when its constructor is called.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'init')
               def receive_init(target, args, kwargs):
                   "listen for the 'init' event"

                   # ... (event handling logic) ...

          This method is only called during a userland construction of
          an object, in conjunction with the object’s constructor, e.g.
          its ‘__init__’ method.  It is not called when an object is
          loaded from the database; see the InstanceEvents.load()
          event in order to intercept a database load.

          The event is called before the actual ‘__init__’ constructor
          of the object is called.  The ‘kwargs’ dictionary may be
          modified in-place in order to affect what is passed to
          ‘__init__’.

          Parameters:

             * ‘target’ – the mapped instance.  If the event is
               configured with ‘raw=True’, this will instead be the
               InstanceState state-management object
               associated with the instance.

             * ‘args’ – positional arguments passed to the ‘__init__’
               method.  This is passed as a tuple and is currently
               immutable.

             * ‘kwargs’ – keyword arguments passed to the ‘__init__’
               method.  This structure `can' be altered in place.

          See also
          ........

          See InstanceEvents.init_failure().

          See InstanceEvents.load().

      -- Method: sqlalchemy.orm.InstanceEvents..init_failure
               (target, args, kwargs)

          Receive an instance when its constructor has been called, and
          raised an exception.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'init_failure')
               def receive_init_failure(target, args, kwargs):
                   "listen for the 'init_failure' event"

                   # ... (event handling logic) ...

          This method is only called during a userland construction of
          an object, in conjunction with the object’s constructor, e.g.
          its ‘__init__’ method.  It is not called when an object is
          loaded from the database.

          The event is invoked after an exception raised by the
          ‘__init__’ method is caught.  After the event is invoked, the
          original exception is re-raised outwards, so that the
          construction of the object still raises an exception.  The
          actual exception and stack trace raised should be present in
          ‘sys.exc_info()’.

          Parameters:

             * ‘target’ – the mapped instance.  If the event is
               configured with ‘raw=True’, this will instead be the
               InstanceState state-management object
               associated with the instance.

             * ‘args’ – positional arguments that were passed to the
               ‘__init__’ method.

             * ‘kwargs’ – keyword arguments that were passed to the
               ‘__init__’ method.

          See also
          ........

          See InstanceEvents.init().

          See InstanceEvents.load().

      -- Method: sqlalchemy.orm.InstanceEvents..load (target,
               context)

          Receive an object instance after it has been created via
          ‘__new__’, and after initial attribute population has
          occurred.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'load')
               def receive_load(target, context):
                   "listen for the 'load' event"

                   # ... (event handling logic) ...

          This typically occurs when the instance is created based on
          incoming result rows, and is only called once for that
          instance’s lifetime.

               Warning: During a result-row load, this event is invoked
               when the first row received for this instance is
               processed.  When using eager loading with
               collection-oriented attributes, the additional rows that
               are to be loaded / processed in order to load subsequent
               collection items have not occurred yet.  This has the
               effect both that collections will not be fully loaded, as
               well as that if an operation occurs within this event
               handler that emits another database load operation for
               the object, the “loading context” for the object can
               change and interfere with the existing eager loaders
               still in progress.

               Examples of what can cause the “loading context” to
               change within the event handler include, but are not
               necessarily limited to:

                  * accessing deferred attributes that weren’t part of
                    the row, will trigger an “undefer” operation and
                    refresh the object

                  * accessing attributes on a joined-inheritance
                    subclass that weren’t part of the row, will trigger
                    a refresh operation.

               As of SQLAlchemy 1.3.14, a warning is emitted when this
               occurs.  The InstanceEvents.restore_load_context
               option may be used on the event to prevent this
               warning; this will ensure that the existing loading
               context is maintained for the object after the event is
               called:

                    @event.listens_for(
                        SomeClass, "load", restore_load_context=True)
                    def on_load(instance, context):
                        instance.some_unloaded_attribute

               Changed in version 1.3.14: Added
               InstanceEvents.restore_load_context and
               SessionEvents.restore_load_context flags which
               apply to “on load” events, which will ensure that the
               loading context for an object is restored when the event
               hook is complete; a warning is emitted if the load
               context of the object changes without this flag being
               set.

          The InstanceEvents.load() event is also available
          in a class-method decorator format called
          reconstructor().

          Parameters:

             * ‘target’ – the mapped instance.  If the event is
               configured with ‘raw=True’, this will instead be the
               InstanceState state-management object
               associated with the instance.

             * ‘context’ – the QueryContext corresponding to
               the current Query in progress.  This argument
               may be ‘None’ if the load does not correspond to a
               Query, such as during Session.merge().

          See also
          ........

          See InstanceEvents.init().

          See InstanceEvents.refresh().

          See SessionEvents.loaded_as_persistent().

          See Constructors and Object Initialization.

      -- Method: sqlalchemy.orm.InstanceEvents..pickle
               (target, state_dict)

          Receive an object instance when its associated state is being
          pickled.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'pickle')
               def receive_pickle(target, state_dict):
                   "listen for the 'pickle' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘target’ – the mapped instance.  If the event is
               configured with ‘raw=True’, this will instead be the
               InstanceState state-management object
               associated with the instance.

             * ‘state_dict’ – the dictionary returned by ‘__getstate__’,
               containing the state to be pickled.

      -- Method: sqlalchemy.orm.InstanceEvents..refresh
               (target, context, attrs)

          Receive an object instance after one or more attributes have
          been refreshed from a query.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'refresh')
               def receive_refresh(target, context, attrs):
                   "listen for the 'refresh' event"

                   # ... (event handling logic) ...

          Contrast this to the InstanceEvents.load() method,
          which is invoked when the object is first loaded from a query.

               Note: This event is invoked within the loader process
               before eager loaders may have been completed, and the
               object’s state may not be complete.  Additionally,
               invoking row-level refresh operations on the object will
               place the object into a new loader context, interfering
               with the existing load context.  See the note on
               InstanceEvents.load() for background on making use
               of the InstanceEvents.restore_load_context
               parameter, in order to resolve this scenario.

          Parameters:

             * ‘target’ – the mapped instance.  If the event is
               configured with ‘raw=True’, this will instead be the
               InstanceState state-management object
               associated with the instance.

             * ‘context’ – the QueryContext corresponding to
               the current Query in progress.

             * ‘attrs’ – sequence of attribute names which were
               populated, or None if all column-mapped, non-deferred
               attributes were populated.

          See also
          ........

          See InstanceEvents.load().

      -- Method: sqlalchemy.orm.InstanceEvents..refresh_flush
               (target, flush_context, attrs)

          Receive an object instance after one or more attributes that
          contain a column-level default or onupdate handler have been
          refreshed during persistence of the object’s state.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'refresh_flush')
               def receive_refresh_flush(target, flush_context, attrs):
                   "listen for the 'refresh_flush' event"

                   # ... (event handling logic) ...

          This event is the same as InstanceEvents.refresh()
          except it is invoked within the unit of work flush process,
          and includes only non-primary-key columns that have column
          level default or onupdate handlers, including Python callables
          as well as server side defaults and triggers which may be
          fetched via the RETURNING clause.

               Note: While the InstanceEvents.refresh_flush()
               event is triggered for an object that was INSERTed
               as well as for an object that was UPDATEd, the event is
               geared primarily towards the UPDATE process; it is mostly
               an internal artifact that INSERT actions can also trigger
               this event, and note that `primary key columns for an
               INSERTed row are explicitly omitted' from this event.  In
               order to intercept the newly INSERTed state of an object,
               the SessionEvents.pending_to_persistent() and
               MapperEvents.after_insert() are better
               choices.

          New in version 1.0.5.

          Parameters:

             * ‘target’ – the mapped instance.  If the event is
               configured with ‘raw=True’, this will instead be the
               InstanceState state-management object
               associated with the instance.

             * ‘flush_context’ – Internal UOWTransaction.
               object which handles the details of the flush.

             * ‘attrs’ – sequence of attribute names which were
               populated.

          See also
          ........

          See Fetching Server-Generated Defaults.

          See Column INSERT/UPDATE Defaults.

      -- Method: sqlalchemy.orm.InstanceEvents..unpickle
               (target, state_dict)

          Receive an object instance after its associated state has been
          unpickled.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass, 'unpickle')
               def receive_unpickle(target, state_dict):
                   "listen for the 'unpickle' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘target’ – the mapped instance.  If the event is
               configured with ‘raw=True’, this will instead be the
               InstanceState state-management object
               associated with the instance.

             * ‘state_dict’ – the dictionary sent to ‘__setstate__’,
               containing the state dictionary which was pickled.

3.6.1.4 Attribute Events
........................

Attribute events are triggered as things occur on individual attributes
of ORM mapped objects.  These events form the basis for things like
custom validation functions as well as backref handlers.

See also
........

See Changing Attribute Behavior.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See AttributeEvents.Define events for object attributes.

 -- Class: sqlalchemy.orm.AttributeEvents

     Define events for object attributes.

     These are typically defined on the class-bound descriptor for the
     target class.

     e.g.:

          from sqlalchemy import event

          @event.listens_for(MyClass.collection, 'append', propagate=True)
          def my_append_listener(target, value, initiator):
              print("received append event for target: %s" % target)

     Listeners have the option to return a possibly modified version of
     the value, when the AttributeEvents.retval flag is
     passed to listen() or listens_for():

          def validate_phone(target, value, oldvalue, initiator):
              "Strip non-numeric characters from a phone number"

              return re.sub(r'\D', '', value)

          # setup listener on UserContact.phone attribute, instructing
          # it to use the return value
          listen(UserContact.phone, 'set', validate_phone, retval=True)

     A validation function like the above can also raise an exception
     such as ‘ValueError’ to halt the operation.

     The AttributeEvents.propagate flag is also important
     when applying listeners to mapped classes that also have mapped
     subclasses, as when using mapper inheritance patterns:

          @event.listens_for(MySuperClass.attr, 'set', propagate=True)
          def receive_set(target, value, initiator):
              print("value set: %s" % target)

     The full list of modifiers available to the listen()
     and listens_for() functions are below.

     Parameters:

        * ‘active_history=False’ – When True, indicates that the “set”
          event would like to receive the “old” value being replaced
          unconditionally, even if this requires firing off database
          loads.  Note that ‘active_history’ can also be set directly
          via column_property() and relationship().

        * ‘propagate=False’ – When True, the listener function will be
          established not just for the class attribute given, but for
          attributes of the same name on all current subclasses of that
          class, as well as all future subclasses of that class, using
          an additional listener that listens for instrumentation
          events.

        * ‘raw=False’ – When True, the “target” argument to the event
          will be the InstanceState management object,
          rather than the mapped instance itself.

        * ‘retval=False’ – when True, the user-defined event listening
          must return the “value” argument from the function.  This
          gives the listening function the opportunity to change the
          value that is ultimately used for a “set” or “append” event.

     `Class signature'

     class sqlalchemy.orm.AttributeEvents.
     (‘sqlalchemy.event.Events’)

      -- Method: sqlalchemy.orm.AttributeEvents..append
               (target, value, initiator)

          Receive a collection append event.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass.some_attribute, 'append')
               def receive_append(target, value, initiator):
                   "listen for the 'append' event"

                   # ... (event handling logic) ...

          The append event is invoked for each element as it is appended
          to the collection.  This occurs for single-item appends as
          well as for a “bulk replace” operation.

          Parameters:

             * ‘target’ – the object instance receiving the event.  If
               the listener is registered with ‘raw=True’, this will be
               the InstanceState object.

             * ‘value’ – the value being appended.  If this listener is
               registered with ‘retval=True’, the listener function must
               return this value, or a new value which replaces it.

             * ‘initiator’ – An instance of ‘Event’ representing the
               initiation of the event.  May be modified from its
               original value by backref handlers in order to control
               chained event propagation, as well as be inspected for
               information about the source of the event.

          Returns: if the event was registered with ‘retval=True’, the
          given value, or a new effective value, should be returned.

          See also
          ........

          See AttributeEvents. - background on listener options
          such as propagation to subclasses.

          See AttributeEvents.bulk_replace().

      -- Method: sqlalchemy.orm.AttributeEvents..bulk_replace
               (target, values, initiator)

          Receive a collection ‘bulk replace’ event.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass.some_attribute, 'bulk_replace')
               def receive_bulk_replace(target, values, initiator):
                   "listen for the 'bulk_replace' event"

                   # ... (event handling logic) ...

          This event is invoked for a sequence of values as they are
          incoming to a bulk collection set operation, which can be
          modified in place before the values are treated as ORM
          objects.  This is an “early hook” that runs before the bulk
          replace routine attempts to reconcile which objects are
          already present in the collection and which are being removed
          by the net replace operation.

          It is typical that this method be combined with use of the
          AttributeEvents.append() event.  When using both
          of these events, note that a bulk replace operation will
          invoke the AttributeEvents.append() event for all
          new items, even after AttributeEvents.bulk_replace()
          has been invoked for the collection as a whole.  In order
          to determine if an AttributeEvents.append() event
          is part of a bulk replace, use the symbol
          ‘attributes.OP_BULK_REPLACE’ to test the incoming initiator:

               from sqlalchemy.orm.attributes import OP_BULK_REPLACE

               @event.listens_for(SomeObject.collection, "bulk_replace")
               def process_collection(target, values, initiator):
                   values[:] = [_make_value(value) for value in values]

               @event.listens_for(SomeObject.collection, "append", retval=True)
               def process_collection(target, value, initiator):
                   # make sure bulk_replace didn't already do it
                   if initiator is None or initiator.op is not OP_BULK_REPLACE:
                       return _make_value(value)
                   else:
                       return value

          New in version 1.2.

          Parameters:

             * ‘target’ – the object instance receiving the event.  If
               the listener is registered with ‘raw=True’, this will be
               the InstanceState object.

             * ‘value’ – a sequence (e.g.  a list) of the values being
               set.  The handler can modify this list in place.

             * ‘initiator’ – An instance of ‘Event’ representing the
               initiation of the event.

          See also
          ........

          See AttributeEvents. - background on listener options
          such as propagation to subclasses.

      -- Method: sqlalchemy.orm.AttributeEvents..
               dispose_collection (target, collection,
               collection_adapter)

          Receive a ‘collection dispose’ event.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass.some_attribute, 'dispose_collection')
               def receive_dispose_collection(target, collection, collection_adapter):
                   "listen for the 'dispose_collection' event"

                   # ... (event handling logic) ...

          This event is triggered for a collection-based attribute when
          a collection is replaced, that is:

               u1.addresses.append(a1)

               u1.addresses = [a2, a3]  # <- old collection is disposed

          The old collection received will contain its previous
          contents.

          Changed in version 1.2: The collection passed to
          AttributeEvents.dispose_collection() will now have its
          contents before the dispose intact; previously, the collection
          would be empty.

          New in version 1.0.0: the
          AttributeEvents.init_collection() and
          AttributeEvents.dispose_collection() events.

          See also
          ........

          See AttributeEvents. - background on listener options
          such as propagation to subclasses.

      -- Method: sqlalchemy.orm.AttributeEvents..
               init_collection (target, collection,
               collection_adapter)

          Receive a ‘collection init’ event.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass.some_attribute, 'init_collection')
               def receive_init_collection(target, collection, collection_adapter):
                   "listen for the 'init_collection' event"

                   # ... (event handling logic) ...

          This event is triggered for a collection-based attribute, when
          the initial “empty collection” is first generated for a blank
          attribute, as well as for when the collection is replaced with
          a new one, such as via a set event.

          E.g., given that ‘User.addresses’ is a relationship-based
          collection, the event is triggered here:

               u1 = User()
               u1.addresses.append(a1)  #  <- new collection

          and also during replace operations:

               u1.addresses = [a2, a3]  #  <- new collection

          Parameters:

             * ‘target’ – the object instance receiving the event.  If
               the listener is registered with ‘raw=True’, this will be
               the InstanceState object.

             * ‘collection’ – the new collection.  This will always be
               generated from what was specified as
               relationship.collection_class, and will always be
               empty.

             * ‘collection_adapter’ – the CollectionAdapter.
               that will mediate internal access to the collection.

          New in version 1.0.0: AttributeEvents.init_collection()
          and AttributeEvents.dispose_collection()
          events.

          See also
          ........

          See AttributeEvents. - background on listener options
          such as propagation to subclasses.

          See AttributeEvents.init_scalar(). - “scalar” version
          of this event.

      -- Method: sqlalchemy.orm.AttributeEvents..init_scalar
               (target, value, dict_)

          Receive a scalar “init” event.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass.some_attribute, 'init_scalar')
               def receive_init_scalar(target, value, dict_):
                   "listen for the 'init_scalar' event"

                   # ... (event handling logic) ...

          This event is invoked when an uninitialized, unpersisted
          scalar attribute is accessed, e.g.  read:

               x = my_object.some_attribute

          The ORM’s default behavior when this occurs for an
          un-initialized attribute is to return the value ‘None’; note
          this differs from Python’s usual behavior of raising
          ‘AttributeError’.  The event here can be used to customize
          what value is actually returned, with the assumption that the
          event listener would be mirroring a default generator that is
          configured on the Core Column object as well.

          Since a default generator on a Column might also
          produce a changing value such as a timestamp, the
          AttributeEvents.init_scalar() event handler can also be
          used to `set' the newly returned value, so that a Core-level
          default generation function effectively fires off only once,
          but at the moment the attribute is accessed on the
          non-persisted object.  Normally, no change to the object’s
          state is made when an uninitialized attribute is accessed
          (much older SQLAlchemy versions did in fact change the
          object’s state).

          If a default generator on a column returned a particular
          constant, a handler might be used as follows:

               SOME_CONSTANT = 3.1415926

               class MyClass(Base):
                   # ...

                   some_attribute = Column(Numeric, default=SOME_CONSTANT)

               @event.listens_for(
                   MyClass.some_attribute, "init_scalar",
                   retval=True, propagate=True)
               def _init_some_attribute(target, dict_, value):
                   dict_['some_attribute'] = SOME_CONSTANT
                   return SOME_CONSTANT

          Above, we initialize the attribute ‘MyClass.some_attribute’ to
          the value of ‘SOME_CONSTANT’.  The above code includes the
          following features:

             * By setting the value ‘SOME_CONSTANT’ in the given
               ‘dict_’, we indicate that this value is to be persisted
               to the database.  This supersedes the use of
               ‘SOME_CONSTANT’ in the default generator for the
               Column.  The ‘active_column_defaults.py’ example
               given at Attribute Instrumentation
               illustrates using the same approach for a changing
               default, e.g.  a timestamp generator.  In this particular
               example, it is not strictly necessary to do this since
               ‘SOME_CONSTANT’ would be part of the INSERT statement in
               either case.

             * By establishing the ‘retval=True’ flag, the value we
               return from the function will be returned by the
               attribute getter.  Without this flag, the event is
               assumed to be a passive observer and the return value of
               our function is ignored.

             * The ‘propagate=True’ flag is significant if the mapped
               class includes inheriting subclasses, which would also
               make use of this event listener.  Without this flag, an
               inheriting subclass will not use our event handler.

          In the above example, the attribute set event
          AttributeEvents.set() as well as the related validation
          feature provided by validates is `not' invoked
          when we apply our value to the given ‘dict_’.  To have these
          events to invoke in response to our newly generated value,
          apply the value to the given object as a normal attribute set
          operation:

               SOME_CONSTANT = 3.1415926

               @event.listens_for(
                   MyClass.some_attribute, "init_scalar",
                   retval=True, propagate=True)
               def _init_some_attribute(target, dict_, value):
                   # will also fire off attribute set events
                   target.some_attribute = SOME_CONSTANT
                   return SOME_CONSTANT

          When multiple listeners are set up, the generation of the
          value is “chained” from one listener to the next by passing
          the value returned by the previous listener that specifies
          ‘retval=True’ as the ‘value’ argument of the next listener.

          New in version 1.1.

          Parameters:

             * ‘target’ – the object instance receiving the event.  If
               the listener is registered with ‘raw=True’, this will be
               the InstanceState object.

             * ‘value’ – the value that is to be returned before this
               event listener were invoked.  This value begins as the
               value ‘None’, however will be the return value of the
               previous event handler function if multiple listeners are
               present.

             * ‘dict_’ – the attribute dictionary of this mapped object.
               This is normally the ‘__dict__’ of the object, but in all
               cases represents the destination that the attribute
               system uses to get at the actual value of this attribute.
               Placing the value in this dictionary has the effect that
               the value will be used in the INSERT statement generated
               by the unit of work.

          See also
          ........

          See AttributeEvents.init_collection(). - collection
          version of this event

          See AttributeEvents. - background on listener options
          such as propagation to subclasses.

          See Attribute Instrumentation. - see the
          ‘active_column_defaults.py’ example.

      -- Method: sqlalchemy.orm.AttributeEvents..modified
               (target, initiator)

          Receive a ‘modified’ event.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass.some_attribute, 'modified')
               def receive_modified(target, initiator):
                   "listen for the 'modified' event"

                   # ... (event handling logic) ...

          This event is triggered when the flag_modified()
          function is used to trigger a modify event on an attribute
          without any specific value being set.

          New in version 1.2.

          Parameters:

             * ‘target’ – the object instance receiving the event.  If
               the listener is registered with ‘raw=True’, this will be
               the InstanceState object.

             * ‘initiator’ – An instance of ‘Event’ representing the
               initiation of the event.

          See also
          ........

          See AttributeEvents. - background on listener options
          such as propagation to subclasses.

      -- Method: sqlalchemy.orm.AttributeEvents..remove
               (target, value, initiator)

          Receive a collection remove event.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass.some_attribute, 'remove')
               def receive_remove(target, value, initiator):
                   "listen for the 'remove' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘target’ – the object instance receiving the event.  If
               the listener is registered with ‘raw=True’, this will be
               the InstanceState object.

             * ‘value’ – the value being removed.

             * ‘initiator’ – An instance of ‘Event’ representing the
               initiation of the event.  May be modified from its
               original value by backref handlers in order to control
               chained event propagation.

               Changed in version 0.9.0: the ‘initiator’ argument is now
               passed as a ‘Event’ object, and may be modified by
               backref handlers within a chain of backref-linked events.

          Returns: No return value is defined for this event.

          See also
          ........

          See AttributeEvents. - background on listener options
          such as propagation to subclasses.

      -- Method: sqlalchemy.orm.AttributeEvents..set (target,
               value, oldvalue, initiator)

          Receive a scalar set event.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeClass.some_attribute, 'set')
               def receive_set(target, value, oldvalue, initiator):
                   "listen for the 'set' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘target’ – the object instance receiving the event.  If
               the listener is registered with ‘raw=True’, this will be
               the InstanceState object.

             * ‘value’ – the value being set.  If this listener is
               registered with ‘retval=True’, the listener function must
               return this value, or a new value which replaces it.

             * ‘oldvalue’ – the previous value being replaced.  This may
               also be the symbol ‘NEVER_SET’ or ‘NO_VALUE’.  If the
               listener is registered with ‘active_history=True’, the
               previous value of the attribute will be loaded from the
               database if the existing value is currently unloaded or
               expired.

             * ‘initiator’ – An instance of ‘Event’ representing the
               initiation of the event.  May be modified from its
               original value by backref handlers in order to control
               chained event propagation.

               Changed in version 0.9.0: the ‘initiator’ argument is now
               passed as a ‘Event’ object, and may be modified by
               backref handlers within a chain of backref-linked events.

          Returns: if the event was registered with ‘retval=True’, the
          given value, or a new effective value, should be returned.

          See also
          ........

          See AttributeEvents. - background on listener options
          such as propagation to subclasses.

3.6.1.5 Query Events
....................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See QueryEvents.Represent events within the construction of a Query object.

 -- Class: sqlalchemy.orm.QueryEvents

     Represent events within the construction of a Query
     object.

     The QueryEvents hooks are now superseded by the
     SessionEvents.do_orm_execute() event hook.

     `Class signature'

     class sqlalchemy.orm.QueryEvents.
     (‘sqlalchemy.event.Events’)

      -- Method: sqlalchemy.orm.QueryEvents..before_compile
               (query)

          Receive the Query object before it is composed
          into a core Select object.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeQuery, 'before_compile')
               def receive_before_compile(query):
                   "listen for the 'before_compile' event"

                   # ... (event handling logic) ...

          Deprecated since version 1.4: The
          QueryEvents.before_compile() event is superseded by the
          much more capable SessionEvents.do_orm_execute()
          hook.  In version 1.4, the QueryEvents.before_compile()
          event is `no longer used' for ORM-level attribute loads,
          such as loads of deferred or expired attributes as well as
          relationship loaders.  See the new examples in ORM Query Events
          which illustrate new ways of intercepting and
          modifying ORM queries for the most common purpose of adding
          arbitrary filter criteria.

          This event is intended to allow changes to the query given:

               @event.listens_for(Query, "before_compile", retval=True)
               def no_deleted(query):
                   for desc in query.column_descriptions:
                       if desc['type'] is User:
                           entity = desc['entity']
                           query = query.filter(entity.deleted == False)
                   return query

          The event should normally be listened with the ‘retval=True’
          parameter set, so that the modified query may be returned.

          The QueryEvents.before_compile() event by default
          will disallow “baked” queries from caching a query, if the
          event hook returns a new Query object.  This
          affects both direct use of the baked query extension as well
          as its operation within lazy loaders and eager loaders for
          relationships.  In order to re-establish the query being
          cached, apply the event adding the ‘bake_ok’ flag:

               @event.listens_for(
                   Query, "before_compile", retval=True, bake_ok=True)
               def my_event(query):
                   for desc in query.column_descriptions:
                       if desc['type'] is User:
                           entity = desc['entity']
                           query = query.filter(entity.deleted == False)
                   return query

          When ‘bake_ok’ is set to True, the event hook will only be
          invoked once, and not called for subsequent invocations of a
          particular query that is being cached.

          New in version 1.3.11: - added the “bake_ok” flag to the
          QueryEvents.before_compile() event and disallowed
          caching via the “baked” extension from occurring for event
          handlers that return a new Query object if this
          flag is not set.

          See also
          ........

          See QueryEvents.before_compile_update().

          See QueryEvents.before_compile_delete().

          See Using the before_compile event.

      -- Method: sqlalchemy.orm.QueryEvents..
               before_compile_delete (query, delete_context)

          Allow modifications to the Query object within
          Query.delete().

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeQuery, 'before_compile_delete')
               def receive_before_compile_delete(query, delete_context):
                   "listen for the 'before_compile_delete' event"

                   # ... (event handling logic) ...

          Deprecated since version 1.4: The
          QueryEvents.before_compile_delete() event is superseded
          by the much more capable SessionEvents.do_orm_execute()
          hook.

          Like the QueryEvents.before_compile() event, this
          event should be configured with ‘retval=True’, and the
          modified Query object returned, as in

               @event.listens_for(Query, "before_compile_delete", retval=True)
               def no_deleted(query, delete_context):
                   for desc in query.column_descriptions:
                       if desc['type'] is User:
                           entity = desc['entity']
                           query = query.filter(entity.deleted == False)
                   return query

          Parameters:

             * ‘query’ – a Query instance; this is also the
               ‘.query’ attribute of the given “delete context” object.

             * ‘delete_context’ – a “delete context” object which is the
               same kind of object as described in
               ‘QueryEvents.after_bulk_delete.delete_context’.

          New in version 1.2.17.

          See also
          ........

          See QueryEvents.before_compile().

          See QueryEvents.before_compile_update().

      -- Method: sqlalchemy.orm.QueryEvents..
               before_compile_update (query, update_context)

          Allow modifications to the Query object within
          Query.update().

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeQuery, 'before_compile_update')
               def receive_before_compile_update(query, update_context):
                   "listen for the 'before_compile_update' event"

                   # ... (event handling logic) ...

          Deprecated since version 1.4: The
          QueryEvents.before_compile_update() event is superseded
          by the much more capable SessionEvents.do_orm_execute()
          hook.

          Like the QueryEvents.before_compile() event, if
          the event is to be used to alter the Query object,
          it should be configured with ‘retval=True’, and the modified
          Query object returned, as in

               @event.listens_for(Query, "before_compile_update", retval=True)
               def no_deleted(query, update_context):
                   for desc in query.column_descriptions:
                       if desc['type'] is User:
                           entity = desc['entity']
                           query = query.filter(entity.deleted == False)

                           update_context.values['timestamp'] = datetime.utcnow()
                   return query

          The ‘.values’ dictionary of the “update context” object can
          also be modified in place as illustrated above.

          Parameters:

             * ‘query’ – a Query instance; this is also the
               ‘.query’ attribute of the given “update context” object.

             * ‘update_context’ – an “update context” object which is
               the same kind of object as described in
               ‘QueryEvents.after_bulk_update.update_context’.  The
               object has a ‘.values’ attribute in an UPDATE context
               which is the dictionary of parameters passed to
               Query.update().  This dictionary can be modified to
               alter the VALUES clause of the resulting UPDATE
               statement.

          New in version 1.2.17.

          See also
          ........

          See QueryEvents.before_compile().

          See QueryEvents.before_compile_delete().

3.6.1.6 Instrumentation Events
..............................

Defines SQLAlchemy’s system of class instrumentation.

This module is usually not directly visible to user applications, but
defines a large part of the ORM’s interactivity.

instrumentation.py deals with registration of end-user classes for state
tracking.  It interacts closely with state.py and attributes.py which
establish per-instance and per-class-attribute instrumentation,
respectively.

The class instrumentation system can be customized on a per-class or
global basis using the sqlalchemy.ext.instrumentation module,
which provides the means to build and specify alternate instrumentation
forms.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See InstrumentationEvents.Events related to class instrumentation events.

 -- Class: sqlalchemy.orm.InstrumentationEvents

     Events related to class instrumentation events.

     The listeners here support being established against any new style
     class, that is any object that is a subclass of ‘type’.  Events
     will then be fired off for events against that class.  If the
     “propagate=True” flag is passed to event.listen(), the event will
     fire off for subclasses of that class as well.

     The Python ‘type’ builtin is also accepted as a target, which when
     used has the effect of events being emitted for all classes.

     Note the “propagate” flag here is defaulted to ‘True’, unlike the
     other class level events where it defaults to ‘False’.  This means
     that new subclasses will also be the subject of these events, when
     a listener is established on a superclass.

     `Class signature'

     class sqlalchemy.orm.InstrumentationEvents.
     (‘sqlalchemy.event.Events’)

      -- Method: sqlalchemy.orm.InstrumentationEvents..
               attribute_instrument (cls, key, inst)

          Called when an attribute is instrumented.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeBaseClass, 'attribute_instrument')
               def receive_attribute_instrument(cls, key, inst):
                   "listen for the 'attribute_instrument' event"

                   # ... (event handling logic) ...

      -- Method: sqlalchemy.orm.InstrumentationEvents..
               class_instrument (cls)

          Called after the given class is instrumented.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeBaseClass, 'class_instrument')
               def receive_class_instrument(cls):
                   "listen for the 'class_instrument' event"

                   # ... (event handling logic) ...

          To get at the ClassManager, use
          ‘manager_of_class()’.

      -- Method: sqlalchemy.orm.InstrumentationEvents..
               class_uninstrument (cls)

          Called before the given class is uninstrumented.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeBaseClass, 'class_uninstrument')
               def receive_class_uninstrument(cls):
                   "listen for the 'class_uninstrument' event"

                   # ... (event handling logic) ...

          To get at the ClassManager, use
          ‘manager_of_class()’.

3.6.2 ORM Internals
-------------------

Key ORM constructs, not otherwise covered in other sections, are listed
here.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See AttributeEvent.A token propagated throughout the course of a chain of attribute events.

See AttributeState.Provide an inspection interface corresponding to a particular attribute on a particular
               mapped object.

See CascadeOptions.Keeps track of the options sent to relationship.cascade.

See ClassManager.Tracks state information at the class level.

See ColumnProperty.Describes an object attribute that corresponds to a table column.

See CompositeProperty.Defines a “composite” mapped attribute, representing a collection of columns as one
               attribute.

See IdentityMap.

See InspectionAttr.A base class applied to all ORM objects that can be returned by the inspect().
               function.

See InspectionAttrInfo.Adds the ‘.info’ attribute to InspectionAttr.

See InstanceState.tracks state information at the instance level.

See InstrumentedAttribute.Class bound instrumented attribute which adds basic descriptor methods.

See MANYTOMANY.Indicates the many-to-many direction for a relationship().

See MANYTOONE.Indicates the many-to-one direction for a relationship().

See Mapped.Represent an ORM mapped descriptor attribute for typing purposes.

See MapperProperty.Represent a particular class attribute mapped by Mapper.

See merge_frozen_result.(session,Merge a FrozenResult back into a Session, returning a new
statement,     see Result object with persistent objects.
frozen_result[,
load])

See merge_result.(query,Merge a result into this Query object’s Session.
iterator[,
load])

See NOT_EXTENSION.Symbol indicating an InspectionAttr that’s not part of sqlalchemy.ext.

See ONETOMANY.Indicates the one-to-many direction for a relationship().

See PropComparator.Defines SQL operators for MapperProperty objects.

See QueryableAttribute.Base class for descriptor objects that intercept attribute events on behalf of a
               MapperProperty object.  The actual MapperProperty is accessible via
               the QueryableAttribute.property attribute.

See QueryContext.

See RelationshipProperty.Describes an object property that holds a single item or list of items that correspond to a
               related database table.

See SynonymProperty.

See UOWTransaction.

 -- Class: sqlalchemy.orm.AttributeState (state, key)

     Provide an inspection interface corresponding to a particular
     attribute on a particular mapped object.

     The AttributeState object is accessed via the
     InstanceState.attrs collection of a particular
     InstanceState:

          from sqlalchemy import inspect

          insp = inspect(some_mapped_object)
          attr_state = insp.attrs.some_attribute

      -- Attribute: sqlalchemy.orm.AttributeState..history

          Return the current `pre-flush' change history for this
          attribute, via the History interface.

          This method will `not' emit loader callables if the value of
          the attribute is unloaded.

               Note: The attribute history system tracks changes on a
               `per flush basis'.  Each time the Session is
               flushed, the history of each attribute is reset to empty.
               The Session by default autoflushes each time a
               Query is invoked.  For options on how to
               control this, see Flushing.

          See also
          ........

          See AttributeState.load_history(). - retrieve history
          using loader callables if the value is not locally present.

          See get_history(). - underlying function

      -- Method: sqlalchemy.orm.AttributeState..load_history
               ()

          Return the current `pre-flush' change history for this
          attribute, via the History interface.

          This method `will' emit loader callables if the value of the
          attribute is unloaded.

               Note: The attribute history system tracks changes on a
               `per flush basis'.  Each time the Session is
               flushed, the history of each attribute is reset to empty.
               The Session by default autoflushes each time a
               Query is invoked.  For options on how to
               control this, see Flushing.

          See also
          ........

          See AttributeState.history.

          See get_history(). - underlying function

          New in version 0.9.0.

      -- Attribute: sqlalchemy.orm.AttributeState..
               loaded_value

          The current value of this attribute as loaded from the
          database.

          If the value has not been loaded, or is otherwise not present
          in the object’s dictionary, returns NO_VALUE.

      -- Attribute: sqlalchemy.orm.AttributeState..value

          Return the value of this attribute.

          This operation is equivalent to accessing the object’s
          attribute directly or via ‘getattr()’, and will fire off any
          pending loader callables if needed.

 -- Class: sqlalchemy.orm.CascadeOptions (value_list)

     Keeps track of the options sent to relationship.cascade.

     `Class signature'

     class sqlalchemy.orm.CascadeOptions.
     (‘builtins.frozenset’)

 -- Class: sqlalchemy.orm.ClassManager (class_)

     Tracks state information at the class level.

     `Class signature'

     class sqlalchemy.orm.ClassManager.
     (‘sqlalchemy.util.langhelpers.HasMemoized’, ‘builtins.dict’)

      -- Method: sqlalchemy.orm.ClassManager..clear () ->
               None. Remove all items from D.

          `inherited from the' ‘builtins.dict.clear’ `method of'
          ‘builtins.dict’

      -- Method: sqlalchemy.orm.ClassManager..copy () -> a
               shallow copy of D

          `inherited from the' ‘builtins.dict.copy’ `method of'
          ‘builtins.dict’

      -- Attribute: sqlalchemy.orm.ClassManager..
               deferred_scalar_loader

          Deprecated since version 1.4: The
          ClassManager.deferred_scalar_loader attribute is now named
          expired_attribute_loader

      -- Attribute: sqlalchemy.orm.ClassManager..
               expired_attribute_loader = None

          previously known as deferred_scalar_loader

      -- Method: sqlalchemy.orm.ClassManager..fromkeys
               (value=None, /)

          `inherited from the' ‘builtins.dict.fromkeys’ `method of'
          ‘builtins.dict’

          Create a new dictionary with keys from iterable and values set
          to value.

      -- Method: sqlalchemy.orm.ClassManager..get (key,
               default=None, /)

          `inherited from the' ‘builtins.dict.get’ `method of'
          ‘builtins.dict’

          Return the value for key if key is in the dictionary, else
          default.

      -- Method: sqlalchemy.orm.ClassManager..has_parent
               (state, key, optimistic=False)

          TODO

      -- Method: sqlalchemy.orm.ClassManager..items () -> a
               set-like object providing a view on D’s items

          `inherited from the' ‘builtins.dict.items’ `method of'
          ‘builtins.dict’

      -- Method: sqlalchemy.orm.ClassManager..keys () -> a
               set-like object providing a view on D’s keys

          `inherited from the' ‘builtins.dict.keys’ `method of'
          ‘builtins.dict’

      -- Method: sqlalchemy.orm.ClassManager..manage ()

          Mark this instance as the manager for its class.

      -- Class: memoized_attribute (fget, doc=None)

          A read-only @property that is only evaluated once.

      -- Method: sqlalchemy.orm.ClassManager..classmethod
               memoized_instancemethod (fn)

          `inherited from the' ‘HasMemoized.memoized_instancemethod()’
          `method of' ‘HasMemoized’

          Decorate a method memoize its return value.

      -- Method: sqlalchemy.orm.ClassManager..pop (k[, d]) ->
               v, remove specified key and return the corresponding
               value.

          `inherited from the' ‘builtins.dict.pop’ `method of'
          ‘builtins.dict’

          If key is not found, d is returned if given, otherwise
          KeyError is raised

      -- Method: sqlalchemy.orm.ClassManager..popitem ()

          `inherited from the' ‘builtins.dict.popitem’ `method of'
          ‘builtins.dict’

          Remove and return a (key, value) pair as a 2-tuple.

          Pairs are returned in LIFO (last-in, first-out) order.  Raises
          KeyError if the dict is empty.

      -- Method: sqlalchemy.orm.ClassManager..setdefault
               (key, default=None, /)

          `inherited from the' ‘builtins.dict.setdefault’ `method of'
          ‘builtins.dict’

          Insert key with a value of default if key is not in the
          dictionary.

          Return the value for key if key is in the dictionary, else
          default.

      -- Method: sqlalchemy.orm.ClassManager..state_getter ()

          Return a (instance) -> InstanceState callable.

          “state getter” callables should raise either KeyError or
          AttributeError if no InstanceState could be found for the
          instance.

      -- Method: sqlalchemy.orm.ClassManager..unregister ()

          remove all instrumentation established by this ClassManager.

      -- Method: sqlalchemy.orm.ClassManager..update ([E],
               **F) -> None. Update D from dict/iterable E and F.

          `inherited from the' ‘builtins.dict.update’ `method of'
          ‘builtins.dict’

          If E is present and has a .keys() method, then does: for k in
          E: D[k] = E[k] If E is present and lacks a .keys() method,
          then does: for k, v in E: D[k] = v In either case, this is
          followed by: for k in F: D[k] = F[k]

      -- Method: sqlalchemy.orm.ClassManager..values () -> an
               object providing a view on D’s values

          `inherited from the' ‘builtins.dict.values’ `method of'
          ‘builtins.dict’

 -- Class: sqlalchemy.orm.ColumnProperty (*columns, **kwargs)

     Describes an object attribute that corresponds to a table column.

     Public constructor is the column_property() function.

     `Class signature'

     class sqlalchemy.orm.ColumnProperty.
     (‘sqlalchemy.orm.StrategizedProperty’)

      -- Attribute: sqlalchemy.orm.ColumnProperty..
               Comparator.expressions

          The full sequence of columns referenced by this attribute,
          adjusted for any aliasing in progress.

          New in version 1.3.17.

          See also
          ........

          See Mapping a Class against Multiple Tables. - usage
          example

      -- Class: Comparator (prop, parentmapper, adapt_to_entity=None)

          Produce boolean, comparison, and other operators for
          ColumnProperty attributes.

          See the documentation for PropComparator for a
          brief overview.

          See also
          ........

          See PropComparator.

          See ColumnOperators.

          See Redefining and Creating New Operators.

          See TypeEngine.comparator_factory.

          `Class signature'

          class sqlalchemy.orm.ColumnProperty.Comparator.
          (‘sqlalchemy.util.langhelpers.MemoizedSlots’, see
          sqlalchemy.orm.PropComparator)

           -- Method: sqlalchemy.orm.ColumnProperty.Comparator..
                    operate (op, *other, **kwargs)

               Operate on an argument.

               This is the lowest level of operation, raises
               ‘NotImplementedError’ by default.

               Overriding this on a subclass can allow common behavior
               to be applied to all operations.  For example, overriding
               ColumnOperators to apply ‘func.lower()’ to
               the left and right side:

                    class MyComparator(ColumnOperators):
                        def operate(self, op, other):
                            return op(func.lower(self), func.lower(other))

               Parameters:

                  * ‘op’ – Operator callable.

                  * ‘*other’ – the ‘other’ side of the operation.  Will
                    be a single scalar for most operations.

                  * ‘**kwargs’ – modifiers.  These may be passed by
                    special operators such as
                    ‘ColumnOperators.contains()’.

           -- Method: sqlalchemy.orm.ColumnProperty.Comparator..
                    reverse_operate (op, other, **kwargs)

               Reverse operate on an argument.

               Usage is the same as operate().

      -- Method: sqlalchemy.orm.ColumnProperty..__init__
               (*columns, **kwargs)

          Construct a new ColumnProperty object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.orm.column_property() for a full usage
          and argument description.

      -- Method: sqlalchemy.orm.ColumnProperty..do_init ()

          Perform subclass-specific initialization post-mapper-creation
          steps.

          This is a template method called by the ‘MapperProperty’
          object’s init() method.

      -- Attribute: sqlalchemy.orm.ColumnProperty..expression

          Return the primary column or expression for this
          ColumnProperty.

          E.g.:

               class File(Base):
                   # ...

                   name = Column(String(64))
                   extension = Column(String(8))
                   filename = column_property(name + '.' + extension)
                   path = column_property('C:/' + filename.expression)

          See also
          ........

          See Composing from Column Properties at Mapping Time.

      -- Method: sqlalchemy.orm.ColumnProperty..
               instrument_class (mapper)

          Hook called by the Mapper to the property to initiate
          instrumentation of the class attribute managed by this
          MapperProperty.

          The MapperProperty here will typically call out to the
          attributes module to set up an InstrumentedAttribute.

          This step is the first of two steps to set up an
          InstrumentedAttribute, and is called early in the mapper setup
          process.

          The second step is typically the init_class_attribute step,
          called from StrategizedProperty via the
          post_instrument_class() hook.  This step assigns additional
          state to the InstrumentedAttribute (specifically the “impl”)
          which has been determined after the MapperProperty has
          determined what kind of persistence management it needs to do
          (e.g.  scalar, object, collection, etc).

      -- Method: sqlalchemy.orm.ColumnProperty..merge
               (session, source_state, source_dict, dest_state,
               dest_dict, load, _recursive, _resolve_conflict_map)

          Merge the attribute represented by this ‘MapperProperty’ from
          source to destination object.

 -- Class: sqlalchemy.orm.CompositeProperty (class_, *attrs, **kwargs)

     Defines a “composite” mapped attribute, representing a collection
     of columns as one attribute.

     CompositeProperty is constructed using the
     composite() function.

     See also
     ........

     See Composite Column Types.

     `Class signature'

     class sqlalchemy.orm.CompositeProperty.
     (‘sqlalchemy.orm.descriptor_props.DescriptorProperty’)

      -- Class: Comparator (prop, parentmapper, adapt_to_entity=None)

          Produce boolean, comparison, and other operators for
          CompositeProperty attributes.

          See the example in Redefining Comparison Operations for Composites
          for an overview of usage , as well as the
          documentation for PropComparator.

          See also
          ........

          See PropComparator.

          See ColumnOperators.

          See Redefining and Creating New Operators.

          See TypeEngine.comparator_factory.

          `Class signature'

          class sqlalchemy.orm.CompositeProperty.Comparator.
          (see sqlalchemy.orm.PropComparator)

           -- Attribute:
                    sqlalchemy.orm.CompositeProperty.Comparator..
                    clauses

           -- Attribute:
                    sqlalchemy.orm.CompositeProperty.Comparator..
                    expression

      -- Class: CompositeBundle (property_, expr)

          `Class signature'

          class sqlalchemy.orm.CompositeProperty.CompositeBundle.
          (see sqlalchemy.orm.Bundle)

           -- Method:
                    sqlalchemy.orm.CompositeProperty.CompositeBundle..
                    create_row_processor (query, procs, labels)

               Produce the “row processing” function for this
               Bundle.

               May be overridden by subclasses.

               See also
               ........

               See Column Bundles. - includes an example of
               subclassing.

      -- Method: sqlalchemy.orm.CompositeProperty..__init__
               (class_, *attrs, **kwargs)

          Construct a new CompositeProperty object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.orm.composite() for a full usage and
          argument description.

      -- Method: sqlalchemy.orm.CompositeProperty..do_init ()

          Initialization which occurs after the CompositeProperty
          has been associated with its parent mapper.

      -- Method: sqlalchemy.orm.CompositeProperty..
               get_history (state, dict_,
               passive=symbol('PASSIVE_OFF'))

          Provided for userland code that uses attributes.get_history().

      -- Method: sqlalchemy.orm.CompositeProperty..
               instrument_class (mapper)

          Hook called by the Mapper to the property to initiate
          instrumentation of the class attribute managed by this
          MapperProperty.

          The MapperProperty here will typically call out to the
          attributes module to set up an InstrumentedAttribute.

          This step is the first of two steps to set up an
          InstrumentedAttribute, and is called early in the mapper setup
          process.

          The second step is typically the init_class_attribute step,
          called from StrategizedProperty via the
          post_instrument_class() hook.  This step assigns additional
          state to the InstrumentedAttribute (specifically the “impl”)
          which has been determined after the MapperProperty has
          determined what kind of persistence management it needs to do
          (e.g.  scalar, object, collection, etc).

 -- Class: sqlalchemy.orm.AttributeEvent (attribute_impl, op)

     A token propagated throughout the course of a chain of attribute
     events.

     Serves as an indicator of the source of the event and also provides
     a means of controlling propagation across a chain of attribute
     operations.

     The ‘Event’ object is sent as the ‘initiator’ argument when dealing
     with events such as AttributeEvents.append(),
     AttributeEvents.set(), and AttributeEvents.remove().

     The ‘Event’ object is currently interpreted by the backref event
     handlers, and is used to control the propagation of operations
     across two mutually-dependent attributes.

     New in version 0.9.0.

     Attribute impl: The ‘AttributeImpl’ which is the current event
     initiator.

     Attribute op: The symbol ‘OP_APPEND’, ‘OP_REMOVE’, ‘OP_REPLACE’, or
     ‘OP_BULK_REPLACE’, indicating the source operation.

 -- Class: sqlalchemy.orm.IdentityMap

      -- Method: sqlalchemy.orm.IdentityMap..check_modified
               ()

          return True if any InstanceStates present have been marked as
          ‘modified’.

 -- Class: sqlalchemy.orm.InspectionAttr

     A base class applied to all ORM objects that can be returned by the
     inspect() function.

     The attributes defined here allow the usage of simple boolean
     checks to test basic facts about the object returned.

     While the boolean checks here are basically the same as using the
     Python isinstance() function, the flags here can be used without
     the need to import all of these classes, and also such that the
     SQLAlchemy class system can change while leaving the flags here
     intact for forwards-compatibility.

      -- Attribute: sqlalchemy.orm.InspectionAttr..
               extension_type = symbol('NOT_EXTENSION')

          The extension type, if any.  Defaults to ‘NOT_EXTENSION’

          See also
          ........

          See HYBRID_METHOD.

          See HYBRID_PROPERTY.

          See ASSOCIATION_PROXY.

      -- Attribute: sqlalchemy.orm.InspectionAttr..
               is_aliased_class = False

          True if this object is an instance of AliasedClass.

      -- Attribute: sqlalchemy.orm.InspectionAttr..
               is_attribute = False

          True if this object is a Python descriptor.

          This can refer to one of many types.  Usually a
          QueryableAttribute which handles attributes events on
          behalf of a MapperProperty.  But can also be an
          extension type such as AssociationProxy or
          hybrid_property.  The
          InspectionAttr.extension_type will refer to a constant
          identifying the specific subtype.

          See also
          ........

          See Mapper.all_orm_descriptors.

      -- Attribute: sqlalchemy.orm.InspectionAttr..is_bundle
               = False

          True if this object is an instance of Bundle.

      -- Attribute: sqlalchemy.orm.InspectionAttr..
               is_clause_element = False

          True if this object is an instance of ClauseElement.

      -- Attribute: sqlalchemy.orm.InspectionAttr..
               is_instance = False

          True if this object is an instance of InstanceState.

      -- Attribute: sqlalchemy.orm.InspectionAttr..is_mapper
               = False

          True if this object is an instance of Mapper.

      -- Attribute: sqlalchemy.orm.InspectionAttr..
               is_property = False

          True if this object is an instance of MapperProperty.

      -- Attribute: sqlalchemy.orm.InspectionAttr..
               is_selectable = False

          Return True if this object is an instance of Selectable.

 -- Class: sqlalchemy.orm.InspectionAttrInfo

     Adds the ‘.info’ attribute to InspectionAttr.

     The rationale for InspectionAttr vs.  see
     InspectionAttrInfo is that the former is compatible as a
     mixin for classes that specify ‘__slots__’; this is essentially an
     implementation artifact.

     `Class signature'

     class sqlalchemy.orm.InspectionAttrInfo.
     (‘sqlalchemy.orm.base.InspectionAttr’)

      -- Attribute: sqlalchemy.orm.InspectionAttrInfo..info

          Info dictionary associated with the object, allowing
          user-defined data to be associated with this
          InspectionAttr.

          The dictionary is generated when first accessed.
          Alternatively, it can be specified as a constructor argument
          to the column_property(), relationship(),
          or composite() functions.

          Changed in version 1.0.0: MapperProperty.info is
          also available on extension types via the
          InspectionAttrInfo.info attribute, so that it can apply
          to a wider variety of ORM and extension constructs.

          See also
          ........

          See QueryableAttribute.info.

          See SchemaItem.info.

 -- Class: sqlalchemy.orm.InstanceState (obj, manager)

     tracks state information at the instance level.

     The InstanceState is a key object used by the
     SQLAlchemy ORM in order to track the state of an object; it is
     created the moment an object is instantiated, typically as a result
     of instrumentation which SQLAlchemy applies to the ‘__init__()’
     method of the class.

     InstanceState is also a semi-public object, available
     for runtime inspection as to the state of a mapped instance,
     including information such as its current status within a
     particular Session and details about data on individual
     attributes.  The public API in order to acquire a
     InstanceState object is to use the inspect()
     system:

          >>> from sqlalchemy import inspect
          >>> insp = inspect(some_mapped_object)

     See also
     ........

     See Runtime Inspection API.

     `Class signature'

     class sqlalchemy.orm.InstanceState.
     (‘sqlalchemy.orm.base.InspectionAttrInfo’)

      -- Attribute: sqlalchemy.orm.InstanceState..attrs

          Return a namespace representing each attribute on the mapped
          object, including its current value and history.

          The returned object is an instance of AttributeState.
          This object allows inspection of the current data within
          an attribute as well as attribute history since the last
          flush.

      -- Attribute: sqlalchemy.orm.InstanceState..callables =
               ()

          A namespace where a per-state loader callable can be
          associated.

          In SQLAlchemy 1.0, this is only used for lazy loaders /
          deferred loaders that were set up via query option.

          Previously, callables was used also to indicate expired
          attributes by storing a link to the InstanceState itself in
          this dictionary.  This role is now handled by the
          expired_attributes set.

      -- Attribute: sqlalchemy.orm.InstanceState..deleted

          Return ‘True’ if the object is deleted.

          An object that is in the deleted state is guaranteed to not be
          within the Session.identity_map of its parent
          Session; however if the session’s transaction is
          rolled back, the object will be restored to the persistent
          state and the identity map.

               Note: The InstanceState.deleted attribute
               refers to a specific state of the object that occurs
               between the “persistent” and “detached” states; once the
               object is detached, the InstanceState.deleted
               attribute `no longer returns True'; in order to detect
               that a state was deleted, regardless of whether or not
               the object is associated with a Session, use
               the InstanceState.was_deleted accessor.

          See also
          ........

          See Quickie Intro to Object States.

      -- Attribute: sqlalchemy.orm.InstanceState..detached

          Return ‘True’ if the object is detached.

          See also
          ........

          See Quickie Intro to Object States.

      -- Attribute: sqlalchemy.orm.InstanceState..dict

          Return the instance dict used by the object.

          Under normal circumstances, this is always synonymous with the
          ‘__dict__’ attribute of the mapped object, unless an
          alternative instrumentation system has been configured.

          In the case that the actual object has been garbage collected,
          this accessor returns a blank dictionary.

      -- Attribute: sqlalchemy.orm.InstanceState..
               expired_attributes = None

          The set of keys which are ‘expired’ to be loaded by the
          manager’s deferred scalar loader, assuming no pending changes.

          see also the ‘unmodified’ collection which is intersected
          against this set when a refresh operation occurs.

      -- Attribute: sqlalchemy.orm.InstanceState..
               has_identity

          Return ‘True’ if this object has an identity key.

          This should always have the same value as the expression
          ‘state.persistent’ or ‘state.detached’.

      -- Attribute: sqlalchemy.orm.InstanceState..identity

          Return the mapped identity of the mapped object.  This is the
          primary key identity as persisted by the ORM which can always
          be passed directly to Query.get().

          Returns ‘None’ if the object has no primary key identity.

               Note: An object which is transient or pending does `not'
               have a mapped identity until it is flushed, even if its
               attributes include primary key values.

      -- Attribute: sqlalchemy.orm.InstanceState..
               identity_key

          Return the identity key for the mapped object.

          This is the key used to locate the object within the
          Session.identity_map mapping.  It contains the identity
          as returned by identity within it.

      -- Attribute: sqlalchemy.orm.InstanceState..mapper

          Return the Mapper used for this mapped object.

      -- Attribute: sqlalchemy.orm.InstanceState..object

          Return the mapped object represented by this
          InstanceState.

      -- Attribute: sqlalchemy.orm.InstanceState..pending

          Return ‘True’ if the object is pending.

          See also
          ........

          See Quickie Intro to Object States.

      -- Attribute: sqlalchemy.orm.InstanceState..persistent

          Return ‘True’ if the object is persistent.

          An object that is in the persistent state is guaranteed to be
          within the Session.identity_map of its parent
          Session.

          Changed in version 1.1: The InstanceState.persistent
          accessor no longer returns True for an object that was
          “deleted” within a flush; use the InstanceState.deleted
          accessor to detect this state.  This allows the
          “persistent” state to guarantee membership in the identity
          map.

          See also
          ........

          See Quickie Intro to Object States.

      -- Attribute: sqlalchemy.orm.InstanceState..session

          Return the owning Session for this instance, or
          ‘None’ if none available.

          Note that the result here can in some cases be `different'
          from that of ‘obj in session’; an object that’s been deleted
          will report as not ‘in session’, however if the transaction is
          still in progress, this attribute will still refer to that
          session.  Only when the transaction is completed does the
          object become fully detached under normal circumstances.

      -- Attribute: sqlalchemy.orm.InstanceState..transient

          Return ‘True’ if the object is transient.

          See also
          ........

          See Quickie Intro to Object States.

      -- Attribute: sqlalchemy.orm.InstanceState..unloaded

          Return the set of keys which do not have a loaded value.

          This includes expired attributes and any other attribute that
          was never populated or modified.

      -- Attribute: sqlalchemy.orm.InstanceState..
               unloaded_expirable

          Return the set of keys which do not have a loaded value.

          This includes expired attributes and any other attribute that
          was never populated or modified.

      -- Attribute: sqlalchemy.orm.InstanceState..unmodified

          Return the set of keys which have no uncommitted changes

      -- Method: sqlalchemy.orm.InstanceState..
               unmodified_intersection (keys)

          Return self.unmodified.intersection(keys).

      -- Attribute: sqlalchemy.orm.InstanceState..was_deleted

          Return True if this object is or was previously in the
          “deleted” state and has not been reverted to persistent.

          This flag returns True once the object was deleted in flush.
          When the object is expunged from the session either explicitly
          or via transaction commit and enters the “detached” state,
          this flag will continue to report True.

          New in version 1.1: - added a local method form of
          was_deleted().

          See also
          ........

          See InstanceState.deleted. - refers to the “deleted”
          state

          See was_deleted(). - standalone function

          See Quickie Intro to Object States.

 -- Class: sqlalchemy.orm.InstrumentedAttribute (class_, key,
          parententity, impl=None, comparator=None, of_type=None,
          extra_criteria=())

     Class bound instrumented attribute which adds basic descriptor
     methods.

     See QueryableAttribute for a description of most
     features.

     `Class signature'

     class sqlalchemy.orm.InstrumentedAttribute. (see
     sqlalchemy.orm.Mapped)

      -- Method: sqlalchemy.orm.InstrumentedAttribute..
               __delete__ (instance)

      -- Method: sqlalchemy.orm.InstrumentedAttribute..
               __get__ (instance, owner)

      -- Method: sqlalchemy.orm.InstrumentedAttribute..
               __set__ (instance, value)

 -- Data: sqlalchemy.orm.MANYTOONE = symbol('MANYTOONE')

     Indicates the many-to-one direction for a relationship().

     This symbol is typically used by the internals but may be exposed
     within certain API features.

 -- Data: sqlalchemy.orm.MANYTOMANY = symbol('MANYTOMANY')

     Indicates the many-to-many direction for a relationship().

     This symbol is typically used by the internals but may be exposed
     within certain API features.

 -- Class: sqlalchemy.orm.Mapped (class_, key, parententity, impl=None,
          comparator=None, of_type=None, extra_criteria=())

     Represent an ORM mapped descriptor attribute for typing purposes.

     This class represents the complete descriptor interface for any
     class attribute that will have been instrumented by the ORM
     Mapper class.  When used with typing stubs, it is the final
     type that would be used by a type checker such as mypy to provide
     the full behavioral contract for the attribute.

          Tip: The Mapped class represents attributes that
          are handled directly by the Mapper class.  It does
          not include other Python descriptor classes that are provided
          as extensions, including Hybrid Attributes and the
          Association Proxy.  While these systems still make
          use of ORM-specific superclasses and structures, they are not
          instrumented by the Mapper and instead provide
          their own functionality when they are accessed on a class.

     When using the SQLAlchemy Mypy plugin, the Mapped
     construct is used in typing annotations to indicate to the
     plugin those attributes that are expected to be mapped; the plugin
     also applies Mapped as an annotation automatically when
     it scans through declarative mappings in Declarative Table
     style.  For more indirect mapping styles such as
     imperative table it is typically applied explicitly to class
     level attributes that expect to be mapped based on a given
     Table configuration.

     Mapped is defined in the sqlalchemy2-stubs(1) project
     as a PEP 484(2) generic class which may subscribe to any arbitrary
     Python type, which represents the Python type handled by the
     attribute:

          class MyMappedClass(Base):
              __table_ = Table(
                  "some_table", Base.metadata,
                  Column("id", Integer, primary_key=True),
                  Column("data", String(50)),
                  Column("created_at", DateTime)
              )

              id : Mapped[int]
              data: Mapped[str]
              created_at: Mapped[datetime]

     For complete background on how to use Mapped with
     pep-484 tools like Mypy, see the link below for background on
     SQLAlchemy’s Mypy plugin.

     New in version 1.4.

     See also
     ........

     See Mypy / Pep-484 Support for ORM Mappings. - complete
     background on Mypy integration

     `Class signature'

     class sqlalchemy.orm.Mapped. (see
     sqlalchemy.orm.QueryableAttribute, ‘typing.Generic’)

 -- Class: sqlalchemy.orm.MapperProperty

     Represent a particular class attribute mapped by Mapper.

     The most common occurrences of MapperProperty are the
     mapped Column, which is represented in a mapping as an
     instance of ColumnProperty, and a reference to another
     class produced by relationship(), represented in the
     mapping as an instance of RelationshipProperty.

     `Class signature'

     class sqlalchemy.orm.MapperProperty.
     (‘sqlalchemy.sql.traversals.HasCacheKey’,
     ‘sqlalchemy.orm.base._MappedAttribute’,
     ‘sqlalchemy.orm.base.InspectionAttr’,
     ‘sqlalchemy.util.langhelpers.MemoizedSlots’)

      -- Attribute: sqlalchemy.orm.MapperProperty..info

          Info dictionary associated with the object, allowing
          user-defined data to be associated with this
          InspectionAttr.

          The dictionary is generated when first accessed.
          Alternatively, it can be specified as a constructor argument
          to the column_property(), relationship(),
          or composite() functions.

          Changed in version 1.0.0: ‘InspectionAttr.info’ moved from
          MapperProperty so that it can apply to a wider
          variety of ORM and extension constructs.

          See also
          ........

          See QueryableAttribute.info.

          See SchemaItem.info.

      -- Attribute: sqlalchemy.orm.MapperProperty..cascade =
               frozenset({})

          The set of ‘cascade’ attribute names.

          This collection is checked before the ‘cascade_iterator’
          method is called.

          The collection typically only applies to a
          RelationshipProperty.

      -- Method: sqlalchemy.orm.MapperProperty..
               cascade_iterator (type_, state, dict_,
               visited_states, halt_on=None)

          Iterate through instances related to the given instance for a
          particular ‘cascade’, starting with this MapperProperty.

          Return an iterator3-tuples (instance, mapper, state).

          Note that the ‘cascade’ collection on this MapperProperty is
          checked first for the given type before cascade_iterator is
          called.

          This method typically only applies to RelationshipProperty.

      -- Attribute: sqlalchemy.orm.MapperProperty..
               class_attribute

          Return the class-bound descriptor corresponding to this
          MapperProperty.

          This is basically a ‘getattr()’ call:

               return getattr(self.parent.class_, self.key)

          I.e.  if this MapperProperty were named
          ‘addresses’, and the class to which it is mapped is ‘User’,
          this sequence is possible:

               >>> from sqlalchemy import inspect
               >>> mapper = inspect(User)
               >>> addresses_property = mapper.attrs.addresses
               >>> addresses_property.class_attribute is User.addresses
               True
               >>> User.addresses.property is addresses_property
               True

      -- Method: sqlalchemy.orm.MapperProperty..
               create_row_processor (context, query_entity, path,
               mapper, result, adapter, populators)

          Produce row processing functions and append to the given set
          of populators lists.

      -- Method: sqlalchemy.orm.MapperProperty..do_init ()

          Perform subclass-specific initialization post-mapper-creation
          steps.

          This is a template method called by the ‘MapperProperty’
          object’s init() method.

      -- Method: sqlalchemy.orm.MapperProperty..init ()

          Called after all mappers are created to assemble relationships
          between mappers and perform other post-mapper-creation
          initialization steps.

      -- Method: sqlalchemy.orm.MapperProperty..
               instrument_class (mapper)

          Hook called by the Mapper to the property to initiate
          instrumentation of the class attribute managed by this
          MapperProperty.

          The MapperProperty here will typically call out to the
          attributes module to set up an InstrumentedAttribute.

          This step is the first of two steps to set up an
          InstrumentedAttribute, and is called early in the mapper setup
          process.

          The second step is typically the init_class_attribute step,
          called from StrategizedProperty via the
          post_instrument_class() hook.  This step assigns additional
          state to the InstrumentedAttribute (specifically the “impl”)
          which has been determined after the MapperProperty has
          determined what kind of persistence management it needs to do
          (e.g.  scalar, object, collection, etc).

      -- Attribute: sqlalchemy.orm.MapperProperty..
               is_property = True

          Part of the InspectionAttr interface; states this object is a
          mapper property.

      -- Method: sqlalchemy.orm.MapperProperty..merge
               (session, source_state, source_dict, dest_state,
               dest_dict, load, _recursive, _resolve_conflict_map)

          Merge the attribute represented by this ‘MapperProperty’ from
          source to destination object.

      -- Method: sqlalchemy.orm.MapperProperty..
               post_instrument_class (mapper)

          Perform instrumentation adjustments that need to occur after
          init() has completed.

          The given Mapper is the Mapper invoking the operation, which
          may not be the same Mapper as self.parent in an inheritance
          scenario; however, Mapper will always at least be a sub-mapper
          of self.parent.

          This method is typically used by StrategizedProperty, which
          delegates it to LoaderStrategy.init_class_attribute() to
          perform final setup on the class-bound InstrumentedAttribute.

      -- Method: sqlalchemy.orm.MapperProperty..set_parent
               (parent, init)

          Set the parent mapper that references this MapperProperty.

          This method is overridden by some subclasses to perform extra
          setup when the mapper is first known.

      -- Method: sqlalchemy.orm.MapperProperty..setup
               (context, query_entity, path, adapter, **kwargs)

          Called by Query for the purposes of constructing a SQL
          statement.

          Each MapperProperty associated with the target mapper
          processes the statement referenced by the query context,
          adding columns and/or criterion as appropriate.

 -- Data: sqlalchemy.orm.NOT_EXTENSION = symbol('NOT_EXTENSION')

     Symbol indicating an InspectionAttr that’s not part of
     sqlalchemy.ext.

     Is assigned to the InspectionAttr.extension_type
     attribute.

 -- Function: sqlalchemy.orm.merge_result (query, iterator, load=True)

     Merge a result into this Query object’s Session.

     Deprecated since version 1.4: The merge_result() method
     is superseded by the merge_frozen_result() function.
     (Background on SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

 -- Function: sqlalchemy.orm.merge_frozen_result (session, statement,
          frozen_result, load=True)

     Merge a FrozenResult back into a Session,
     returning a new Result object with persistent objects.

     See the section Re-Executing Statements for an example.

     See also
     ........

     See Re-Executing Statements.

     See Result.freeze().

     See FrozenResult.

 -- Data: sqlalchemy.orm.ONETOMANY = symbol('ONETOMANY')

     Indicates the one-to-many direction for a relationship().

     This symbol is typically used by the internals but may be exposed
     within certain API features.

 -- Class: sqlalchemy.orm.PropComparator (prop, parentmapper,
          adapt_to_entity=None)

     Defines SQL operators for MapperProperty objects.

     SQLAlchemy allows for operators to be redefined at both the Core
     and ORM level.  PropComparator is the base class of
     operator redefinition for ORM-level operations, including those of
     ColumnProperty, RelationshipProperty, and
     CompositeProperty.

          Note: With the advent of Hybrid properties introduced in
          SQLAlchemy 0.7, as well as Core-level operator redefinition in
          SQLAlchemy 0.8, the use case for user-defined
          PropComparator instances is extremely rare.  See
          Hybrid Attributes as well as Redefining and Creating New Operators.

     User-defined subclasses of PropComparator may be
     created.  The built-in Python comparison and math operator methods,
     such as ‘ColumnOperators.__eq__()’, ‘ColumnOperators.__lt__()’, and
     ‘ColumnOperators.__add__()’, can be overridden to provide new
     operator behavior.  The custom PropComparator is passed
     to the MapperProperty instance via the
     ‘comparator_factory’ argument.  In each case, the appropriate
     subclass of PropComparator should be used:

          # definition of custom PropComparator subclasses

          from sqlalchemy.orm.properties import \
                                  ColumnProperty,\
                                  CompositeProperty,\
                                  RelationshipProperty

          class MyColumnComparator(ColumnProperty.Comparator):
              def __eq__(self, other):
                  return self.__clause_element__() == other

          class MyRelationshipComparator(RelationshipProperty.Comparator):
              def any(self, expression):
                  "define the 'any' operation"
                  # ...

          class MyCompositeComparator(CompositeProperty.Comparator):
              def __gt__(self, other):
                  "redefine the 'greater than' operation"

                  return sql.and_(*[a>b for a, b in
                                    zip(self.__clause_element__().clauses,
                                        other.__composite_values__())])

          # application of custom PropComparator subclasses

          from sqlalchemy.orm import column_property, relationship, composite
          from sqlalchemy import Column, String

          class SomeMappedClass(Base):
              some_column = column_property(Column("some_column", String),
                                  comparator_factory=MyColumnComparator)

              some_relationship = relationship(SomeOtherClass,
                                  comparator_factory=MyRelationshipComparator)

              some_composite = composite(
                      Column("a", String), Column("b", String),
                      comparator_factory=MyCompositeComparator
                  )

     Note that for column-level operator redefinition, it’s usually
     simpler to define the operators at the Core level, using the
     TypeEngine.comparator_factory attribute.  See
     Redefining and Creating New Operators for more detail.

     See also
     ........

     See Comparator.

     See Comparator.

     See Comparator.

     See ColumnOperators.

     See Redefining and Creating New Operators.

     See TypeEngine.comparator_factory.

     `Class signature'

     class sqlalchemy.orm.PropComparator. (see
     sqlalchemy.sql.expression.ColumnOperators)

      -- Method: sqlalchemy.orm.PropComparator..__eq__
               (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__eq__’ `method of'
          ColumnOperators.

          Implement the ‘==’ operator.

          In a column context, produces the clause ‘a = b’.  If the
          target is ‘None’, produces ‘a IS NULL’.

      -- Method: sqlalchemy.orm.PropComparator..__le__
               (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__le__’ `method of'
          ColumnOperators.

          Implement the ‘<=’ operator.

          In a column context, produces the clause ‘a <= b’.

      -- Method: sqlalchemy.orm.PropComparator..__lt__
               (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__lt__’ `method of'
          ColumnOperators.

          Implement the ‘<’ operator.

          In a column context, produces the clause ‘a < b’.

      -- Method: sqlalchemy.orm.PropComparator..__ne__
               (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__ne__’ `method of'
          ColumnOperators.

          Implement the ‘!=’ operator.

          In a column context, produces the clause ‘a != b’.  If the
          target is ‘None’, produces ‘a IS NOT NULL’.

      -- Method: sqlalchemy.orm.PropComparator..
               adapt_to_entity (adapt_to_entity)

          Return a copy of this PropComparator which will use the given
          AliasedInsp to produce corresponding expressions.

      -- Attribute: sqlalchemy.orm.PropComparator..adapter

          Produce a callable that adapts column expressions to suit an
          aliased version of this comparator.

      -- Method: sqlalchemy.orm.PropComparator..all_ ()

          `inherited from the' ColumnOperators.all_().
          `method of' ColumnOperators.

          Produce a all_() clause against the parent object.

          This operator is only appropriate against a scalar subquery
          object, or for some backends an column expression that is
          against the ARRAY type, e.g.:

               # postgresql '5 = ALL (somearray)'
               expr = 5 == mytable.c.somearray.all_()

               # mysql '5 = ALL (SELECT value FROM table)'
               expr = 5 == select(table.c.value).scalar_subquery().all_()

          See also
          ........

          See all_(). - standalone version

          See any_(). - ANY operator

          New in version 1.1.

      -- Method: sqlalchemy.orm.PropComparator..and_
               (*criteria)

          Add additional criteria to the ON clause that’s represented by
          this relationship attribute.

          E.g.:

               stmt = select(User).join(
                   User.addresses.and_(Address.email_address != 'foo')
               )

               stmt = select(User).options(
                   joinedload(User.addresses.and_(Address.email_address != 'foo'))
               )

          New in version 1.4.

          See also
          ........

          See Augmenting Built-in ON Clauses.

          See Adding Criteria to loader options.

          See with_loader_criteria().

      -- Method: sqlalchemy.orm.PropComparator..any
               (criterion=None, **kwargs)

          Return true if this collection contains any member that meets
          the given criterion.

          The usual implementation of ‘any()’ is Comparator.any().

          Parameters:

             * ‘criterion’ – an optional ClauseElement formulated
               against the member class’ table or attributes.

             * ‘**kwargs’ – key/value pairs corresponding to member
               class attribute names which will be compared via equality
               to the corresponding values.

      -- Method: sqlalchemy.orm.PropComparator..any_ ()

          `inherited from the' ColumnOperators.any_().
          `method of' ColumnOperators.

          Produce a any_() clause against the parent object.

          This operator is only appropriate against a scalar subquery
          object, or for some backends an column expression that is
          against the ARRAY type, e.g.:

               # postgresql '5 = ANY (somearray)'
               expr = 5 == mytable.c.somearray.any_()

               # mysql '5 = ANY (SELECT value FROM table)'
               expr = 5 == select(table.c.value).scalar_subquery().any_()

          See also
          ........

          See any_(). - standalone version

          See all_(). - ALL operator

          New in version 1.1.

      -- Method: sqlalchemy.orm.PropComparator..asc ()

          `inherited from the' ColumnOperators.asc(). `method
          of' ColumnOperators.

          Produce a asc() clause against the parent object.

      -- Method: sqlalchemy.orm.PropComparator..between
               (cleft, cright, symmetric=False)

          `inherited from the' ColumnOperators.between().
          `method of' ColumnOperators.

          Produce a between() clause against the parent
          object, given the lower and upper range.

      -- Method: sqlalchemy.orm.PropComparator..bool_op
               (opstring, precedence=0)

          `inherited from the' Operators.bool_op(). `method
          of' Operators.

          Return a custom boolean operator.

          This method is shorthand for calling Operators.op()
          and passing the Operators.op.is_comparison
          flag with True.

          See also
          ........

          See Operators.op().

      -- Method: sqlalchemy.orm.PropComparator..collate
               (collation)

          `inherited from the' ColumnOperators.collate().
          `method of' ColumnOperators.

          Produce a collate() clause against the parent
          object, given the collation string.

          See also
          ........

          See collate().

      -- Method: sqlalchemy.orm.PropComparator..concat
               (other)

          `inherited from the' ColumnOperators.concat().
          `method of' ColumnOperators.

          Implement the ‘concat’ operator.

          In a column context, produces the clause ‘a || b’, or uses the
          ‘concat()’ operator on MySQL.

      -- Method: sqlalchemy.orm.PropComparator..contains
               (other, **kwargs)

          `inherited from the' ColumnOperators.contains().
          `method of' ColumnOperators.

          Implement the ‘contains’ operator.

          Produces a LIKE expression that tests against a match for the
          middle of a string value:

               column LIKE '%' || <other> || '%'

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.contains("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.contains.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.contains.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.contains.autoescape flag is set to
               True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.contains("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE '%' || :param || '%' ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.contains("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE '%' || :param || '%' ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.contains.autoescape:

                    somecolumn.contains("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.startswith().

          See ColumnOperators.endswith().

          See ColumnOperators.like().

      -- Method: sqlalchemy.orm.PropComparator..desc ()

          `inherited from the' ColumnOperators.desc().
          `method of' ColumnOperators.

          Produce a desc() clause against the parent object.

      -- Method: sqlalchemy.orm.PropComparator..distinct ()

          `inherited from the' ColumnOperators.distinct().
          `method of' ColumnOperators.

          Produce a distinct() clause against the parent
          object.

      -- Method: sqlalchemy.orm.PropComparator..endswith
               (other, **kwargs)

          `inherited from the' ColumnOperators.endswith().
          `method of' ColumnOperators.

          Implement the ‘endswith’ operator.

          Produces a LIKE expression that tests against a match for the
          end of a string value:

               column LIKE '%' || <other>

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.endswith("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.endswith.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.endswith.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.endswith.autoescape flag is set to
               True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.endswith("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE '%' || :param ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.endswith("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE '%' || :param ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.endswith.autoescape:

                    somecolumn.endswith("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.startswith().

          See ColumnOperators.contains().

          See ColumnOperators.like().

      -- Method: sqlalchemy.orm.PropComparator..has
               (criterion=None, **kwargs)

          Return true if this element references a member which meets
          the given criterion.

          The usual implementation of ‘has()’ is Comparator.has().

          Parameters:

             * ‘criterion’ – an optional ClauseElement formulated
               against the member class’ table or attributes.

             * ‘**kwargs’ – key/value pairs corresponding to member
               class attribute names which will be compared via equality
               to the corresponding values.

      -- Method: sqlalchemy.orm.PropComparator..ilike (other,
               escape=None)

          `inherited from the' ColumnOperators.ilike().
          `method of' ColumnOperators.

          Implement the ‘ilike’ operator, e.g.  case insensitive LIKE.

          In a column context, produces an expression either of the
          form:

               lower(a) LIKE lower(other)

          Or on backends that support the ILIKE operator:

               a ILIKE other

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.ilike("%foobar%"))

          Parameters:

             * ‘other’ – expression to be compared

             * ‘escape’ – optional escape character, renders the
               ‘ESCAPE’ keyword, e.g.:

                    somecolumn.ilike("foo/%bar", escape="/")

          See also
          ........

          See ColumnOperators.like().

      -- Method: sqlalchemy.orm.PropComparator..in_ (other)

          `inherited from the' ColumnOperators.in_(). `method
          of' ColumnOperators.

          Implement the ‘in’ operator.

          In a column context, produces the clause ‘column IN <other>’.

          The given parameter ‘other’ may be:

             * A list of literal values, e.g.:

                    stmt.where(column.in_([1, 2, 3]))

               In this calling form, the list of items is converted to a
               set of bound parameters the same length as the list
               given:

                    WHERE COL IN (?, ?, ?)

             * A list of tuples may be provided if the comparison is
               against a tuple_() containing multiple
               expressions:

                    from sqlalchemy import tuple_
                    stmt.where(tuple_(col1, col2).in_([(1, 10), (2, 20), (3, 30)]))

             * An empty list, e.g.:

                    stmt.where(column.in_([]))

               In this calling form, the expression renders an “empty
               set” expression.  These expressions are tailored to
               individual backends and are generally trying to get an
               empty SELECT statement as a subquery.  Such as on SQLite,
               the expression is:

                    WHERE col IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)

               Changed in version 1.4: empty IN expressions now use an
               execution-time generated SELECT subquery in all cases.

             * A bound parameter, e.g.  see bindparam(), may be
               used if it includes the bindparam.expanding
               flag:

                    stmt.where(column.in_(bindparam('value', expanding=True)))

               In this calling form, the expression renders a special
               non-SQL placeholder expression that looks like:

                    WHERE COL IN ([EXPANDING_value])

               This placeholder expression is intercepted at statement
               execution time to be converted into the variable number
               of bound parameter form illustrated earlier.  If the
               statement were executed as:

                    connection.execute(stmt, {"value": [1, 2, 3]})

               The database would be passed a bound parameter for each
               value:

                    WHERE COL IN (?, ?, ?)

               New in version 1.2: added “expanding” bound parameters

               If an empty list is passed, a special “empty list”
               expression, which is specific to the database in use, is
               rendered.  On SQLite this would be:

                    WHERE COL IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)

               New in version 1.3: “expanding” bound parameters now
               support empty lists

             * a select() construct, which is usually a
               correlated scalar select:

                    stmt.where(
                        column.in_(
                            select(othertable.c.y).
                            where(table.c.x == othertable.c.x)
                        )
                    )

               In this calling form, see ColumnOperators.in_()
               renders as given:

                    WHERE COL IN (SELECT othertable.y
                    FROM othertable WHERE othertable.x = table.x)

          Parameters: ‘other’ – a list of literals, a select()
          construct, or a bindparam() construct that
          includes the bindparam.expanding flag set to True.

      -- Method: sqlalchemy.orm.PropComparator..is_ (other)

          `inherited from the' ColumnOperators.is_(). `method
          of' ColumnOperators.

          Implement the ‘IS’ operator.

          Normally, ‘IS’ is generated automatically when comparing to a
          value of ‘None’, which resolves to ‘NULL’.  However, explicit
          usage of ‘IS’ may be desirable if comparing to boolean values
          on certain platforms.

          See also
          ........

          See ColumnOperators.is_not().

      -- Method: sqlalchemy.orm.PropComparator..
               is_distinct_from (other)

          `inherited from the' ColumnOperators.is_distinct_from().
          `method of' ColumnOperators.

          Implement the ‘IS DISTINCT FROM’ operator.

          Renders “a IS DISTINCT FROM b” on most platforms; on some such
          as SQLite may render “a IS NOT b”.

          New in version 1.1.

      -- Method: sqlalchemy.orm.PropComparator..is_not
               (other)

          `inherited from the' ColumnOperators.is_not().
          `method of' ColumnOperators.

          Implement the ‘IS NOT’ operator.

          Normally, ‘IS NOT’ is generated automatically when comparing
          to a value of ‘None’, which resolves to ‘NULL’.  However,
          explicit usage of ‘IS NOT’ may be desirable if comparing to
          boolean values on certain platforms.

          Changed in version 1.4: The ‘is_not()’ operator is renamed
          from ‘isnot()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.is_().

      -- Method: sqlalchemy.orm.PropComparator..
               is_not_distinct_from (other)

          `inherited from the'
          ColumnOperators.is_not_distinct_from(). `method of'
          ColumnOperators.

          Implement the ‘IS NOT DISTINCT FROM’ operator.

          Renders “a IS NOT DISTINCT FROM b” on most platforms; on some
          such as SQLite may render “a IS b”.

          Changed in version 1.4: The ‘is_not_distinct_from()’ operator
          is renamed from ‘isnot_distinct_from()’ in previous releases.
          The previous name remains available for backwards
          compatibility.

          New in version 1.1.

      -- Method: sqlalchemy.orm.PropComparator..isnot (other)

          `inherited from the' ColumnOperators.isnot().
          `method of' ColumnOperators.

          Implement the ‘IS NOT’ operator.

          Normally, ‘IS NOT’ is generated automatically when comparing
          to a value of ‘None’, which resolves to ‘NULL’.  However,
          explicit usage of ‘IS NOT’ may be desirable if comparing to
          boolean values on certain platforms.

          Changed in version 1.4: The ‘is_not()’ operator is renamed
          from ‘isnot()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.is_().

      -- Method: sqlalchemy.orm.PropComparator..
               isnot_distinct_from (other)

          `inherited from the'
          ColumnOperators.isnot_distinct_from(). `method of'
          ColumnOperators.

          Implement the ‘IS NOT DISTINCT FROM’ operator.

          Renders “a IS NOT DISTINCT FROM b” on most platforms; on some
          such as SQLite may render “a IS b”.

          Changed in version 1.4: The ‘is_not_distinct_from()’ operator
          is renamed from ‘isnot_distinct_from()’ in previous releases.
          The previous name remains available for backwards
          compatibility.

          New in version 1.1.

      -- Method: sqlalchemy.orm.PropComparator..like (other,
               escape=None)

          `inherited from the' ColumnOperators.like().
          `method of' ColumnOperators.

          Implement the ‘like’ operator.

          In a column context, produces the expression:

               a LIKE other

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.like("%foobar%"))

          Parameters:

             * ‘other’ – expression to be compared

             * ‘escape’ – optional escape character, renders the
               ‘ESCAPE’ keyword, e.g.:

                    somecolumn.like("foo/%bar", escape="/")

          See also
          ........

          See ColumnOperators.ilike().

      -- Method: sqlalchemy.orm.PropComparator..match (other,
               **kwargs)

          `inherited from the' ColumnOperators.match().
          `method of' ColumnOperators.

          Implements a database-specific ‘match’ operator.

          ColumnOperators.match() attempts to resolve to a
          MATCH-like function or operator provided by the backend.
          Examples include:

             * PostgreSQL - renders ‘x @@ to_tsquery(y)’

             * MySQL - renders ‘MATCH (x) AGAINST (y IN BOOLEAN MODE)’

             * Oracle - renders ‘CONTAINS(x, y)’

             * other backends may provide special implementations.

             * Backends without any special implementation will emit the
               operator as “MATCH”.  This is compatible with SQLite, for
               example.

      -- Method: sqlalchemy.orm.PropComparator..not_ilike
               (other, escape=None)

          `inherited from the' ColumnOperators.not_ilike().
          `method of' ColumnOperators.

          implement the ‘NOT ILIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.ilike(), i.e.  ‘~x.ilike(y)’.

          Changed in version 1.4: The ‘not_ilike()’ operator is renamed
          from ‘notilike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.ilike().

      -- Method: sqlalchemy.orm.PropComparator..not_in
               (other)

          `inherited from the' ColumnOperators.not_in().
          `method of' ColumnOperators.

          implement the ‘NOT IN’ operator.

          This is equivalent to using negation with
          ColumnOperators.in_(), i.e.  ‘~x.in_(y)’.

          In the case that ‘other’ is an empty sequence, the compiler
          produces an “empty not in” expression.  This defaults to the
          expression “1 = 1” to produce true in all cases.  The
          create_engine.empty_in_strategy may be used to alter
          this behavior.

          Changed in version 1.4: The ‘not_in()’ operator is renamed
          from ‘notin_()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          Changed in version 1.2: The ColumnOperators.in_()
          and ColumnOperators.not_in() operators now produce
          a “static” expression for an empty IN sequence by default.

          See also
          ........

          See ColumnOperators.in_().

      -- Method: sqlalchemy.orm.PropComparator..not_like
               (other, escape=None)

          `inherited from the' ColumnOperators.not_like().
          `method of' ColumnOperators.

          implement the ‘NOT LIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.like(), i.e.  ‘~x.like(y)’.

          Changed in version 1.4: The ‘not_like()’ operator is renamed
          from ‘notlike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.like().

      -- Method: sqlalchemy.orm.PropComparator..notilike
               (other, escape=None)

          `inherited from the' ColumnOperators.notilike().
          `method of' ColumnOperators.

          implement the ‘NOT ILIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.ilike(), i.e.  ‘~x.ilike(y)’.

          Changed in version 1.4: The ‘not_ilike()’ operator is renamed
          from ‘notilike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.ilike().

      -- Method: sqlalchemy.orm.PropComparator..notin_
               (other)

          `inherited from the' ColumnOperators.notin_().
          `method of' ColumnOperators.

          implement the ‘NOT IN’ operator.

          This is equivalent to using negation with
          ColumnOperators.in_(), i.e.  ‘~x.in_(y)’.

          In the case that ‘other’ is an empty sequence, the compiler
          produces an “empty not in” expression.  This defaults to the
          expression “1 = 1” to produce true in all cases.  The
          create_engine.empty_in_strategy may be used to alter
          this behavior.

          Changed in version 1.4: The ‘not_in()’ operator is renamed
          from ‘notin_()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          Changed in version 1.2: The ColumnOperators.in_()
          and ColumnOperators.not_in() operators now produce
          a “static” expression for an empty IN sequence by default.

          See also
          ........

          See ColumnOperators.in_().

      -- Method: sqlalchemy.orm.PropComparator..notlike
               (other, escape=None)

          `inherited from the' ColumnOperators.notlike().
          `method of' ColumnOperators.

          implement the ‘NOT LIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.like(), i.e.  ‘~x.like(y)’.

          Changed in version 1.4: The ‘not_like()’ operator is renamed
          from ‘notlike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.like().

      -- Method: sqlalchemy.orm.PropComparator..nulls_first
               ()

          `inherited from the' ColumnOperators.nulls_first().
          `method of' ColumnOperators.

          Produce a nulls_first() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_first()’ operator is
          renamed from ‘nullsfirst()’ in previous releases.  The
          previous name remains available for backwards compatibility.

      -- Method: sqlalchemy.orm.PropComparator..nulls_last ()

          `inherited from the' ColumnOperators.nulls_last().
          `method of' ColumnOperators.

          Produce a nulls_last() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_last()’ operator is renamed
          from ‘nullslast()’ in previous releases.  The previous name
          remains available for backwards compatibility.

      -- Method: sqlalchemy.orm.PropComparator..nullsfirst ()

          `inherited from the' ColumnOperators.nullsfirst().
          `method of' ColumnOperators.

          Produce a nulls_first() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_first()’ operator is
          renamed from ‘nullsfirst()’ in previous releases.  The
          previous name remains available for backwards compatibility.

      -- Method: sqlalchemy.orm.PropComparator..nullslast ()

          `inherited from the' ColumnOperators.nullslast().
          `method of' ColumnOperators.

          Produce a nulls_last() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_last()’ operator is renamed
          from ‘nullslast()’ in previous releases.  The previous name
          remains available for backwards compatibility.

      -- Method: sqlalchemy.orm.PropComparator..of_type
               (class_)

          Redefine this object in terms of a polymorphic subclass, see
          with_polymorphic() construct, or aliased()
          construct.

          Returns a new PropComparator from which further criterion can
          be evaluated.

          e.g.:

               query.join(Company.employees.of_type(Engineer)).\
                  filter(Engineer.name=='foo')

          Parameters: ‘class_’ – a class or mapper indicating that
          criterion will be against this specific subclass.

          See also
          ........

          See Referring to specific subtypes on relationships.

      -- Method: sqlalchemy.orm.PropComparator..op (opstring,
               precedence=0, is_comparison=False, return_type=None)

          `inherited from the' Operators.op(). `method of'
          Operators.

          Produce a generic operator function.

          e.g.:

               somecolumn.op("*")(5)

          produces:

               somecolumn * 5

          This function can also be used to make bitwise operators
          explicit.  For example:

               somecolumn.op('&')(0xff)

          is a bitwise AND of the value in ‘somecolumn’.

          Parameters:

             * ‘operator’ – a string which will be output as the infix
               operator between this element and the expression passed
               to the generated function.

             * ‘precedence’ – precedence to apply to the operator, when
               parenthesizing expressions.  A lower number will cause
               the expression to be parenthesized when applied against
               another operator with higher precedence.  The default
               value of ‘0’ is lower than all operators except for the
               comma (‘,’) and ‘AS’ operators.  A value of 100 will be
               higher or equal to all operators, and -100 will be lower
               than or equal to all operators.

             * ‘is_comparison’ – if True, the operator will be
               considered as a “comparison” operator, that is which
               evaluates to a boolean true/false value, like ‘==’, ‘>’,
               etc.  This flag should be set so that ORM relationships
               can establish that the operator is a comparison operator
               when used in a custom join condition.

               New in version 0.9.2: - added the
               Operators.op.is_comparison flag.

             * ‘return_type’ – a TypeEngine class or object
               that will force the return type of an expression produced
               by this operator to be of that type.  By default,
               operators that specify Operators.op.is_comparison
               will resolve to Boolean, and those that
               do not will be of the same type as the left-hand operand.

          See also
          ........

          See Redefining and Creating New Operators.

          See Using custom operators in join conditions.

      -- Method: sqlalchemy.orm.PropComparator..operate (op,
               *other, **kwargs)

          `inherited from the' Operators.operate(). `method
          of' Operators.

          Operate on an argument.

          This is the lowest level of operation, raises
          ‘NotImplementedError’ by default.

          Overriding this on a subclass can allow common behavior to be
          applied to all operations.  For example, overriding
          ColumnOperators to apply ‘func.lower()’ to the left and
          right side:

               class MyComparator(ColumnOperators):
                   def operate(self, op, other):
                       return op(func.lower(self), func.lower(other))

          Parameters:

             * ‘op’ – Operator callable.

             * ‘*other’ – the ‘other’ side of the operation.  Will be a
               single scalar for most operations.

             * ‘**kwargs’ – modifiers.  These may be passed by special
               operators such as ‘ColumnOperators.contains()’.

      -- Method: sqlalchemy.orm.PropComparator..regexp_match
               (pattern, flags=None)

          `inherited from the' ColumnOperators.regexp_match().
          `method of' ColumnOperators.

          Implements a database-specific ‘regexp match’ operator.

          E.g.:

               stmt = select(table.c.some_column).where(
                   table.c.some_column.regexp_match('^(b|c)')
               )

          ColumnOperators.regexp_match() attempts to resolve
          to a REGEXP-like function or operator provided by the backend,
          however the specific regular expression syntax and flags
          available are `not backend agnostic'.

          Examples include:

             * PostgreSQL - renders ‘x ~ y’ or ‘x !~ y’ when negated.

             * Oracle - renders ‘REGEXP_LIKE(x, y)’

             * SQLite - uses SQLite’s ‘REGEXP’ placeholder operator and
               calls into the Python ‘re.match()’ builtin.

             * other backends may provide special implementations.

             * Backends without any special implementation will emit the
               operator as “REGEXP” or “NOT REGEXP”.  This is compatible
               with SQLite and MySQL, for example.

          Regular expression support is currently implemented for
          Oracle, PostgreSQL, MySQL and MariaDB. Partial support is
          available for SQLite.  Support among third-party dialects may
          vary.

          Parameters:

             * ‘pattern’ – The regular expression pattern string or
               column clause.

             * ‘flags’ – Any regular expression string flags to apply.
               Flags tend to be backend specific.  It can be a string or
               a column clause.  Some backends, like PostgreSQL and
               MariaDB, may alternatively specify the flags as part of
               the pattern.  When using the ignore case flag ‘i’ in
               PostgreSQL, the ignore case regexp match operator ‘~*’ or
               ‘!~*’ will be used.

          New in version 1.4.

          See also
          ........

          See ColumnOperators.regexp_replace().

      -- Method: sqlalchemy.orm.PropComparator..
               regexp_replace (pattern, replacement, flags=None)

          `inherited from the' ColumnOperators.regexp_replace().
          `method of' ColumnOperators.

          Implements a database-specific ‘regexp replace’ operator.

          E.g.:

               stmt = select(
                   table.c.some_column.regexp_replace(
                       'b(..)',
                       'X^AY',
                       flags='g'
                   )
               )

          ColumnOperators.regexp_replace() attempts to
          resolve to a REGEXP_REPLACE-like function provided by the
          backend, that usually emit the function ‘REGEXP_REPLACE()’.
          However, the specific regular expression syntax and flags
          available are `not backend agnostic'.

          Regular expression replacement support is currently
          implemented for Oracle, PostgreSQL, MySQL 8 or greater and
          MariaDB. Support among third-party dialects may vary.

          Parameters:

             * ‘pattern’ – The regular expression pattern string or
               column clause.

             * ‘pattern’ – The replacement string or column clause.

             * ‘flags’ – Any regular expression string flags to apply.
               Flags tend to be backend specific.  It can be a string or
               a column clause.  Some backends, like PostgreSQL and
               MariaDB, may alternatively specify the flags as part of
               the pattern.

          New in version 1.4.

          See also
          ........

          See ColumnOperators.regexp_match().

      -- Method: sqlalchemy.orm.PropComparator..
               reverse_operate (op, other, **kwargs)

          `inherited from the' Operators.reverse_operate().
          `method of' Operators.

          Reverse operate on an argument.

          Usage is the same as operate().

      -- Method: sqlalchemy.orm.PropComparator..startswith
               (other, **kwargs)

          `inherited from the' ColumnOperators.startswith().
          `method of' ColumnOperators.

          Implement the ‘startswith’ operator.

          Produces a LIKE expression that tests against a match for the
          start of a string value:

               column LIKE <other> || '%'

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.startswith("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.startswith.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.startswith.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.startswith.autoescape flag is set
               to True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.startswith("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE :param || '%' ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.startswith("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE :param || '%' ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.startswith.autoescape:

                    somecolumn.startswith("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.endswith().

          See ColumnOperators.contains().

          See ColumnOperators.like().

 -- Class: sqlalchemy.orm.RelationshipProperty (argument,
          secondary=None, primaryjoin=None, secondaryjoin=None,
          foreign_keys=None, uselist=None, order_by=False, backref=None,
          back_populates=None, overlaps=None, post_update=False,
          cascade=False, viewonly=False, lazy='select',
          collection_class=None, passive_deletes=False,
          passive_updates=True, remote_side=None,
          enable_typechecks=True, join_depth=None,
          comparator_factory=None, single_parent=False, innerjoin=False,
          distinct_target_key=None, doc=None, active_history=False,
          cascade_backrefs=True, load_on_pending=False,
          bake_queries=True, _local_remote_pairs=None, query_class=None,
          info=None, omit_join=None, sync_backref=None)

     Describes an object property that holds a single item or list of
     items that correspond to a related database table.

     Public constructor is the relationship() function.

     See also
     ........

     See Relationship Configuration.

     `Class signature'

     class sqlalchemy.orm.RelationshipProperty.
     (‘sqlalchemy.orm.StrategizedProperty’)

      -- Class: Comparator (prop, parentmapper, adapt_to_entity=None,
               of_type=None, extra_criteria=())

          Produce boolean, comparison, and other operators for
          RelationshipProperty attributes.

          See the documentation for PropComparator for a
          brief overview of ORM level operator definition.

          See also
          ........

          See PropComparator.

          See Comparator.

          See ColumnOperators.

          See Redefining and Creating New Operators.

          See TypeEngine.comparator_factory.

          `Class signature'

          class sqlalchemy.orm.RelationshipProperty.Comparator.
          (see sqlalchemy.orm.PropComparator)

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    __eq__ (other)

               Implement the ‘==’ operator.

               In a many-to-one context, such as:

                    MyClass.some_prop == <some object>

               this will typically produce a clause such as:

                    mytable.related_id == <some id>

               Where ‘<some id>’ is the primary key of the given object.

               The ‘==’ operator provides partial functionality for non-
               many-to-one comparisons:

                  * Comparisons against collections are not supported.
                    Use Comparator.contains().

                  * Compared to a scalar one-to-many, will produce a
                    clause that compares the target columns in the
                    parent to the given target.

                  * Compared to a scalar many-to-many, an alias of the
                    association table will be rendered as well, forming
                    a natural join that is part of the main body of the
                    query.  This will not work for queries that go
                    beyond simple AND conjunctions of comparisons, such
                    as those which use OR. Use explicit joins,
                    outerjoins, or Comparator.has() for more
                    comprehensive non-many-to-one scalar membership
                    tests.

                  * Comparisons against ‘None’ given in a one-to-many or
                    many-to-many context produce a NOT EXISTS clause.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    __init__ (prop, parentmapper,
                    adapt_to_entity=None, of_type=None,
                    extra_criteria=())

               Construction of Comparator is internal to the
               ORM’s attribute mechanics.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    __le__ (other)

               `inherited from the'
               ‘sqlalchemy.sql.expression.ColumnOperators.__le__’
               `method of' ColumnOperators.

               Implement the ‘<=’ operator.

               In a column context, produces the clause ‘a <= b’.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    __lt__ (other)

               `inherited from the'
               ‘sqlalchemy.sql.expression.ColumnOperators.__lt__’
               `method of' ColumnOperators.

               Implement the ‘<’ operator.

               In a column context, produces the clause ‘a < b’.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    __ne__ (other)

               Implement the ‘!=’ operator.

               In a many-to-one context, such as:

                    MyClass.some_prop != <some object>

               This will typically produce a clause such as:

                    mytable.related_id != <some id>

               Where ‘<some id>’ is the primary key of the given object.

               The ‘!=’ operator provides partial functionality for non-
               many-to-one comparisons:

                  * Comparisons against collections are not supported.
                    Use Comparator.contains() in conjunction
                    with not_().

                  * Compared to a scalar one-to-many, will produce a
                    clause that compares the target columns in the
                    parent to the given target.

                  * Compared to a scalar many-to-many, an alias of the
                    association table will be rendered as well, forming
                    a natural join that is part of the main body of the
                    query.  This will not work for queries that go
                    beyond simple AND conjunctions of comparisons, such
                    as those which use OR. Use explicit joins,
                    outerjoins, or Comparator.has() in
                    conjunction with not_() for more
                    comprehensive non-many-to-one scalar membership
                    tests.

                  * Comparisons against ‘None’ given in a one-to-many or
                    many-to-many context produce an EXISTS clause.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    adapt_to_entity (adapt_to_entity)

               Return a copy of this PropComparator which will use the
               given AliasedInsp to produce corresponding
               expressions.

           -- Attribute:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    adapter

               `inherited from the' PropComparator.adapter.
               `attribute of' PropComparator.

               Produce a callable that adapts column expressions to suit
               an aliased version of this comparator.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    all_ ()

               `inherited from the' ColumnOperators.all_().
               `method of' ColumnOperators.

               Produce a all_() clause against the parent
               object.

               This operator is only appropriate against a scalar
               subquery object, or for some backends an column
               expression that is against the ARRAY type, e.g.:

                    # postgresql '5 = ALL (somearray)'
                    expr = 5 == mytable.c.somearray.all_()

                    # mysql '5 = ALL (SELECT value FROM table)'
                    expr = 5 == select(table.c.value).scalar_subquery().all_()

               See also
               ........

               See all_(). - standalone version

               See any_(). - ANY operator

               New in version 1.1.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    and_ (*other)

               Add AND criteria.

               See PropComparator.and_() for an example.

               New in version 1.4.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    any (criterion=None, **kwargs)

               Produce an expression that tests a collection against
               particular criterion, using EXISTS.

               An expression like:

                    session.query(MyClass).filter(
                        MyClass.somereference.any(SomeRelated.x==2)
                    )

               Will produce a query like:

                    SELECT * FROM my_table WHERE
                    EXISTS (SELECT 1 FROM related WHERE related.my_id=my_table.id
                    AND related.x=2)

               Because Comparator.any() uses a correlated
               subquery, its performance is not nearly as good when
               compared against large target tables as that of using a
               join.

               Comparator.any() is particularly useful for
               testing for empty collections:

                    session.query(MyClass).filter(
                        ~MyClass.somereference.any()
                    )

               will produce:

                    SELECT * FROM my_table WHERE
                    NOT (EXISTS (SELECT 1 FROM related WHERE
                    related.my_id=my_table.id))

               Comparator.any() is only valid for
               collections, i.e.  a relationship() that has
               ‘uselist=True’.  For scalar references, use
               Comparator.has().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    any_ ()

               `inherited from the' ColumnOperators.any_().
               `method of' ColumnOperators.

               Produce a any_() clause against the parent
               object.

               This operator is only appropriate against a scalar
               subquery object, or for some backends an column
               expression that is against the ARRAY type, e.g.:

                    # postgresql '5 = ANY (somearray)'
                    expr = 5 == mytable.c.somearray.any_()

                    # mysql '5 = ANY (SELECT value FROM table)'
                    expr = 5 == select(table.c.value).scalar_subquery().any_()

               See also
               ........

               See any_(). - standalone version

               See all_(). - ALL operator

               New in version 1.1.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    static any_op (a, b, **kwargs)

               `inherited from the' ‘PropComparator.any_op()’ `method
               of' PropComparator.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    asc ()

               `inherited from the' ColumnOperators.asc().
               `method of' ColumnOperators.

               Produce a asc() clause against the parent
               object.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    between (cleft, cright, symmetric=False)

               `inherited from the' ColumnOperators.between().
               `method of' ColumnOperators.

               Produce a between() clause against the parent
               object, given the lower and upper range.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    bool_op (opstring, precedence=0)

               `inherited from the' Operators.bool_op().
               `method of' Operators.

               Return a custom boolean operator.

               This method is shorthand for calling
               Operators.op() and passing the
               Operators.op.is_comparison flag with True.

               See also
               ........

               See Operators.op().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    collate (collation)

               `inherited from the' ColumnOperators.collate().
               `method of' ColumnOperators.

               Produce a collate() clause against the parent
               object, given the collation string.

               See also
               ........

               See collate().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    concat (other)

               `inherited from the' ColumnOperators.concat().
               `method of' ColumnOperators.

               Implement the ‘concat’ operator.

               In a column context, produces the clause ‘a || b’, or
               uses the ‘concat()’ operator on MySQL.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    contains (other, **kwargs)

               Return a simple expression that tests a collection for
               containment of a particular item.

               Comparator.contains() is only valid for a
               collection, i.e.  a relationship() that
               implements one-to-many or many-to-many with
               ‘uselist=True’.

               When used in a simple one-to-many context, an expression
               like:

                    MyClass.contains(other)

               Produces a clause like:

                    mytable.id == <some id>

               Where ‘<some id>’ is the value of the foreign key
               attribute on ‘other’ which refers to the primary key of
               its parent object.  From this it follows that
               Comparator.contains() is very useful when used with
               simple one-to-many operations.

               For many-to-many operations, the behavior of
               Comparator.contains() has more caveats.  The
               association table will be rendered in the statement,
               producing an “implicit” join, that is, includes multiple
               tables in the FROM clause which are equated in the WHERE
               clause:

                    query(MyClass).filter(MyClass.contains(other))

               Produces a query like:

                    SELECT * FROM my_table, my_association_table AS
                    my_association_table_1 WHERE
                    my_table.id = my_association_table_1.parent_id
                    AND my_association_table_1.child_id = <some id>

               Where ‘<some id>’ would be the primary key of ‘other’.
               From the above, it is clear that
               Comparator.contains() will `not' work with
               many-to-many collections when used in queries that move
               beyond simple AND conjunctions, such as multiple
               Comparator.contains() expressions joined by OR. In
               such cases subqueries or explicit “outer joins” will need
               to be used instead.  See Comparator.any() for
               a less-performant alternative using EXISTS, or refer to
               Query.outerjoin() as well as Querying with Joins
               for more details on constructing outer
               joins.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    desc ()

               `inherited from the' ColumnOperators.desc().
               `method of' ColumnOperators.

               Produce a desc() clause against the parent
               object.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    distinct ()

               `inherited from the' ColumnOperators.distinct().
               `method of' ColumnOperators.

               Produce a distinct() clause against the
               parent object.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    endswith (other, **kwargs)

               `inherited from the' ColumnOperators.endswith().
               `method of' ColumnOperators.

               Implement the ‘endswith’ operator.

               Produces a LIKE expression that tests against a match for
               the end of a string value:

                    column LIKE '%' || <other>

               E.g.:

                    stmt = select(sometable).\
                        where(sometable.c.column.endswith("foobar"))

               Since the operator uses ‘LIKE’, wildcard characters ‘"%"’
               and ‘"_"’ that are present inside the <other> expression
               will behave like wildcards as well.  For literal string
               values, the ColumnOperators.endswith.autoescape
               flag may be set to ‘True’ to apply escaping to
               occurrences of these characters within the string value
               so that they match as themselves and not as wildcard
               characters.  Alternatively, the
               ColumnOperators.endswith.escape parameter will
               establish a given character as an escape character which
               can be of use when the target expression is not a literal
               string.

               Parameters:

                  * ‘other’ – expression to be compared.  This is
                    usually a plain string value, but can also be an
                    arbitrary SQL expression.  LIKE wildcard characters
                    ‘%’ and ‘_’ are not escaped by default unless the
                    ColumnOperators.endswith.autoescape flag
                    is set to True.

                  * ‘autoescape’ – boolean; when True, establishes an
                    escape character within the LIKE expression, then
                    applies it to all occurrences of ‘"%"’, ‘"_"’ and
                    the escape character itself within the comparison
                    value, which is assumed to be a literal string and
                    not a SQL expression.

                    An expression such as:

                         somecolumn.endswith("foo%bar", autoescape=True)

                    Will render as:

                         somecolumn LIKE '%' || :param ESCAPE '/'

                    With the value of ‘:param’ as ‘"foo/%bar"’.

                  * ‘escape’ – a character which when given will render
                    with the ‘ESCAPE’ keyword to establish that
                    character as the escape character.  This character
                    can then be placed preceding occurrences of ‘%’ and
                    ‘_’ to allow them to act as themselves and not
                    wildcard characters.

                    An expression such as:

                         somecolumn.endswith("foo/%bar", escape="^")

                    Will render as:

                         somecolumn LIKE '%' || :param ESCAPE '^'

                    The parameter may also be combined with
                    ColumnOperators.endswith.autoescape:

                         somecolumn.endswith("foo%bar^bat", escape="^", autoescape=True)

                    Where above, the given literal parameter will be
                    converted to ‘"foo^%bar^^bat"’ before being passed
                    to the database.

               See also
               ........

               See ColumnOperators.startswith().

               See ColumnOperators.contains().

               See ColumnOperators.like().

           -- Attribute:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    entity

               The target entity referred to by this Comparator.

               This is either a Mapper or AliasedInsp
               object.

               This is the “target” or “remote” side of the
               relationship().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    has (criterion=None, **kwargs)

               Produce an expression that tests a scalar reference
               against particular criterion, using EXISTS.

               An expression like:

                    session.query(MyClass).filter(
                        MyClass.somereference.has(SomeRelated.x==2)
                    )

               Will produce a query like:

                    SELECT * FROM my_table WHERE
                    EXISTS (SELECT 1 FROM related WHERE
                    related.id==my_table.related_id AND related.x=2)

               Because Comparator.has() uses a correlated
               subquery, its performance is not nearly as good when
               compared against large target tables as that of using a
               join.

               Comparator.has() is only valid for scalar
               references, i.e.  a relationship() that has
               ‘uselist=False’.  For collection references, use
               Comparator.any().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    static has_op (a, b, **kwargs)

               `inherited from the' ‘PropComparator.has_op()’ `method
               of' PropComparator.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    ilike (other, escape=None)

               `inherited from the' ColumnOperators.ilike().
               `method of' ColumnOperators.

               Implement the ‘ilike’ operator, e.g.  case insensitive
               LIKE.

               In a column context, produces an expression either of the
               form:

                    lower(a) LIKE lower(other)

               Or on backends that support the ILIKE operator:

                    a ILIKE other

               E.g.:

                    stmt = select(sometable).\
                        where(sometable.c.column.ilike("%foobar%"))

               Parameters:

                  * ‘other’ – expression to be compared

                  * ‘escape’ – optional escape character, renders the
                    ‘ESCAPE’ keyword, e.g.:

                         somecolumn.ilike("foo/%bar", escape="/")

               See also
               ........

               See ColumnOperators.like().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    in_ (other)

               Produce an IN clause - this is not implemented for
               relationship().-based attributes at this time.

           -- Attribute:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    info

               `inherited from the' ‘PropComparator.info’ `attribute of'
               PropComparator.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    is_ (other)

               `inherited from the' ColumnOperators.is_().
               `method of' ColumnOperators.

               Implement the ‘IS’ operator.

               Normally, ‘IS’ is generated automatically when comparing
               to a value of ‘None’, which resolves to ‘NULL’.  However,
               explicit usage of ‘IS’ may be desirable if comparing to
               boolean values on certain platforms.

               See also
               ........

               See ColumnOperators.is_not().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    is_distinct_from (other)

               `inherited from the'
               ColumnOperators.is_distinct_from(). `method of'
               ColumnOperators.

               Implement the ‘IS DISTINCT FROM’ operator.

               Renders “a IS DISTINCT FROM b” on most platforms; on some
               such as SQLite may render “a IS NOT b”.

               New in version 1.1.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    is_not (other)

               `inherited from the' ColumnOperators.is_not().
               `method of' ColumnOperators.

               Implement the ‘IS NOT’ operator.

               Normally, ‘IS NOT’ is generated automatically when
               comparing to a value of ‘None’, which resolves to ‘NULL’.
               However, explicit usage of ‘IS NOT’ may be desirable if
               comparing to boolean values on certain platforms.

               Changed in version 1.4: The ‘is_not()’ operator is
               renamed from ‘isnot()’ in previous releases.  The
               previous name remains available for backwards
               compatibility.

               See also
               ........

               See ColumnOperators.is_().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    is_not_distinct_from (other)

               `inherited from the'
               ColumnOperators.is_not_distinct_from(). `method of'
               ColumnOperators.

               Implement the ‘IS NOT DISTINCT FROM’ operator.

               Renders “a IS NOT DISTINCT FROM b” on most platforms; on
               some such as SQLite may render “a IS b”.

               Changed in version 1.4: The ‘is_not_distinct_from()’
               operator is renamed from ‘isnot_distinct_from()’ in
               previous releases.  The previous name remains available
               for backwards compatibility.

               New in version 1.1.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    isnot (other)

               `inherited from the' ColumnOperators.isnot().
               `method of' ColumnOperators.

               Implement the ‘IS NOT’ operator.

               Normally, ‘IS NOT’ is generated automatically when
               comparing to a value of ‘None’, which resolves to ‘NULL’.
               However, explicit usage of ‘IS NOT’ may be desirable if
               comparing to boolean values on certain platforms.

               Changed in version 1.4: The ‘is_not()’ operator is
               renamed from ‘isnot()’ in previous releases.  The
               previous name remains available for backwards
               compatibility.

               See also
               ........

               See ColumnOperators.is_().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    isnot_distinct_from (other)

               `inherited from the'
               ColumnOperators.isnot_distinct_from(). `method of'
               ColumnOperators.

               Implement the ‘IS NOT DISTINCT FROM’ operator.

               Renders “a IS NOT DISTINCT FROM b” on most platforms; on
               some such as SQLite may render “a IS b”.

               Changed in version 1.4: The ‘is_not_distinct_from()’
               operator is renamed from ‘isnot_distinct_from()’ in
               previous releases.  The previous name remains available
               for backwards compatibility.

               New in version 1.1.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    like (other, escape=None)

               `inherited from the' ColumnOperators.like().
               `method of' ColumnOperators.

               Implement the ‘like’ operator.

               In a column context, produces the expression:

                    a LIKE other

               E.g.:

                    stmt = select(sometable).\
                        where(sometable.c.column.like("%foobar%"))

               Parameters:

                  * ‘other’ – expression to be compared

                  * ‘escape’ – optional escape character, renders the
                    ‘ESCAPE’ keyword, e.g.:

                         somecolumn.like("foo/%bar", escape="/")

               See also
               ........

               See ColumnOperators.ilike().

           -- Attribute:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    mapper

               The target Mapper referred to by this
               Comparator.

               This is the “target” or “remote” side of the
               relationship().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    match (other, **kwargs)

               `inherited from the' ColumnOperators.match().
               `method of' ColumnOperators.

               Implements a database-specific ‘match’ operator.

               ColumnOperators.match() attempts to resolve
               to a MATCH-like function or operator provided by the
               backend.  Examples include:

                  * PostgreSQL - renders ‘x @@ to_tsquery(y)’

                  * MySQL - renders ‘MATCH (x) AGAINST (y IN BOOLEAN
                    MODE)’

                  * Oracle - renders ‘CONTAINS(x, y)’

                  * other backends may provide special implementations.

                  * Backends without any special implementation will
                    emit the operator as “MATCH”.  This is compatible
                    with SQLite, for example.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    not_ilike (other, escape=None)

               `inherited from the' ColumnOperators.not_ilike().
               `method of' ColumnOperators.

               implement the ‘NOT ILIKE’ operator.

               This is equivalent to using negation with
               ColumnOperators.ilike(), i.e.  ‘~x.ilike(y)’.

               Changed in version 1.4: The ‘not_ilike()’ operator is
               renamed from ‘notilike()’ in previous releases.  The
               previous name remains available for backwards
               compatibility.

               See also
               ........

               See ColumnOperators.ilike().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    not_in (other)

               `inherited from the' ColumnOperators.not_in().
               `method of' ColumnOperators.

               implement the ‘NOT IN’ operator.

               This is equivalent to using negation with
               ColumnOperators.in_(), i.e.  ‘~x.in_(y)’.

               In the case that ‘other’ is an empty sequence, the
               compiler produces an “empty not in” expression.  This
               defaults to the expression “1 = 1” to produce true in all
               cases.  The create_engine.empty_in_strategy
               may be used to alter this behavior.

               Changed in version 1.4: The ‘not_in()’ operator is
               renamed from ‘notin_()’ in previous releases.  The
               previous name remains available for backwards
               compatibility.

               Changed in version 1.2: The ColumnOperators.in_()
               and ColumnOperators.not_in() operators
               now produce a “static” expression for an empty IN
               sequence by default.

               See also
               ........

               See ColumnOperators.in_().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    not_like (other, escape=None)

               `inherited from the' ColumnOperators.not_like().
               `method of' ColumnOperators.

               implement the ‘NOT LIKE’ operator.

               This is equivalent to using negation with
               ColumnOperators.like(), i.e.  ‘~x.like(y)’.

               Changed in version 1.4: The ‘not_like()’ operator is
               renamed from ‘notlike()’ in previous releases.  The
               previous name remains available for backwards
               compatibility.

               See also
               ........

               See ColumnOperators.like().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    notilike (other, escape=None)

               `inherited from the' ColumnOperators.notilike().
               `method of' ColumnOperators.

               implement the ‘NOT ILIKE’ operator.

               This is equivalent to using negation with
               ColumnOperators.ilike(), i.e.  ‘~x.ilike(y)’.

               Changed in version 1.4: The ‘not_ilike()’ operator is
               renamed from ‘notilike()’ in previous releases.  The
               previous name remains available for backwards
               compatibility.

               See also
               ........

               See ColumnOperators.ilike().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    notin_ (other)

               `inherited from the' ColumnOperators.notin_().
               `method of' ColumnOperators.

               implement the ‘NOT IN’ operator.

               This is equivalent to using negation with
               ColumnOperators.in_(), i.e.  ‘~x.in_(y)’.

               In the case that ‘other’ is an empty sequence, the
               compiler produces an “empty not in” expression.  This
               defaults to the expression “1 = 1” to produce true in all
               cases.  The create_engine.empty_in_strategy
               may be used to alter this behavior.

               Changed in version 1.4: The ‘not_in()’ operator is
               renamed from ‘notin_()’ in previous releases.  The
               previous name remains available for backwards
               compatibility.

               Changed in version 1.2: The ColumnOperators.in_()
               and ColumnOperators.not_in() operators
               now produce a “static” expression for an empty IN
               sequence by default.

               See also
               ........

               See ColumnOperators.in_().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    notlike (other, escape=None)

               `inherited from the' ColumnOperators.notlike().
               `method of' ColumnOperators.

               implement the ‘NOT LIKE’ operator.

               This is equivalent to using negation with
               ColumnOperators.like(), i.e.  ‘~x.like(y)’.

               Changed in version 1.4: The ‘not_like()’ operator is
               renamed from ‘notlike()’ in previous releases.  The
               previous name remains available for backwards
               compatibility.

               See also
               ........

               See ColumnOperators.like().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    nulls_first ()

               `inherited from the' ColumnOperators.nulls_first().
               `method of' ColumnOperators.

               Produce a nulls_first() clause against the
               parent object.

               Changed in version 1.4: The ‘nulls_first()’ operator is
               renamed from ‘nullsfirst()’ in previous releases.  The
               previous name remains available for backwards
               compatibility.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    nulls_last ()

               `inherited from the' ColumnOperators.nulls_last().
               `method of' ColumnOperators.

               Produce a nulls_last() clause against the
               parent object.

               Changed in version 1.4: The ‘nulls_last()’ operator is
               renamed from ‘nullslast()’ in previous releases.  The
               previous name remains available for backwards
               compatibility.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    nullsfirst ()

               `inherited from the' ColumnOperators.nullsfirst().
               `method of' ColumnOperators.

               Produce a nulls_first() clause against the
               parent object.

               Changed in version 1.4: The ‘nulls_first()’ operator is
               renamed from ‘nullsfirst()’ in previous releases.  The
               previous name remains available for backwards
               compatibility.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    nullslast ()

               `inherited from the' ColumnOperators.nullslast().
               `method of' ColumnOperators.

               Produce a nulls_last() clause against the
               parent object.

               Changed in version 1.4: The ‘nulls_last()’ operator is
               renamed from ‘nullslast()’ in previous releases.  The
               previous name remains available for backwards
               compatibility.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    of_type (cls)

               Redefine this object in terms of a polymorphic subclass.

               See PropComparator.of_type() for an example.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    static of_type_op (a, class_)

               `inherited from the' ‘PropComparator.of_type_op()’
               `method of' PropComparator.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    op (opstring, precedence=0, is_comparison=False,
                    return_type=None)

               `inherited from the' Operators.op(). `method
               of' Operators.

               Produce a generic operator function.

               e.g.:

                    somecolumn.op("*")(5)

               produces:

                    somecolumn * 5

               This function can also be used to make bitwise operators
               explicit.  For example:

                    somecolumn.op('&')(0xff)

               is a bitwise AND of the value in ‘somecolumn’.

               Parameters:

                  * ‘operator’ – a string which will be output as the
                    infix operator between this element and the
                    expression passed to the generated function.

                  * ‘precedence’ – precedence to apply to the operator,
                    when parenthesizing expressions.  A lower number
                    will cause the expression to be parenthesized when
                    applied against another operator with higher
                    precedence.  The default value of ‘0’ is lower than
                    all operators except for the comma (‘,’) and ‘AS’
                    operators.  A value of 100 will be higher or equal
                    to all operators, and -100 will be lower than or
                    equal to all operators.

                  * ‘is_comparison’ – if True, the operator will be
                    considered as a “comparison” operator, that is which
                    evaluates to a boolean true/false value, like ‘==’,
                    ‘>’, etc.  This flag should be set so that ORM
                    relationships can establish that the operator is a
                    comparison operator when used in a custom join
                    condition.

                    New in version 0.9.2: - added the
                    Operators.op.is_comparison flag.

                  * ‘return_type’ – a TypeEngine class or
                    object that will force the return type of an
                    expression produced by this operator to be of that
                    type.  By default, operators that specify
                    Operators.op.is_comparison will resolve to
                    Boolean, and those that do not will be of
                    the same type as the left-hand operand.

               See also
               ........

               See Redefining and Creating New Operators.

               See Using custom operators in join conditions.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    operate (op, *other, **kwargs)

               `inherited from the' Operators.operate().
               `method of' Operators.

               Operate on an argument.

               This is the lowest level of operation, raises
               ‘NotImplementedError’ by default.

               Overriding this on a subclass can allow common behavior
               to be applied to all operations.  For example, overriding
               ColumnOperators to apply ‘func.lower()’ to
               the left and right side:

                    class MyComparator(ColumnOperators):
                        def operate(self, op, other):
                            return op(func.lower(self), func.lower(other))

               Parameters:

                  * ‘op’ – Operator callable.

                  * ‘*other’ – the ‘other’ side of the operation.  Will
                    be a single scalar for most operations.

                  * ‘**kwargs’ – modifiers.  These may be passed by
                    special operators such as
                    ‘ColumnOperators.contains()’.

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    regexp_match (pattern, flags=None)

               `inherited from the'
               ColumnOperators.regexp_match(). `method of'
               ColumnOperators.

               Implements a database-specific ‘regexp match’ operator.

               E.g.:

                    stmt = select(table.c.some_column).where(
                        table.c.some_column.regexp_match('^(b|c)')
                    )

               ColumnOperators.regexp_match() attempts to
               resolve to a REGEXP-like function or operator provided by
               the backend, however the specific regular expression
               syntax and flags available are `not backend agnostic'.

               Examples include:

                  * PostgreSQL - renders ‘x ~ y’ or ‘x !~ y’ when
                    negated.

                  * Oracle - renders ‘REGEXP_LIKE(x, y)’

                  * SQLite - uses SQLite’s ‘REGEXP’ placeholder operator
                    and calls into the Python ‘re.match()’ builtin.

                  * other backends may provide special implementations.

                  * Backends without any special implementation will
                    emit the operator as “REGEXP” or “NOT REGEXP”.  This
                    is compatible with SQLite and MySQL, for example.

               Regular expression support is currently implemented for
               Oracle, PostgreSQL, MySQL and MariaDB. Partial support is
               available for SQLite.  Support among third-party dialects
               may vary.

               Parameters:

                  * ‘pattern’ – The regular expression pattern string or
                    column clause.

                  * ‘flags’ – Any regular expression string flags to
                    apply.  Flags tend to be backend specific.  It can
                    be a string or a column clause.  Some backends, like
                    PostgreSQL and MariaDB, may alternatively specify
                    the flags as part of the pattern.  When using the
                    ignore case flag ‘i’ in PostgreSQL, the ignore case
                    regexp match operator ‘~*’ or ‘!~*’ will be used.

               New in version 1.4.

               See also
               ........

               See ColumnOperators.regexp_replace().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    regexp_replace (pattern, replacement,
                    flags=None)

               `inherited from the'
               ColumnOperators.regexp_replace(). `method of'
               ColumnOperators.

               Implements a database-specific ‘regexp replace’ operator.

               E.g.:

                    stmt = select(
                        table.c.some_column.regexp_replace(
                            'b(..)',
                            'X^AY',
                            flags='g'
                        )
                    )

               ColumnOperators.regexp_replace() attempts to
               resolve to a REGEXP_REPLACE-like function provided by the
               backend, that usually emit the function
               ‘REGEXP_REPLACE()’.  However, the specific regular
               expression syntax and flags available are `not backend
               agnostic'.

               Regular expression replacement support is currently
               implemented for Oracle, PostgreSQL, MySQL 8 or greater
               and MariaDB. Support among third-party dialects may vary.

               Parameters:

                  * ‘pattern’ – The regular expression pattern string or
                    column clause.

                  * ‘pattern’ – The replacement string or column clause.

                  * ‘flags’ – Any regular expression string flags to
                    apply.  Flags tend to be backend specific.  It can
                    be a string or a column clause.  Some backends, like
                    PostgreSQL and MariaDB, may alternatively specify
                    the flags as part of the pattern.

               New in version 1.4.

               See also
               ........

               See ColumnOperators.regexp_match().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    reverse_operate (op, other, **kwargs)

               `inherited from the' Operators.reverse_operate().
               `method of' Operators.

               Reverse operate on an argument.

               Usage is the same as operate().

           -- Method:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    startswith (other, **kwargs)

               `inherited from the' ColumnOperators.startswith().
               `method of' ColumnOperators.

               Implement the ‘startswith’ operator.

               Produces a LIKE expression that tests against a match for
               the start of a string value:

                    column LIKE <other> || '%'

               E.g.:

                    stmt = select(sometable).\
                        where(sometable.c.column.startswith("foobar"))

               Since the operator uses ‘LIKE’, wildcard characters ‘"%"’
               and ‘"_"’ that are present inside the <other> expression
               will behave like wildcards as well.  For literal string
               values, the ColumnOperators.startswith.autoescape
               flag may be set to ‘True’ to apply escaping to
               occurrences of these characters within the string value
               so that they match as themselves and not as wildcard
               characters.  Alternatively, the
               ColumnOperators.startswith.escape parameter will
               establish a given character as an escape character which
               can be of use when the target expression is not a literal
               string.

               Parameters:

                  * ‘other’ – expression to be compared.  This is
                    usually a plain string value, but can also be an
                    arbitrary SQL expression.  LIKE wildcard characters
                    ‘%’ and ‘_’ are not escaped by default unless the
                    ColumnOperators.startswith.autoescape
                    flag is set to True.

                  * ‘autoescape’ – boolean; when True, establishes an
                    escape character within the LIKE expression, then
                    applies it to all occurrences of ‘"%"’, ‘"_"’ and
                    the escape character itself within the comparison
                    value, which is assumed to be a literal string and
                    not a SQL expression.

                    An expression such as:

                         somecolumn.startswith("foo%bar", autoescape=True)

                    Will render as:

                         somecolumn LIKE :param || '%' ESCAPE '/'

                    With the value of ‘:param’ as ‘"foo/%bar"’.

                  * ‘escape’ – a character which when given will render
                    with the ‘ESCAPE’ keyword to establish that
                    character as the escape character.  This character
                    can then be placed preceding occurrences of ‘%’ and
                    ‘_’ to allow them to act as themselves and not
                    wildcard characters.

                    An expression such as:

                         somecolumn.startswith("foo/%bar", escape="^")

                    Will render as:

                         somecolumn LIKE :param || '%' ESCAPE '^'

                    The parameter may also be combined with
                    ColumnOperators.startswith.autoescape:

                         somecolumn.startswith("foo%bar^bat", escape="^", autoescape=True)

                    Where above, the given literal parameter will be
                    converted to ‘"foo^%bar^^bat"’ before being passed
                    to the database.

               See also
               ........

               See ColumnOperators.endswith().

               See ColumnOperators.contains().

               See ColumnOperators.like().

           -- Attribute:
                    sqlalchemy.orm.RelationshipProperty.Comparator..
                    timetuple = None

               `inherited from the' ColumnOperators.timetuple.
               `attribute of' ColumnOperators.

               Hack, allows datetime objects to be compared on the LHS.

      -- Method: sqlalchemy.orm.RelationshipProperty..
               __init__ (argument, secondary=None, primaryjoin=None,
               secondaryjoin=None, foreign_keys=None, uselist=None,
               order_by=False, backref=None, back_populates=None,
               overlaps=None, post_update=False, cascade=False,
               viewonly=False, lazy='select', collection_class=None,
               passive_deletes=False, passive_updates=True,
               remote_side=None, enable_typechecks=True,
               join_depth=None, comparator_factory=None,
               single_parent=False, innerjoin=False,
               distinct_target_key=None, doc=None, active_history=False,
               cascade_backrefs=True, load_on_pending=False,
               bake_queries=True, _local_remote_pairs=None,
               query_class=None, info=None, omit_join=None,
               sync_backref=None)

          Construct a new RelationshipProperty object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.orm.relationship() for a full usage and
          argument description.

      -- Attribute: sqlalchemy.orm.RelationshipProperty..
               cascade

          The set of ‘cascade’ attribute names.

          This collection is checked before the ‘cascade_iterator’
          method is called.

          The collection typically only applies to a
          RelationshipProperty.

      -- Method: sqlalchemy.orm.RelationshipProperty..
               cascade_iterator (type_, state, dict_,
               visited_states, halt_on=None)

          Iterate through instances related to the given instance for a
          particular ‘cascade’, starting with this MapperProperty.

          Return an iterator3-tuples (instance, mapper, state).

          Note that the ‘cascade’ collection on this MapperProperty is
          checked first for the given type before cascade_iterator is
          called.

          This method typically only applies to RelationshipProperty.

      -- Attribute: sqlalchemy.orm.RelationshipProperty..
               class_attribute

          `inherited from the' MapperProperty.class_attribute.
          `attribute of' MapperProperty.

          Return the class-bound descriptor corresponding to this
          MapperProperty.

          This is basically a ‘getattr()’ call:

               return getattr(self.parent.class_, self.key)

          I.e.  if this MapperProperty were named
          ‘addresses’, and the class to which it is mapped is ‘User’,
          this sequence is possible:

               >>> from sqlalchemy import inspect
               >>> mapper = inspect(User)
               >>> addresses_property = mapper.attrs.addresses
               >>> addresses_property.class_attribute is User.addresses
               True
               >>> User.addresses.property is addresses_property
               True

      -- Method: sqlalchemy.orm.RelationshipProperty..
               create_row_processor (context, query_entity, path,
               mapper, result, adapter, populators)

          `inherited from the'
          ‘StrategizedProperty.create_row_processor()’ `method of'
          ‘StrategizedProperty’

          Produce row processing functions and append to the given set
          of populators lists.

      -- Method: sqlalchemy.orm.RelationshipProperty..do_init
               ()

          Perform subclass-specific initialization post-mapper-creation
          steps.

          This is a template method called by the ‘MapperProperty’
          object’s init() method.

      -- Attribute: sqlalchemy.orm.RelationshipProperty..
               entity

          Return the target mapped entity, which is an inspect() of the
          class or aliased class that is referred towards.

      -- Attribute: sqlalchemy.orm.RelationshipProperty..
               extension_type = symbol('NOT_EXTENSION')

          `inherited from the' ‘InspectionAttr.extension_type’
          `attribute of' ‘InspectionAttr’

          The extension type, if any.  Defaults to ‘NOT_EXTENSION’

          See also
          ........

          See HYBRID_METHOD.

          See HYBRID_PROPERTY.

          See ASSOCIATION_PROXY.

      -- Method: sqlalchemy.orm.RelationshipProperty..init ()

          `inherited from the' MapperProperty.init(). `method
          of' MapperProperty.

          Called after all mappers are created to assemble relationships
          between mappers and perform other post-mapper-creation
          initialization steps.

      -- Method: sqlalchemy.orm.RelationshipProperty..
               instrument_class (mapper)

          Hook called by the Mapper to the property to initiate
          instrumentation of the class attribute managed by this
          MapperProperty.

          The MapperProperty here will typically call out to the
          attributes module to set up an InstrumentedAttribute.

          This step is the first of two steps to set up an
          InstrumentedAttribute, and is called early in the mapper setup
          process.

          The second step is typically the init_class_attribute step,
          called from StrategizedProperty via the
          post_instrument_class() hook.  This step assigns additional
          state to the InstrumentedAttribute (specifically the “impl”)
          which has been determined after the MapperProperty has
          determined what kind of persistence management it needs to do
          (e.g.  scalar, object, collection, etc).

      -- Attribute: sqlalchemy.orm.RelationshipProperty..
               mapper

          Return the targeted Mapper for this
          RelationshipProperty.

          This is a lazy-initializing static attribute.

      -- Method: sqlalchemy.orm.RelationshipProperty..merge
               (session, source_state, source_dict, dest_state,
               dest_dict, load, _recursive, _resolve_conflict_map)

          Merge the attribute represented by this ‘MapperProperty’ from
          source to destination object.

      -- Method: sqlalchemy.orm.RelationshipProperty..
               post_instrument_class (mapper)

          `inherited from the'
          ‘StrategizedProperty.post_instrument_class()’ `method of'
          ‘StrategizedProperty’

          Perform instrumentation adjustments that need to occur after
          init() has completed.

          The given Mapper is the Mapper invoking the operation, which
          may not be the same Mapper as self.parent in an inheritance
          scenario; however, Mapper will always at least be a sub-mapper
          of self.parent.

          This method is typically used by StrategizedProperty, which
          delegates it to LoaderStrategy.init_class_attribute() to
          perform final setup on the class-bound InstrumentedAttribute.

      -- Method: sqlalchemy.orm.RelationshipProperty..
               set_parent (parent, init)

          `inherited from the' MapperProperty.set_parent().
          `method of' MapperProperty.

          Set the parent mapper that references this MapperProperty.

          This method is overridden by some subclasses to perform extra
          setup when the mapper is first known.

      -- Method: sqlalchemy.orm.RelationshipProperty..setup
               (context, query_entity, path, adapter, **kwargs)

          `inherited from the' ‘StrategizedProperty.setup()’ `method of'
          ‘StrategizedProperty’

          Called by Query for the purposes of constructing a SQL
          statement.

          Each MapperProperty associated with the target mapper
          processes the statement referenced by the query context,
          adding columns and/or criterion as appropriate.

 -- Class: sqlalchemy.orm.SynonymProperty (name, map_column=None,
          descriptor=None, comparator_factory=None, doc=None, info=None)

     `Class signature'

     class sqlalchemy.orm.SynonymProperty.
     (‘sqlalchemy.orm.descriptor_props.DescriptorProperty’)

      -- Method: sqlalchemy.orm.SynonymProperty..__init__
               (name, map_column=None, descriptor=None,
               comparator_factory=None, doc=None, info=None)

          Construct a new SynonymProperty object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.orm.synonym() for a full usage and
          argument description.

      -- Method: sqlalchemy.orm.SynonymProperty..
               cascade_iterator (type_, state, dict_,
               visited_states, halt_on=None)

          `inherited from the' MapperProperty.cascade_iterator().
          `method of' MapperProperty.

          Iterate through instances related to the given instance for a
          particular ‘cascade’, starting with this MapperProperty.

          Return an iterator3-tuples (instance, mapper, state).

          Note that the ‘cascade’ collection on this MapperProperty is
          checked first for the given type before cascade_iterator is
          called.

          This method typically only applies to RelationshipProperty.

      -- Attribute: sqlalchemy.orm.SynonymProperty..
               class_attribute

          `inherited from the' MapperProperty.class_attribute.
          `attribute of' MapperProperty.

          Return the class-bound descriptor corresponding to this
          MapperProperty.

          This is basically a ‘getattr()’ call:

               return getattr(self.parent.class_, self.key)

          I.e.  if this MapperProperty were named
          ‘addresses’, and the class to which it is mapped is ‘User’,
          this sequence is possible:

               >>> from sqlalchemy import inspect
               >>> mapper = inspect(User)
               >>> addresses_property = mapper.attrs.addresses
               >>> addresses_property.class_attribute is User.addresses
               True
               >>> User.addresses.property is addresses_property
               True

      -- Method: sqlalchemy.orm.SynonymProperty..
               create_row_processor (context, query_entity, path,
               mapper, result, adapter, populators)

          `inherited from the'
          MapperProperty.create_row_processor(). `method of'
          MapperProperty.

          Produce row processing functions and append to the given set
          of populators lists.

      -- Method: sqlalchemy.orm.SynonymProperty..do_init ()

          `inherited from the' MapperProperty.do_init().
          `method of' MapperProperty.

          Perform subclass-specific initialization post-mapper-creation
          steps.

          This is a template method called by the ‘MapperProperty’
          object’s init() method.

      -- Attribute: sqlalchemy.orm.SynonymProperty..
               extension_type = symbol('NOT_EXTENSION')

          `inherited from the' ‘InspectionAttr.extension_type’
          `attribute of' ‘InspectionAttr’

          The extension type, if any.  Defaults to ‘NOT_EXTENSION’

          See also
          ........

          See HYBRID_METHOD.

          See HYBRID_PROPERTY.

          See ASSOCIATION_PROXY.

      -- Method: sqlalchemy.orm.SynonymProperty..init ()

          `inherited from the' MapperProperty.init(). `method
          of' MapperProperty.

          Called after all mappers are created to assemble relationships
          between mappers and perform other post-mapper-creation
          initialization steps.

      -- Method: sqlalchemy.orm.SynonymProperty..
               instrument_class (mapper)

          `inherited from the' ‘DescriptorProperty.instrument_class()’
          `method of' ‘DescriptorProperty’

          Hook called by the Mapper to the property to initiate
          instrumentation of the class attribute managed by this
          MapperProperty.

          The MapperProperty here will typically call out to the
          attributes module to set up an InstrumentedAttribute.

          This step is the first of two steps to set up an
          InstrumentedAttribute, and is called early in the mapper setup
          process.

          The second step is typically the init_class_attribute step,
          called from StrategizedProperty via the
          post_instrument_class() hook.  This step assigns additional
          state to the InstrumentedAttribute (specifically the “impl”)
          which has been determined after the MapperProperty has
          determined what kind of persistence management it needs to do
          (e.g.  scalar, object, collection, etc).

      -- Method: sqlalchemy.orm.SynonymProperty..merge
               (session, source_state, source_dict, dest_state,
               dest_dict, load, _recursive, _resolve_conflict_map)

          `inherited from the' MapperProperty.merge().
          `method of' MapperProperty.

          Merge the attribute represented by this ‘MapperProperty’ from
          source to destination object.

      -- Method: sqlalchemy.orm.SynonymProperty..
               post_instrument_class (mapper)

          `inherited from the'
          MapperProperty.post_instrument_class(). `method of'
          MapperProperty.

          Perform instrumentation adjustments that need to occur after
          init() has completed.

          The given Mapper is the Mapper invoking the operation, which
          may not be the same Mapper as self.parent in an inheritance
          scenario; however, Mapper will always at least be a sub-mapper
          of self.parent.

          This method is typically used by StrategizedProperty, which
          delegates it to LoaderStrategy.init_class_attribute() to
          perform final setup on the class-bound InstrumentedAttribute.

      -- Method: sqlalchemy.orm.SynonymProperty..set_parent
               (parent, init)

          Set the parent mapper that references this MapperProperty.

          This method is overridden by some subclasses to perform extra
          setup when the mapper is first known.

      -- Method: sqlalchemy.orm.SynonymProperty..setup
               (context, query_entity, path, adapter, **kwargs)

          `inherited from the' MapperProperty.setup().
          `method of' MapperProperty.

          Called by Query for the purposes of constructing a SQL
          statement.

          Each MapperProperty associated with the target mapper
          processes the statement referenced by the query context,
          adding columns and/or criterion as appropriate.

      -- Attribute: sqlalchemy.orm.SynonymProperty..
               uses_objects

 -- Class: sqlalchemy.orm.QueryContext (compile_state, statement,
          params, session, load_options, execution_options=None,
          bind_arguments=None)

      -- Class: default_load_options (**kw)

          `Class signature'

          class sqlalchemy.orm.QueryContext.default_load_options.
          (‘sqlalchemy.sql.expression.Options’)

 -- Class: sqlalchemy.orm.QueryableAttribute (class_, key, parententity,
          impl=None, comparator=None, of_type=None, extra_criteria=())

     Base class for descriptor objects that intercept attribute events
     on behalf of a MapperProperty object.  The actual
     MapperProperty is accessible via the
     QueryableAttribute.property attribute.

     See also
     ........

     See InstrumentedAttribute.

     See MapperProperty.

     See Mapper.all_orm_descriptors.

     See Mapper.attrs.

     `Class signature'

     class sqlalchemy.orm.QueryableAttribute.
     (‘sqlalchemy.orm.base._MappedAttribute’,
     ‘sqlalchemy.orm.base.InspectionAttr’, see
     sqlalchemy.orm.PropComparator,
     ‘sqlalchemy.sql.traversals.HasCopyInternals’,
     ‘sqlalchemy.sql.roles.JoinTargetRole’,
     ‘sqlalchemy.sql.roles.OnClauseRole’,
     ‘sqlalchemy.sql.expression.Immutable’,
     ‘sqlalchemy.sql.traversals.MemoizedHasCacheKey’)

      -- Method: sqlalchemy.orm.QueryableAttribute..__eq__
               (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__eq__’ `method of'
          ColumnOperators.

          Implement the ‘==’ operator.

          In a column context, produces the clause ‘a = b’.  If the
          target is ‘None’, produces ‘a IS NULL’.

      -- Method: sqlalchemy.orm.QueryableAttribute..__le__
               (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__le__’ `method of'
          ColumnOperators.

          Implement the ‘<=’ operator.

          In a column context, produces the clause ‘a <= b’.

      -- Method: sqlalchemy.orm.QueryableAttribute..__lt__
               (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__lt__’ `method of'
          ColumnOperators.

          Implement the ‘<’ operator.

          In a column context, produces the clause ‘a < b’.

      -- Method: sqlalchemy.orm.QueryableAttribute..__ne__
               (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__ne__’ `method of'
          ColumnOperators.

          Implement the ‘!=’ operator.

          In a column context, produces the clause ‘a != b’.  If the
          target is ‘None’, produces ‘a IS NOT NULL’.

      -- Method: sqlalchemy.orm.QueryableAttribute..
               adapt_to_entity (adapt_to_entity)

          Return a copy of this PropComparator which will use the given
          AliasedInsp to produce corresponding expressions.

      -- Attribute: sqlalchemy.orm.QueryableAttribute..
               adapter

          `inherited from the' PropComparator.adapter.
          `attribute of' PropComparator.

          Produce a callable that adapts column expressions to suit an
          aliased version of this comparator.

      -- Method: sqlalchemy.orm.QueryableAttribute..all_ ()

          `inherited from the' ColumnOperators.all_().
          `method of' ColumnOperators.

          Produce a all_() clause against the parent object.

          This operator is only appropriate against a scalar subquery
          object, or for some backends an column expression that is
          against the ARRAY type, e.g.:

               # postgresql '5 = ALL (somearray)'
               expr = 5 == mytable.c.somearray.all_()

               # mysql '5 = ALL (SELECT value FROM table)'
               expr = 5 == select(table.c.value).scalar_subquery().all_()

          See also
          ........

          See all_(). - standalone version

          See any_(). - ANY operator

          New in version 1.1.

      -- Method: sqlalchemy.orm.QueryableAttribute..and_
               (*other)

          Add additional criteria to the ON clause that’s represented by
          this relationship attribute.

          E.g.:

               stmt = select(User).join(
                   User.addresses.and_(Address.email_address != 'foo')
               )

               stmt = select(User).options(
                   joinedload(User.addresses.and_(Address.email_address != 'foo'))
               )

          New in version 1.4.

          See also
          ........

          See Augmenting Built-in ON Clauses.

          See Adding Criteria to loader options.

          See with_loader_criteria().

      -- Method: sqlalchemy.orm.QueryableAttribute..any
               (criterion=None, **kwargs)

          `inherited from the' PropComparator.any(). `method
          of' PropComparator.

          Return true if this collection contains any member that meets
          the given criterion.

          The usual implementation of ‘any()’ is Comparator.any().

          Parameters:

             * ‘criterion’ – an optional ClauseElement formulated
               against the member class’ table or attributes.

             * ‘**kwargs’ – key/value pairs corresponding to member
               class attribute names which will be compared via equality
               to the corresponding values.

      -- Method: sqlalchemy.orm.QueryableAttribute..any_ ()

          `inherited from the' ColumnOperators.any_().
          `method of' ColumnOperators.

          Produce a any_() clause against the parent object.

          This operator is only appropriate against a scalar subquery
          object, or for some backends an column expression that is
          against the ARRAY type, e.g.:

               # postgresql '5 = ANY (somearray)'
               expr = 5 == mytable.c.somearray.any_()

               # mysql '5 = ANY (SELECT value FROM table)'
               expr = 5 == select(table.c.value).scalar_subquery().any_()

          See also
          ........

          See any_(). - standalone version

          See all_(). - ALL operator

          New in version 1.1.

      -- Method: sqlalchemy.orm.QueryableAttribute..asc ()

          `inherited from the' ColumnOperators.asc(). `method
          of' ColumnOperators.

          Produce a asc() clause against the parent object.

      -- Method: sqlalchemy.orm.QueryableAttribute..between
               (cleft, cright, symmetric=False)

          `inherited from the' ColumnOperators.between().
          `method of' ColumnOperators.

          Produce a between() clause against the parent
          object, given the lower and upper range.

      -- Method: sqlalchemy.orm.QueryableAttribute..bool_op
               (opstring, precedence=0)

          `inherited from the' Operators.bool_op(). `method
          of' Operators.

          Return a custom boolean operator.

          This method is shorthand for calling Operators.op()
          and passing the Operators.op.is_comparison
          flag with True.

          See also
          ........

          See Operators.op().

      -- Method: sqlalchemy.orm.QueryableAttribute..collate
               (collation)

          `inherited from the' ColumnOperators.collate().
          `method of' ColumnOperators.

          Produce a collate() clause against the parent
          object, given the collation string.

          See also
          ........

          See collate().

      -- Method: sqlalchemy.orm.QueryableAttribute..concat
               (other)

          `inherited from the' ColumnOperators.concat().
          `method of' ColumnOperators.

          Implement the ‘concat’ operator.

          In a column context, produces the clause ‘a || b’, or uses the
          ‘concat()’ operator on MySQL.

      -- Method: sqlalchemy.orm.QueryableAttribute..contains
               (other, **kwargs)

          `inherited from the' ColumnOperators.contains().
          `method of' ColumnOperators.

          Implement the ‘contains’ operator.

          Produces a LIKE expression that tests against a match for the
          middle of a string value:

               column LIKE '%' || <other> || '%'

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.contains("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.contains.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.contains.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.contains.autoescape flag is set to
               True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.contains("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE '%' || :param || '%' ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.contains("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE '%' || :param || '%' ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.contains.autoescape:

                    somecolumn.contains("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.startswith().

          See ColumnOperators.endswith().

          See ColumnOperators.like().

      -- Method: sqlalchemy.orm.QueryableAttribute..desc ()

          `inherited from the' ColumnOperators.desc().
          `method of' ColumnOperators.

          Produce a desc() clause against the parent object.

      -- Method: sqlalchemy.orm.QueryableAttribute..distinct
               ()

          `inherited from the' ColumnOperators.distinct().
          `method of' ColumnOperators.

          Produce a distinct() clause against the parent
          object.

      -- Method: sqlalchemy.orm.QueryableAttribute..endswith
               (other, **kwargs)

          `inherited from the' ColumnOperators.endswith().
          `method of' ColumnOperators.

          Implement the ‘endswith’ operator.

          Produces a LIKE expression that tests against a match for the
          end of a string value:

               column LIKE '%' || <other>

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.endswith("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.endswith.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.endswith.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.endswith.autoescape flag is set to
               True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.endswith("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE '%' || :param ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.endswith("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE '%' || :param ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.endswith.autoescape:

                    somecolumn.endswith("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.startswith().

          See ColumnOperators.contains().

          See ColumnOperators.like().

      -- Attribute: sqlalchemy.orm.QueryableAttribute..
               expression

          The SQL expression object represented by this
          QueryableAttribute.

          This will typically be an instance of a ColumnElement
          subclass representing a column expression.

      -- Attribute: sqlalchemy.orm.QueryableAttribute..
               extension_type = symbol('NOT_EXTENSION')

          `inherited from the' ‘InspectionAttr.extension_type’
          `attribute of' ‘InspectionAttr’

          The extension type, if any.  Defaults to ‘NOT_EXTENSION’

          See also
          ........

          See HYBRID_METHOD.

          See HYBRID_PROPERTY.

          See ASSOCIATION_PROXY.

      -- Method: sqlalchemy.orm.QueryableAttribute..has
               (criterion=None, **kwargs)

          `inherited from the' PropComparator.has(). `method
          of' PropComparator.

          Return true if this element references a member which meets
          the given criterion.

          The usual implementation of ‘has()’ is Comparator.has().

          Parameters:

             * ‘criterion’ – an optional ClauseElement formulated
               against the member class’ table or attributes.

             * ‘**kwargs’ – key/value pairs corresponding to member
               class attribute names which will be compared via equality
               to the corresponding values.

      -- Method: sqlalchemy.orm.QueryableAttribute..ilike
               (other, escape=None)

          `inherited from the' ColumnOperators.ilike().
          `method of' ColumnOperators.

          Implement the ‘ilike’ operator, e.g.  case insensitive LIKE.

          In a column context, produces an expression either of the
          form:

               lower(a) LIKE lower(other)

          Or on backends that support the ILIKE operator:

               a ILIKE other

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.ilike("%foobar%"))

          Parameters:

             * ‘other’ – expression to be compared

             * ‘escape’ – optional escape character, renders the
               ‘ESCAPE’ keyword, e.g.:

                    somecolumn.ilike("foo/%bar", escape="/")

          See also
          ........

          See ColumnOperators.like().

      -- Method: sqlalchemy.orm.QueryableAttribute..in_
               (other)

          `inherited from the' ColumnOperators.in_(). `method
          of' ColumnOperators.

          Implement the ‘in’ operator.

          In a column context, produces the clause ‘column IN <other>’.

          The given parameter ‘other’ may be:

             * A list of literal values, e.g.:

                    stmt.where(column.in_([1, 2, 3]))

               In this calling form, the list of items is converted to a
               set of bound parameters the same length as the list
               given:

                    WHERE COL IN (?, ?, ?)

             * A list of tuples may be provided if the comparison is
               against a tuple_() containing multiple
               expressions:

                    from sqlalchemy import tuple_
                    stmt.where(tuple_(col1, col2).in_([(1, 10), (2, 20), (3, 30)]))

             * An empty list, e.g.:

                    stmt.where(column.in_([]))

               In this calling form, the expression renders an “empty
               set” expression.  These expressions are tailored to
               individual backends and are generally trying to get an
               empty SELECT statement as a subquery.  Such as on SQLite,
               the expression is:

                    WHERE col IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)

               Changed in version 1.4: empty IN expressions now use an
               execution-time generated SELECT subquery in all cases.

             * A bound parameter, e.g.  see bindparam(), may be
               used if it includes the bindparam.expanding
               flag:

                    stmt.where(column.in_(bindparam('value', expanding=True)))

               In this calling form, the expression renders a special
               non-SQL placeholder expression that looks like:

                    WHERE COL IN ([EXPANDING_value])

               This placeholder expression is intercepted at statement
               execution time to be converted into the variable number
               of bound parameter form illustrated earlier.  If the
               statement were executed as:

                    connection.execute(stmt, {"value": [1, 2, 3]})

               The database would be passed a bound parameter for each
               value:

                    WHERE COL IN (?, ?, ?)

               New in version 1.2: added “expanding” bound parameters

               If an empty list is passed, a special “empty list”
               expression, which is specific to the database in use, is
               rendered.  On SQLite this would be:

                    WHERE COL IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)

               New in version 1.3: “expanding” bound parameters now
               support empty lists

             * a select() construct, which is usually a
               correlated scalar select:

                    stmt.where(
                        column.in_(
                            select(othertable.c.y).
                            where(table.c.x == othertable.c.x)
                        )
                    )

               In this calling form, see ColumnOperators.in_()
               renders as given:

                    WHERE COL IN (SELECT othertable.y
                    FROM othertable WHERE othertable.x = table.x)

          Parameters: ‘other’ – a list of literals, a select()
          construct, or a bindparam() construct that
          includes the bindparam.expanding flag set to True.

      -- Attribute: sqlalchemy.orm.QueryableAttribute..info

          Return the ‘info’ dictionary for the underlying SQL element.

          The behavior here is as follows:

             * If the attribute is a column-mapped property, i.e.  see
               ColumnProperty, which is mapped directly to a
               schema-level Column object, this attribute
               will return the SchemaItem.info dictionary
               associated with the core-level Column object.

             * If the attribute is a ColumnProperty but is
               mapped to any other kind of SQL expression other than a
               Column, the attribute will refer to the
               MapperProperty.info dictionary associated directly
               with the ColumnProperty, assuming the SQL
               expression itself does not have its own ‘.info’ attribute
               (which should be the case, unless a user-defined SQL
               construct has defined one).

             * If the attribute refers to any other kind of
               MapperProperty, including
               RelationshipProperty, the attribute will refer to
               the MapperProperty.info dictionary associated
               with that MapperProperty.

             * To access the MapperProperty.info dictionary
               of the MapperProperty unconditionally,
               including for a ColumnProperty that’s
               associated directly with a Column, the
               attribute can be referred to using
               QueryableAttribute.property attribute, as
               ‘MyClass.someattribute.property.info’.

          See also
          ........

          See SchemaItem.info.

          See MapperProperty.info.

      -- Method: sqlalchemy.orm.QueryableAttribute..is_
               (other)

          `inherited from the' ColumnOperators.is_(). `method
          of' ColumnOperators.

          Implement the ‘IS’ operator.

          Normally, ‘IS’ is generated automatically when comparing to a
          value of ‘None’, which resolves to ‘NULL’.  However, explicit
          usage of ‘IS’ may be desirable if comparing to boolean values
          on certain platforms.

          See also
          ........

          See ColumnOperators.is_not().

      -- Method: sqlalchemy.orm.QueryableAttribute..
               is_distinct_from (other)

          `inherited from the' ColumnOperators.is_distinct_from().
          `method of' ColumnOperators.

          Implement the ‘IS DISTINCT FROM’ operator.

          Renders “a IS DISTINCT FROM b” on most platforms; on some such
          as SQLite may render “a IS NOT b”.

          New in version 1.1.

      -- Method: sqlalchemy.orm.QueryableAttribute..is_not
               (other)

          `inherited from the' ColumnOperators.is_not().
          `method of' ColumnOperators.

          Implement the ‘IS NOT’ operator.

          Normally, ‘IS NOT’ is generated automatically when comparing
          to a value of ‘None’, which resolves to ‘NULL’.  However,
          explicit usage of ‘IS NOT’ may be desirable if comparing to
          boolean values on certain platforms.

          Changed in version 1.4: The ‘is_not()’ operator is renamed
          from ‘isnot()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.is_().

      -- Method: sqlalchemy.orm.QueryableAttribute..
               is_not_distinct_from (other)

          `inherited from the'
          ColumnOperators.is_not_distinct_from(). `method of'
          ColumnOperators.

          Implement the ‘IS NOT DISTINCT FROM’ operator.

          Renders “a IS NOT DISTINCT FROM b” on most platforms; on some
          such as SQLite may render “a IS b”.

          Changed in version 1.4: The ‘is_not_distinct_from()’ operator
          is renamed from ‘isnot_distinct_from()’ in previous releases.
          The previous name remains available for backwards
          compatibility.

          New in version 1.1.

      -- Method: sqlalchemy.orm.QueryableAttribute..isnot
               (other)

          `inherited from the' ColumnOperators.isnot().
          `method of' ColumnOperators.

          Implement the ‘IS NOT’ operator.

          Normally, ‘IS NOT’ is generated automatically when comparing
          to a value of ‘None’, which resolves to ‘NULL’.  However,
          explicit usage of ‘IS NOT’ may be desirable if comparing to
          boolean values on certain platforms.

          Changed in version 1.4: The ‘is_not()’ operator is renamed
          from ‘isnot()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.is_().

      -- Method: sqlalchemy.orm.QueryableAttribute..
               isnot_distinct_from (other)

          `inherited from the'
          ColumnOperators.isnot_distinct_from(). `method of'
          ColumnOperators.

          Implement the ‘IS NOT DISTINCT FROM’ operator.

          Renders “a IS NOT DISTINCT FROM b” on most platforms; on some
          such as SQLite may render “a IS b”.

          Changed in version 1.4: The ‘is_not_distinct_from()’ operator
          is renamed from ‘isnot_distinct_from()’ in previous releases.
          The previous name remains available for backwards
          compatibility.

          New in version 1.1.

      -- Method: sqlalchemy.orm.QueryableAttribute..like
               (other, escape=None)

          `inherited from the' ColumnOperators.like().
          `method of' ColumnOperators.

          Implement the ‘like’ operator.

          In a column context, produces the expression:

               a LIKE other

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.like("%foobar%"))

          Parameters:

             * ‘other’ – expression to be compared

             * ‘escape’ – optional escape character, renders the
               ‘ESCAPE’ keyword, e.g.:

                    somecolumn.like("foo/%bar", escape="/")

          See also
          ........

          See ColumnOperators.ilike().

      -- Method: sqlalchemy.orm.QueryableAttribute..match
               (other, **kwargs)

          `inherited from the' ColumnOperators.match().
          `method of' ColumnOperators.

          Implements a database-specific ‘match’ operator.

          ColumnOperators.match() attempts to resolve to a
          MATCH-like function or operator provided by the backend.
          Examples include:

             * PostgreSQL - renders ‘x @@ to_tsquery(y)’

             * MySQL - renders ‘MATCH (x) AGAINST (y IN BOOLEAN MODE)’

             * Oracle - renders ‘CONTAINS(x, y)’

             * other backends may provide special implementations.

             * Backends without any special implementation will emit the
               operator as “MATCH”.  This is compatible with SQLite, for
               example.

      -- Class: memoized_attribute (fget, doc=None)

          A read-only @property that is only evaluated once.

      -- Method: sqlalchemy.orm.QueryableAttribute..
               classmethod memoized_instancemethod (fn)

          `inherited from the' ‘HasMemoized.memoized_instancemethod()’
          `method of' ‘HasMemoized’

          Decorate a method memoize its return value.

      -- Method: sqlalchemy.orm.QueryableAttribute..not_ilike
               (other, escape=None)

          `inherited from the' ColumnOperators.not_ilike().
          `method of' ColumnOperators.

          implement the ‘NOT ILIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.ilike(), i.e.  ‘~x.ilike(y)’.

          Changed in version 1.4: The ‘not_ilike()’ operator is renamed
          from ‘notilike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.ilike().

      -- Method: sqlalchemy.orm.QueryableAttribute..not_in
               (other)

          `inherited from the' ColumnOperators.not_in().
          `method of' ColumnOperators.

          implement the ‘NOT IN’ operator.

          This is equivalent to using negation with
          ColumnOperators.in_(), i.e.  ‘~x.in_(y)’.

          In the case that ‘other’ is an empty sequence, the compiler
          produces an “empty not in” expression.  This defaults to the
          expression “1 = 1” to produce true in all cases.  The
          create_engine.empty_in_strategy may be used to alter
          this behavior.

          Changed in version 1.4: The ‘not_in()’ operator is renamed
          from ‘notin_()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          Changed in version 1.2: The ColumnOperators.in_()
          and ColumnOperators.not_in() operators now produce
          a “static” expression for an empty IN sequence by default.

          See also
          ........

          See ColumnOperators.in_().

      -- Method: sqlalchemy.orm.QueryableAttribute..not_like
               (other, escape=None)

          `inherited from the' ColumnOperators.not_like().
          `method of' ColumnOperators.

          implement the ‘NOT LIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.like(), i.e.  ‘~x.like(y)’.

          Changed in version 1.4: The ‘not_like()’ operator is renamed
          from ‘notlike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.like().

      -- Method: sqlalchemy.orm.QueryableAttribute..notilike
               (other, escape=None)

          `inherited from the' ColumnOperators.notilike().
          `method of' ColumnOperators.

          implement the ‘NOT ILIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.ilike(), i.e.  ‘~x.ilike(y)’.

          Changed in version 1.4: The ‘not_ilike()’ operator is renamed
          from ‘notilike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.ilike().

      -- Method: sqlalchemy.orm.QueryableAttribute..notin_
               (other)

          `inherited from the' ColumnOperators.notin_().
          `method of' ColumnOperators.

          implement the ‘NOT IN’ operator.

          This is equivalent to using negation with
          ColumnOperators.in_(), i.e.  ‘~x.in_(y)’.

          In the case that ‘other’ is an empty sequence, the compiler
          produces an “empty not in” expression.  This defaults to the
          expression “1 = 1” to produce true in all cases.  The
          create_engine.empty_in_strategy may be used to alter
          this behavior.

          Changed in version 1.4: The ‘not_in()’ operator is renamed
          from ‘notin_()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          Changed in version 1.2: The ColumnOperators.in_()
          and ColumnOperators.not_in() operators now produce
          a “static” expression for an empty IN sequence by default.

          See also
          ........

          See ColumnOperators.in_().

      -- Method: sqlalchemy.orm.QueryableAttribute..notlike
               (other, escape=None)

          `inherited from the' ColumnOperators.notlike().
          `method of' ColumnOperators.

          implement the ‘NOT LIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.like(), i.e.  ‘~x.like(y)’.

          Changed in version 1.4: The ‘not_like()’ operator is renamed
          from ‘notlike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.like().

      -- Method: sqlalchemy.orm.QueryableAttribute..
               nulls_first ()

          `inherited from the' ColumnOperators.nulls_first().
          `method of' ColumnOperators.

          Produce a nulls_first() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_first()’ operator is
          renamed from ‘nullsfirst()’ in previous releases.  The
          previous name remains available for backwards compatibility.

      -- Method: sqlalchemy.orm.QueryableAttribute..
               nulls_last ()

          `inherited from the' ColumnOperators.nulls_last().
          `method of' ColumnOperators.

          Produce a nulls_last() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_last()’ operator is renamed
          from ‘nullslast()’ in previous releases.  The previous name
          remains available for backwards compatibility.

      -- Method: sqlalchemy.orm.QueryableAttribute..
               nullsfirst ()

          `inherited from the' ColumnOperators.nullsfirst().
          `method of' ColumnOperators.

          Produce a nulls_first() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_first()’ operator is
          renamed from ‘nullsfirst()’ in previous releases.  The
          previous name remains available for backwards compatibility.

      -- Method: sqlalchemy.orm.QueryableAttribute..nullslast
               ()

          `inherited from the' ColumnOperators.nullslast().
          `method of' ColumnOperators.

          Produce a nulls_last() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_last()’ operator is renamed
          from ‘nullslast()’ in previous releases.  The previous name
          remains available for backwards compatibility.

      -- Method: sqlalchemy.orm.QueryableAttribute..of_type
               (entity)

          Redefine this object in terms of a polymorphic subclass, see
          with_polymorphic() construct, or aliased()
          construct.

          Returns a new PropComparator from which further criterion can
          be evaluated.

          e.g.:

               query.join(Company.employees.of_type(Engineer)).\
                  filter(Engineer.name=='foo')

          Parameters: ‘class_’ – a class or mapper indicating that
          criterion will be against this specific subclass.

          See also
          ........

          See Referring to specific subtypes on relationships.

      -- Method: sqlalchemy.orm.QueryableAttribute..op
               (opstring, precedence=0, is_comparison=False,
               return_type=None)

          `inherited from the' Operators.op(). `method of'
          Operators.

          Produce a generic operator function.

          e.g.:

               somecolumn.op("*")(5)

          produces:

               somecolumn * 5

          This function can also be used to make bitwise operators
          explicit.  For example:

               somecolumn.op('&')(0xff)

          is a bitwise AND of the value in ‘somecolumn’.

          Parameters:

             * ‘operator’ – a string which will be output as the infix
               operator between this element and the expression passed
               to the generated function.

             * ‘precedence’ – precedence to apply to the operator, when
               parenthesizing expressions.  A lower number will cause
               the expression to be parenthesized when applied against
               another operator with higher precedence.  The default
               value of ‘0’ is lower than all operators except for the
               comma (‘,’) and ‘AS’ operators.  A value of 100 will be
               higher or equal to all operators, and -100 will be lower
               than or equal to all operators.

             * ‘is_comparison’ – if True, the operator will be
               considered as a “comparison” operator, that is which
               evaluates to a boolean true/false value, like ‘==’, ‘>’,
               etc.  This flag should be set so that ORM relationships
               can establish that the operator is a comparison operator
               when used in a custom join condition.

               New in version 0.9.2: - added the
               Operators.op.is_comparison flag.

             * ‘return_type’ – a TypeEngine class or object
               that will force the return type of an expression produced
               by this operator to be of that type.  By default,
               operators that specify Operators.op.is_comparison
               will resolve to Boolean, and those that
               do not will be of the same type as the left-hand operand.

          See also
          ........

          See Redefining and Creating New Operators.

          See Using custom operators in join conditions.

      -- Method: sqlalchemy.orm.QueryableAttribute..operate
               (op, *other, **kwargs)

          Operate on an argument.

          This is the lowest level of operation, raises
          ‘NotImplementedError’ by default.

          Overriding this on a subclass can allow common behavior to be
          applied to all operations.  For example, overriding
          ColumnOperators to apply ‘func.lower()’ to the left and
          right side:

               class MyComparator(ColumnOperators):
                   def operate(self, op, other):
                       return op(func.lower(self), func.lower(other))

          Parameters:

             * ‘op’ – Operator callable.

             * ‘*other’ – the ‘other’ side of the operation.  Will be a
               single scalar for most operations.

             * ‘**kwargs’ – modifiers.  These may be passed by special
               operators such as ‘ColumnOperators.contains()’.

      -- Attribute: sqlalchemy.orm.QueryableAttribute..parent

          Return an inspection instance representing the parent.

          This will be either an instance of Mapper or
          AliasedInsp, depending upon the nature of the parent
          entity which this attribute is associated with.

      -- Attribute: sqlalchemy.orm.QueryableAttribute..
               property

          Return the MapperProperty associated with this
          QueryableAttribute.

          Return values here will commonly be instances of
          ColumnProperty or RelationshipProperty.

      -- Method: sqlalchemy.orm.QueryableAttribute..
               regexp_match (pattern, flags=None)

          `inherited from the' ColumnOperators.regexp_match().
          `method of' ColumnOperators.

          Implements a database-specific ‘regexp match’ operator.

          E.g.:

               stmt = select(table.c.some_column).where(
                   table.c.some_column.regexp_match('^(b|c)')
               )

          ColumnOperators.regexp_match() attempts to resolve
          to a REGEXP-like function or operator provided by the backend,
          however the specific regular expression syntax and flags
          available are `not backend agnostic'.

          Examples include:

             * PostgreSQL - renders ‘x ~ y’ or ‘x !~ y’ when negated.

             * Oracle - renders ‘REGEXP_LIKE(x, y)’

             * SQLite - uses SQLite’s ‘REGEXP’ placeholder operator and
               calls into the Python ‘re.match()’ builtin.

             * other backends may provide special implementations.

             * Backends without any special implementation will emit the
               operator as “REGEXP” or “NOT REGEXP”.  This is compatible
               with SQLite and MySQL, for example.

          Regular expression support is currently implemented for
          Oracle, PostgreSQL, MySQL and MariaDB. Partial support is
          available for SQLite.  Support among third-party dialects may
          vary.

          Parameters:

             * ‘pattern’ – The regular expression pattern string or
               column clause.

             * ‘flags’ – Any regular expression string flags to apply.
               Flags tend to be backend specific.  It can be a string or
               a column clause.  Some backends, like PostgreSQL and
               MariaDB, may alternatively specify the flags as part of
               the pattern.  When using the ignore case flag ‘i’ in
               PostgreSQL, the ignore case regexp match operator ‘~*’ or
               ‘!~*’ will be used.

          New in version 1.4.

          See also
          ........

          See ColumnOperators.regexp_replace().

      -- Method: sqlalchemy.orm.QueryableAttribute..
               regexp_replace (pattern, replacement, flags=None)

          `inherited from the' ColumnOperators.regexp_replace().
          `method of' ColumnOperators.

          Implements a database-specific ‘regexp replace’ operator.

          E.g.:

               stmt = select(
                   table.c.some_column.regexp_replace(
                       'b(..)',
                       'X^AY',
                       flags='g'
                   )
               )

          ColumnOperators.regexp_replace() attempts to
          resolve to a REGEXP_REPLACE-like function provided by the
          backend, that usually emit the function ‘REGEXP_REPLACE()’.
          However, the specific regular expression syntax and flags
          available are `not backend agnostic'.

          Regular expression replacement support is currently
          implemented for Oracle, PostgreSQL, MySQL 8 or greater and
          MariaDB. Support among third-party dialects may vary.

          Parameters:

             * ‘pattern’ – The regular expression pattern string or
               column clause.

             * ‘pattern’ – The replacement string or column clause.

             * ‘flags’ – Any regular expression string flags to apply.
               Flags tend to be backend specific.  It can be a string or
               a column clause.  Some backends, like PostgreSQL and
               MariaDB, may alternatively specify the flags as part of
               the pattern.

          New in version 1.4.

          See also
          ........

          See ColumnOperators.regexp_match().

      -- Method: sqlalchemy.orm.QueryableAttribute..
               reverse_operate (op, other, **kwargs)

          Reverse operate on an argument.

          Usage is the same as operate().

      -- Method: sqlalchemy.orm.QueryableAttribute..
               startswith (other, **kwargs)

          `inherited from the' ColumnOperators.startswith().
          `method of' ColumnOperators.

          Implement the ‘startswith’ operator.

          Produces a LIKE expression that tests against a match for the
          start of a string value:

               column LIKE <other> || '%'

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.startswith("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.startswith.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.startswith.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.startswith.autoescape flag is set
               to True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.startswith("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE :param || '%' ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.startswith("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE :param || '%' ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.startswith.autoescape:

                    somecolumn.startswith("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.endswith().

          See ColumnOperators.contains().

          See ColumnOperators.like().

 -- Class: sqlalchemy.orm.UOWTransaction (session)

      -- Method: sqlalchemy.orm.UOWTransaction..
               filter_states_for_dep (dep, states)

          Filter the given list of InstanceStates to those relevant to
          the given DependencyProcessor.

      -- Method: sqlalchemy.orm.UOWTransaction..
               finalize_flush_changes ()

          Mark processed objects as clean / deleted after a successful
          flush().

          This method is called within the flush() method after the
          execute() method has succeeded and the transaction has been
          committed.

      -- Method: sqlalchemy.orm.UOWTransaction..
               get_attribute_history (state, key,
               passive=symbol('PASSIVE_NO_INITIALIZE'))

          Facade to attributes.get_state_history(), including caching of
          results.

      -- Method: sqlalchemy.orm.UOWTransaction..is_deleted
               (state)

          Return ‘True’ if the given state is marked as deleted within
          this uowtransaction.

      -- Method: sqlalchemy.orm.UOWTransaction..
               remove_state_actions (state)

          Remove pending actions for a state from the uowtransaction.

      -- Method: sqlalchemy.orm.UOWTransaction..
               was_already_deleted (state)

          Return ‘True’ if the given state is expired and was deleted
          previously.

   ---------- Footnotes ----------

   (1) https://pypi.org/project/sqlalchemy2-stubs

   (2) https://www.python.org/dev/peps/pep-0484

3.6.3 ORM Exceptions
--------------------

SQLAlchemy ORM exceptions.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See ConcurrentModificationError.alias of sqlalchemy.orm.exc.StaleDataError.

See NO_STATE.Exception types that may be raised by instrumentation implementations.

 -- Attribute: sqlalchemy.orm.exc...
          sqlalchemy.orm.exc.ConcurrentModificationError

     alias of sqlalchemy.orm.exc.StaleDataError.

 -- Exception: sqlalchemy.orm.exc.DetachedInstanceError (*arg, **kw)

     An attempt to access unloaded attributes on a mapped instance that
     is detached.

 -- Exception: sqlalchemy.orm.exc.FlushError (*arg, **kw)

     A invalid condition was detected during flush().

 -- Exception: sqlalchemy.orm.exc.LoaderStrategyException
          (applied_to_property_type, requesting_property, applies_to,
          actual_strategy_type, strategy_key)

     A loader strategy for an attribute does not exist.

 -- Data: sqlalchemy.orm.exc.NO_STATE = (<class 'AttributeError'>,
          <class 'KeyError'>)

     Exception types that may be raised by instrumentation
     implementations.

 -- Exception: sqlalchemy.orm.exc.ObjectDeletedError (state, msg=None)

     A refresh operation failed to retrieve the database row
     corresponding to an object’s known primary key identity.

     A refresh operation proceeds when an expired attribute is accessed
     on an object, or when Query.get() is used to retrieve
     an object which is, upon retrieval, detected as expired.  A SELECT
     is emitted for the target row based on primary key; if no row is
     returned, this exception is raised.

     The true meaning of this exception is simply that no row exists for
     the primary key identifier associated with a persistent object.
     The row may have been deleted, or in some cases the primary key
     updated to a new value, outside of the ORM’s management of the
     target object.

 -- Exception: sqlalchemy.orm.exc.ObjectDereferencedError (*arg, **kw)

     An operation cannot complete due to an object being garbage
     collected.

 -- Exception: sqlalchemy.orm.exc.StaleDataError (*arg, **kw)

     An operation encountered database state that is unaccounted for.

     Conditions which cause this to happen include:

        * A flush may have attempted to update or delete rows and an
          unexpected number of rows were matched during the UPDATE or
          DELETE statement.  Note that when version_id_col is used, rows
          in UPDATE or DELETE statements are also matched against the
          current known version identifier.

        * A mapped object with version_id_col was refreshed, and the
          version number coming back from the database does not match
          that of the object itself.

        * A object is detached from its parent object, however the
          object was previously attached to a different parent identity
          which was garbage collected, and a decision cannot be made if
          the new parent was really the most recent “parent”.

 -- Exception: sqlalchemy.orm.exc.UnmappedClassError (cls, msg=None)

     An mapping operation was requested for an unknown class.

 -- Exception: sqlalchemy.orm.exc.UnmappedColumnError (*arg, **kw)

     Mapping operation was requested on an unknown column.

 -- Exception: sqlalchemy.orm.exc.UnmappedError (*arg, **kw)

     Base for exceptions that involve expected mappings not present.

 -- Exception: sqlalchemy.orm.exc.UnmappedInstanceError (obj, msg=None)

     An mapping operation was requested for an unknown instance.

3.7 ORM Extensions
==================

SQLAlchemy has a variety of ORM extensions available, which add
additional functionality to the core behavior.

The extensions build almost entirely on public core and ORM APIs and
users should be encouraged to read their source code to further their
understanding of their behavior.  In particular the “Horizontal
Sharding”, “Hybrid Attributes”, and “Mutation Tracking” extensions are
very succinct.

3.7.1 Asynchronous I/O (asyncio)
--------------------------------

Support for Python asyncio.  Support for Core and ORM usage is included,
using asyncio-compatible dialects.

New in version 1.4.

The asyncio extension requires at least Python version 3.6.

     Note: The asyncio should be regarded as `alpha level' for the 1.4
     release of SQLAlchemy.  API details are `subject to change' at any
     time.

See also
........

See Asynchronous IO Support for Core and ORM. - initial feature
announcement

See Asyncio Integration. - example scripts illustrating working
examples of Core and ORM use within the asyncio extension.

3.7.1.1 Synopsis - Core
.......................

For Core use, the create_async_engine() function creates an
instance of AsyncEngine which then offers an async version
of the traditional Engine. API. The AsyncEngine
delivers an AsyncConnection via its
AsyncEngine.connect() and AsyncEngine.begin() methods
which both deliver asynchronous context managers.  The
AsyncConnection can then invoke statements using either the
AsyncConnection.execute() method to deliver a buffered
Result, or the AsyncConnection.stream() method to
deliver a streaming server-side AsyncResult:

     import asyncio

     from sqlalchemy.ext.asyncio import create_async_engine

     async def async_main():
         engine = create_async_engine(
             "postgresql+asyncpg://scott:tiger@localhost/test", echo=True,
         )

         async with engine.begin() as conn:
             await conn.run_sync(meta.drop_all)
             await conn.run_sync(meta.create_all)

             await conn.execute(
                 t1.insert(), [{"name": "some name 1"}, {"name": "some name 2"}]
             )

         async with engine.connect() as conn:

             # select a Result, which will be delivered with buffered
             # results
             result = await conn.execute(select(t1).where(t1.c.name == "some name 1"))

             print(result.fetchall())

     asyncio.run(async_main())

Above, the AsyncConnection.run_sync() method may be used to
invoke special DDL functions such as MetaData.create_all()
that don’t include an awaitable hook.

The AsyncConnection also features a “streaming” API via the
AsyncConnection.stream() method that returns an
AsyncResult object.  This result object uses a server-side cursor
and provides an async/await API, such as an async iterator:

     async with engine.connect() as conn:
         async_result = await conn.stream(select(t1))

         async for row in async_result:
             print("row: %s" % (row, ))

3.7.1.2 Synopsis - ORM
......................

Using 2.0 style querying, the AsyncSession class provides
full ORM functionality.  Within the default mode of use, special care
must be taken to avoid lazy loading or other expired-attribute access
involving ORM relationships and column attributes; the next section
Preventing Implicit IO when Using AsyncSession details this.
The example below illustrates a complete example including mapper and
session configuration:

     import asyncio

     from sqlalchemy import Column
     from sqlalchemy import DateTime
     from sqlalchemy import ForeignKey
     from sqlalchemy import func
     from sqlalchemy import Integer
     from sqlalchemy import String
     from sqlalchemy.ext.asyncio import AsyncSession
     from sqlalchemy.ext.asyncio import create_async_engine
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.future import select
     from sqlalchemy.orm import relationship
     from sqlalchemy.orm import selectinload
     from sqlalchemy.orm import sessionmaker

     Base = declarative_base()

     class A(Base):
         __tablename__ = "a"

         id = Column(Integer, primary_key=True)
         data = Column(String)
         create_date = Column(DateTime, server_default=func.now())
         bs = relationship("B")

         # required in order to access columns with server defaults
         # or SQL expression defaults, subsequent to a flush, without
         # triggering an expired load
         __mapper_args__ = {"eager_defaults": True}

     class B(Base):
         __tablename__ = "b"
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey("a.id"))
         data = Column(String)

     async def async_main():
         engine = create_async_engine(
             "postgresql+asyncpg://scott:tiger@localhost/test",
             echo=True,
         )

         async with engine.begin() as conn:
             await conn.run_sync(Base.metadata.drop_all)
             await conn.run_sync(Base.metadata.create_all)

         # expire_on_commit=False will prevent attributes from being expired
         # after commit.
         async_session = sessionmaker(
             engine, expire_on_commit=False, class_=AsyncSession
         )

         async with async_session() as session:
             async with session.begin():
                 session.add_all(
                     [
                         A(bs=[B(), B()], data="a1"),
                         A(bs=[B()], data="a2"),
                         A(bs=[B(), B()], data="a3"),
                     ]
                 )

             stmt = select(A).options(selectinload(A.bs))

             result = await session.execute(stmt)

             for a1 in result.scalars():
                 print(a1)
                 print(f"created at: {a1.create_date}")
                 for b1 in a1.bs:
                     print(b1)

             result = await session.execute(select(A).order_by(A.id))

             a1 = result.scalars().first()

             a1.data = "new data"

             await session.commit()

             # access attribute subsequent to commit; this is what
             # expire_on_commit=False allows
             print(a1.data)

     asyncio.run(async_main())

In the example above, the AsyncSession is instantiated using
the optional sessionmaker helper, and associated with an
AsyncEngine against particular database URL. It is then used
in a Python asynchronous context manager (i.e.  ‘async with:’ statement)
so that it is automatically closed at the end of the block; this is
equivalent to calling the AsyncSession.close() method.

3.7.1.3 Preventing Implicit IO when Using AsyncSession
......................................................

Using traditional asyncio, the application needs to avoid any points at
which IO-on-attribute access may occur.  Above, the following measures
are taken to prevent this:

   * The selectinload() eager loader is employed in order to
     eagerly load the ‘A.bs’ collection within the scope of the ‘await
     session.execute()’ call:

          stmt = select(A).options(selectinload(A.bs))

     If the default loader strategy of “lazyload” were left in place,
     the access of the ‘A.bs’ attribute would raise an asyncio
     exception.  There are a variety of ORM loader options available,
     which may be configured at the default mapping level or used on a
     per-query basis, documented at Relationship Loading Techniques.

   * The AsyncSession is configured using
     Session.expire_on_commit set to False, so that we may access
     attributes on an object subsequent to a call to
     AsyncSession.commit(), as in the line at the end where we
     access an attribute:

          # create AsyncSession with expire_on_commit=False
          async_session = AsyncSession(engine, expire_on_commit=False)

          # sessionmaker version
          async_session = sessionmaker(
              engine, expire_on_commit=False, class_=AsyncSession
          )

          async with async_session() as session:

              result = await session.execute(select(A).order_by(A.id))

              a1 = result.scalars().first()

              # commit would normally expire all attributes
              await session.commit()

              # access attribute subsequent to commit; this is what
              # expire_on_commit=False allows
              print(a1.data)

   * The Column.server_default value on the ‘created_at’
     column will not be refreshed by default after an INSERT; instead,
     it is normally expired so that it can be loaded when needed.
     Similar behavior applies to a column where the
     Column.default parameter is assigned to a SQL expression
     object.  To access this value with asyncio, it has to be refreshed
     within the flush process, which is achieved by setting the
     mapper.eager_defaults parameter on the mapping:

          class A(Base):
              # ...

              # column with a server_default, or SQL expression default
              create_date = Column(DateTime, server_default=func.now())

              # add this so that it can be accessed
              __mapper_args__ = {"eager_defaults": True}

Other guidelines include:

   * Methods like AsyncSession.expire() should be avoided in
     favor of AsyncSession.refresh().

   * Appropriate loader options should be employed for deferred()
     columns, if used at all, in addition to that of
     relationship() constructs as noted above.  See Deferred Column Loading
     for background on deferred column loading.

   * The “dynamic” relationship loader strategy described at
     Dynamic Relationship Loaders is not compatible with the
     asyncio approach and cannot be used, unless invoked within the
     AsyncSession.run_sync() method described at
     Running Synchronous Methods and Functions under asyncio.

3.7.1.4 Running Synchronous Methods and Functions under asyncio
...............................................................

     deepalchemy: This approach is essentially exposing publicly the
     mechanism by which SQLAlchemy is able to provide the asyncio
     interface in the first place.  While there is no technical issue
     with doing so, overall the approach can probably be considered
     “controversial” as it works against some of the central
     philosophies of the asyncio programming model, which is essentially
     that any programming statement that can potentially result in IO
     being invoked `must' have an ‘await’ call, lest the program does
     not make it explicitly clear every line at which IO may occur.
     This approach does not change that general idea, except that it
     allows a series of synchronous IO instructions to be exempted from
     this rule within the scope of a function call, essentially bundled
     up into a single awaitable.

As an alternative means of integrating traditional SQLAlchemy “lazy
loading” within an asyncio event loop, an `optional' method known as
AsyncSession.run_sync() is provided which will run any
Python function inside of a greenlet, where traditional synchronous
programming concepts will be translated to use ‘await’ when they reach
the database driver.  A hypothetical approach here is an
asyncio-oriented application can package up database-related methods
into functions that are invoked using AsyncSession.run_sync().

Altering the above example, if we didn’t use selectinload()
for the ‘A.bs’ collection, we could accomplish our treatment of these
attribute accesses within a separate function:

     import asyncio

     from sqlalchemy.ext.asyncio import create_async_engine
     from sqlalchemy.ext.asyncio import AsyncSession

     def fetch_and_update_objects(session):
         """run traditional sync-style ORM code in a function that will be
         invoked within an awaitable.

         """

         # the session object here is a traditional ORM Session.
         # all features are available here including legacy Query use.

         stmt = select(A)

         result = session.execute(stmt)
         for a1 in result.scalars():
             print(a1)

             # lazy loads
             for b1 in a1.bs:
                 print(b1)

         # legacy Query use
         a1 = session.query(A).order_by(A.id).first()

         a1.data = "new data"

     async def async_main():
         engine = create_async_engine(
             "postgresql+asyncpg://scott:tiger@localhost/test", echo=True,
         )
         async with engine.begin() as conn:
             await conn.run_sync(Base.metadata.drop_all)
             await conn.run_sync(Base.metadata.create_all)

         async with AsyncSession(engine) as session:
             async with session.begin():
                 session.add_all(
                     [
                         A(bs=[B(), B()], data="a1"),
                         A(bs=[B()], data="a2"),
                         A(bs=[B(), B()], data="a3"),
                     ]
                 )

             await session.run_sync(fetch_and_update_objects)

             await session.commit()

     asyncio.run(async_main())

The above approach of running certain functions within a “sync” runner
has some parallels to an application that runs a SQLAlchemy application
on top of an event-based programming library such as ‘gevent’.  The
differences are as follows:

  1. unlike when using ‘gevent’, we can continue to use the standard
     Python asyncio event loop, or any custom event loop, without the
     need to integrate into the ‘gevent’ event loop.

  2. There is no “monkeypatching” whatsoever.  The above example makes
     use of a real asyncio driver and the underlying SQLAlchemy
     connection pool is also using the Python built-in ‘asyncio.Queue’
     for pooling connections.

  3. The program can freely switch between async/await code and
     contained functions that use sync code with virtually no
     performance penalty.  There is no “thread executor” or any
     additional waiters or synchronization in use.

  4. The underlying network drivers are also using pure Python asyncio
     concepts, no third party networking libraries as ‘gevent’ and
     ‘eventlet’ provides are in use.

3.7.1.5 Using multiple asyncio event loops
..........................................

An application that makes use of multiple event loops, for example by
combining asyncio with multithreading, should not share the same
AsyncEngine with different event loops when using the default pool
implementation.

If an AsyncEngine is be passed from one event loop to
another, the method AsyncEngine.dispose() should be called
before it’s re-used on a new event loop.  Failing to do so may lead to a
‘RuntimeError’ along the lines of ‘Task <Task pending ...> got Future
attached to a different loop’

If the same engine must be shared between different loop, it should be
configured to disable pooling using NullPool, preventing the
Engine from using any connection more than once:

     from sqlalchemy.pool import NullPool
     engine = create_async_engine(
         "postgresql+asyncpg://user:pass@host/dbname", poolclass=NullPool
     )

3.7.1.6 Engine API Documentation
................................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See AsyncConnection.An asyncio proxy for a Connection.

See AsyncEngine.An asyncio proxy for a Engine.

See AsyncTransaction.An asyncio proxy for a Transaction.

See create_async_engine.(*arg,Create a new async engine instance.
**kw)

 -- Function: sqlalchemy.ext.asyncio.create_async_engine (*arg, **kw)

     Create a new async engine instance.

     Arguments passed to create_async_engine() are mostly
     identical to those passed to the create_engine()
     function.  The specified dialect must be an asyncio-compatible
     dialect such as asyncpg.

     New in version 1.4.

 -- Class: sqlalchemy.ext.asyncio.AsyncEngine (sync_engine:
          sqlalchemy.future.engine.Engine)

     An asyncio proxy for a Engine.

     AsyncEngine is acquired using the
     create_async_engine() function:

          from sqlalchemy.ext.asyncio import create_async_engine
          engine = create_async_engine("postgresql+asyncpg://user:pass@host/dbname")

     New in version 1.4.

     `Class signature'

     class sqlalchemy.ext.asyncio.AsyncEngine.
     (‘sqlalchemy.ext.asyncio.base.ProxyComparable’,
     ‘sqlalchemy.ext.asyncio.AsyncConnectable’)

      -- Method: sqlalchemy.ext.asyncio.AsyncEngine..begin ()

          Return a context manager which when entered will deliver an
          AsyncConnection with an AsyncTransaction
          established.

          E.g.:

               async with async_engine.begin() as conn:
                   await conn.execute(
                       text("insert into table (x, y, z) values (1, 2, 3)")
                   )
                   await conn.execute(text("my_special_procedure(5)"))

      -- Method: sqlalchemy.ext.asyncio.AsyncEngine..
               clear_compiled_cache ()

          Clear the compiled cache associated with the dialect.

          Proxied for the Engine class on behalf of the
          AsyncEngine class.

          This applies `only' to the built-in cache that is established
          via the ‘create_engine.query_cache_size’ parameter.  It will
          not impact any dictionary caches that were passed via the
          Connection.execution_options.query_cache
          parameter.

          New in version 1.4.

      -- Method: sqlalchemy.ext.asyncio.AsyncEngine..connect
               () -> sqlalchemy.ext.asyncio.AsyncConnection

          Return an AsyncConnection object.

          The AsyncConnection will procure a database
          connection from the underlying connection pool when it is
          entered as an async context manager:

               async with async_engine.connect() as conn:
                   result = await conn.execute(select(user_table))

          The AsyncConnection may also be started outside of
          a context manager by invoking its
          AsyncConnection.start() method.

      -- Method: async sqlalchemy.ext.asyncio.AsyncEngine..
               dispose ()

          Dispose of the connection pool used by this AsyncEngine.

          This will close all connection pool connections that are
          `currently checked in'.  See the documentation for the
          underlying ‘Engine.dispose()’ method for further notes.

          See also
          ........

          ‘Engine.dispose()’

      -- Method: sqlalchemy.ext.asyncio.AsyncEngine..
               execution_options (**opt)

          Return a new AsyncEngine that will provide
          AsyncConnection objects with the given execution
          options.

          Proxied from ‘Engine.execution_options()’.  See that method
          for details.

      -- Method: sqlalchemy.ext.asyncio.AsyncEngine..
               get_execution_options ()

          Get the non-SQL options which will take effect during
          execution.

          Proxied for the Engine class on behalf of the
          AsyncEngine class.

          See also
          ........

          See Engine.execution_options().

      -- Method: async sqlalchemy.ext.asyncio.AsyncEngine..
               raw_connection () -> Any

          Return a “raw” DBAPI connection from the connection pool.

          See also
          ........

          See Working with Driver SQL and Raw DBAPI Connections.

      -- Method: sqlalchemy.ext.asyncio.AsyncEngine..
               update_execution_options (**opt)

          Update the default execution_options dictionary of this
          Engine.

          Proxied for the Engine class on behalf of the
          AsyncEngine class.

          The given keys/values in **opt are added to the default
          execution options that will be used for all connections.  The
          initial contents of this dictionary can be sent via the
          ‘execution_options’ parameter to create_engine().

          See also
          ........

          See Connection.execution_options().

          See Engine.execution_options().

 -- Class: sqlalchemy.ext.asyncio.AsyncConnection (async_engine:
          sqlalchemy.ext.asyncio.engine.AsyncEngine, sync_connection:
          Optional[sqlalchemy.future.engine.Connection] = None)

     An asyncio proxy for a Connection.

     AsyncConnection is acquired using the
     AsyncEngine.connect() method of AsyncEngine:

          from sqlalchemy.ext.asyncio import create_async_engine
          engine = create_async_engine("postgresql+asyncpg://user:pass@host/dbname")

          async with engine.connect() as conn:
              result = await conn.execute(select(table))

     New in version 1.4.

     `Class signature'

     class sqlalchemy.ext.asyncio.AsyncConnection.
     (‘sqlalchemy.ext.asyncio.base.ProxyComparable’,
     ‘sqlalchemy.ext.asyncio.base.StartableContext’,
     ‘sqlalchemy.ext.asyncio.AsyncConnectable’)

      -- Method: sqlalchemy.ext.asyncio.AsyncConnection..
               begin () -> sqlalchemy.ext.asyncio.AsyncTransaction

          Begin a transaction prior to autobegin occurring.

      -- Method: sqlalchemy.ext.asyncio.AsyncConnection..
               begin_nested () ->
               sqlalchemy.ext.asyncio.AsyncTransaction

          Begin a nested transaction and return a transaction handle.

      -- Method: async sqlalchemy.ext.asyncio.AsyncConnection..
               close ()

          Close this AsyncConnection.

          This has the effect of also rolling back the transaction if
          one is in place.

      -- Method: async sqlalchemy.ext.asyncio.AsyncConnection..
               commit ()

          Commit the transaction that is currently in progress.

          This method commits the current transaction if one has been
          started.  If no transaction was started, the method has no
          effect, assuming the connection is in a non-invalidated state.

          A transaction is begun on a Connection
          automatically whenever a statement is first executed, or when
          the Connection.begin() method is called.

      -- Attribute: sqlalchemy.ext.asyncio.AsyncConnection..
               connection

          Not implemented for async; call
          AsyncConnection.get_raw_connection().

      -- Method: async sqlalchemy.ext.asyncio.AsyncConnection..
               exec_driver_sql (statement:
               sqlalchemy.sql.base.Executable, parameters:
               Optional[Mapping] = None, execution_options: Mapping =
               {}) -> sqlalchemy.engine.Result

          Executes a driver-level SQL string and return buffered
          Result.

      -- Method: async sqlalchemy.ext.asyncio.AsyncConnection..
               execute (statement: sqlalchemy.sql.base.Executable,
               parameters: Optional[Mapping] = None, execution_options:
               Mapping = {}) -> sqlalchemy.engine.Result

          Executes a SQL statement construct and return a buffered
          Result.

          Parameters:

             * ‘object’ – The statement to be executed.  This is always
               an object that is in both the ClauseElement
               and Executable hierarchies, including:

                  * Select.

                  * Insert, Update, Delete.

                  * TextClause and TextualSelect.

                  * DDL and objects which inherit from
                    DDLElement.

             * ‘parameters’ – parameters which will be bound into the
               statement.  This may be either a dictionary of parameter
               names to values, or a mutable sequence (e.g.  a list) of
               dictionaries.  When a list of dictionaries is passed, the
               underlying statement execution will make use of the DBAPI
               ‘cursor.executemany()’ method.  When a single dictionary
               is passed, the DBAPI ‘cursor.execute()’ method will be
               used.

             * ‘execution_options’ – optional dictionary of execution
               options, which will be associated with the statement
               execution.  This dictionary can provide a subset of the
               options that are accepted by
               ‘Connection.execution_options()’.

          Returns: a Result object.

      -- Method: async sqlalchemy.ext.asyncio.AsyncConnection..
               execution_options (**opt)

          Set non-SQL options for the connection which take effect
          during execution.

          This returns this AsyncConnection object with the
          new options added.

          See ‘Connection.execution_options()’ for full details on this
          method.

      -- Method: sqlalchemy.ext.asyncio.AsyncConnection..
               get_nested_transaction ()

          Return an AsyncTransaction representing the
          current nested (savepoint) transaction, if any.

          This makes use of the underlying synchronous connection’s
          Connection.get_nested_transaction() method to get
          the current Transaction, which is then proxied in a
          new AsyncTransaction object.

          New in version 1.4.0b2.

      -- Method: async sqlalchemy.ext.asyncio.AsyncConnection..
               get_raw_connection ()

          Return the pooled DBAPI-level connection in use by this
          AsyncConnection.

          This is typically the SQLAlchemy connection-pool proxied
          connection which then has an attribute .connection that refers
          to the actual DBAPI-level connection.

      -- Method: sqlalchemy.ext.asyncio.AsyncConnection..
               get_transaction ()

          Return an AsyncTransaction representing the
          current transaction, if any.

          This makes use of the underlying synchronous connection’s
          Connection.get_transaction() method to get the
          current Transaction, which is then proxied in a new
          AsyncTransaction object.

          New in version 1.4.0b2.

      -- Method: sqlalchemy.ext.asyncio.AsyncConnection..
               in_nested_transaction ()

          Return True if a transaction is in progress.

          New in version 1.4.0b2.

      -- Method: sqlalchemy.ext.asyncio.AsyncConnection..
               in_transaction ()

          Return True if a transaction is in progress.

          New in version 1.4.0b2.

      -- Attribute: sqlalchemy.ext.asyncio.AsyncConnection..
               info

          Return the Connection.info dictionary of the
          underlying Connection.

          This dictionary is freely writable for user-defined state to
          be associated with the database connection.

          This attribute is only available if the AsyncConnection
          is currently connected.  If the ‘AsyncConnection.closed’
          attribute is ‘True’, then accessing this attribute will raise
          ResourceClosedError.

          New in version 1.4.0b2.

      -- Method: async sqlalchemy.ext.asyncio.AsyncConnection..
               invalidate (exception=None)

          Invalidate the underlying DBAPI connection associated with
          this Connection.

          See the method Connection.invalidate() for full
          detail on this method.

      -- Method: async sqlalchemy.ext.asyncio.AsyncConnection..
               rollback ()

          Roll back the transaction that is currently in progress.

          This method rolls back the current transaction if one has been
          started.  If no transaction was started, the method has no
          effect.  If a transaction was started and the connection is in
          an invalidated state, the transaction is cleared using this
          method.

          A transaction is begun on a Connection
          automatically whenever a statement is first executed, or when
          the Connection.begin() method is called.

      -- Method: async sqlalchemy.ext.asyncio.AsyncConnection..
               run_sync (fn: Callable, *arg, **kw) -> Any

          Invoke the given sync callable passing self as the first
          argument.

          This method maintains the asyncio event loop all the way
          through to the database connection by running the given
          callable in a specially instrumented greenlet.

          E.g.:

               with async_engine.begin() as conn:
                   await conn.run_sync(metadata.create_all)

               Note: The provided callable is invoked inline within the
               asyncio event loop, and will block on traditional IO
               calls.  IO within this callable should only call into
               SQLAlchemy’s asyncio database APIs which will be properly
               adapted to the greenlet context.

          See also
          ........

          See Running Synchronous Methods and Functions under asyncio.

      -- Method: async sqlalchemy.ext.asyncio.AsyncConnection..
               scalar (statement: sqlalchemy.sql.base.Executable,
               parameters: Optional[Mapping] = None, execution_options:
               Mapping = {}) -> Any

          Executes a SQL statement construct and returns a scalar
          object.

          This method is shorthand for invoking the
          Result.scalar() method after invoking the
          Connection.execute() method.  Parameters are equivalent.

          Returns: a scalar Python value representing the first column
          of the first row returned.

      -- Method: async sqlalchemy.ext.asyncio.AsyncConnection..
               start ()

          Start this AsyncConnection object’s context
          outside of using a Python ‘with:’ block.

      -- Method: async sqlalchemy.ext.asyncio.AsyncConnection..
               stream (statement: sqlalchemy.sql.base.Executable,
               parameters: Optional[Mapping] = None, execution_options:
               Mapping = {}) -> sqlalchemy.ext.asyncio.AsyncResult

          Execute a statement and return a streaming AsyncResult
          object.

 -- Class: sqlalchemy.ext.asyncio.AsyncTransaction (connection:
          sqlalchemy.ext.asyncio.engine.AsyncConnection, nested: bool =
          False)

     An asyncio proxy for a Transaction.

     `Class signature'

     class sqlalchemy.ext.asyncio.AsyncTransaction.
     (‘sqlalchemy.ext.asyncio.base.ProxyComparable’,
     ‘sqlalchemy.ext.asyncio.base.StartableContext’)

      -- Method: async sqlalchemy.ext.asyncio.AsyncTransaction..
               close ()

          Close this Transaction.

          If this transaction is the base transaction in a begin/commit
          nesting, the transaction will rollback().  Otherwise, the
          method returns.

          This is used to cancel a Transaction without affecting the
          scope of an enclosing transaction.

      -- Method: async sqlalchemy.ext.asyncio.AsyncTransaction..
               commit ()

          Commit this Transaction.

      -- Method: async sqlalchemy.ext.asyncio.AsyncTransaction..
               rollback ()

          Roll back this Transaction.

      -- Method: async sqlalchemy.ext.asyncio.AsyncTransaction..
               start ()

          Start this AsyncTransaction object’s context
          outside of using a Python ‘with:’ block.

3.7.1.7 Result Set API Documentation
....................................

The AsyncResult object is an async-adapted version of the
Result object.  It is only returned when using the
AsyncConnection.stream() or AsyncSession.stream()
methods, which return a result object that is on top of an active
database cursor.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See AsyncMappingResult.A wrapper for a AsyncResult that returns dictionary values rather than
               Row values.

See AsyncResult.An asyncio wrapper around a Result object.

See AsyncScalarResult.A wrapper for a AsyncResult that returns scalar values rather than
               Row values.

 -- Class: sqlalchemy.ext.asyncio.AsyncResult (real_result)

     An asyncio wrapper around a Result object.

     The AsyncResult only applies to statement executions
     that use a server-side cursor.  It is returned only from the
     AsyncConnection.stream() and AsyncSession.stream()
     methods.

     New in version 1.4.

     `Class signature'

     class sqlalchemy.ext.asyncio.AsyncResult.
     (‘sqlalchemy.ext.asyncio.AsyncCommon’)

      -- Method: async sqlalchemy.ext.asyncio.AsyncResult..
               all () -> List[Row]

          Return all rows in a list.

          Closes the result set after invocation.  Subsequent
          invocations will return an empty list.

          Returns: a list of Row objects.

      -- Method: sqlalchemy.ext.asyncio.AsyncResult..columns
               (*col_expressions: object) ->
               sqlalchemy.ext.asyncio.AsyncResult

          Establish the columns that should be returned in each row.

          Refer to Result.columns() in the synchronous
          SQLAlchemy API for a complete behavioral description.

      -- Method: async sqlalchemy.ext.asyncio.AsyncResult..
               fetchmany (size: Optional[Int] = None) -> List[Row]

          Fetch many rows.

          When all rows are exhausted, returns an empty list.

          This method is provided for backwards compatibility with
          SQLAlchemy 1.x.x.

          To fetch rows in groups, use the
          AsyncResult.partitions() method.

          Returns: a list of Row objects.

          See also
          ........

          See AsyncResult.partitions().

      -- Method: async sqlalchemy.ext.asyncio.AsyncResult..
               fetchone () -> Row

          Fetch one row.

          When all rows are exhausted, returns None.

          This method is provided for backwards compatibility with
          SQLAlchemy 1.x.x.

          To fetch the first row of a result only, use the
          Result.first() method.  To iterate through all rows,
          iterate the Result object directly.

          Returns: a Row object if no filters are applied, or
          None if no rows remain.

      -- Method: async sqlalchemy.ext.asyncio.AsyncResult..
               first () -> Row

          Fetch the first row or None if no row is present.

          Closes the result set and discards remaining rows.

               Note: This method returns one `row', e.g.  tuple, by
               default.  To return exactly one single scalar value, that
               is, the first column of the first row, use the
               AsyncResult.scalar() method, or combine
               AsyncResult.scalars() and
               AsyncResult.first().

          Returns: a Row object, or None if no rows remain.

          See also
          ........

          See AsyncResult.scalar().

          See AsyncResult.one().

      -- Method: async sqlalchemy.ext.asyncio.AsyncResult..
               freeze ()

          Return a callable object that will produce copies of this
          AsyncResult when invoked.

          The callable object returned is an instance of
          FrozenResult.

          This is used for result set caching.  The method must be
          called on the result when it has been unconsumed, and calling
          the method will consume the result fully.  When the
          FrozenResult is retrieved from a cache, it can be called
          any number of times where it will produce a new Result
          object each time against its stored set of rows.

          See also
          ........

          See Re-Executing Statements. - example usage within the
          ORM to implement a result-set cache.

      -- Method: sqlalchemy.ext.asyncio.AsyncResult..keys ()

          Return the Result.keys() collection from the
          underlying Result.

      -- Method: sqlalchemy.ext.asyncio.AsyncResult..mappings
               ()

          Apply a mappings filter to returned rows, returning an
          instance of AsyncMappingResult.

          When this filter is applied, fetching rows will return
          RowMapping objects instead of Row objects.

          Refer to Result.mappings() in the synchronous
          SQLAlchemy API for a complete behavioral description.

          Returns: a new AsyncMappingResult filtering object
          referring to the underlying Result object.

      -- Method: sqlalchemy.ext.asyncio.AsyncResult..merge
               (*others)

          Merge this AsyncResult with other compatible
          result objects.

          The object returned is an instance of MergedResult,
          which will be composed of iterators from the given result
          objects.

          The new result will use the metadata from this result object.
          The subsequent result objects must be against an identical set
          of result / cursor metadata, otherwise the behavior is
          undefined.

      -- Method: async sqlalchemy.ext.asyncio.AsyncResult..
               one () -> Row

          Return exactly one row or raise an exception.

          Raises NoResultFound if the result returns no
          rows, or MultipleResultsFound if multiple rows
          would be returned.

               Note: This method returns one `row', e.g.  tuple, by
               default.  To return exactly one single scalar value, that
               is, the first column of the first row, use the
               AsyncResult.scalar_one() method, or combine
               AsyncResult.scalars() and AsyncResult.one().

          New in version 1.4.

          Returns: The first Row.

          Raises: MultipleResultsFound, NoResultFound.

          See also
          ........

          See AsyncResult.first().

          See AsyncResult.one_or_none().

          See AsyncResult.scalar_one().

      -- Method: async sqlalchemy.ext.asyncio.AsyncResult..
               one_or_none () -> Optional[Row]

          Return at most one result or raise an exception.

          Returns ‘None’ if the result has no rows.  Raises
          MultipleResultsFound if multiple rows are returned.

          New in version 1.4.

          Returns: The first Row or None if no row is
          available.

          Raises: MultipleResultsFound.

          See also
          ........

          See AsyncResult.first().

          See AsyncResult.one().

      -- Method: sqlalchemy.ext.asyncio.AsyncResult..
               partitions (size: Optional[Int] = None) ->
               Iterator[List[Any]]

          Iterate through sub-lists of rows of the size given.

          An async iterator is returned:

               async def scroll_results(connection):
                   result = await connection.stream(select(users_table))

                   async for partition in result.partitions(100):
                       print("list of rows: %s" % partition)

          See also
          ........

          See Result.partitions().

      -- Method: async sqlalchemy.ext.asyncio.AsyncResult..
               scalar () -> Optional[Any]

          Fetch the first column of the first row, and close the result
          set.

          Returns None if there are no rows to fetch.

          No validation is performed to test if additional rows remain.

          After calling this method, the object is fully closed, e.g.
          the CursorResult.close() method will have been
          called.

          Returns: a Python scalar value , or None if no rows remain.

      -- Method: async sqlalchemy.ext.asyncio.AsyncResult..
               scalar_one () -> Any

          Return exactly one scalar result or raise an exception.

          This is equivalent to calling AsyncResult.scalars()
          and then AsyncResult.one().

          See also
          ........

          See AsyncResult.one().

          See AsyncResult.scalars().

      -- Method: async sqlalchemy.ext.asyncio.AsyncResult..
               scalar_one_or_none () -> Optional[Any]

          Return exactly one or no scalar result.

          This is equivalent to calling AsyncResult.scalars()
          and then AsyncResult.one_or_none().

          See also
          ........

          See AsyncResult.one_or_none().

          See AsyncResult.scalars().

      -- Method: sqlalchemy.ext.asyncio.AsyncResult..scalars
               (index: Int = 0) -> AsyncScalarResult

          Return an AsyncScalarResult filtering object which
          will return single elements rather than Row
          objects.

          Refer to Result.scalars() in the synchronous
          SQLAlchemy API for a complete behavioral description.

          Parameters: ‘index’ – integer or row key indicating the column
          to be fetched from each row, defaults to ‘0’ indicating the
          first column.

          Returns: a new AsyncScalarResult filtering object
          referring to this AsyncResult object.

      -- Method: sqlalchemy.ext.asyncio.AsyncResult..unique
               (strategy=None)

          Apply unique filtering to the objects returned by this
          AsyncResult.

          Refer to Result.unique() in the synchronous
          SQLAlchemy API for a complete behavioral description.

 -- Class: sqlalchemy.ext.asyncio.AsyncScalarResult (real_result, index)

     A wrapper for a AsyncResult that returns scalar values
     rather than Row values.

     The AsyncScalarResult object is acquired by calling the
     AsyncResult.scalars() method.

     Refer to the ScalarResult object in the synchronous
     SQLAlchemy API for a complete behavioral description.

     New in version 1.4.

     `Class signature'

     class sqlalchemy.ext.asyncio.AsyncScalarResult.
     (‘sqlalchemy.ext.asyncio.AsyncCommon’)

      -- Method: async sqlalchemy.ext.asyncio.AsyncScalarResult..
               all () -> List[Any]

          Return all scalar values in a list.

          Equivalent to AsyncResult.all() except that scalar
          values, rather than Row objects, are returned.

      -- Method: async sqlalchemy.ext.asyncio.AsyncScalarResult..
               fetchall () -> List[Any]

          A synonym for the AsyncScalarResult.all() method.

      -- Method: async sqlalchemy.ext.asyncio.AsyncScalarResult..
               fetchmany (size: Optional[Int] = None) -> List[Any]

          Fetch many objects.

          Equivalent to AsyncResult.fetchmany() except that
          scalar values, rather than Row objects, are
          returned.

      -- Method: async sqlalchemy.ext.asyncio.AsyncScalarResult..
               first () -> Optional[Any]

          Fetch the first object or None if no object is present.

          Equivalent to AsyncResult.first() except that
          scalar values, rather than Row objects, are
          returned.

      -- Method: async sqlalchemy.ext.asyncio.AsyncScalarResult..
               one () -> Any

          Return exactly one object or raise an exception.

          Equivalent to AsyncResult.one() except that scalar
          values, rather than Row objects, are returned.

      -- Method: async sqlalchemy.ext.asyncio.AsyncScalarResult..
               one_or_none () -> Optional[Any]

          Return at most one object or raise an exception.

          Equivalent to AsyncResult.one_or_none() except
          that scalar values, rather than Row objects, are
          returned.

      -- Method: sqlalchemy.ext.asyncio.AsyncScalarResult..
               partitions (size: Optional[Int] = None) ->
               Iterator[List[Any]]

          Iterate through sub-lists of elements of the size given.

          Equivalent to AsyncResult.partitions() except that
          scalar values, rather than Row objects, are
          returned.

      -- Method: sqlalchemy.ext.asyncio.AsyncScalarResult..
               unique (strategy=None) ->
               sqlalchemy.ext.asyncio.AsyncScalarResult

          Apply unique filtering to the objects returned by this
          AsyncScalarResult.

          See AsyncResult.unique() for usage details.

 -- Class: sqlalchemy.ext.asyncio.AsyncMappingResult (result)

     A wrapper for a AsyncResult that returns dictionary
     values rather than Row values.

     The AsyncMappingResult object is acquired by calling
     the AsyncResult.mappings() method.

     Refer to the MappingResult object in the synchronous
     SQLAlchemy API for a complete behavioral description.

     New in version 1.4.

     `Class signature'

     class sqlalchemy.ext.asyncio.AsyncMappingResult.
     (‘sqlalchemy.ext.asyncio.AsyncCommon’)

      -- Method: async sqlalchemy.ext.asyncio.AsyncMappingResult..
               all () -> List[Mapping]

          Return all scalar values in a list.

          Equivalent to AsyncResult.all() except that
          mapping values, rather than Row objects, are
          returned.

      -- Method: sqlalchemy.ext.asyncio.AsyncMappingResult..
               columns (*col_expressions: object) ->
               sqlalchemy.ext.asyncio.AsyncMappingResult

          Establish the columns that should be returned in each row.

      -- Method: async sqlalchemy.ext.asyncio.AsyncMappingResult..
               fetchall () -> List[Mapping]

          A synonym for the AsyncMappingResult.all() method.

      -- Method: async sqlalchemy.ext.asyncio.AsyncMappingResult..
               fetchmany (size: Optional[Int] = None) ->
               List[Mapping]

          Fetch many objects.

          Equivalent to AsyncResult.fetchmany() except that
          mapping values, rather than Row objects, are
          returned.

      -- Method: async sqlalchemy.ext.asyncio.AsyncMappingResult..
               fetchone () -> Mapping

          Fetch one object.

          Equivalent to AsyncResult.fetchone() except that
          mapping values, rather than Row objects, are
          returned.

      -- Method: async sqlalchemy.ext.asyncio.AsyncMappingResult..
               first () -> Optional[Mapping]

          Fetch the first object or None if no object is present.

          Equivalent to AsyncResult.first() except that
          mapping values, rather than Row objects, are
          returned.

      -- Method: sqlalchemy.ext.asyncio.AsyncMappingResult..
               keys ()

          Return an iterable view which yields the string keys that
          would be represented by each Row.

          The view also can be tested for key containment using the
          Python ‘in’ operator, which will test both for the string keys
          represented in the view, as well as for alternate keys such as
          column objects.

          Changed in version 1.4: a key view object is returned rather
          than a plain list.

      -- Method: async sqlalchemy.ext.asyncio.AsyncMappingResult..
               one () -> Mapping

          Return exactly one object or raise an exception.

          Equivalent to AsyncResult.one() except that
          mapping values, rather than Row objects, are
          returned.

      -- Method: async sqlalchemy.ext.asyncio.AsyncMappingResult..
               one_or_none () -> Optional[Mapping]

          Return at most one object or raise an exception.

          Equivalent to AsyncResult.one_or_none() except
          that mapping values, rather than Row objects, are
          returned.

      -- Method: sqlalchemy.ext.asyncio.AsyncMappingResult..
               partitions (size: Optional[Int] = None) ->
               Iterator[List[Mapping]]

          Iterate through sub-lists of elements of the size given.

          Equivalent to AsyncResult.partitions() except that
          mapping values, rather than Row objects, are
          returned.

      -- Method: sqlalchemy.ext.asyncio.AsyncMappingResult..
               unique (strategy=None) ->
               sqlalchemy.ext.asyncio.AsyncMappingResult

          Apply unique filtering to the objects returned by this
          AsyncMappingResult.

          See AsyncResult.unique() for usage details.

3.7.1.8 ORM Session API Documentation
.....................................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See AsyncSession.Asyncio version of Session.

See AsyncSessionTransaction.A wrapper for the ORM SessionTransaction object.

 -- Class: sqlalchemy.ext.asyncio.AsyncSession (bind:
          Optional[sqlalchemy.ext.asyncio.engine.AsyncEngine] = None,
          binds: Optional[Mapping[object,
          sqlalchemy.ext.asyncio.engine.AsyncEngine]] = None, **kw)

     Asyncio version of Session.

     New in version 1.4.

      -- Method: sqlalchemy.ext.asyncio.AsyncSession..add
               (instance, _warn=True)

          Place an object in the ‘Session’.

          Proxied for the Session class on behalf of the
          AsyncSession class.

          Its state will be persisted to the database on the next flush
          operation.

          Repeated calls to ‘add()’ will be ignored.  The opposite of
          ‘add()’ is ‘expunge()’.

      -- Method: sqlalchemy.ext.asyncio.AsyncSession..add_all
               (instances)

          Add the given collection of instances to this ‘Session’.

          Proxied for the Session class on behalf of the
          AsyncSession class.

      -- Method: sqlalchemy.ext.asyncio.AsyncSession..begin
               (**kw)

          Return an AsyncSessionTransaction object.

          The underlying Session will perform the “begin”
          action when the AsyncSessionTransaction object is
          entered:

               async with async_session.begin():
                   # .. ORM transaction is begun

          Note that database IO will not normally occur when the
          session-level transaction is begun, as database transactions
          begin on an on-demand basis.  However, the begin block is
          async to accommodate for a
          SessionEvents.after_transaction_create() event hook that
          may perform IO.

          For a general description of ORM begin, see
          Session.begin().

      -- Method: sqlalchemy.ext.asyncio.AsyncSession..
               begin_nested (**kw)

          Return an AsyncSessionTransaction object which
          will begin a “nested” transaction, e.g.  SAVEPOINT.

          Behavior is the same as that of AsyncSession.begin().

          For a general description of ORM begin nested, see
          Session.begin_nested().

      -- Method: async sqlalchemy.ext.asyncio.AsyncSession..
               close ()

          Close this AsyncSession.

      -- Method: sqlalchemy.ext.asyncio.AsyncSession..async
               classmethod close_all ()

          Close all AsyncSession sessions.

      -- Method: async sqlalchemy.ext.asyncio.AsyncSession..
               commit ()

          Commit the current transaction in progress.

      -- Method: async sqlalchemy.ext.asyncio.AsyncSession..
               connection ()

          Return a AsyncConnection object corresponding to
          this Session object’s transactional state.

      -- Method: async sqlalchemy.ext.asyncio.AsyncSession..
               delete (instance)

          Mark an instance as deleted.

          The database delete operation occurs upon ‘flush()’.

          As this operation may need to cascade along unloaded
          relationships, it is awaitable to allow for those queries to
          take place.

      -- Attribute: sqlalchemy.ext.asyncio.AsyncSession..
               deleted

          The set of all instances marked as ‘deleted’ within this
          ‘Session’

          Proxied for the Session class on behalf of the
          AsyncSession class.

      -- Attribute: sqlalchemy.ext.asyncio.AsyncSession..
               dirty

          The set of all persistent instances considered dirty.

          Proxied for the Session class on behalf of the
          AsyncSession class.

          E.g.:

               some_mapped_object in session.dirty

          Instances are considered dirty when they were modified but not
          deleted.

          Note that this ‘dirty’ calculation is ‘optimistic’; most
          attribute-setting or collection modification operations will
          mark an instance as ‘dirty’ and place it in this set, even if
          there is no net change to the attribute’s value.  At flush
          time, the value of each attribute is compared to its
          previously saved value, and if there’s no net change, no SQL
          operation will occur (this is a more expensive operation so
          it’s only done at flush time).

          To check if an instance has actionable net changes to its
          attributes, use the Session.is_modified() method.

      -- Method: async sqlalchemy.ext.asyncio.AsyncSession..
               execute (statement: sqlalchemy.sql.base.Executable,
               params: Optional[Mapping] = None, execution_options:
               Mapping = {}, bind_arguments: Optional[Mapping] = None,
               **kw) -> sqlalchemy.engine.Result

          Execute a statement and return a buffered Result
          object.

      -- Method: sqlalchemy.ext.asyncio.AsyncSession..expire
               (instance, attribute_names=None)

          Expire the attributes on an instance.

          Proxied for the Session class on behalf of the
          AsyncSession class.

          Marks the attributes of an instance as out of date.  When an
          expired attribute is next accessed, a query will be issued to
          the Session object’s current transactional context
          in order to load all expired attributes for the given
          instance.  Note that a highly isolated transaction will return
          the same values as were previously read in that same
          transaction, regardless of changes in database state outside
          of that transaction.

          To expire all objects in the Session
          simultaneously, use ‘Session.expire_all()’.

          The Session object’s default behavior is to expire
          all state whenever the ‘Session.rollback()’ or
          ‘Session.commit()’ methods are called, so that new state can
          be loaded for the new transaction.  For this reason, calling
          ‘Session.expire()’ only makes sense for the specific case that
          a non-ORM SQL statement was emitted in the current
          transaction.

          Parameters:

             * ‘instance’ – The instance to be refreshed.

             * ‘attribute_names’ – optional list of string attribute
               names indicating a subset of attributes to be expired.

          See also
          ........

          See Refreshing / Expiring. - introductory material

          See Session.expire().

          See Session.refresh().

          See Query.populate_existing().

      -- Method: sqlalchemy.ext.asyncio.AsyncSession..
               expire_all ()

          Expires all persistent instances within this Session.

          Proxied for the Session class on behalf of the
          AsyncSession class.

          When any attributes on a persistent instance is next accessed,
          a query will be issued using the Session object’s
          current transactional context in order to load all expired
          attributes for the given instance.  Note that a highly
          isolated transaction will return the same values as were
          previously read in that same transaction, regardless of
          changes in database state outside of that transaction.

          To expire individual objects and individual attributes on
          those objects, use ‘Session.expire()’.

          The Session object’s default behavior is to expire
          all state whenever the ‘Session.rollback()’ or
          ‘Session.commit()’ methods are called, so that new state can
          be loaded for the new transaction.  For this reason, calling
          ‘Session.expire_all()’ should not be needed when autocommit is
          ‘False’, assuming the transaction is isolated.

          See also
          ........

          See Refreshing / Expiring. - introductory material

          See Session.expire().

          See Session.refresh().

          See Query.populate_existing().

      -- Method: sqlalchemy.ext.asyncio.AsyncSession..expunge
               (instance)

          Remove the ‘instance’ from this ‘Session’.

          Proxied for the Session class on behalf of the
          AsyncSession class.

          This will free all internal references to the instance.
          Cascading will be applied according to the `expunge' cascade
          rule.

      -- Method: sqlalchemy.ext.asyncio.AsyncSession..
               expunge_all ()

          Remove all object instances from this ‘Session’.

          Proxied for the Session class on behalf of the
          AsyncSession class.

          This is equivalent to calling ‘expunge(obj)’ on all objects in
          this ‘Session’.

      -- Method: async sqlalchemy.ext.asyncio.AsyncSession..
               flush (objects=None)

          Flush all the object changes to the database.

          See also
          ........

          See Session.flush().

      -- Method: async sqlalchemy.ext.asyncio.AsyncSession..
               get (entity, ident, options=None,
               populate_existing=False, with_for_update=None,
               identity_token=None)

          Return an instance based on the given primary key identifier,
          or ‘None’ if not found.

      -- Method: sqlalchemy.ext.asyncio.AsyncSession..
               get_bind (mapper=None, clause=None, bind=None,
               _sa_skip_events=None,
               _sa_skip_for_implicit_returning=False)

          Return a “bind” to which this Session is bound.

          Proxied for the Session class on behalf of the
          AsyncSession class.

          The “bind” is usually an instance of Engine, except
          in the case where the Session has been explicitly
          bound directly to a Connection.

          For a multiply-bound or unbound Session, the
          ‘mapper’ or ‘clause’ arguments are used to determine the
          appropriate bind to return.

          Note that the “mapper” argument is usually present when
          Session.get_bind() is called via an ORM operation such
          as a Session.query(), each individual
          INSERT/UPDATE/DELETE operation within a Session.flush(),
          call, etc.

          The order of resolution is:

            1. if mapper given and Session.binds is present,
               locate a bind based first on the mapper in use, then on
               the mapped class in use, then on any base classes that
               are present in the ‘__mro__’ of the mapped class, from
               more specific superclasses to more general.

            2. if clause given and ‘Session.binds’ is present, locate a
               bind based on Table objects found in the given
               clause present in ‘Session.binds’.

            3. if ‘Session.binds’ is present, return that.

            4. if clause given, attempt to return a bind linked to the
               MetaData ultimately associated with the
               clause.

            5. if mapper given, attempt to return a bind linked to the
               MetaData ultimately associated with the
               Table or other selectable to which the mapper is
               mapped.

            6. No bind can be found, see UnboundExecutionError.
               is raised.

          Note that the Session.get_bind() method can be
          overridden on a user-defined subclass of Session to
          provide any kind of bind resolution scheme.  See the example
          at Custom Vertical Partitioning.

          Parameters:

             * ‘mapper’ – Optional mapper() mapped class or
               instance of Mapper.  The bind can be derived
               from a Mapper first by consulting the “binds”
               map associated with this Session, and secondly
               by consulting the MetaData associated with the
               Table to which the Mapper is
               mapped for a bind.

             * ‘clause’ – A ClauseElement. (i.e.  see
               select(), text(), etc.).  If the ‘mapper’
               argument is not present or could not produce a bind, the
               given expression construct will be searched for a bound
               element, typically a Table associated with
               bound MetaData.

          See also
          ........

          See Partitioning Strategies (e.g. multiple database backends per Session).

          See Session.binds.

          See Session.bind_mapper().

          See Session.bind_table().

      -- Method: sqlalchemy.ext.asyncio.AsyncSession..
               classmethod identity_key (*args, **kwargs)

          Return an identity key.

          Proxied for the Session class on behalf of the
          AsyncSession class.

          This is an alias of identity_key().

      -- Method: sqlalchemy.ext.asyncio.AsyncSession..
               in_transaction ()

          Return True if this Session has begun a
          transaction.

          Proxied for the Session class on behalf of the
          AsyncSession class.

          New in version 1.4.

          See also
          ........

          See Session.is_active.

      -- Attribute: sqlalchemy.ext.asyncio.AsyncSession..info

          A user-modifiable dictionary.

          Proxied for the Session class on behalf of the
          AsyncSession class.

          The initial value of this dictionary can be populated using
          the ‘info’ argument to the Session constructor or
          sessionmaker constructor or factory methods.  The
          dictionary here is always local to this Session and
          can be modified independently of all other Session
          objects.

      -- Attribute: sqlalchemy.ext.asyncio.AsyncSession..
               is_active

          True if this Session not in “partial rollback”
          state.

          Proxied for the Session class on behalf of the
          AsyncSession class.

          Changed in version 1.4: The Session no longer
          begins a new transaction immediately, so this attribute will
          be False when the Session is first instantiated.

          “partial rollback” state typically indicates that the flush
          process of the Session has failed, and that the
          Session.rollback() method must be emitted in order
          to fully roll back the transaction.

          If this Session is not in a transaction at all, the
          Session will autobegin when it is first used, so in
          this case Session.is_active will return True.

          Otherwise, if this Session is within a transaction,
          and that transaction has not been rolled back internally, the
          Session.is_active will also return True.

          See also
          ........

          See “This Session’s transaction has been rolled back due to a previous exception during flush.” (or similar).

          See Session.in_transaction().

      -- Method: sqlalchemy.ext.asyncio.AsyncSession..
               is_modified (instance, include_collections=True)

          Return ‘True’ if the given instance has locally modified
          attributes.

          Proxied for the Session class on behalf of the
          AsyncSession class.

          This method retrieves the history for each instrumented
          attribute on the instance and performs a comparison of the
          current value to its previously committed value, if any.

          It is in effect a more expensive and accurate version of
          checking for the given instance in the Session.dirty
          collection; a full test for each attribute’s net “dirty”
          status is performed.

          E.g.:

               return session.is_modified(someobject)

          A few caveats to this method apply:

             * Instances present in the Session.dirty.
               collection may report ‘False’ when tested with this
               method.  This is because the object may have received
               change events via attribute mutation, thus placing it in
               Session.dirty, but ultimately the state is the
               same as that loaded from the database, resulting in no
               net change here.

             * Scalar attributes may not have recorded the previously
               set value when a new value was applied, if the attribute
               was not loaded, or was expired, at the time the new value
               was received - in these cases, the attribute is assumed
               to have a change, even if there is ultimately no net
               change against its database value.  SQLAlchemy in most
               cases does not need the “old” value when a set event
               occurs, so it skips the expense of a SQL call if the old
               value isn’t present, based on the assumption that an
               UPDATE of the scalar value is usually needed, and in
               those few cases where it isn’t, is less expensive on
               average than issuing a defensive SELECT.

               The “old” value is fetched unconditionally upon set only
               if the attribute container has the ‘active_history’ flag
               set to ‘True’.  This flag is set typically for primary
               key attributes and scalar object references that are not
               a simple many-to-one.  To set this flag for any arbitrary
               mapped column, use the ‘active_history’ argument with
               column_property().

          Parameters:

             * ‘instance’ – mapped instance to be tested for pending
               changes.

             * ‘include_collections’ – Indicates if multivalued
               collections should be included in the operation.  Setting
               this to ‘False’ is a way to detect only local-column
               based properties (i.e.  scalar columns or many-to-one
               foreign keys) that would result in an UPDATE for this
               instance upon flush.

      -- Method: async sqlalchemy.ext.asyncio.AsyncSession..
               merge (instance, load=True)

          Copy the state of a given instance into a corresponding
          instance within this AsyncSession.

      -- Attribute: sqlalchemy.ext.asyncio.AsyncSession..new

          The set of all instances marked as ‘new’ within this
          ‘Session’.

          Proxied for the Session class on behalf of the
          AsyncSession class.

      -- Attribute: sqlalchemy.ext.asyncio.AsyncSession..
               no_autoflush

          Return a context manager that disables autoflush.

          Proxied for the Session class on behalf of the
          AsyncSession class.

          e.g.:

               with session.no_autoflush:

                   some_object = SomeClass()
                   session.add(some_object)
                   # won't autoflush
                   some_object.related_thing = session.query(SomeRelated).first()

          Operations that proceed within the ‘with:’ block will not be
          subject to flushes occurring upon query access.  This is
          useful when initializing a series of objects which involve
          existing database queries, where the uncompleted object should
          not yet be flushed.

      -- Method: sqlalchemy.ext.asyncio.AsyncSession..
               classmethod object_session (instance)

          Return the Session to which an object belongs.

          Proxied for the Session class on behalf of the
          AsyncSession class.

          This is an alias of object_session().

      -- Method: async sqlalchemy.ext.asyncio.AsyncSession..
               refresh (instance, attribute_names=None,
               with_for_update=None)

          Expire and refresh the attributes on the given instance.

          A query will be issued to the database and all attributes will
          be refreshed with their current database value.

          This is the async version of the Session.refresh()
          method.  See that method for a complete description of all
          options.

      -- Method: async sqlalchemy.ext.asyncio.AsyncSession..
               rollback ()

          Rollback the current transaction in progress.

      -- Method: async sqlalchemy.ext.asyncio.AsyncSession..
               run_sync (fn: Callable[[…], T], *arg, **kw) -> T

          Invoke the given sync callable passing sync self as the first
          argument.

          This method maintains the asyncio event loop all the way
          through to the database connection by running the given
          callable in a specially instrumented greenlet.

          E.g.:

               with AsyncSession(async_engine) as session:
                   await session.run_sync(some_business_method)

               Note: The provided callable is invoked inline within the
               asyncio event loop, and will block on traditional IO
               calls.  IO within this callable should only call into
               SQLAlchemy’s asyncio database APIs which will be properly
               adapted to the greenlet context.

          See also
          ........

          See Running Synchronous Methods and Functions under asyncio.

      -- Method: async sqlalchemy.ext.asyncio.AsyncSession..
               scalar (statement: sqlalchemy.sql.base.Executable,
               params: Optional[Mapping] = None, execution_options:
               Mapping = {}, bind_arguments: Optional[Mapping] = None,
               **kw) -> Any

          Execute a statement and return a scalar result.

      -- Method: async sqlalchemy.ext.asyncio.AsyncSession..
               stream (statement, params=None, execution_options={},
               bind_arguments=None, **kw)

          Execute a statement and return a streaming AsyncResult
          object.

 -- Class: sqlalchemy.ext.asyncio.AsyncSessionTransaction (session,
          nested=False)

     A wrapper for the ORM SessionTransaction object.

     This object is provided so that a transaction-holding object for
     the AsyncSession.begin() may be returned.

     The object supports both explicit calls to
     AsyncSessionTransaction.commit() and
     AsyncSessionTransaction.rollback(), as well as use as an async
     context manager.

     New in version 1.4.

     `Class signature'

     class sqlalchemy.ext.asyncio.AsyncSessionTransaction.
     (‘sqlalchemy.ext.asyncio.base.StartableContext’)

      -- Method: async
               sqlalchemy.ext.asyncio.AsyncSessionTransaction..
               commit ()

          Commit this AsyncTransaction.

      -- Method: async
               sqlalchemy.ext.asyncio.AsyncSessionTransaction..
               rollback ()

          Roll back this AsyncTransaction.

3.7.2 Association Proxy
-----------------------

‘associationproxy’ is used to create a read/write view of a target
attribute across a relationship.  It essentially conceals the usage of a
“middle” attribute between two endpoints, and can be used to cherry-pick
fields from a collection of related objects or to reduce the verbosity
of using the association object pattern.  Applied creatively, the
association proxy allows the construction of sophisticated collections
and dictionary views of virtually any geometry, persisted to the
database using standard, transparently configured relational patterns.

3.7.2.1 Simplifying Scalar Collections
......................................

Consider a many-to-many mapping between two classes, ‘User’ and
‘Keyword’.  Each ‘User’ can have any number of ‘Keyword’ objects, and
vice-versa (the many-to-many pattern is described at Many To Many):

     from sqlalchemy import Column, Integer, String, ForeignKey, Table
     from sqlalchemy.orm import relationship
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         name = Column(String(64))
         kw = relationship("Keyword", secondary=lambda: userkeywords_table)

         def __init__(self, name):
             self.name = name

     class Keyword(Base):
         __tablename__ = 'keyword'
         id = Column(Integer, primary_key=True)
         keyword = Column('keyword', String(64))

         def __init__(self, keyword):
             self.keyword = keyword

     userkeywords_table = Table('userkeywords', Base.metadata,
         Column('user_id', Integer, ForeignKey("user.id"),
                primary_key=True),
         Column('keyword_id', Integer, ForeignKey("keyword.id"),
                primary_key=True)
     )

Reading and manipulating the collection of “keyword” strings associated
with ‘User’ requires traversal from each collection element to the
‘.keyword’ attribute, which can be awkward:

     >>> user = User('jek')
     >>> user.kw.append(Keyword('cheese inspector'))
     >>> print(user.kw)
     [<__main__.Keyword object at 0x12bf830>]
     >>> print(user.kw[0].keyword)
     cheese inspector
     >>> print([keyword.keyword for keyword in user.kw])
     ['cheese inspector']

The ‘association_proxy’ is applied to the ‘User’ class to produce a
“view” of the ‘kw’ relationship, which only exposes the string value of
‘.keyword’ associated with each ‘Keyword’ object:

     from sqlalchemy.ext.associationproxy import association_proxy

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         name = Column(String(64))
         kw = relationship("Keyword", secondary=lambda: userkeywords_table)

         def __init__(self, name):
             self.name = name

         # proxy the 'keyword' attribute from the 'kw' relationship
         keywords = association_proxy('kw', 'keyword')

We can now reference the ‘.keywords’ collection as a listing of strings,
which is both readable and writable.  New ‘Keyword’ objects are created
for us transparently:

     >>> user = User('jek')
     >>> user.keywords.append('cheese inspector')
     >>> user.keywords
     ['cheese inspector']
     >>> user.keywords.append('snack ninja')
     >>> user.kw
     [<__main__.Keyword object at 0x12cdd30>, <__main__.Keyword object at 0x12cde30>]

The AssociationProxy object produced by the
association_proxy() function is an instance of a Python
descriptor(1).  It is always declared with the user-defined class being
mapped, regardless of whether Declarative or classical mappings via the
mapper() function are used.

The proxy functions by operating upon the underlying mapped attribute or
collection in response to operations, and changes made via the proxy are
immediately apparent in the mapped attribute, as well as vice versa.
The underlying attribute remains fully accessible.

When first accessed, the association proxy performs introspection
operations on the target collection so that its behavior corresponds
correctly.  Details such as if the locally proxied attribute is a
collection (as is typical) or a scalar reference, as well as if the
collection acts like a set, list, or dictionary is taken into account,
so that the proxy should act just like the underlying collection or
attribute does.

   ---------- Footnotes ----------

   (1) http://docs.python.org/howto/descriptor.html

3.7.2.2 Creation of New Values
..............................

When a list append() event (or set add(), dictionary __setitem__(), or
scalar assignment event) is intercepted by the association proxy, it
instantiates a new instance of the “intermediary” object using its
constructor, passing as a single argument the given value.  In our
example above, an operation like:

     user.keywords.append('cheese inspector')

Is translated by the association proxy into the operation:

     user.kw.append(Keyword('cheese inspector'))

The example works here because we have designed the constructor for
‘Keyword’ to accept a single positional argument, ‘keyword’.  For those
cases where a single-argument constructor isn’t feasible, the
association proxy’s creational behavior can be customized using the
‘creator’ argument, which references a callable (i.e.  Python function)
that will produce a new object instance given the singular argument.
Below we illustrate this using a lambda as is typical:

     class User(Base):
         # ...

         # use Keyword(keyword=kw) on append() events
         keywords = association_proxy('kw', 'keyword',
                         creator=lambda kw: Keyword(keyword=kw))

The ‘creator’ function accepts a single argument in the case of a list-
or set- based collection, or a scalar attribute.  In the case of a
dictionary-based collection, it accepts two arguments, “key” and
“value”.  An example of this is below in Proxying to Dictionary Based Collections.

3.7.2.3 Simplifying Association Objects
.......................................

The “association object” pattern is an extended form of a many-to-many
relationship, and is described at Association Object.
Association proxies are useful for keeping “association objects” out of
the way during regular use.

Suppose our ‘userkeywords’ table above had additional columns which we’d
like to map explicitly, but in most cases we don’t require direct access
to these attributes.  Below, we illustrate a new mapping which
introduces the ‘UserKeyword’ class, which is mapped to the
‘userkeywords’ table illustrated earlier.  This class adds an additional
column ‘special_key’, a value which we occasionally want to access, but
not in the usual case.  We create an association proxy on the ‘User’
class called ‘keywords’, which will bridge the gap from the
‘user_keywords’ collection of ‘User’ to the ‘.keyword’ attribute present
on each ‘UserKeyword’:

     from sqlalchemy import Column, Integer, String, ForeignKey
     from sqlalchemy.orm import relationship, backref

     from sqlalchemy.ext.associationproxy import association_proxy
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         name = Column(String(64))

         # association proxy of "user_keywords" collection
         # to "keyword" attribute
         keywords = association_proxy('user_keywords', 'keyword')

         def __init__(self, name):
             self.name = name

     class UserKeyword(Base):
         __tablename__ = 'user_keyword'
         user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
         keyword_id = Column(Integer, ForeignKey('keyword.id'), primary_key=True)
         special_key = Column(String(50))

         # bidirectional attribute/collection of "user"/"user_keywords"
         user = relationship(User,
                     backref=backref("user_keywords",
                                     cascade="all, delete-orphan")
                 )

         # reference to the "Keyword" object
         keyword = relationship("Keyword")

         def __init__(self, keyword=None, user=None, special_key=None):
             self.user = user
             self.keyword = keyword
             self.special_key = special_key

     class Keyword(Base):
         __tablename__ = 'keyword'
         id = Column(Integer, primary_key=True)
         keyword = Column('keyword', String(64))

         def __init__(self, keyword):
             self.keyword = keyword

         def __repr__(self):
             return 'Keyword(%s)' % repr(self.keyword)

With the above configuration, we can operate upon the ‘.keywords’
collection of each ‘User’ object, and the usage of ‘UserKeyword’ is
concealed:

     >>> user = User('log')
     >>> for kw in (Keyword('new_from_blammo'), Keyword('its_big')):
     ...     user.keywords.append(kw)
     ...
     >>> print(user.keywords)
     [Keyword('new_from_blammo'), Keyword('its_big')]

Where above, each ‘.keywords.append()’ operation is equivalent to:

     >>> user.user_keywords.append(UserKeyword(Keyword('its_heavy')))

The ‘UserKeyword’ association object has two attributes here which are
populated; the ‘.keyword’ attribute is populated directly as a result of
passing the ‘Keyword’ object as the first argument.  The ‘.user’
argument is then assigned as the ‘UserKeyword’ object is appended to the
‘User.user_keywords’ collection, where the bidirectional relationship
configured between ‘User.user_keywords’ and ‘UserKeyword.user’ results
in a population of the ‘UserKeyword.user’ attribute.  The ‘special_key’
argument above is left at its default value of ‘None’.

For those cases where we do want ‘special_key’ to have a value, we
create the ‘UserKeyword’ object explicitly.  Below we assign all three
attributes, where the assignment of ‘.user’ has the effect of the
‘UserKeyword’ being appended to the ‘User.user_keywords’ collection:

     >>> UserKeyword(Keyword('its_wood'), user, special_key='my special key')

The association proxy returns to us a collection of ‘Keyword’ objects
represented by all these operations:

     >>> user.keywords
     [Keyword('new_from_blammo'), Keyword('its_big'), Keyword('its_heavy'), Keyword('its_wood')]

3.7.2.4 Proxying to Dictionary Based Collections
................................................

The association proxy can proxy to dictionary based collections as well.
SQLAlchemy mappings usually use the attribute_mapped_collection()
collection type to create dictionary collections, as well as the
extended techniques described in Custom Dictionary-Based Collections.

The association proxy adjusts its behavior when it detects the usage of
a dictionary-based collection.  When new values are added to the
dictionary, the association proxy instantiates the intermediary object
by passing two arguments to the creation function instead of one, the
key and the value.  As always, this creation function defaults to the
constructor of the intermediary class, and can be customized using the
‘creator’ argument.

Below, we modify our ‘UserKeyword’ example such that the
‘User.user_keywords’ collection will now be mapped using a dictionary,
where the ‘UserKeyword.special_key’ argument will be used as the key for
the dictionary.  We then apply a ‘creator’ argument to the
‘User.keywords’ proxy so that these values are assigned appropriately
when new elements are added to the dictionary:

     from sqlalchemy import Column, Integer, String, ForeignKey
     from sqlalchemy.orm import relationship, backref
     from sqlalchemy.ext.associationproxy import association_proxy
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.orm.collections import attribute_mapped_collection

     Base = declarative_base()

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         name = Column(String(64))

         # proxy to 'user_keywords', instantiating UserKeyword
         # assigning the new key to 'special_key', values to
         # 'keyword'.
         keywords = association_proxy('user_keywords', 'keyword',
                         creator=lambda k, v:
                                     UserKeyword(special_key=k, keyword=v)
                     )

         def __init__(self, name):
             self.name = name

     class UserKeyword(Base):
         __tablename__ = 'user_keyword'
         user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
         keyword_id = Column(Integer, ForeignKey('keyword.id'), primary_key=True)
         special_key = Column(String)

         # bidirectional user/user_keywords relationships, mapping
         # user_keywords with a dictionary against "special_key" as key.
         user = relationship(User, backref=backref(
                         "user_keywords",
                         collection_class=attribute_mapped_collection("special_key"),
                         cascade="all, delete-orphan"
                         )
                     )
         keyword = relationship("Keyword")

     class Keyword(Base):
         __tablename__ = 'keyword'
         id = Column(Integer, primary_key=True)
         keyword = Column('keyword', String(64))

         def __init__(self, keyword):
             self.keyword = keyword

         def __repr__(self):
             return 'Keyword(%s)' % repr(self.keyword)

We illustrate the ‘.keywords’ collection as a dictionary, mapping the
‘UserKeyword.special_key’ value to ‘Keyword’ objects:

     >>> user = User('log')

     >>> user.keywords['sk1'] = Keyword('kw1')
     >>> user.keywords['sk2'] = Keyword('kw2')

     >>> print(user.keywords)
     {'sk1': Keyword('kw1'), 'sk2': Keyword('kw2')}

3.7.2.5 Composite Association Proxies
.....................................

Given our previous examples of proxying from relationship to scalar
attribute, proxying across an association object, and proxying
dictionaries, we can combine all three techniques together to give
‘User’ a ‘keywords’ dictionary that deals strictly with the string value
of ‘special_key’ mapped to the string ‘keyword’.  Both the ‘UserKeyword’
and ‘Keyword’ classes are entirely concealed.  This is achieved by
building an association proxy on ‘User’ that refers to an association
proxy present on ‘UserKeyword’:

     from sqlalchemy import Column, Integer, String, ForeignKey
     from sqlalchemy.orm import relationship, backref

     from sqlalchemy.ext.associationproxy import association_proxy
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.orm.collections import attribute_mapped_collection

     Base = declarative_base()

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         name = Column(String(64))

         # the same 'user_keywords'->'keyword' proxy as in
         # the basic dictionary example.
         keywords = association_proxy(
             'user_keywords',
             'keyword',
             creator=lambda k, v: UserKeyword(special_key=k, keyword=v)
         )

         # another proxy that is directly column-targeted
         special_keys = association_proxy("user_keywords", "special_key")

         def __init__(self, name):
             self.name = name

     class UserKeyword(Base):
         __tablename__ = 'user_keyword'
         user_id = Column(ForeignKey('user.id'), primary_key=True)
         keyword_id = Column(ForeignKey('keyword.id'), primary_key=True)
         special_key = Column(String)
         user = relationship(
             User,
             backref=backref(
                 "user_keywords",
                 collection_class=attribute_mapped_collection("special_key"),
                 cascade="all, delete-orphan"
             )
         )

         # the relationship to Keyword is now called
         # 'kw'
         kw = relationship("Keyword")

         # 'keyword' is changed to be a proxy to the
         # 'keyword' attribute of 'Keyword'
         keyword = association_proxy('kw', 'keyword')

     class Keyword(Base):
         __tablename__ = 'keyword'
         id = Column(Integer, primary_key=True)
         keyword = Column('keyword', String(64))

         def __init__(self, keyword):
             self.keyword = keyword

‘User.keywords’ is now a dictionary of string to string, where
‘UserKeyword’ and ‘Keyword’ objects are created and removed for us
transparently using the association proxy.  In the example below, we
illustrate usage of the assignment operator, also appropriately handled
by the association proxy, to apply a dictionary value to the collection
at once:

     >>> user = User('log')
     >>> user.keywords = {
     ...     'sk1':'kw1',
     ...     'sk2':'kw2'
     ... }
     >>> print(user.keywords)
     {'sk1': 'kw1', 'sk2': 'kw2'}

     >>> user.keywords['sk3'] = 'kw3'
     >>> del user.keywords['sk2']
     >>> print(user.keywords)
     {'sk1': 'kw1', 'sk3': 'kw3'}

     >>> # illustrate un-proxied usage
     ... print(user.user_keywords['sk3'].kw)
     <__main__.Keyword object at 0x12ceb90>

One caveat with our example above is that because ‘Keyword’ objects are
created for each dictionary set operation, the example fails to maintain
uniqueness for the ‘Keyword’ objects on their string name, which is a
typical requirement for a tagging scenario such as this one.  For this
use case the recipe UniqueObject(1), or a comparable creational
strategy, is recommended, which will apply a “lookup first, then create”
strategy to the constructor of the ‘Keyword’ class, so that an already
existing ‘Keyword’ is returned if the given name is already present.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/wiki/UsageRecipes/UniqueObject

3.7.2.6 Querying with Association Proxies
.........................................

The AssociationProxy features simple SQL construction
capabilities which work at the class level in a similar way as other
ORM-mapped attributes.  Class-bound attributes such as ‘User.keywords’
and ‘User.special_keys’ in the preceding example will provide for a SQL
generating construct when accessed at the class level.

     Note: The primary purpose of the association proxy extension is to
     allow for improved persistence and object-access patterns with
     mapped object instances that are already loaded.  The class-bound
     querying feature is of limited use and will not replace the need to
     refer to the underlying attributes when constructing SQL queries
     with JOINs, eager loading options, etc.

The SQL generated takes the form of a correlated subquery against the
EXISTS SQL operator so that it can be used in a WHERE clause without the
need for additional modifications to the enclosing query.  If the
immediate target of an association proxy is a `mapped column
expression', standard column operators can be used which will be
embedded in the subquery.  For example a straight equality operator:

     >>> print(session.query(User).filter(User.special_keys == "jek"))
     SELECT "user".id AS user_id, "user".name AS user_name
     FROM "user"
     WHERE EXISTS (SELECT 1
     FROM user_keyword
     WHERE "user".id = user_keyword.user_id AND user_keyword.special_key = :special_key_1)

a LIKE operator:

     >>> print(session.query(User).filter(User.special_keys.like("%jek")))
     SELECT "user".id AS user_id, "user".name AS user_name
     FROM "user"
     WHERE EXISTS (SELECT 1
     FROM user_keyword
     WHERE "user".id = user_keyword.user_id AND user_keyword.special_key LIKE :special_key_1)

For association proxies where the immediate target is a `related object
or collection, or another association proxy or attribute on the related
object', relationship-oriented operators can be used instead, such as
PropComparator.has() and PropComparator.any().
The ‘User.keywords’ attribute is in fact two association proxies linked
together, so when using this proxy for generating SQL phrases, we get
two levels of EXISTS subqueries:

     >>> print(session.query(User).filter(User.keywords.any(Keyword.keyword == "jek")))
     SELECT "user".id AS user_id, "user".name AS user_name
     FROM "user"
     WHERE EXISTS (SELECT 1
     FROM user_keyword
     WHERE "user".id = user_keyword.user_id AND (EXISTS (SELECT 1
     FROM keyword
     WHERE keyword.id = user_keyword.keyword_id AND keyword.keyword = :keyword_1)))

This is not the most efficient form of SQL, so while association proxies
can be convenient for generating WHERE criteria quickly, SQL results
should be inspected and “unrolled” into explicit JOIN criteria for best
use, especially when chaining association proxies together.

Changed in version 1.3: Association proxy features distinct querying
modes based on the type of target.  See AssociationProxy now provides standard column operators for a column-oriented target.

3.7.2.7 Cascading Scalar Deletes
................................

New in version 1.3.

Given a mapping as:

     class A(Base):
         __tablename__ = 'test_a'
         id = Column(Integer, primary_key=True)
         ab = relationship(
             'AB', backref='a', uselist=False)
         b = association_proxy(
             'ab', 'b', creator=lambda b: AB(b=b),
             cascade_scalar_deletes=True)

     class B(Base):
         __tablename__ = 'test_b'
         id = Column(Integer, primary_key=True)
         ab = relationship('AB', backref='b', cascade='all, delete-orphan')

     class AB(Base):
         __tablename__ = 'test_ab'
         a_id = Column(Integer, ForeignKey(A.id), primary_key=True)
         b_id = Column(Integer, ForeignKey(B.id), primary_key=True)

An assignment to ‘A.b’ will generate an ‘AB’ object:

     a.b = B()

The ‘A.b’ association is scalar, and includes use of the flag
AssociationProxy.cascade_scalar_deletes.  When set, setting ‘A.b’
to ‘None’ will remove ‘A.ab’ as well:

     a.b = None
     assert a.ab is None

When AssociationProxy.cascade_scalar_deletes is not set, the
association object ‘a.ab’ above would remain in place.

Note that this is not the behavior for collection-based association
proxies; in that case, the intermediary association object is always
removed when members of the proxied collection are removed.  Whether or
not the row is deleted depends on the relationship cascade setting.

See also
........

See Cascades.

3.7.2.8 API Documentation
.........................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See association_proxy.(target_collection,Return a Python property implementing a view of a target attribute which references an
attr, **kw)    attribute on members of the target.

See ASSOCIATION_PROXY.

See AssociationProxy.A descriptor that presents a read/write view of an object attribute.

See AssociationProxyInstance.A per-class object that serves class- and object-specific results.

See ColumnAssociationProxyInstance.an AssociationProxyInstance that has a database column as a target.

See ObjectAssociationProxyInstance.an AssociationProxyInstance that has an object as a target.

 -- Function: sqlalchemy.ext.associationproxy.association_proxy
          (target_collection, attr, **kw)

     Return a Python property implementing a view of a target attribute
     which references an attribute on members of the target.

     The returned value is an instance of AssociationProxy.

     Implements a Python property representing a relationship as a
     collection of simpler values, or a scalar value.  The proxied
     property will mimic the collection type of the target (list, dict
     or set), or, in the case of a one to one relationship, a simple
     scalar value.

     Parameters:

        * ‘target_collection’ – Name of the attribute we’ll proxy to.
          This attribute is typically mapped by relationship()
          to link to a target collection, but can also be a
          many-to-one or non-scalar relationship.

        * ‘attr’ – Attribute on the associated instance or instances
          we’ll proxy for.

          For example, given a target collection of [obj1, obj2], a list
          created by this proxy property would look like [getattr(obj1,
          `attr'), getattr(obj2, `attr')]

          If the relationship is one-to-one or otherwise uselist=False,
          then simply: getattr(obj, `attr')

        * ‘creator’ – optional.

          When new items are added to this proxied collection, new
          instances of the class collected by the target collection will
          be created.  For list and set collections, the target class
          constructor will be called with the ‘value’ for the new
          instance.  For dict types, two arguments are passed: key and
          value.

          If you want to construct instances differently, supply a
          `creator' function that takes arguments as above and returns
          instances.

          For scalar relationships, creator() will be called if the
          target is None.  If the target is present, set operations are
          proxied to setattr() on the associated object.

          If you have an associated object with multiple attributes, you
          may set up multiple association proxies mapping to different
          attributes.  See the unit tests for examples, and for examples
          of how creator() functions can be used to construct the scalar
          relationship on-demand in this situation.

        * ‘**kw’ – Passes along any other keyword arguments to
          AssociationProxy.

 -- Class: sqlalchemy.ext.associationproxy.AssociationProxy
          (target_collection, attr, creator=None, getset_factory=None,
          proxy_factory=None, proxy_bulk_set=None, info=None,
          cascade_scalar_deletes=False)

     A descriptor that presents a read/write view of an object
     attribute.

     `Class signature'

     class sqlalchemy.ext.associationproxy.AssociationProxy.
     (‘sqlalchemy.orm.base.InspectionAttrInfo’)

      -- Method:
               sqlalchemy.ext.associationproxy.AssociationProxy..
               __init__ (target_collection, attr, creator=None,
               getset_factory=None, proxy_factory=None,
               proxy_bulk_set=None, info=None,
               cascade_scalar_deletes=False)

          Construct a new AssociationProxy.

          The association_proxy() function is provided as
          the usual entrypoint here, though AssociationProxy
          can be instantiated and/or subclassed directly.

          Parameters:

             * ‘target_collection’ – Name of the collection we’ll proxy
               to, usually created with relationship().

             * ‘attr’ – Attribute on the collected instances we’ll proxy
               for.  For example, given a target collection of [obj1,
               obj2], a list created by this proxy property would look
               like [getattr(obj1, attr), getattr(obj2, attr)]

             * ‘creator’ – Optional.  When new items are added to this
               proxied collection, new instances of the class collected
               by the target collection will be created.  For list and
               set collections, the target class constructor will be
               called with the ‘value’ for the new instance.  For dict
               types, two arguments are passed: key and value.

               If you want to construct instances differently, supply a
               ‘creator’ function that takes arguments as above and
               returns instances.

             * ‘cascade_scalar_deletes’ – when True, indicates that
               setting the proxied value to ‘None’, or deleting it via
               ‘del’, should also remove the source object.  Only
               applies to scalar attributes.  Normally, removing the
               proxied target will not remove the proxy source, as this
               object may have other state that is still to be kept.

               New in version 1.3.

               See also
               ........

               See Cascading Scalar Deletes. - complete usage
               example

             * ‘getset_factory’ – Optional.  Proxied attribute access is
               automatically handled by routines that get and set values
               based on the ‘attr’ argument for this proxy.

               If you would like to customize this behavior, you may
               supply a ‘getset_factory’ callable that produces a tuple
               of ‘getter’ and ‘setter’ functions.  The factory is
               called with two arguments, the abstract type of the
               underlying collection and this proxy instance.

             * ‘proxy_factory’ – Optional.  The type of collection to
               emulate is determined by sniffing the target collection.
               If your collection type can’t be determined by duck
               typing or you’d like to use a different collection
               implementation, you may supply a factory function to
               produce those collections.  Only applicable to non-scalar
               relationships.

             * ‘proxy_bulk_set’ – Optional, use with proxy_factory.  See
               the _set() method for details.

             * ‘info’ – optional, will be assigned to
               AssociationProxy.info if present.

               New in version 1.0.9.

      -- Attribute:
               sqlalchemy.ext.associationproxy.AssociationProxy..
               extension_type = symbol('ASSOCIATION_PROXY')

          The extension type, if any.  Defaults to ‘NOT_EXTENSION’

          See also
          ........

          See HYBRID_METHOD.

          See HYBRID_PROPERTY.

          See ASSOCIATION_PROXY.

      -- Method:
               sqlalchemy.ext.associationproxy.AssociationProxy..
               for_class (class_, obj=None)

          Return the internal state local to a specific mapped class.

          E.g., given a class ‘User’:

               class User(Base):
                   # ...

                   keywords = association_proxy('kws', 'keyword')

          If we access this AssociationProxy from
          Mapper.all_orm_descriptors, and we want to view the
          target class for this proxy as mapped by ‘User’:

               inspect(User).all_orm_descriptors["keywords"].for_class(User).target_class

          This returns an instance of AssociationProxyInstance
          that is specific to the ‘User’ class.  The
          AssociationProxy object remains agnostic of its parent
          class.

          Parameters:

             * ‘class_’ – the class that we are returning state for.

             * ‘obj’ – optional, an instance of the class that is
               required if the attribute refers to a polymorphic target,
               e.g.  where we have to look at the type of the actual
               destination object to get the complete path.

          New in version 1.3: - see AssociationProxy no longer
          stores any state specific to a particular parent class; the
          state is now stored in per-class
          AssociationProxyInstance objects.

      -- Attribute:
               sqlalchemy.ext.associationproxy.AssociationProxy..
               info

          `inherited from the' ‘InspectionAttrInfo.info’ `attribute of'
          ‘InspectionAttrInfo’

          Info dictionary associated with the object, allowing
          user-defined data to be associated with this
          InspectionAttr.

          The dictionary is generated when first accessed.
          Alternatively, it can be specified as a constructor argument
          to the column_property(), relationship(),
          or composite() functions.

          Changed in version 1.0.0: MapperProperty.info is
          also available on extension types via the
          InspectionAttrInfo.info attribute, so that it can apply
          to a wider variety of ORM and extension constructs.

          See also
          ........

          See QueryableAttribute.info.

          See SchemaItem.info.

      -- Attribute:
               sqlalchemy.ext.associationproxy.AssociationProxy..
               is_aliased_class = False

          `inherited from the' ‘InspectionAttr.is_aliased_class’
          `attribute of' ‘InspectionAttr’

          True if this object is an instance of AliasedClass.

      -- Attribute:
               sqlalchemy.ext.associationproxy.AssociationProxy..
               is_attribute = True

          True if this object is a Python descriptor.

          This can refer to one of many types.  Usually a
          QueryableAttribute which handles attributes events on
          behalf of a MapperProperty.  But can also be an
          extension type such as AssociationProxy or
          hybrid_property.  The
          InspectionAttr.extension_type will refer to a constant
          identifying the specific subtype.

          See also
          ........

          See Mapper.all_orm_descriptors.

      -- Attribute:
               sqlalchemy.ext.associationproxy.AssociationProxy..
               is_bundle = False

          `inherited from the' ‘InspectionAttr.is_bundle’ `attribute of'
          ‘InspectionAttr’

          True if this object is an instance of Bundle.

      -- Attribute:
               sqlalchemy.ext.associationproxy.AssociationProxy..
               is_clause_element = False

          `inherited from the' ‘InspectionAttr.is_clause_element’
          `attribute of' ‘InspectionAttr’

          True if this object is an instance of ClauseElement.

      -- Attribute:
               sqlalchemy.ext.associationproxy.AssociationProxy..
               is_instance = False

          `inherited from the' ‘InspectionAttr.is_instance’ `attribute
          of' ‘InspectionAttr’

          True if this object is an instance of InstanceState.

      -- Attribute:
               sqlalchemy.ext.associationproxy.AssociationProxy..
               is_mapper = False

          `inherited from the' ‘InspectionAttr.is_mapper’ `attribute of'
          ‘InspectionAttr’

          True if this object is an instance of Mapper.

      -- Attribute:
               sqlalchemy.ext.associationproxy.AssociationProxy..
               is_property = False

          `inherited from the' ‘InspectionAttr.is_property’ `attribute
          of' ‘InspectionAttr’

          True if this object is an instance of MapperProperty.

      -- Attribute:
               sqlalchemy.ext.associationproxy.AssociationProxy..
               is_selectable = False

          `inherited from the' ‘InspectionAttr.is_selectable’ `attribute
          of' ‘InspectionAttr’

          Return True if this object is an instance of Selectable.

 -- Class: sqlalchemy.ext.associationproxy.AssociationProxyInstance
          (parent, owning_class, target_class, value_attr)

     A per-class object that serves class- and object-specific results.

     This is used by AssociationProxy when it is invoked in
     terms of a specific class or instance of a class, i.e.  when it is
     used as a regular Python descriptor.

     When referring to the AssociationProxy as a normal
     Python descriptor, the AssociationProxyInstance is the
     object that actually serves the information.  Under normal
     circumstances, its presence is transparent:

          >>> User.keywords.scalar
          False

     In the special case that the AssociationProxy object is
     being accessed directly, in order to get an explicit handle to the
     AssociationProxyInstance, use the
     AssociationProxy.for_class() method:

          proxy_state = inspect(User).all_orm_descriptors["keywords"].for_class(User)

          # view if proxy object is scalar or not
          >>> proxy_state.scalar
          False

     New in version 1.3.

      -- Method:
               sqlalchemy.ext.associationproxy.AssociationProxyInstance..
               any (criterion=None, **kwargs)

          Produce a proxied ‘any’ expression using EXISTS.

          This expression will be a composed product using the
          Comparator.any() and/or Comparator.has()
          operators of the underlying proxied attributes.

      -- Attribute:
               sqlalchemy.ext.associationproxy.AssociationProxyInstance..
               attr

          Return a tuple of ‘(local_attr, remote_attr)’.

          This attribute is convenient when specifying a join using
          Query.join() across two relationships:

               sess.query(Parent).join(*Parent.proxied.attr)

          See also
          ........

          See AssociationProxyInstance.local_attr.

          See AssociationProxyInstance.remote_attr.

      -- Method:
               sqlalchemy.ext.associationproxy.AssociationProxyInstance..
               delete (obj)

      -- Method:
               sqlalchemy.ext.associationproxy.AssociationProxyInstance..
               classmethod for_proxy (parent, owning_class,
               parent_instance)

      -- Method:
               sqlalchemy.ext.associationproxy.AssociationProxyInstance..
               get (obj)

      -- Method:
               sqlalchemy.ext.associationproxy.AssociationProxyInstance..
               has (criterion=None, **kwargs)

          Produce a proxied ‘has’ expression using EXISTS.

          This expression will be a composed product using the
          Comparator.any() and/or Comparator.has()
          operators of the underlying proxied attributes.

      -- Attribute:
               sqlalchemy.ext.associationproxy.AssociationProxyInstance..
               info

      -- Attribute:
               sqlalchemy.ext.associationproxy.AssociationProxyInstance..
               local_attr

          The ‘local’ class attribute referenced by this
          AssociationProxyInstance.

          See also
          ........

          See AssociationProxyInstance.attr.

          See AssociationProxyInstance.remote_attr.

      -- Attribute:
               sqlalchemy.ext.associationproxy.AssociationProxyInstance..
               remote_attr

          The ‘remote’ class attribute referenced by this
          AssociationProxyInstance.

          See also
          ........

          See AssociationProxyInstance.attr.

          See AssociationProxyInstance.local_attr.

      -- Attribute:
               sqlalchemy.ext.associationproxy.AssociationProxyInstance..
               scalar

          Return ‘True’ if this AssociationProxyInstance
          proxies a scalar relationship on the local side.

      -- Method:
               sqlalchemy.ext.associationproxy.AssociationProxyInstance..
               set (obj, values)

      -- Attribute:
               sqlalchemy.ext.associationproxy.AssociationProxyInstance..
               target_class = None

          The intermediary class handled by this
          AssociationProxyInstance.

          Intercepted append/set/assignment events will result in the
          generation of new instances of this class.

 -- Class:
          sqlalchemy.ext.associationproxy.ObjectAssociationProxyInstance
          (parent, owning_class, target_class, value_attr)

     an AssociationProxyInstance that has an object as a
     target.

     `Class signature'

     class
     sqlalchemy.ext.associationproxy.ObjectAssociationProxyInstance.
     (see
     sqlalchemy.ext.associationproxy.AssociationProxyInstance)

      -- Method:
               sqlalchemy.ext.associationproxy.ObjectAssociationProxyInstance..
               any (criterion=None, **kwargs)

          `inherited from the' AssociationProxyInstance.any().
          `method of' AssociationProxyInstance.

          Produce a proxied ‘any’ expression using EXISTS.

          This expression will be a composed product using the
          Comparator.any() and/or Comparator.has()
          operators of the underlying proxied attributes.

      -- Attribute:
               sqlalchemy.ext.associationproxy.ObjectAssociationProxyInstance..
               attr

          `inherited from the' AssociationProxyInstance.attr.
          `attribute of' AssociationProxyInstance.

          Return a tuple of ‘(local_attr, remote_attr)’.

          This attribute is convenient when specifying a join using
          Query.join() across two relationships:

               sess.query(Parent).join(*Parent.proxied.attr)

          See also
          ........

          See AssociationProxyInstance.local_attr.

          See AssociationProxyInstance.remote_attr.

      -- Method:
               sqlalchemy.ext.associationproxy.ObjectAssociationProxyInstance..
               contains (obj)

          Produce a proxied ‘contains’ expression using EXISTS.

          This expression will be a composed product using the
          Comparator.any(), Comparator.has(), and/or
          Comparator.contains() operators of the underlying
          proxied attributes.

      -- Method:
               sqlalchemy.ext.associationproxy.ObjectAssociationProxyInstance..
               has (criterion=None, **kwargs)

          `inherited from the' AssociationProxyInstance.has().
          `method of' AssociationProxyInstance.

          Produce a proxied ‘has’ expression using EXISTS.

          This expression will be a composed product using the
          Comparator.any() and/or Comparator.has()
          operators of the underlying proxied attributes.

      -- Attribute:
               sqlalchemy.ext.associationproxy.ObjectAssociationProxyInstance..
               local_attr

          `inherited from the'
          AssociationProxyInstance.local_attr. `attribute of'
          AssociationProxyInstance.

          The ‘local’ class attribute referenced by this
          AssociationProxyInstance.

          See also
          ........

          See AssociationProxyInstance.attr.

          See AssociationProxyInstance.remote_attr.

      -- Attribute:
               sqlalchemy.ext.associationproxy.ObjectAssociationProxyInstance..
               remote_attr

          `inherited from the'
          AssociationProxyInstance.remote_attr. `attribute of'
          AssociationProxyInstance.

          The ‘remote’ class attribute referenced by this
          AssociationProxyInstance.

          See also
          ........

          See AssociationProxyInstance.attr.

          See AssociationProxyInstance.local_attr.

      -- Attribute:
               sqlalchemy.ext.associationproxy.ObjectAssociationProxyInstance..
               scalar

          `inherited from the' AssociationProxyInstance.scalar.
          `attribute of' AssociationProxyInstance.

          Return ‘True’ if this AssociationProxyInstance
          proxies a scalar relationship on the local side.

 -- Class:
          sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance
          (parent, owning_class, target_class, value_attr)

     an AssociationProxyInstance that has a database column
     as a target.

     `Class signature'

     class
     sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance.
     (see sqlalchemy.sql.expression.ColumnOperators,
     sqlalchemy.ext.associationproxy.AssociationProxyInstance)

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               __le__ (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__le__’ `method of'
          ColumnOperators.

          Implement the ‘<=’ operator.

          In a column context, produces the clause ‘a <= b’.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               __lt__ (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__lt__’ `method of'
          ColumnOperators.

          Implement the ‘<’ operator.

          In a column context, produces the clause ‘a < b’.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               __ne__ (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__ne__’ `method of'
          ColumnOperators.

          Implement the ‘!=’ operator.

          In a column context, produces the clause ‘a != b’.  If the
          target is ‘None’, produces ‘a IS NOT NULL’.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               all_ ()

          `inherited from the' ColumnOperators.all_().
          `method of' ColumnOperators.

          Produce a all_() clause against the parent object.

          This operator is only appropriate against a scalar subquery
          object, or for some backends an column expression that is
          against the ARRAY type, e.g.:

               # postgresql '5 = ALL (somearray)'
               expr = 5 == mytable.c.somearray.all_()

               # mysql '5 = ALL (SELECT value FROM table)'
               expr = 5 == select(table.c.value).scalar_subquery().all_()

          See also
          ........

          See all_(). - standalone version

          See any_(). - ANY operator

          New in version 1.1.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               any (criterion=None, **kwargs)

          `inherited from the' AssociationProxyInstance.any().
          `method of' AssociationProxyInstance.

          Produce a proxied ‘any’ expression using EXISTS.

          This expression will be a composed product using the
          Comparator.any() and/or Comparator.has()
          operators of the underlying proxied attributes.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               any_ ()

          `inherited from the' ColumnOperators.any_().
          `method of' ColumnOperators.

          Produce a any_() clause against the parent object.

          This operator is only appropriate against a scalar subquery
          object, or for some backends an column expression that is
          against the ARRAY type, e.g.:

               # postgresql '5 = ANY (somearray)'
               expr = 5 == mytable.c.somearray.any_()

               # mysql '5 = ANY (SELECT value FROM table)'
               expr = 5 == select(table.c.value).scalar_subquery().any_()

          See also
          ........

          See any_(). - standalone version

          See all_(). - ALL operator

          New in version 1.1.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               asc ()

          `inherited from the' ColumnOperators.asc(). `method
          of' ColumnOperators.

          Produce a asc() clause against the parent object.

      -- Attribute:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               attr

          `inherited from the' AssociationProxyInstance.attr.
          `attribute of' AssociationProxyInstance.

          Return a tuple of ‘(local_attr, remote_attr)’.

          This attribute is convenient when specifying a join using
          Query.join() across two relationships:

               sess.query(Parent).join(*Parent.proxied.attr)

          See also
          ........

          See AssociationProxyInstance.local_attr.

          See AssociationProxyInstance.remote_attr.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               between (cleft, cright, symmetric=False)

          `inherited from the' ColumnOperators.between().
          `method of' ColumnOperators.

          Produce a between() clause against the parent
          object, given the lower and upper range.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               bool_op (opstring, precedence=0)

          `inherited from the' Operators.bool_op(). `method
          of' Operators.

          Return a custom boolean operator.

          This method is shorthand for calling Operators.op()
          and passing the Operators.op.is_comparison
          flag with True.

          See also
          ........

          See Operators.op().

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               collate (collation)

          `inherited from the' ColumnOperators.collate().
          `method of' ColumnOperators.

          Produce a collate() clause against the parent
          object, given the collation string.

          See also
          ........

          See collate().

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               concat (other)

          `inherited from the' ColumnOperators.concat().
          `method of' ColumnOperators.

          Implement the ‘concat’ operator.

          In a column context, produces the clause ‘a || b’, or uses the
          ‘concat()’ operator on MySQL.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               contains (other, **kwargs)

          `inherited from the' ColumnOperators.contains().
          `method of' ColumnOperators.

          Implement the ‘contains’ operator.

          Produces a LIKE expression that tests against a match for the
          middle of a string value:

               column LIKE '%' || <other> || '%'

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.contains("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.contains.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.contains.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.contains.autoescape flag is set to
               True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.contains("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE '%' || :param || '%' ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.contains("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE '%' || :param || '%' ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.contains.autoescape:

                    somecolumn.contains("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.startswith().

          See ColumnOperators.endswith().

          See ColumnOperators.like().

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               desc ()

          `inherited from the' ColumnOperators.desc().
          `method of' ColumnOperators.

          Produce a desc() clause against the parent object.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               distinct ()

          `inherited from the' ColumnOperators.distinct().
          `method of' ColumnOperators.

          Produce a distinct() clause against the parent
          object.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               endswith (other, **kwargs)

          `inherited from the' ColumnOperators.endswith().
          `method of' ColumnOperators.

          Implement the ‘endswith’ operator.

          Produces a LIKE expression that tests against a match for the
          end of a string value:

               column LIKE '%' || <other>

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.endswith("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.endswith.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.endswith.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.endswith.autoescape flag is set to
               True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.endswith("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE '%' || :param ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.endswith("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE '%' || :param ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.endswith.autoescape:

                    somecolumn.endswith("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.startswith().

          See ColumnOperators.contains().

          See ColumnOperators.like().

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               has (criterion=None, **kwargs)

          `inherited from the' AssociationProxyInstance.has().
          `method of' AssociationProxyInstance.

          Produce a proxied ‘has’ expression using EXISTS.

          This expression will be a composed product using the
          Comparator.any() and/or Comparator.has()
          operators of the underlying proxied attributes.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               ilike (other, escape=None)

          `inherited from the' ColumnOperators.ilike().
          `method of' ColumnOperators.

          Implement the ‘ilike’ operator, e.g.  case insensitive LIKE.

          In a column context, produces an expression either of the
          form:

               lower(a) LIKE lower(other)

          Or on backends that support the ILIKE operator:

               a ILIKE other

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.ilike("%foobar%"))

          Parameters:

             * ‘other’ – expression to be compared

             * ‘escape’ – optional escape character, renders the
               ‘ESCAPE’ keyword, e.g.:

                    somecolumn.ilike("foo/%bar", escape="/")

          See also
          ........

          See ColumnOperators.like().

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               in_ (other)

          `inherited from the' ColumnOperators.in_(). `method
          of' ColumnOperators.

          Implement the ‘in’ operator.

          In a column context, produces the clause ‘column IN <other>’.

          The given parameter ‘other’ may be:

             * A list of literal values, e.g.:

                    stmt.where(column.in_([1, 2, 3]))

               In this calling form, the list of items is converted to a
               set of bound parameters the same length as the list
               given:

                    WHERE COL IN (?, ?, ?)

             * A list of tuples may be provided if the comparison is
               against a tuple_() containing multiple
               expressions:

                    from sqlalchemy import tuple_
                    stmt.where(tuple_(col1, col2).in_([(1, 10), (2, 20), (3, 30)]))

             * An empty list, e.g.:

                    stmt.where(column.in_([]))

               In this calling form, the expression renders an “empty
               set” expression.  These expressions are tailored to
               individual backends and are generally trying to get an
               empty SELECT statement as a subquery.  Such as on SQLite,
               the expression is:

                    WHERE col IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)

               Changed in version 1.4: empty IN expressions now use an
               execution-time generated SELECT subquery in all cases.

             * A bound parameter, e.g.  see bindparam(), may be
               used if it includes the bindparam.expanding
               flag:

                    stmt.where(column.in_(bindparam('value', expanding=True)))

               In this calling form, the expression renders a special
               non-SQL placeholder expression that looks like:

                    WHERE COL IN ([EXPANDING_value])

               This placeholder expression is intercepted at statement
               execution time to be converted into the variable number
               of bound parameter form illustrated earlier.  If the
               statement were executed as:

                    connection.execute(stmt, {"value": [1, 2, 3]})

               The database would be passed a bound parameter for each
               value:

                    WHERE COL IN (?, ?, ?)

               New in version 1.2: added “expanding” bound parameters

               If an empty list is passed, a special “empty list”
               expression, which is specific to the database in use, is
               rendered.  On SQLite this would be:

                    WHERE COL IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)

               New in version 1.3: “expanding” bound parameters now
               support empty lists

             * a select() construct, which is usually a
               correlated scalar select:

                    stmt.where(
                        column.in_(
                            select(othertable.c.y).
                            where(table.c.x == othertable.c.x)
                        )
                    )

               In this calling form, see ColumnOperators.in_()
               renders as given:

                    WHERE COL IN (SELECT othertable.y
                    FROM othertable WHERE othertable.x = table.x)

          Parameters: ‘other’ – a list of literals, a select()
          construct, or a bindparam() construct that
          includes the bindparam.expanding flag set to True.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               is_ (other)

          `inherited from the' ColumnOperators.is_(). `method
          of' ColumnOperators.

          Implement the ‘IS’ operator.

          Normally, ‘IS’ is generated automatically when comparing to a
          value of ‘None’, which resolves to ‘NULL’.  However, explicit
          usage of ‘IS’ may be desirable if comparing to boolean values
          on certain platforms.

          See also
          ........

          See ColumnOperators.is_not().

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               is_distinct_from (other)

          `inherited from the' ColumnOperators.is_distinct_from().
          `method of' ColumnOperators.

          Implement the ‘IS DISTINCT FROM’ operator.

          Renders “a IS DISTINCT FROM b” on most platforms; on some such
          as SQLite may render “a IS NOT b”.

          New in version 1.1.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               is_not (other)

          `inherited from the' ColumnOperators.is_not().
          `method of' ColumnOperators.

          Implement the ‘IS NOT’ operator.

          Normally, ‘IS NOT’ is generated automatically when comparing
          to a value of ‘None’, which resolves to ‘NULL’.  However,
          explicit usage of ‘IS NOT’ may be desirable if comparing to
          boolean values on certain platforms.

          Changed in version 1.4: The ‘is_not()’ operator is renamed
          from ‘isnot()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.is_().

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               is_not_distinct_from (other)

          `inherited from the'
          ColumnOperators.is_not_distinct_from(). `method of'
          ColumnOperators.

          Implement the ‘IS NOT DISTINCT FROM’ operator.

          Renders “a IS NOT DISTINCT FROM b” on most platforms; on some
          such as SQLite may render “a IS b”.

          Changed in version 1.4: The ‘is_not_distinct_from()’ operator
          is renamed from ‘isnot_distinct_from()’ in previous releases.
          The previous name remains available for backwards
          compatibility.

          New in version 1.1.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               isnot (other)

          `inherited from the' ColumnOperators.isnot().
          `method of' ColumnOperators.

          Implement the ‘IS NOT’ operator.

          Normally, ‘IS NOT’ is generated automatically when comparing
          to a value of ‘None’, which resolves to ‘NULL’.  However,
          explicit usage of ‘IS NOT’ may be desirable if comparing to
          boolean values on certain platforms.

          Changed in version 1.4: The ‘is_not()’ operator is renamed
          from ‘isnot()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.is_().

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               isnot_distinct_from (other)

          `inherited from the'
          ColumnOperators.isnot_distinct_from(). `method of'
          ColumnOperators.

          Implement the ‘IS NOT DISTINCT FROM’ operator.

          Renders “a IS NOT DISTINCT FROM b” on most platforms; on some
          such as SQLite may render “a IS b”.

          Changed in version 1.4: The ‘is_not_distinct_from()’ operator
          is renamed from ‘isnot_distinct_from()’ in previous releases.
          The previous name remains available for backwards
          compatibility.

          New in version 1.1.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               like (other, escape=None)

          `inherited from the' ColumnOperators.like().
          `method of' ColumnOperators.

          Implement the ‘like’ operator.

          In a column context, produces the expression:

               a LIKE other

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.like("%foobar%"))

          Parameters:

             * ‘other’ – expression to be compared

             * ‘escape’ – optional escape character, renders the
               ‘ESCAPE’ keyword, e.g.:

                    somecolumn.like("foo/%bar", escape="/")

          See also
          ........

          See ColumnOperators.ilike().

      -- Attribute:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               local_attr

          `inherited from the'
          AssociationProxyInstance.local_attr. `attribute of'
          AssociationProxyInstance.

          The ‘local’ class attribute referenced by this
          AssociationProxyInstance.

          See also
          ........

          See AssociationProxyInstance.attr.

          See AssociationProxyInstance.remote_attr.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               match (other, **kwargs)

          `inherited from the' ColumnOperators.match().
          `method of' ColumnOperators.

          Implements a database-specific ‘match’ operator.

          ColumnOperators.match() attempts to resolve to a
          MATCH-like function or operator provided by the backend.
          Examples include:

             * PostgreSQL - renders ‘x @@ to_tsquery(y)’

             * MySQL - renders ‘MATCH (x) AGAINST (y IN BOOLEAN MODE)’

             * Oracle - renders ‘CONTAINS(x, y)’

             * other backends may provide special implementations.

             * Backends without any special implementation will emit the
               operator as “MATCH”.  This is compatible with SQLite, for
               example.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               not_ilike (other, escape=None)

          `inherited from the' ColumnOperators.not_ilike().
          `method of' ColumnOperators.

          implement the ‘NOT ILIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.ilike(), i.e.  ‘~x.ilike(y)’.

          Changed in version 1.4: The ‘not_ilike()’ operator is renamed
          from ‘notilike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.ilike().

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               not_in (other)

          `inherited from the' ColumnOperators.not_in().
          `method of' ColumnOperators.

          implement the ‘NOT IN’ operator.

          This is equivalent to using negation with
          ColumnOperators.in_(), i.e.  ‘~x.in_(y)’.

          In the case that ‘other’ is an empty sequence, the compiler
          produces an “empty not in” expression.  This defaults to the
          expression “1 = 1” to produce true in all cases.  The
          create_engine.empty_in_strategy may be used to alter
          this behavior.

          Changed in version 1.4: The ‘not_in()’ operator is renamed
          from ‘notin_()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          Changed in version 1.2: The ColumnOperators.in_()
          and ColumnOperators.not_in() operators now produce
          a “static” expression for an empty IN sequence by default.

          See also
          ........

          See ColumnOperators.in_().

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               not_like (other, escape=None)

          `inherited from the' ColumnOperators.not_like().
          `method of' ColumnOperators.

          implement the ‘NOT LIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.like(), i.e.  ‘~x.like(y)’.

          Changed in version 1.4: The ‘not_like()’ operator is renamed
          from ‘notlike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.like().

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               notilike (other, escape=None)

          `inherited from the' ColumnOperators.notilike().
          `method of' ColumnOperators.

          implement the ‘NOT ILIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.ilike(), i.e.  ‘~x.ilike(y)’.

          Changed in version 1.4: The ‘not_ilike()’ operator is renamed
          from ‘notilike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.ilike().

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               notin_ (other)

          `inherited from the' ColumnOperators.notin_().
          `method of' ColumnOperators.

          implement the ‘NOT IN’ operator.

          This is equivalent to using negation with
          ColumnOperators.in_(), i.e.  ‘~x.in_(y)’.

          In the case that ‘other’ is an empty sequence, the compiler
          produces an “empty not in” expression.  This defaults to the
          expression “1 = 1” to produce true in all cases.  The
          create_engine.empty_in_strategy may be used to alter
          this behavior.

          Changed in version 1.4: The ‘not_in()’ operator is renamed
          from ‘notin_()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          Changed in version 1.2: The ColumnOperators.in_()
          and ColumnOperators.not_in() operators now produce
          a “static” expression for an empty IN sequence by default.

          See also
          ........

          See ColumnOperators.in_().

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               notlike (other, escape=None)

          `inherited from the' ColumnOperators.notlike().
          `method of' ColumnOperators.

          implement the ‘NOT LIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.like(), i.e.  ‘~x.like(y)’.

          Changed in version 1.4: The ‘not_like()’ operator is renamed
          from ‘notlike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.like().

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               nulls_first ()

          `inherited from the' ColumnOperators.nulls_first().
          `method of' ColumnOperators.

          Produce a nulls_first() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_first()’ operator is
          renamed from ‘nullsfirst()’ in previous releases.  The
          previous name remains available for backwards compatibility.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               nulls_last ()

          `inherited from the' ColumnOperators.nulls_last().
          `method of' ColumnOperators.

          Produce a nulls_last() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_last()’ operator is renamed
          from ‘nullslast()’ in previous releases.  The previous name
          remains available for backwards compatibility.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               nullsfirst ()

          `inherited from the' ColumnOperators.nullsfirst().
          `method of' ColumnOperators.

          Produce a nulls_first() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_first()’ operator is
          renamed from ‘nullsfirst()’ in previous releases.  The
          previous name remains available for backwards compatibility.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               nullslast ()

          `inherited from the' ColumnOperators.nullslast().
          `method of' ColumnOperators.

          Produce a nulls_last() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_last()’ operator is renamed
          from ‘nullslast()’ in previous releases.  The previous name
          remains available for backwards compatibility.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               op (opstring, precedence=0, is_comparison=False,
               return_type=None)

          `inherited from the' Operators.op(). `method of'
          Operators.

          Produce a generic operator function.

          e.g.:

               somecolumn.op("*")(5)

          produces:

               somecolumn * 5

          This function can also be used to make bitwise operators
          explicit.  For example:

               somecolumn.op('&')(0xff)

          is a bitwise AND of the value in ‘somecolumn’.

          Parameters:

             * ‘operator’ – a string which will be output as the infix
               operator between this element and the expression passed
               to the generated function.

             * ‘precedence’ – precedence to apply to the operator, when
               parenthesizing expressions.  A lower number will cause
               the expression to be parenthesized when applied against
               another operator with higher precedence.  The default
               value of ‘0’ is lower than all operators except for the
               comma (‘,’) and ‘AS’ operators.  A value of 100 will be
               higher or equal to all operators, and -100 will be lower
               than or equal to all operators.

             * ‘is_comparison’ – if True, the operator will be
               considered as a “comparison” operator, that is which
               evaluates to a boolean true/false value, like ‘==’, ‘>’,
               etc.  This flag should be set so that ORM relationships
               can establish that the operator is a comparison operator
               when used in a custom join condition.

               New in version 0.9.2: - added the
               Operators.op.is_comparison flag.

             * ‘return_type’ – a TypeEngine class or object
               that will force the return type of an expression produced
               by this operator to be of that type.  By default,
               operators that specify Operators.op.is_comparison
               will resolve to Boolean, and those that
               do not will be of the same type as the left-hand operand.

          See also
          ........

          See Redefining and Creating New Operators.

          See Using custom operators in join conditions.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               operate (op, *other, **kwargs)

          Operate on an argument.

          This is the lowest level of operation, raises
          ‘NotImplementedError’ by default.

          Overriding this on a subclass can allow common behavior to be
          applied to all operations.  For example, overriding
          ColumnOperators to apply ‘func.lower()’ to the left and
          right side:

               class MyComparator(ColumnOperators):
                   def operate(self, op, other):
                       return op(func.lower(self), func.lower(other))

          Parameters:

             * ‘op’ – Operator callable.

             * ‘*other’ – the ‘other’ side of the operation.  Will be a
               single scalar for most operations.

             * ‘**kwargs’ – modifiers.  These may be passed by special
               operators such as ‘ColumnOperators.contains()’.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               regexp_match (pattern, flags=None)

          `inherited from the' ColumnOperators.regexp_match().
          `method of' ColumnOperators.

          Implements a database-specific ‘regexp match’ operator.

          E.g.:

               stmt = select(table.c.some_column).where(
                   table.c.some_column.regexp_match('^(b|c)')
               )

          ColumnOperators.regexp_match() attempts to resolve
          to a REGEXP-like function or operator provided by the backend,
          however the specific regular expression syntax and flags
          available are `not backend agnostic'.

          Examples include:

             * PostgreSQL - renders ‘x ~ y’ or ‘x !~ y’ when negated.

             * Oracle - renders ‘REGEXP_LIKE(x, y)’

             * SQLite - uses SQLite’s ‘REGEXP’ placeholder operator and
               calls into the Python ‘re.match()’ builtin.

             * other backends may provide special implementations.

             * Backends without any special implementation will emit the
               operator as “REGEXP” or “NOT REGEXP”.  This is compatible
               with SQLite and MySQL, for example.

          Regular expression support is currently implemented for
          Oracle, PostgreSQL, MySQL and MariaDB. Partial support is
          available for SQLite.  Support among third-party dialects may
          vary.

          Parameters:

             * ‘pattern’ – The regular expression pattern string or
               column clause.

             * ‘flags’ – Any regular expression string flags to apply.
               Flags tend to be backend specific.  It can be a string or
               a column clause.  Some backends, like PostgreSQL and
               MariaDB, may alternatively specify the flags as part of
               the pattern.  When using the ignore case flag ‘i’ in
               PostgreSQL, the ignore case regexp match operator ‘~*’ or
               ‘!~*’ will be used.

          New in version 1.4.

          See also
          ........

          See ColumnOperators.regexp_replace().

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               regexp_replace (pattern, replacement, flags=None)

          `inherited from the' ColumnOperators.regexp_replace().
          `method of' ColumnOperators.

          Implements a database-specific ‘regexp replace’ operator.

          E.g.:

               stmt = select(
                   table.c.some_column.regexp_replace(
                       'b(..)',
                       'X^AY',
                       flags='g'
                   )
               )

          ColumnOperators.regexp_replace() attempts to
          resolve to a REGEXP_REPLACE-like function provided by the
          backend, that usually emit the function ‘REGEXP_REPLACE()’.
          However, the specific regular expression syntax and flags
          available are `not backend agnostic'.

          Regular expression replacement support is currently
          implemented for Oracle, PostgreSQL, MySQL 8 or greater and
          MariaDB. Support among third-party dialects may vary.

          Parameters:

             * ‘pattern’ – The regular expression pattern string or
               column clause.

             * ‘pattern’ – The replacement string or column clause.

             * ‘flags’ – Any regular expression string flags to apply.
               Flags tend to be backend specific.  It can be a string or
               a column clause.  Some backends, like PostgreSQL and
               MariaDB, may alternatively specify the flags as part of
               the pattern.

          New in version 1.4.

          See also
          ........

          See ColumnOperators.regexp_match().

      -- Attribute:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               remote_attr

          `inherited from the'
          AssociationProxyInstance.remote_attr. `attribute of'
          AssociationProxyInstance.

          The ‘remote’ class attribute referenced by this
          AssociationProxyInstance.

          See also
          ........

          See AssociationProxyInstance.attr.

          See AssociationProxyInstance.local_attr.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               reverse_operate (op, other, **kwargs)

          `inherited from the' Operators.reverse_operate().
          `method of' Operators.

          Reverse operate on an argument.

          Usage is the same as operate().

      -- Attribute:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               scalar

          `inherited from the' AssociationProxyInstance.scalar.
          `attribute of' AssociationProxyInstance.

          Return ‘True’ if this AssociationProxyInstance
          proxies a scalar relationship on the local side.

      -- Method:
               sqlalchemy.ext.associationproxy.ColumnAssociationProxyInstance..
               startswith (other, **kwargs)

          `inherited from the' ColumnOperators.startswith().
          `method of' ColumnOperators.

          Implement the ‘startswith’ operator.

          Produces a LIKE expression that tests against a match for the
          start of a string value:

               column LIKE <other> || '%'

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.startswith("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.startswith.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.startswith.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.startswith.autoescape flag is set
               to True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.startswith("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE :param || '%' ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.startswith("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE :param || '%' ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.startswith.autoescape:

                    somecolumn.startswith("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.endswith().

          See ColumnOperators.contains().

          See ColumnOperators.like().

 -- Data: sqlalchemy.ext.associationproxy.ASSOCIATION_PROXY =
          symbol('ASSOCIATION_PROXY')

     Symbol indicating an InspectionAttr that’s

          of type AssociationProxy.

     Is assigned to the InspectionAttr.extension_type
     attribute.

3.7.3 Automap
-------------

Define an extension to the sqlalchemy.ext.declarative system
which automatically generates mapped classes and relationships from a
database schema, typically though not necessarily one which is
reflected.

New in version 0.9.1: Added sqlalchemy.ext.automap.

It is hoped that the AutomapBase system provides a quick and
modernized solution to the problem that the very famous SQLSoup(1) also
tries to solve, that of generating a quick and rudimentary object model
from an existing database on the fly.  By addressing the issue strictly
at the mapper configuration level, and integrating fully with existing
Declarative class techniques, see AutomapBase seeks to provide a
well-integrated approach to the issue of expediently auto-generating
ad-hoc mappings.

   ---------- Footnotes ----------

   (1) https://sqlsoup.readthedocs.io/en/latest/

3.7.3.1 Basic Use
.................

The simplest usage is to reflect an existing database into a new model.
We create a new AutomapBase class in a similar manner as to
how we create a declarative base class, using automap_base().
We then call AutomapBase.prepare() on the resulting base
class, asking it to reflect the schema and produce mappings:

     from sqlalchemy.ext.automap import automap_base
     from sqlalchemy.orm import Session
     from sqlalchemy import create_engine

     Base = automap_base()

     # engine, suppose it has two tables 'user' and 'address' set up
     engine = create_engine("sqlite:///mydatabase.db")

     # reflect the tables
     Base.prepare(engine, reflect=True)

     # mapped classes are now created with names by default
     # matching that of the table name.
     User = Base.classes.user
     Address = Base.classes.address

     session = Session(engine)

     # rudimentary relationships are produced
     session.add(Address(email_address="foo@bar.com", user=User(name="foo")))
     session.commit()

     # collection-based relationships are by default named
     # "<classname>_collection"
     print (u1.address_collection)

Above, calling AutomapBase.prepare() while passing along the
AutomapBase.prepare.reflect parameter indicates that the
MetaData.reflect() method will be called on this declarative
base classes’ MetaData collection; then, each `viable'
Table within the MetaData will get a new mapped class
generated automatically.  The ForeignKeyConstraint objects
which link the various tables together will be used to produce new,
bidirectional relationship() objects between classes.  The
classes and relationships follow along a default naming scheme that we
can customize.  At this point, our basic mapping consisting of related
‘User’ and ‘Address’ classes is ready to use in the traditional way.

     Note: By `viable', we mean that for a table to be mapped, it must
     specify a primary key.  Additionally, if the table is detected as
     being a pure association table between two other tables, it will
     not be directly mapped and will instead be configured as a
     many-to-many table between the mappings for the two referring
     tables.

3.7.3.2 Generating Mappings from an Existing MetaData
.....................................................

We can pass a pre-declared MetaData object to
automap_base().  This object can be constructed in any way,
including programmatically, from a serialized file, or from itself being
reflected using MetaData.reflect().  Below we illustrate a
combination of reflection and explicit table declaration:

     from sqlalchemy import create_engine, MetaData, Table, Column, ForeignKey
     from sqlalchemy.ext.automap import automap_base
     engine = create_engine("sqlite:///mydatabase.db")

     # produce our own MetaData object
     metadata = MetaData()

     # we can reflect it ourselves from a database, using options
     # such as 'only' to limit what tables we look at...
     metadata.reflect(engine, only=['user', 'address'])

     # ... or just define our own Table objects with it (or combine both)
     Table('user_order', metadata,
                     Column('id', Integer, primary_key=True),
                     Column('user_id', ForeignKey('user.id'))
                 )

     # we can then produce a set of mappings from this MetaData.
     Base = automap_base(metadata=metadata)

     # calling prepare() just sets up mapped classes and relationships.
     Base.prepare()

     # mapped classes are ready
     User, Address, Order = Base.classes.user, Base.classes.address,\
         Base.classes.user_order

3.7.3.3 Specifying Classes Explicitly
.....................................

The automap extension allows classes to be defined
explicitly, in a way similar to that of the DeferredReflection
class.  Classes that extend from AutomapBase act like
regular declarative classes, but are not immediately mapped after their
construction, and are instead mapped when we call
AutomapBase.prepare().  The AutomapBase.prepare()
method will make use of the classes we’ve established based on the table
name we use.  If our schema contains tables ‘user’ and ‘address’, we can
define one or both of the classes to be used:

     from sqlalchemy.ext.automap import automap_base
     from sqlalchemy import create_engine

     # automap base
     Base = automap_base()

     # pre-declare User for the 'user' table
     class User(Base):
         __tablename__ = 'user'

         # override schema elements like Columns
         user_name = Column('name', String)

         # override relationships too, if desired.
         # we must use the same name that automap would use for the
         # relationship, and also must refer to the class name that automap will
         # generate for "address"
         address_collection = relationship("address", collection_class=set)

     # reflect
     engine = create_engine("sqlite:///mydatabase.db")
     Base.prepare(engine, reflect=True)

     # we still have Address generated from the tablename "address",
     # but User is the same as Base.classes.User now

     Address = Base.classes.address

     u1 = session.query(User).first()
     print (u1.address_collection)

     # the backref is still there:
     a1 = session.query(Address).first()
     print (a1.user)

Above, one of the more intricate details is that we illustrated
overriding one of the relationship() objects that automap
would have created.  To do this, we needed to make sure the names match
up with what automap would normally generate, in that the relationship
name would be ‘User.address_collection’ and the name of the class
referred to, from automap’s perspective, is called ‘address’, even
though we are referring to it as ‘Address’ within our usage of this
class.

3.7.3.4 Overriding Naming Schemes
.................................

automap is tasked with producing mapped classes and
relationship names based on a schema, which means it has decision points
in how these names are determined.  These three decision points are
provided using functions which can be passed to the
AutomapBase.prepare() method, and are known as
classname_for_table(), name_for_scalar_relationship(),
and name_for_collection_relationship().  Any or all of these
functions are provided as in the example below, where we use a “camel
case” scheme for class names and a “pluralizer” for collection names
using the Inflect(1) package:

     import re
     import inflect

     def camelize_classname(base, tablename, table):
         "Produce a 'camelized' class name, e.g. "
         "'words_and_underscores' -> 'WordsAndUnderscores'"

         return str(tablename[0].upper() + \
                 re.sub(r'_([a-z])', lambda m: m.group(1).upper(), tablename[1:]))

     _pluralizer = inflect.engine()
     def pluralize_collection(base, local_cls, referred_cls, constraint):
         "Produce an 'uncamelized', 'pluralized' class name, e.g. "
         "'SomeTerm' -> 'some_terms'"

         referred_name = referred_cls.__name__
         uncamelized = re.sub(r'[A-Z]',
                              lambda m: "_%s" % m.group(0).lower(),
                              referred_name)[1:]
         pluralized = _pluralizer.plural(uncamelized)
         return pluralized

     from sqlalchemy.ext.automap import automap_base

     Base = automap_base()

     engine = create_engine("sqlite:///mydatabase.db")

     Base.prepare(engine, reflect=True,
                 classname_for_table=camelize_classname,
                 name_for_collection_relationship=pluralize_collection
         )

From the above mapping, we would now have classes ‘User’ and ‘Address’,
where the collection from ‘User’ to ‘Address’ is called
‘User.addresses’:

     User, Address = Base.classes.User, Base.classes.Address

     u1 = User(addresses=[Address(email="foo@bar.com")])

   ---------- Footnotes ----------

   (1) https://pypi.python.org/pypi/inflect

3.7.3.5 Relationship Detection
..............................

The vast majority of what automap accomplishes is the generation of
relationship() structures based on foreign keys.  The
mechanism by which this works for many-to-one and one-to-many
relationships is as follows:

  1. A given Table, known to be mapped to a particular class,
     is examined for ForeignKeyConstraint objects.

  2. From each ForeignKeyConstraint, the remote Table
     object present is matched up to the class to which it is to be
     mapped, if any, else it is skipped.

  3. As the ForeignKeyConstraint we are examining corresponds
     to a reference from the immediate mapped class, the relationship
     will be set up as a many-to-one referring to the referred class; a
     corresponding one-to-many backref will be created on the referred
     class referring to this class.

  4. If any of the columns that are part of the
     ForeignKeyConstraint are not nullable (e.g.
     ‘nullable=False’), a relationship.cascade keyword
     argument of ‘all, delete-orphan’ will be added to the keyword
     arguments to be passed to the relationship or backref.  If the
     ForeignKeyConstraint reports that
     ForeignKeyConstraint.ondelete is set to ‘CASCADE’ for a not
     null or ‘SET NULL’ for a nullable set of columns, the option
     relationship.passive_deletes flag is set to ‘True’ in the set
     of relationship keyword arguments.  Note that not all backends
     support reflection of ON DELETE.

     New in version 1.0.0: - automap will detect non-nullable foreign
     key constraints when producing a one-to-many relationship and
     establish a default cascade of ‘all, delete-orphan’ if so;
     additionally, if the constraint specifies
     ForeignKeyConstraint.ondelete of ‘CASCADE’ for non-nullable
     or ‘SET NULL’ for nullable columns, the ‘passive_deletes=True’
     option is also added.

  5. The names of the relationships are determined using the
     AutomapBase.prepare.name_for_scalar_relationship and
     AutomapBase.prepare.name_for_collection_relationship callable
     functions.  It is important to note that the default relationship
     naming derives the name from the `the actual class name'.  If
     you’ve given a particular class an explicit name by declaring it,
     or specified an alternate class naming scheme, that’s the name from
     which the relationship name will be derived.

  6. The classes are inspected for an existing mapped property matching
     these names.  If one is detected on one side, but none on the other
     side, see AutomapBase attempts to create a relationship on
     the missing side, then uses the relationship.back_populates
     parameter in order to point the new relationship to the other
     side.

  7. In the usual case where no relationship is on either side, see
     AutomapBase.prepare() produces a relationship() on
     the “many-to-one” side and matches it to the other using the
     relationship.backref parameter.

  8. Production of the relationship() and optionally the
     backref() is handed off to the
     AutomapBase.prepare.generate_relationship function, which can
     be supplied by the end-user in order to augment the arguments
     passed to relationship() or backref() or to
     make use of custom implementations of these functions.

3.7.3.6 Custom Relationship Arguments
.....................................

The AutomapBase.prepare.generate_relationship hook can be
used to add parameters to relationships.  For most cases, we can make
use of the existing generate_relationship() function to
return the object, after augmenting the given keyword dictionary with
our own arguments.

Below is an illustration of how to send relationship.cascade
and relationship.passive_deletes options along to all
one-to-many relationships:

     from sqlalchemy.ext.automap import generate_relationship

     def _gen_relationship(base, direction, return_fn,
                                     attrname, local_cls, referred_cls, **kw):
         if direction is interfaces.ONETOMANY:
             kw['cascade'] = 'all, delete-orphan'
             kw['passive_deletes'] = True
         # make use of the built-in function to actually return
         # the result.
         return generate_relationship(base, direction, return_fn,
                                      attrname, local_cls, referred_cls, **kw)

     from sqlalchemy.ext.automap import automap_base
     from sqlalchemy import create_engine

     # automap base
     Base = automap_base()

     engine = create_engine("sqlite:///mydatabase.db")
     Base.prepare(engine, reflect=True,
                 generate_relationship=_gen_relationship)

3.7.3.7 Many-to-Many relationships
..................................

automap will generate many-to-many relationships, e.g.  those
which contain a ‘secondary’ argument.  The process for producing these
is as follows:

  1. A given Table is examined for
     ForeignKeyConstraint objects, before any mapped class has been
     assigned to it.

  2. If the table contains two and exactly two
     ForeignKeyConstraint objects, and all columns within this
     table are members of these two ForeignKeyConstraint
     objects, the table is assumed to be a “secondary” table, and will
     `not be mapped directly'.

  3. The two (or one, for self-referential) external tables to which the
     Table refers to are matched to the classes to which they
     will be mapped, if any.

  4. If mapped classes for both sides are located, a many-to-many
     bi-directional relationship(). / see backref()
     pair is created between the two classes.

  5. The override logic for many-to-many works the same as that of
     one-to-many/ many-to-one; the generate_relationship()
     function is called upon to generate the structures and existing
     attributes will be maintained.

3.7.3.8 Relationships with Inheritance
......................................

automap will not generate any relationships between two
classes that are in an inheritance relationship.  That is, with two
classes given as follows:

     class Employee(Base):
         __tablename__ = 'employee'
         id = Column(Integer, primary_key=True)
         type = Column(String(50))
         __mapper_args__ = {
              'polymorphic_identity':'employee', 'polymorphic_on': type
         }

     class Engineer(Employee):
         __tablename__ = 'engineer'
         id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
         __mapper_args__ = {
             'polymorphic_identity':'engineer',
         }

The foreign key from ‘Engineer’ to ‘Employee’ is used not for a
relationship, but to establish joined inheritance between the two
classes.

Note that this means automap will not generate `any' relationships for
foreign keys that link from a subclass to a superclass.  If a mapping
has actual relationships from subclass to superclass as well, those need
to be explicit.  Below, as we have two separate foreign keys from
‘Engineer’ to ‘Employee’, we need to set up both the relationship we
want as well as the ‘inherit_condition’, as these are not things
SQLAlchemy can guess:

     class Employee(Base):
         __tablename__ = 'employee'
         id = Column(Integer, primary_key=True)
         type = Column(String(50))

         __mapper_args__ = {
             'polymorphic_identity':'employee', 'polymorphic_on':type
         }

     class Engineer(Employee):
         __tablename__ = 'engineer'
         id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
         favorite_employee_id = Column(Integer, ForeignKey('employee.id'))

         favorite_employee = relationship(Employee,
                                          foreign_keys=favorite_employee_id)

         __mapper_args__ = {
             'polymorphic_identity':'engineer',
             'inherit_condition': id == Employee.id
         }

3.7.3.9 Handling Simple Naming Conflicts
........................................

In the case of naming conflicts during mapping, override any of
classname_for_table(), name_for_scalar_relationship(),
and name_for_collection_relationship() as needed.  For
example, if automap is attempting to name a many-to-one relationship the
same as an existing column, an alternate convention can be conditionally
selected.  Given a schema:

     CREATE TABLE table_a (
         id INTEGER PRIMARY KEY
     );

     CREATE TABLE table_b (
         id INTEGER PRIMARY KEY,
         table_a INTEGER,
         FOREIGN KEY(table_a) REFERENCES table_a(id)
     );

The above schema will first automap the ‘table_a’ table as a class named
‘table_a’; it will then automap a relationship onto the class for
‘table_b’ with the same name as this related class, e.g.  ‘table_a’.
This relationship name conflicts with the mapping column
‘table_b.table_a’, and will emit an error on mapping.

We can resolve this conflict by using an underscore as follows:

     def name_for_scalar_relationship(base, local_cls, referred_cls, constraint):
         name = referred_cls.__name__.lower()
         local_table = local_cls.__table__
         if name in local_table.columns:
             newname = name + "_"
             warnings.warn(
                 "Already detected name %s present.  using %s" %
                 (name, newname))
             return newname
         return name

     Base.prepare(engine, reflect=True,
         name_for_scalar_relationship=name_for_scalar_relationship)

Alternatively, we can change the name on the column side.  The columns
that are mapped can be modified using the technique described at
Naming Columns Distinctly from Attribute Names, by assigning the
column explicitly to a new name:

     Base = automap_base()

     class TableB(Base):
         __tablename__ = 'table_b'
         _table_a = Column('table_a', ForeignKey('table_a.id'))

     Base.prepare(engine, reflect=True)

3.7.3.10 Using Automap with Explicit Declarations
.................................................

As noted previously, automap has no dependency on reflection, and can
make use of any collection of Table objects within a
MetaData collection.  From this, it follows that automap can also
be used generate missing relationships given an otherwise complete model
that fully defines table metadata:

     from sqlalchemy.ext.automap import automap_base
     from sqlalchemy import Column, Integer, String, ForeignKey

     Base = automap_base()

     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         name = Column(String)

     class Address(Base):
         __tablename__ = 'address'

         id = Column(Integer, primary_key=True)
         email = Column(String)
         user_id = Column(ForeignKey('user.id'))

     # produce relationships
     Base.prepare()

     # mapping is complete, with "address_collection" and
     # "user" relationships
     a1 = Address(email='u1')
     a2 = Address(email='u2')
     u1 = User(address_collection=[a1, a2])
     assert a1.user is u1

Above, given mostly complete ‘User’ and ‘Address’ mappings, the
ForeignKey which we defined on ‘Address.user_id’ allowed a
bidirectional relationship pair ‘Address.user’ and
‘User.address_collection’ to be generated on the mapped classes.

Note that when subclassing AutomapBase, the
AutomapBase.prepare() method is required; if not called, the
classes we’ve declared are in an un-mapped state.

3.7.3.11 Intercepting Column Definitions
........................................

The MetaData and Table objects support an event
hook DDLEvents.column_reflect() that may be used to
intercept the information reflected about a database column before the
Column object is constructed.  For example if we wanted to
map columns using a naming convention such as ‘"attr_<columnname>"’, the
event could be applied as:

     @event.listens_for(Base.metadata, "column_reflect")
     def column_reflect(inspector, table, column_info):
         # set column.key = "attr_<lower_case_name>"
         column_info['key'] = "attr_%s" % column_info['name'].lower()

     # run reflection
     Base.prepare(engine, reflect=True)

New in version 1.4.0b2: the DDLEvents.column_reflect() event
may be applied to a MetaData object.

See also
........

See DDLEvents.column_reflect().

See Automating Column Naming Schemes from Reflected Tables. - in
the ORM mapping documentation

3.7.3.12 API Reference
......................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See automap_base.([declarative_base],Produce a declarative automap base.
**kw)

See AutomapBase.Base class for an “automap” schema.

See classname_for_table.(base,Return the class name that should be used, given the name of a table.
tablename,
table)

See generate_relationship.(base,Generate a relationship() or backref() on behalf of two mapped
direction,     classes.
return_fn,
attrname,
..., **kw)

See name_for_collection_relationship.(base,Return the attribute name that should be used to refer from one class to another, for a
local_cls,     collection reference.
referred_cls,
constraint)

See name_for_scalar_relationship.(base,Return the attribute name that should be used to refer from one class to another, for a
local_cls,     scalar object reference.
referred_cls,
constraint)

 -- Function: sqlalchemy.ext.automap.automap_base
          (declarative_base=None, **kw)

     Produce a declarative automap base.

     This function produces a new base class that is a product of the
     AutomapBase class as well a declarative base produced
     by ‘declarative_base()’.

     All parameters other than ‘declarative_base’ are keyword arguments
     that are passed directly to the ‘declarative_base()’ function.

     Parameters:

        * ‘declarative_base’ – an existing class produced by
          ‘declarative_base()’.  When this is passed, the function no
          longer invokes ‘declarative_base()’ itself, and all other
          keyword arguments are ignored.

        * ‘**kw’ – keyword arguments are passed along to
          ‘declarative_base()’.

 -- Class: sqlalchemy.ext.automap.AutomapBase

     Base class for an “automap” schema.

     The AutomapBase class can be compared to the
     “declarative base” class that is produced by the
     ‘declarative_base()’ function.  In practice, the AutomapBase
     class is always used as a mixin along with an actual
     declarative base.

     A new subclassable AutomapBase is typically
     instantiated using the automap_base() function.

     See also
     ........

     See Automap.

      -- Attribute: sqlalchemy.ext.automap.AutomapBase..
               classes = None

          An instance of ‘Properties’ containing classes.

          This object behaves much like the ‘.c’ collection on a table.
          Classes are present under the name they were given, e.g.:

               Base = automap_base()
               Base.prepare(engine=some_engine, reflect=True)

               User, Address = Base.classes.User, Base.classes.Address

      -- Method: sqlalchemy.ext.automap.AutomapBase..
               classmethod prepare (autoload_with=None, engine=None,
               reflect=False, schema=None, classname_for_table=None,
               collection_class=None, name_for_scalar_relationship=None,
               name_for_collection_relationship=None,
               generate_relationship=None, reflection_options={})

          Extract mapped classes and relationships from the
          MetaData and perform mappings.

          Parameters:

             * ‘engine’ – an Engine or Connection
               with which to perform schema reflection, if
               specified.  If the AutomapBase.prepare.reflect
               argument is False, this object is not used.

               Deprecated since version 1.4: The
               AutomapBase.prepare.engine parameter is deprecated
               and will be removed in a future release.  Please use the
               AutomapBase.prepare.autoload_with parameter.

             * ‘reflect’ – if True, the MetaData.reflect().
               method is called on the MetaData associated
               with this AutomapBase.  The Engine
               passed via AutomapBase.prepare.engine will be
               used to perform the reflection if present; else, the
               MetaData should already be bound to some
               engine else the operation will fail.

               Deprecated since version 1.4: The
               AutomapBase.prepare.reflect parameter is deprecated
               and will be removed in a future release.  Reflection is
               enabled when AutomapBase.prepare.autoload_with
               is passed.

             * ‘classname_for_table’ – callable function which will be
               used to produce new class names, given a table name.
               Defaults to classname_for_table().

             * ‘name_for_scalar_relationship’ – callable function which
               will be used to produce relationship names for scalar
               relationships.  Defaults to
               name_for_scalar_relationship().

             * ‘name_for_collection_relationship’ – callable function
               which will be used to produce relationship names for
               collection-oriented relationships.  Defaults to
               name_for_collection_relationship().

             * ‘generate_relationship’ – callable function which will be
               used to actually generate relationship() and
               backref() constructs.  Defaults to
               generate_relationship().

             * ‘collection_class’ – the Python collection class that
               will be used when a new relationship() object
               is created that represents a collection.  Defaults to
               ‘list’.

             * ‘schema’ – When present in conjunction with the
               AutomapBase.prepare.reflect flag, is passed to
               MetaData.reflect() to indicate the primary
               schema where tables should be reflected from.  When
               omitted, the default schema in use by the database
               connection is used.

               New in version 1.1.

             * ‘reflection_options’ – When present, this dictionary of
               options will be passed to MetaData.reflect()
               to supply general reflection-specific options like ‘only’
               and/or dialect-specific options like
               ‘oracle_resolve_synonyms’.

               New in version 1.4.

 -- Function: sqlalchemy.ext.automap.classname_for_table (base,
          tablename, table)

     Return the class name that should be used, given the name of a
     table.

     The default implementation is:

          return str(tablename)

     Alternate implementations can be specified using the
     AutomapBase.prepare.classname_for_table parameter.

     Parameters:

        * ‘base’ – the AutomapBase class doing the prepare.

        * ‘tablename’ – string name of the Table.

        * ‘table’ – the Table object itself.

     Returns:

     a string class name.

          Note: In Python 2, the string used for the class name `must'
          be a non-Unicode object, e.g.  a ‘str()’ object.  The ‘.name’
          attribute of Table is typically a Python unicode
          subclass, so the ‘str()’ function should be applied to this
          name, after accounting for any non-ASCII characters.

 -- Function: sqlalchemy.ext.automap.name_for_scalar_relationship (base,
          local_cls, referred_cls, constraint)

     Return the attribute name that should be used to refer from one
     class to another, for a scalar object reference.

     The default implementation is:

          return referred_cls.__name__.lower()

     Alternate implementations can be specified using the
     AutomapBase.prepare.name_for_scalar_relationship parameter.

     Parameters:

        * ‘base’ – the AutomapBase class doing the prepare.

        * ‘local_cls’ – the class to be mapped on the local side.

        * ‘referred_cls’ – the class to be mapped on the referring side.

        * ‘constraint’ – the ForeignKeyConstraint that is
          being inspected to produce this relationship.

 -- Function: sqlalchemy.ext.automap.name_for_collection_relationship
          (base, local_cls, referred_cls, constraint)

     Return the attribute name that should be used to refer from one
     class to another, for a collection reference.

     The default implementation is:

          return referred_cls.__name__.lower() + "_collection"

     Alternate implementations can be specified using the
     AutomapBase.prepare.name_for_collection_relationship
     parameter.

     Parameters:

        * ‘base’ – the AutomapBase class doing the prepare.

        * ‘local_cls’ – the class to be mapped on the local side.

        * ‘referred_cls’ – the class to be mapped on the referring side.

        * ‘constraint’ – the ForeignKeyConstraint that is
          being inspected to produce this relationship.

 -- Function: sqlalchemy.ext.automap.generate_relationship (base,
          direction, return_fn, attrname, local_cls, referred_cls, **kw)

     Generate a relationship() or backref() on
     behalf of two mapped classes.

     An alternate implementation of this function can be specified using
     the AutomapBase.prepare.generate_relationship
     parameter.

     The default implementation of this function is as follows:

          if return_fn is backref:
              return return_fn(attrname, **kw)
          elif return_fn is relationship:
              return return_fn(referred_cls, **kw)
          else:
              raise TypeError("Unknown relationship function: %s" % return_fn)

     Parameters:

        * ‘base’ – the AutomapBase class doing the prepare.

        * ‘direction’ – indicate the “direction” of the relationship;
          this will be one of ONETOMANY, MANYTOONE,
          see MANYTOMANY.

        * ‘return_fn’ – the function that is used by default to create
          the relationship.  This will be either relationship()
          or backref().  The backref()
          function’s result will be used to produce a new
          relationship() in a second step, so it is critical that
          user-defined implementations correctly differentiate between
          the two functions, if a custom relationship function is being
          used.

        * ‘attrname’ – the attribute name to which this relationship is
          being assigned.  If the value of
          generate_relationship.return_fn is the backref()
          function, then this name is the name that is being
          assigned to the backref.

        * ‘local_cls’ – the “local” class to which this relationship or
          backref will be locally present.

        * ‘referred_cls’ – the “referred” class to which the
          relationship or backref refers to.

        * ‘**kw’ – all additional keyword arguments are passed along to
          the function.

     Returns: a relationship() or backref()
     construct, as dictated by the
     generate_relationship.return_fn parameter.

3.7.4 Baked Queries
-------------------

‘baked’ provides an alternative creational pattern for ‘Query’ objects,
which allows for caching of the object’s construction and
string-compilation steps.  This means that for a particular ‘Query’
building scenario that is used more than once, all of the Python
function invocation involved in building the query from its initial
construction up through generating a SQL string will only occur `once',
rather than for each time that query is built up and executed.

The rationale for this system is to greatly reduce Python interpreter
overhead for everything that occurs `before the SQL is emitted'.  The
caching of the “baked” system does `not' in any way reduce SQL calls or
cache the `return results' from the database.  A technique that
demonstrates the caching of the SQL calls and result sets themselves is
available in Dogpile Caching.

Deprecated since version 1.4: SQLAlchemy 1.4 and 2.0 feature an all-new
direct query caching system that removes the need for the
BakedQuery system.  Caching is now transparently active for all
Core and ORM queries with no action taken by the user, using the system
described at SQL Compilation Caching.

     deepalchemy: The sqlalchemy.ext.baked extension is `not
     for beginners'.  Using it correctly requires a good high level
     understanding of how SQLAlchemy, the database driver, and the
     backend database interact with each other.  This extension presents
     a very specific kind of optimization that is not ordinarily needed.
     As noted above, it `does not cache queries', only the string
     formulation of the SQL itself.

3.7.4.1 Synopsis
................

Usage of the baked system starts by producing a so-called “bakery”,
which represents storage for a particular series of query objects:

     from sqlalchemy.ext import baked

     bakery = baked.bakery()

The above “bakery” will store cached data in an LRU cache that defaults
to 200 elements, noting that an ORM query will typically contain one
entry for the ORM query as invoked, as well as one entry per database
dialect for the SQL string.

The bakery allows us to build up a ‘Query’ object by specifying its
construction as a series of Python callables, which are typically
lambdas.  For succinct usage, it overrides the ‘+=’ operator so that a
typical query build-up looks like the following:

     from sqlalchemy import bindparam

     def search_for_user(session, username, email=None):

         baked_query = bakery(lambda session: session.query(User))
         baked_query += lambda q: q.filter(User.name == bindparam('username'))

         baked_query += lambda q: q.order_by(User.id)

         if email:
             baked_query += lambda q: q.filter(User.email == bindparam('email'))

         result = baked_query(session).params(username=username, email=email).all()

         return result

Following are some observations about the above code:

  1. The ‘baked_query’ object is an instance of BakedQuery.
     This object is essentially the “builder” for a real orm ‘Query’
     object, but it is not itself the `actual' ‘Query’ object.

  2. The actual ‘Query’ object is not built at all, until the very end
     of the function when Result.all() is called.

  3. The steps that are added to the ‘baked_query’ object are all
     expressed as Python functions, typically lambdas.  The first lambda
     given to the bakery() function receives a
     Session as its argument.  The remaining lambdas each receive a
     ‘Query’ as their argument.

  4. In the above code, even though our application may call upon
     ‘search_for_user()’ many times, and even though within each
     invocation we build up an entirely new BakedQuery
     object, `all of the lambdas are only called once'.  Each lambda is
     `never' called a second time for as long as this query is cached in
     the bakery.

  5. The caching is achieved by storing references to the `lambda
     objects themselves' in order to formulate a cache key; that is, the
     fact that the Python interpreter assigns an in-Python identity to
     these functions is what determines how to identify the query on
     successive runs.  For those invocations of ‘search_for_user()’
     where the ‘email’ parameter is specified, the callable ‘lambda q:
     q.filter(User.email == bindparam('email'))’ will be part of the
     cache key that’s retrieved; when ‘email’ is ‘None’, this callable
     is not part of the cache key.

  6. Because the lambdas are all called only once, it is essential that
     no variables which may change across calls are referenced `within'
     the lambdas; instead, assuming these are values to be bound into
     the SQL string, we use bindparam() to construct named
     parameters, where we apply their actual values later using
     Result.params().

3.7.4.2 Performance
...................

The baked query probably looks a little odd, a little bit awkward and a
little bit verbose.  However, the savings in Python performance for a
query which is invoked lots of times in an application are very
dramatic.  The example suite ‘short_selects’ demonstrated in
Performance illustrates a comparison of queries which each return
only one row, such as the following regular query:

     session = Session(bind=engine)
     for id_ in random.sample(ids, n):
         session.query(Customer).filter(Customer.id == id_).one()

compared to the equivalent “baked” query:

     bakery = baked.bakery()
     s = Session(bind=engine)
     for id_ in random.sample(ids, n):
         q = bakery(lambda s: s.query(Customer))
         q += lambda q: q.filter(Customer.id == bindparam('id'))
         q(s).params(id=id_).one()

The difference in Python function call count for an iteration of 10000
calls to each block are:

     test_baked_query : test a baked query of the full entity.
                        (10000 iterations); total fn calls 1951294

     test_orm_query :   test a straight ORM query of the full entity.
                        (10000 iterations); total fn calls 7900535

In terms of number of seconds on a powerful laptop, this comes out as:

     test_baked_query : test a baked query of the full entity.
                        (10000 iterations); total time 2.174126 sec

     test_orm_query :   test a straight ORM query of the full entity.
                        (10000 iterations); total time 7.958516 sec

Note that this test very intentionally features queries that only return
one row.  For queries that return many rows, the performance advantage
of the baked query will have less and less of an impact, proportional to
the time spent fetching rows.  It is critical to keep in mind that the
`baked query feature only applies to building the query itself, not the
fetching of results'.  Using the baked feature is by no means a
guarantee to a much faster application; it is only a potentially useful
feature for those applications that have been measured as being impacted
by this particular form of overhead.

Measure twice, cut once
.......................

For background on how to profile a SQLAlchemy application, please see
the section Performance.  It is essential that performance
measurement techniques are used when attempting to improve the
performance of an application.

3.7.4.3 Rationale
.................

The “lambda” approach above is a superset of what would be a more
traditional “parameterized” approach.  Suppose we wished to build a
simple system where we build a ‘Query’ just once, then store it in a
dictionary for re-use.  This is possible right now by just building up
the query, and removing its Session by calling
‘my_cached_query = query.with_session(None)’:

     my_simple_cache = {}

     def lookup(session, id_argument):
         if "my_key" not in my_simple_cache:
             query = session.query(Model).filter(Model.id == bindparam('id'))
             my_simple_cache["my_key"] = query.with_session(None)
         else:
             query = my_simple_cache["my_key"].with_session(session)

         return query.params(id=id_argument).all()

The above approach gets us a very minimal performance benefit.  By
re-using a ‘Query’, we save on the Python work within the
‘session.query(Model)’ constructor as well as calling upon
‘filter(Model.id == bindparam('id'))’, which will skip for us the
building up of the Core expression as well as sending it to
Query.filter().  However, the approach still regenerates the full
Select object every time when Query.all() is
called and additionally this brand new Select is sent off to
the string compilation step every time, which for a simple case like the
above is probably about 70% of the overhead.

To reduce the additional overhead, we need some more specialized logic,
some way to memoize the construction of the select object and the
construction of the SQL. There is an example of this on the wiki in the
section BakedQuery(1), a precursor to this feature, however in that
system, we aren’t caching the `construction' of the query.  In order to
remove all the overhead, we need to cache both the construction of the
query as well as the SQL compilation.  Let’s assume we adapted the
recipe in this way and made ourselves a method ‘.bake()’ that
pre-compiles the SQL for the query, producing a new object that can be
invoked with minimal overhead.  Our example becomes:

     my_simple_cache = {}

     def lookup(session, id_argument):

         if "my_key" not in my_simple_cache:
             query = session.query(Model).filter(Model.id == bindparam('id'))
             my_simple_cache["my_key"] = query.with_session(None).bake()
         else:
             query = my_simple_cache["my_key"].with_session(session)

         return query.params(id=id_argument).all()

Above, we’ve fixed the performance situation, but we still have this
string cache key to deal with.

We can use the “bakery” approach to re-frame the above in a way that
looks less unusual than the “building up lambdas” approach, and more
like a simple improvement upon the simple “reuse a query” approach:

     bakery = baked.bakery()

     def lookup(session, id_argument):
         def create_model_query(session):
             return session.query(Model).filter(Model.id == bindparam('id'))

         parameterized_query = bakery.bake(create_model_query)
         return parameterized_query(session).params(id=id_argument).all()

Above, we use the “baked” system in a manner that is very similar to the
simplistic “cache a query” system.  However, it uses two fewer lines of
code, does not need to manufacture a cache key of “my_key”, and also
includes the same feature as our custom “bake” function that caches 100%
of the Python invocation work from the constructor of the query, to the
filter call, to the production of the Select object, to the
string compilation step.

From the above, if we ask ourselves, “what if lookup needs to make
conditional decisions as to the structure of the query?”, this is where
hopefully it becomes apparent why “baked” is the way it is.  Instead of
a parameterized query building off from exactly one function (which is
how we thought baked might work originally), we can build it from `any
number' of functions.  Consider our naive example, if we needed to have
an additional clause in our query on a conditional basis:

     my_simple_cache = {}

     def lookup(session, id_argument, include_frobnizzle=False):
         if include_frobnizzle:
             cache_key = "my_key_with_frobnizzle"
         else:
             cache_key = "my_key_without_frobnizzle"

         if cache_key not in my_simple_cache:
             query = session.query(Model).filter(Model.id == bindparam('id'))
             if include_frobnizzle:
                 query = query.filter(Model.frobnizzle == True)

             my_simple_cache[cache_key] = query.with_session(None).bake()
         else:
             query = my_simple_cache[cache_key].with_session(session)

         return query.params(id=id_argument).all()

Our “simple” parameterized system must now be tasked with generating
cache keys which take into account whether or not the
“include_frobnizzle” flag was passed, as the presence of this flag means
that the generated SQL would be entirely different.  It should be
apparent that as the complexity of query building goes up, the task of
caching these queries becomes burdensome very quickly.  We can convert
the above example into a direct use of “bakery” as follows:

     bakery = baked.bakery()

     def lookup(session, id_argument, include_frobnizzle=False):
         def create_model_query(session):
             return session.query(Model).filter(Model.id == bindparam('id'))

         parameterized_query = bakery.bake(create_model_query)

         if include_frobnizzle:
             def include_frobnizzle_in_query(query):
                 return query.filter(Model.frobnizzle == True)

             parameterized_query = parameterized_query.with_criteria(
                 include_frobnizzle_in_query)

         return parameterized_query(session).params(id=id_argument).all()

Above, we again cache not just the query object but all the work it
needs to do in order to generate SQL. We also no longer need to deal
with making sure we generate a cache key that accurately takes into
account all of the structural modifications we’ve made; this is now
handled automatically and without the chance of mistakes.

This code sample is a few lines shorter than the naive example, removes
the need to deal with cache keys, and has the vast performance benefits
of the full so-called “baked” feature.  But still a little verbose!
Hence we take methods like BakedQuery.add_criteria() and
BakedQuery.with_criteria() and shorten them into operators,
and encourage (though certainly not require!)  using simple lambdas,
only as a means to reduce verbosity:

     bakery = baked.bakery()

     def lookup(session, id_argument, include_frobnizzle=False):
         parameterized_query = bakery.bake(
             lambda s: s.query(Model).filter(Model.id == bindparam('id'))
           )

         if include_frobnizzle:
             parameterized_query += lambda q: q.filter(Model.frobnizzle == True)

         return parameterized_query(session).params(id=id_argument).all()

Where above, the approach is simpler to implement and much more similar
in code flow to what a non-cached querying function would look like,
hence making code easier to port.

The above description is essentially a summary of the design process
used to arrive at the current “baked” approach.  Starting from the
“normal” approaches, the additional issues of cache key construction and
management, removal of all redundant Python execution, and queries built
up with conditionals needed to be addressed, leading to the final
approach.

   ---------- Footnotes ----------

   (1)
https://bitbucket.org/zzzeek/sqlalchemy/wiki/UsageRecipes/BakedQuery

3.7.4.4 Special Query Techniques
................................

This section will describe some techniques for specific query
situations.

3.7.4.5 Using IN expressions
............................

The ColumnOperators.in_() method in SQLAlchemy historically
renders a variable set of bound parameters based on the list of items
that’s passed to the method.  This doesn’t work for baked queries as the
length of that list can change on different calls.  To solve this
problem, the bindparam.expanding parameter supports a
late-rendered IN expression that is safe to be cached inside of baked
query.  The actual list of elements is rendered at statement execution
time, rather than at statement compilation time:

     bakery = baked.bakery()

     baked_query = bakery(lambda session: session.query(User))
     baked_query += lambda q: q.filter(
       User.name.in_(bindparam('username', expanding=True)))

     result = baked_query.with_session(session).params(
       username=['ed', 'fred']).all()

See also
........

See bindparam.expanding.

See ColumnOperators.in_().

3.7.4.6 Using Subqueries
........................

When using Query objects, it is often needed that one
Query object is used to generate a subquery within another.  In
the case where the Query is currently in baked form, an
interim method may be used to retrieve the Query object,
using the BakedQuery.to_query() method.  This method is
passed the Session or Query that is the argument
to the lambda callable used to generate a particular step of the baked
query:

     bakery = baked.bakery()

     # a baked query that will end up being used as a subquery
     my_subq = bakery(lambda s: s.query(User.id))
     my_subq += lambda q: q.filter(User.id == Address.user_id)

     # select a correlated subquery in the top columns list,
     # we have the "session" argument, pass that
     my_q = bakery(
       lambda s: s.query(Address.id, my_subq.to_query(s).as_scalar()))

     # use a correlated subquery in some of the criteria, we have
     # the "query" argument, pass that.
     my_q += lambda q: q.filter(my_subq.to_query(q).exists())

New in version 1.3.

3.7.4.7 Using the before_compile event
......................................

As of SQLAlchemy 1.3.11, the use of the
QueryEvents.before_compile() event against a particular
Query will disallow the baked query system from caching the query,
if the event hook returns a new Query object that is
different from the one passed in.  This is so that the
QueryEvents.before_compile() hook may be invoked against a
particular Query every time it is used, to accommodate for
hooks that alter the query differently each time.  To allow a
QueryEvents.before_compile() to alter a
sqlalchemy.orm.Query() object, but still to allow the result to be
cached, the event can be registered passing the ‘bake_ok=True’ flag:

     @event.listens_for(
         Query, "before_compile", retval=True, bake_ok=True)
     def my_event(query):
         for desc in query.column_descriptions:
             if desc['type'] is User:
                 entity = desc['entity']
                 query = query.filter(entity.deleted == False)
         return query

The above strategy is appropriate for an event that will modify a given
Query in exactly the same way every time, not dependent on
specific parameters or external state that changes.

New in version 1.3.11: - added the “bake_ok” flag to the
QueryEvents.before_compile() event and disallowed caching via the
“baked” extension from occurring for event handlers that return a new
Query object if this flag is not set.

3.7.4.8 Disabling Baked Queries Session-wide
............................................

The flag Session.enable_baked_queries may be set to False,
causing all baked queries to not use the cache when used against that
Session:

     session = Session(engine, enable_baked_queries=False)

Like all session flags, it is also accepted by factory objects like
sessionmaker and methods like
sessionmaker.configure().

The immediate rationale for this flag is so that an application which is
seeing issues potentially due to cache key conflicts from user-defined
baked queries or other baked query issues can turn the behavior off, in
order to identify or eliminate baked queries as the cause of an issue.

New in version 1.2.

3.7.4.9 Lazy Loading Integration
................................

Changed in version 1.4: As of SQLAlchemy 1.4, the “baked query” system
is no longer part of the relationship loading system.  The native caching
system is used instead.

3.7.4.10 API Documentation
..........................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See BakedQuery.A builder object for ‘Query’ objects.

See bakery.Construct a new bakery.

See Bakery.Callable which returns a BakedQuery.

See Result.Invokes a BakedQuery against a Session.

 -- Function: sqlalchemy.ext.baked.bakery (size=200, _size_alert=None)

     Construct a new bakery.

     Returns: an instance of Bakery.

 -- Class: sqlalchemy.ext.baked.BakedQuery (bakery, initial_fn, args=())

     A builder object for ‘Query’ objects.

      -- Method: sqlalchemy.ext.baked.BakedQuery..
               add_criteria (fn, *args)

          Add a criteria function to this BakedQuery.

          This is equivalent to using the ‘+=’ operator to modify a
          BakedQuery in-place.

      -- Method: sqlalchemy.ext.baked.BakedQuery..classmethod
               bakery (size=200, _size_alert=None)

          Construct a new bakery.

          Returns: an instance of Bakery.

      -- Method: sqlalchemy.ext.baked.BakedQuery..for_session
               (session)

          Return a Result object for this BakedQuery.

          This is equivalent to calling the BakedQuery as a
          Python callable, e.g.  ‘result = my_baked_query(session)’.

      -- Method: sqlalchemy.ext.baked.BakedQuery..spoil
               (full=False)

          Cancel any query caching that will occur on this BakedQuery
          object.

          The BakedQuery can continue to be used normally, however
          additional creational functions will not be cached; they will
          be called on every invocation.

          This is to support the case where a particular step in
          constructing a baked query disqualifies the query from being
          cacheable, such as a variant that relies upon some uncacheable
          value.

          Parameters: ‘full’ – if False, only functions added to this
          BakedQuery object subsequent to the spoil step
          will be non-cached; the state of the BakedQuery up
          until this point will be pulled from the cache.  If True, then
          the entire Query object is built from scratch each
          time, with all creational functions being called on each
          invocation.

      -- Method: sqlalchemy.ext.baked.BakedQuery..to_query
               (query_or_session)

          Return the Query object for use as a subquery.

          This method should be used within the lambda callable being
          used to generate a step of an enclosing BakedQuery.
          The parameter should normally be the Query object
          that is passed to the lambda:

               sub_bq = self.bakery(lambda s: s.query(User.name))
               sub_bq += lambda q: q.filter(
                   User.id == Address.user_id).correlate(Address)

               main_bq = self.bakery(lambda s: s.query(Address))
               main_bq += lambda q: q.filter(
                   sub_bq.to_query(q).exists())

          In the case where the subquery is used in the first callable
          against a Session, the Session is also
          accepted:

               sub_bq = self.bakery(lambda s: s.query(User.name))
               sub_bq += lambda q: q.filter(
                   User.id == Address.user_id).correlate(Address)

               main_bq = self.bakery(
                   lambda s: s.query(
                   Address.id, sub_bq.to_query(q).scalar_subquery())
               )

          Parameters: ‘query_or_session’ – a Query object or
          a class Session object, that is assumed to be
          within the context of an enclosing BakedQuery
          callable.

          New in version 1.3.

      -- Method: sqlalchemy.ext.baked.BakedQuery..
               with_criteria (fn, *args)

          Add a criteria function to a BakedQuery cloned
          from this one.

          This is equivalent to using the ‘+’ operator to produce a new
          BakedQuery with modifications.

 -- Class: sqlalchemy.ext.baked.Bakery (cls_, cache)

     Callable which returns a BakedQuery.

     This object is returned by the class method
     BakedQuery.bakery().  It exists as an object so that the
     “cache” can be easily inspected.

     New in version 1.2.

 -- Class: sqlalchemy.ext.baked.Result (bq, session)

     Invokes a BakedQuery against a Session.

     The Result object is where the actual ‘Query’ object
     gets created, or retrieved from the cache, against a target
     Session, and is then invoked for results.

      -- Method: sqlalchemy.ext.baked.Result..all ()

          Return all rows.

          Equivalent to Query.all().

      -- Method: sqlalchemy.ext.baked.Result..count ()

          return the ‘count’.

          Equivalent to Query.count().

          Note this uses a subquery to ensure an accurate count
          regardless of the structure of the original statement.

          New in version 1.1.6.

      -- Method: sqlalchemy.ext.baked.Result..first ()

          Return the first row.

          Equivalent to Query.first().

      -- Method: sqlalchemy.ext.baked.Result..get (ident)

          Retrieve an object based on identity.

          Equivalent to Query.get().

      -- Method: sqlalchemy.ext.baked.Result..one ()

          Return exactly one result or raise an exception.

          Equivalent to Query.one().

      -- Method: sqlalchemy.ext.baked.Result..one_or_none ()

          Return one or zero results, or raise an exception for multiple
          rows.

          Equivalent to Query.one_or_none().

          New in version 1.0.9.

      -- Method: sqlalchemy.ext.baked.Result..params (*args,
               **kw)

          Specify parameters to be replaced into the string SQL
          statement.

      -- Method: sqlalchemy.ext.baked.Result..scalar ()

          Return the first element of the first result or None if no
          rows present.  If multiple rows are returned, raises
          MultipleResultsFound.

          Equivalent to Query.scalar().

          New in version 1.1.6.

      -- Method: sqlalchemy.ext.baked.Result..
               with_post_criteria (fn)

          Add a criteria function that will be applied post-cache.

          This adds a function that will be run against the Query
          object after it is retrieved from the cache.  This
          currently includes `only' the Query.params() and
          Query.execution_options() methods.

               Warning: Result.with_post_criteria()
               functions are applied to the Query object
               `after' the query’s SQL statement object has been
               retrieved from the cache.  Only Query.params()
               and Query.execution_options() methods
               should be used.

          New in version 1.2.

3.7.5 Declarative Extensions
----------------------------

Extensions specific to the Declarative mapping API.

Changed in version 1.4: The vast majority of the Declarative extension
is now integrated into the SQLAlchemy ORM and is importable from the
‘sqlalchemy.orm’ namespace.  See the documentation at Declarative Mapping
for new documentation.  For an overview of the change, see
Declarative is now integrated into the ORM with new features.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See AbstractConcreteBase.A helper class for ‘concrete’ declarative mappings.

See ConcreteBase.A helper class for ‘concrete’ declarative mappings.

See DeferredReflection.A helper class for construction of mappings based on a deferred reflection step.

 -- Class: sqlalchemy.ext.declarative.AbstractConcreteBase

     A helper class for ‘concrete’ declarative mappings.

     AbstractConcreteBase will use the
     polymorphic_union() function automatically, against all
     tables mapped as a subclass to this class.  The function is called
     via the ‘__declare_last__()’ function, which is essentially a hook
     for the after_configured() event.

     AbstractConcreteBase does produce a mapped class for
     the base class, however it is not persisted to any table; it is
     instead mapped directly to the “polymorphic” selectable directly
     and is only used for selecting.  Compare to ConcreteBase,
     which does create a persisted table for the base class.

          Note: The AbstractConcreteBase class does not
          intend to set up the mapping for the base class until all the
          subclasses have been defined, as it needs to create a mapping
          against a selectable that will include all subclass tables.
          In order to achieve this, it waits for the `mapper
          configuration event' to occur, at which point it scans through
          all the configured subclasses and sets up a mapping that will
          query against all subclasses at once.

          While this event is normally invoked automatically, in the
          case of AbstractConcreteBase, it may be necessary
          to invoke it explicitly after `all' subclass mappings are
          defined, if the first operation is to be a query against this
          base class.  To do so, invoke configure_mappers()
          once all the desired classes have been configured:

               from sqlalchemy.orm import configure_mappers

               configure_mappers()

          See also
          ........

          See configure_mappers().

     Example:

          from sqlalchemy.ext.declarative import AbstractConcreteBase

          class Employee(AbstractConcreteBase, Base):
              pass

          class Manager(Employee):
              __tablename__ = 'manager'
              employee_id = Column(Integer, primary_key=True)
              name = Column(String(50))
              manager_data = Column(String(40))

              __mapper_args__ = {
                  'polymorphic_identity':'manager',
                  'concrete':True}

          configure_mappers()

     The abstract base class is handled by declarative in a special way;
     at class configuration time, it behaves like a declarative mixin or
     an ‘__abstract__’ base class.  Once classes are configured and
     mappings are produced, it then gets mapped itself, but after all of
     its descendants.  This is a very unique system of mapping not found
     in any other SQLAlchemy system.

     Using this approach, we can specify columns and properties that
     will take place on mapped subclasses, in the way that we normally
     do as in Mixin and Custom Base Classes:

          class Company(Base):
              __tablename__ = 'company'
              id = Column(Integer, primary_key=True)

          class Employee(AbstractConcreteBase, Base):
              employee_id = Column(Integer, primary_key=True)

              @declared_attr
              def company_id(cls):
                  return Column(ForeignKey('company.id'))

              @declared_attr
              def company(cls):
                  return relationship("Company")

          class Manager(Employee):
              __tablename__ = 'manager'

              name = Column(String(50))
              manager_data = Column(String(40))

              __mapper_args__ = {
                  'polymorphic_identity':'manager',
                  'concrete':True}

          configure_mappers()

     When we make use of our mappings however, both ‘Manager’ and
     ‘Employee’ will have an independently usable ‘.company’ attribute:

          session.query(Employee).filter(Employee.company.has(id=5))

     Changed in version 1.0.0: - The mechanics of
     AbstractConcreteBase have been reworked to support
     relationships established directly on the abstract base, without
     any special configurational steps.

     See also
     ........

     See ConcreteBase.

     See Concrete Table Inheritance.

     `Class signature'

     class sqlalchemy.ext.declarative.AbstractConcreteBase.
     (‘sqlalchemy.ext.declarative.extensions.ConcreteBase’)

 -- Class: sqlalchemy.ext.declarative.ConcreteBase

     A helper class for ‘concrete’ declarative mappings.

     ConcreteBase will use the polymorphic_union()
     function automatically, against all tables mapped as a
     subclass to this class.  The function is called via the
     ‘__declare_last__()’ function, which is essentially a hook for the
     after_configured() event.

     ConcreteBase produces a mapped table for the class
     itself.  Compare to AbstractConcreteBase, which does
     not.

     Example:

          from sqlalchemy.ext.declarative import ConcreteBase

          class Employee(ConcreteBase, Base):
              __tablename__ = 'employee'
              employee_id = Column(Integer, primary_key=True)
              name = Column(String(50))
              __mapper_args__ = {
                              'polymorphic_identity':'employee',
                              'concrete':True}

          class Manager(Employee):
              __tablename__ = 'manager'
              employee_id = Column(Integer, primary_key=True)
              name = Column(String(50))
              manager_data = Column(String(40))
              __mapper_args__ = {
                              'polymorphic_identity':'manager',
                              'concrete':True}

     The name of the discriminator column used by
     polymorphic_union() defaults to the name ‘type’.  To suit the
     use case of a mapping where an actual column in a mapped table is
     already named ‘type’, the discriminator name can be configured by
     setting the ‘_concrete_discriminator_name’ attribute:

          class Employee(ConcreteBase, Base):
              _concrete_discriminator_name = '_concrete_discriminator'

     New in version 1.3.19: Added the ‘_concrete_discriminator_name’
     attribute to ConcreteBase so that the virtual
     discriminator column name can be customized.

     Changed in version 1.4.2: The ‘_concrete_discriminator_name’
     attribute need only be placed on the basemost class to take correct
     effect for all subclasses.  An explicit error message is now raised
     if the mapped column names conflict with the discriminator name,
     whereas in the 1.3.x series there would be some warnings and then a
     non-useful query would be generated.

     See also
     ........

     See AbstractConcreteBase.

     See Concrete Table Inheritance.

 -- Class: sqlalchemy.ext.declarative.DeferredReflection

     A helper class for construction of mappings based on a deferred
     reflection step.

     Normally, declarative can be used with reflection by setting a
     Table object using autoload_with=engine as the
     ‘__table__’ attribute on a declarative class.  The caveat is that
     the Table must be fully reflected, or at the very least
     have a primary key column, at the point at which a normal
     declarative mapping is constructed, meaning the Engine
     must be available at class declaration time.

     The DeferredReflection mixin moves the construction of
     mappers to be at a later point, after a specific method is called
     which first reflects all Table objects created so far.
     Classes can define it as such:

          from sqlalchemy.ext.declarative import declarative_base
          from sqlalchemy.ext.declarative import DeferredReflection
          Base = declarative_base()

          class MyClass(DeferredReflection, Base):
              __tablename__ = 'mytable'

     Above, ‘MyClass’ is not yet mapped.  After a series of classes have
     been defined in the above fashion, all tables can be reflected and
     mappings created using prepare():

          engine = create_engine("someengine://...")
          DeferredReflection.prepare(engine)

     The DeferredReflection mixin can be applied to
     individual classes, used as the base for the declarative base
     itself, or used in a custom abstract class.  Using an abstract base
     allows that only a subset of classes to be prepared for a
     particular prepare step, which is necessary for applications that
     use more than one engine.  For example, if an application has two
     engines, you might use two bases, and prepare each separately,
     e.g.:

          class ReflectedOne(DeferredReflection, Base):
              __abstract__ = True

          class ReflectedTwo(DeferredReflection, Base):
              __abstract__ = True

          class MyClass(ReflectedOne):
              __tablename__ = 'mytable'

          class MyOtherClass(ReflectedOne):
              __tablename__ = 'myothertable'

          class YetAnotherClass(ReflectedTwo):
              __tablename__ = 'yetanothertable'

          # ... etc.

     Above, the class hierarchies for ‘ReflectedOne’ and ‘ReflectedTwo’
     can be configured separately:

          ReflectedOne.prepare(engine_one)
          ReflectedTwo.prepare(engine_two)

      -- Method: sqlalchemy.ext.declarative.DeferredReflection..
               classmethod prepare (engine)

          Reflect all Table objects for all current
          DeferredReflection subclasses

3.7.5.1 Declarative API
.......................

3.7.5.2 API Reference
.....................

Changed in version 1.4: The fundamental structures of the declarative
system are now part of SQLAlchemy ORM directly.  For these components
see:

   * declarative_base().

   * declared_attr.

   * has_inherited_table().

   * synonym_for().

   * sqlalchemy.orm.as_declarative().

See Declarative Extensions for the remaining Declarative
extension classes.

3.7.5.3 Basic Use
.................

This section has moved to Declarative Mapping.

3.7.5.4 Defining Attributes
...........................

This section is covered by Mapping Table Columns.

3.7.5.5 Accessing the MetaData
..............................

This section has moved to Accessing Table and Metadata.

3.7.5.6 Class Constructor
.........................

As a convenience feature, the ‘declarative_base()’ sets a default
constructor on classes which takes keyword arguments, and assigns them
to the named attributes:

     e = Engineer(primary_language='python')

3.7.5.7 Mapper Configuration
............................

This section is moved to Mapper Configuration Options with Declarative.

3.7.5.8 Defining SQL Expressions
................................

See SQL Expressions as Mapped Attributes for examples on
declaratively mapping attributes to SQL expressions.

3.7.5.9 Declarative Inheritance
...............................

See Mapping Class Inheritance Hierarchies for this section.

3.7.5.10 Mixin and Custom Base Classes
......................................

See Composing Mapped Hierarchies with Mixins for this
section.

3.7.5.11 Configuring Relationships
..................................

This section is covered by Defining Mapped Properties with Declarative.

3.7.5.12 Evaluation of relationship arguments
.............................................

This section is moved to Late-Evaluation of Relationship Arguments.

3.7.5.13 Configuring Many-to-Many Relationships
...............................................

This section is moved to Late-Evaluation for a many-to-many relationship.

3.7.5.14 Table Configuration
............................

This section has moved; see Declarative Table Configuration.

3.7.5.15 Using a Hybrid Approach with __table__
...............................................

This section has moved; see Declarative with Imperative Table (a.k.a. Hybrid Declarative).

3.7.5.16 Using Reflection with Declarative
..........................................

This section has moved to Mapping Declaratively with Reflected Tables.

3.7.6 Mypy / Pep-484 Support for ORM Mappings
---------------------------------------------

Support for PEP 484(1) typing annotations as well as the Mypy(2) type
checking tool.

     Note: The Mypy plugin and typing annotations should be regarded as
     `alpha level' for the early 1.4 releases of SQLAlchemy.  The plugin
     has not been tested in real world scenarios and may have many
     unhandled cases and error conditions.  Specifics of the new typing
     stubs are also `subject to change' during the 1.4 series.

   ---------- Footnotes ----------

   (1) https://www.python.org/dev/peps/pep-0484

   (2) https://mypy.readthedocs.io/

3.7.6.1 Installation
....................

The Mypy plugin depends upon new stubs for SQLAlchemy packaged at
sqlalchemy2-stubs(1).  These stubs necessarily fully replace the
previous ‘sqlalchemy-stubs’ typing annotations published by Dropbox, as
they occupy the same ‘sqlalchemy-stubs’ namespace as specified by PEP
561(2).  The Mypy(3) package itself is also a dependency.

Both packages may be installed using the “mypy” extras hook using pip:

     pip install sqlalchemy[mypy]

The plugin itself is configured as described in Configuring mypy to use
Plugins(4), using the ‘sqlalchemy.ext.mypy.plugin’ module name, such as
within ‘setup.cfg’:

     [mypy]
     plugins = sqlalchemy.ext.mypy.plugin

   ---------- Footnotes ----------

   (1) https://pypi.org/project/sqlalchemy2-stubs/

   (2) https://www.python.org/dev/peps/pep-0561

   (3) https://pypi.org/project/mypy/

   (4)
https://mypy.readthedocs.io/en/latest/extending_mypy.html#configuring-mypy-to-use-plugins

3.7.6.2 What the Plugin Does
............................

The primary purpose of the Mypy plugin is to intercept and alter the
static definition of SQLAlchemy declarative mappings so that
they match up to how they are structured after they have been
instrumented by their Mapper objects.  This allows both the
class structure itself as well as code that uses the class to make sense
to the Mypy tool, which otherwise would not be the case based on how
declarative mappings currently function.  The plugin is not unlike
similar plugins that are required for libraries like dataclasses(1)
which alter classes dynamically at runtime.

To cover the major areas where this occurs, consider the following ORM
mapping, using the typical example of the ‘User’ class:

     from sqlalchemy import Column
     from sqlalchemy import Integer
     from sqlalchemy import String
     from sqlalchemy import select
     from sqlalchemy.orm import declarative_base

     # "Base" is a class that is created dynamically from the
     # declarative_base() function
     Base = declarative_base()

     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         name = Column(String)

     # "some_user" is an instance of the User class, which
     # accepts "id" and "name" kwargs based on the mapping
     some_user = User(id=5, name='user')

     # it has an attribute called .name that's a string
     print(f"Username: {some_user.name}")

     # a select() construct makes use of SQL expressions derived from the
     # User class itself
     select_stmt = select(User).where(User.id.in_([3, 4, 5])).where(User.name.contains('s'))

Above, the steps that the Mypy extension can take include:

   * Interpretation of the ‘Base’ dynamic class generated by
     declarative_base(), so that classes which inherit from it are
     known to be mapped.  It also can accommodate the class decorator
     approach described at Declarative Mapping using a Decorator (no declarative base).

   * Type inference for ORM mapped attributes that are defined in
     declarative “inline” style, in the above example the ‘id’ and
     ‘name’ attributes of the ‘User’ class.  This includes that an
     instance of ‘User’ will use ‘int’ for ‘id’ and ‘str’ for ‘name’.
     It also includes that when the ‘User.id’ and ‘User.name’
     class-level attributes are accessed, as they are above in the
     ‘select()’ statement, they are compatible with SQL expression
     behavior, which is derived from the InstrumentedAttribute
     attribute descriptor class.

   * Application of an ‘__init__()’ method to mapped classes that do not
     already include an explicit constructor, which accepts keyword
     arguments of specific types for all mapped attributes detected.

When the Mypy plugin processes the above file, the resulting static
class definition and Python code passed to the Mypy tool is equivalent
to the following:

     from sqlalchemy import Column
     from sqlalchemy import Integer
     from sqlalchemy import String
     from sqlalchemy import select
     from sqlalchemy.orm import declarative_base
     from sqlalchemy.orm.decl_api import DeclarativeMeta
     from sqlalchemy.orm import Mapped

     class Base(metaclass=DeclarativeMeta):
         __abstract__ = True

     class User(Base):
         __tablename__ = 'user'

         id: Mapped[Optional[int]] = Mapped._special_method(
             Column(Integer, primary_key=True)
         )
         name: Mapped[Optional[str]] = Mapped._special_method(
             Column(String)
         )

         def __init__(self, id: Optional[int] = ..., name: Optional[str] = ...) -> None:
             ...

     some_user = User(id=5, name='user')

     print(f"Username: {some_user.name}")

     select_stmt = select(User).where(User.id.in_([3, 4, 5])).where(User.name.contains('s'))

The key steps which have been taken above include:

   * The ‘Base’ class is now defined in terms of the ‘DeclarativeMeta’
     class explicitly, rather than being a dynamic class.

   * The ‘id’ and ‘name’ attributes are defined in terms of the
     Mapped class, which represents a Python descriptor that
     exhibits different behaviors at the class vs.  instance levels.
     The Mapped class is now the base class for the
     InstrumentedAttribute class that is used for all ORM mapped
     attributes.

     In ‘sqlalchemy2-stubs’, see Mapped is defined as a generic
     class against arbitrary Python types, meaning specific occurrences
     of Mapped are associated with a specific Python type,
     such as ‘Mapped[Optional[int]]’ and ‘Mapped[Optional[str]]’ above.

   * The right-hand side of the declarative mapped attribute assignments
     are `removed', as this resembles the operation that the
     Mapper class would normally be doing, which is that it would
     be replacing these attributes with specific instances of
     InstrumentedAttribute.  The original expression is moved into
     a function call that will allow it to still be type-checked without
     conflicting with the left-hand side of the expression.  For Mypy
     purposes, the left-hand typing annotation is sufficient for the
     attribute’s behavior to be understood.

   * A type stub for the ‘User.__init__()’ method is added which
     includes the correct keywords and datatypes.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/dataclasses.html

3.7.6.3 Usage
.............

The following subsections will address individual uses cases that have
so far been considered for pep-484 compliance.

3.7.6.4 Introspection of Columns based on TypeEngine
....................................................

For mapped columns that include an explicit datatype, when they are
mapped as inline attributes, the mapped type will be introspected
automatically:

     class MyClass(Base):
         # ...

         id = Column(Integer, primary_key=True)
         name = Column("employee_name", String(50), nullable=False)
         other_name = Column(String(50))

Above, the ultimate class-level datatypes of ‘id’, ‘name’ and
‘other_name’ will be introspected as ‘Mapped[Optional[int]]’,
‘Mapped[Optional[str]]’ and ‘Mapped[Optional[str]]’.  The types are by
default `always' considered to be ‘Optional’, even for the primary key
and non-nullable column.  The reason is because while the database
columns “id” and “name” can’t be NULL, the Python attributes ‘id’ and
‘name’ most certainly can be ‘None’ without an explicit constructor:

     >>> m1 = MyClass()
     >>> m1.id
     None

The types of the above columns can be stated `explicitly', providing the
two advantages of clearer self-documentation as well as being able to
control which types are optional:

     class MyClass(Base):
         # ...

         id: int = Column(Integer, primary_key=True)
         name: str = Column("employee_name", String(50), nullable=False)
         other_name: Optional[str] = Column(String(50))

The Mypy plugin will accept the above ‘int’, ‘str’ and ‘Optional[str]’
and convert them to include the ‘Mapped[]’ type surrounding them.  The
‘Mapped[]’ construct may also be used explicitly:

     from sqlalchemy.orm import Mapped

     class MyClass(Base):
         # ...

         id: Mapped[int] = Column(Integer, primary_key=True)
         name: Mapped[str] = Column("employee_name", String(50), nullable=False)
         other_name: Mapped[Optional[str]] = Column(String(50))

When the type is non-optional, it simply means that the attribute as
accessed from an instance of ‘MyClass’ will be considered to be
non-None:

     mc = MyClass(...)

     # will pass mypy --strict
     name: str = mc.name

For optional attributes, Mypy considers that the type must include None
or otherwise be ‘Optional’:

     mc = MyClass(...)

     # will pass mypy --strict
     other_name: Optional[str] = mc.name

Whether or not the mapped attribute is typed as ‘Optional’, the
generation of the ‘__init__()’ method will `still consider all keywords
to be optional'.  This is again matching what the SQLAlchemy ORM
actually does when it creates the constructor, and should not be
confused with the behavior of a validating system such as Python
‘dataclasses’ which will generate a constructor that matches the
annotations in terms of optional vs.  required attributes.

     Tip: In the above examples the Integer and String
     datatypes are both TypeEngine subclasses.  In
     ‘sqlalchemy2-stubs’, the Column object is a generic(1)
     which subscribes to the type, e.g.  above the column types are
     ‘Column[Integer]’, ‘Column[String]’, and ‘Column[String]’.  The
     Integer and String classes are in turn
     generically subscribed to the Python types they correspond towards,
     i.e.  ‘Integer(TypeEngine[int])’, ‘String(TypeEngine[str])’.

   ---------- Footnotes ----------

   (1) https://www.python.org/dev/peps/pep-0484/#generics

3.7.6.5 Columns that Don’t have an Explicit Type
................................................

Columns that include a ForeignKey modifier do not need to
specify a datatype in a SQLAlchemy declarative mapping.  For this type
of attribute, the Mypy plugin will inform the user that it needs an
explicit type to be sent:

     # .. other imports
     from sqlalchemy.sql.schema import ForeignKey

     Base = declarative_base()

     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         name = Column(String)

     class Address(Base):
         __tablename__ = 'address'

         id = Column(Integer, primary_key=True)
         user_id = Column(ForeignKey("user.id"))

The plugin will deliver the message as follows:

     $ mypy test3.py --strict
     test3.py:20: error: [SQLAlchemy Mypy plugin] Can't infer type from
     ORM mapped expression assigned to attribute 'user_id'; please specify a
     Python type or Mapped[<python type>] on the left hand side.
     Found 1 error in 1 file (checked 1 source file)

To resolve, apply an explicit type annotation to the ‘Address.user_id’
column:

     class Address(Base):
         __tablename__ = 'address'

         id = Column(Integer, primary_key=True)
         user_id: int = Column(ForeignKey("user.id"))

3.7.6.6 Mapping Columns with Imperative Table
.............................................

In imperative table style, the Column definitions
are given inside of a Table construct which is separate from
the mapped attributes themselves.  The Mypy plugin does not consider
this Table, but instead supports that the attributes can be
explicitly stated with a complete annotation that `must' use the
Mapped class to identify them as mapped attributes:

     class MyClass(Base):
         __table__ = Table(
             "mytable",
             Base.metadata,
             Column(Integer, primary_key=True),
             Column("employee_name", String(50), nullable=False),
             Column(String(50))
         )

         id: Mapped[int]
         name: Mapped[str]
         other_name: Mapped[Optional[str]]

The above Mapped annotations are considered as mapped
columns and will be included in the default constructor, as well as
provide the correct typing profile for ‘MyClass’ both at the class level
and the instance level.

3.7.6.7 Mapping Relationships
.............................

The plugin has limited support for using type inference to detect the
types for relationships.  For all those cases where it can’t detect the
type, it will emit an informative error message, and in all cases the
appropriate type may be provided explicitly, either with the
Mapped class or optionally omitting it for an inline declaration.
The plugin also needs to determine whether or not the relationship
refers to a collection or a scalar, and for that it relies upon the
explicit value of the relationship.uselist and/or
relationship.collection_class parameters.  An explicit type is
needed if neither of these parameters are present, as well as if the
target type of the relationship() is a string or callable,
and not a class:

     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         name = Column(String)

     class Address(Base):
         __tablename__ = 'address'

         id = Column(Integer, primary_key=True)
         user_id: int = Column(ForeignKey("user.id"))

         user = relationship(User)

The above mapping will produce the following error:

     test3.py:22: error: [SQLAlchemy Mypy plugin] Can't infer scalar or
     collection for ORM mapped expression assigned to attribute 'user'
     if both 'uselist' and 'collection_class' arguments are absent from the
     relationship(); please specify a type annotation on the left hand side.
     Found 1 error in 1 file (checked 1 source file)

The error can be resolved either by using ‘relationship(User,
uselist=False)’ or by providing the type, in this case the scalar ‘User’
object:

     class Address(Base):
         __tablename__ = 'address'

         id = Column(Integer, primary_key=True)
         user_id: int = Column(ForeignKey("user.id"))

         user: User = relationship(User)

For collections, a similar pattern applies, where in the absence of
‘uselist=True’ or a relationship.collection_class, a
collection annotation such as ‘List’ may be used.  It is also fully
appropriate to use the string name of the class in the annotation as
supported by pep-484, ensuring the class is imported with in the
TYPE_CHECKING block(1) as approriate:

     from typing import List, TYPE_CHECKING
     from .mymodel import Base

     if TYPE_CHECKING:
         # if the target of the relationship is in another module
         # that cannot normally be imported at runtime
         from .myaddressmodel import Address

     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         name = Column(String)
         addresses: List["Address"] = relationship("Address")

As is the case with columns, the Mapped class may also be
applied explicitly:

     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         name = Column(String)

         addresses: Mapped[List["Address"]] = relationship("Address", back_populates="user")

     class Address(Base):
         __tablename__ = 'address'

         id = Column(Integer, primary_key=True)
         user_id: int = Column(ForeignKey("user.id"))

         user: Mapped[User] = relationship(User, back_populates="addresses")

   ---------- Footnotes ----------

   (1)
https://www.python.org/dev/peps/pep-0484/#runtime-or-type-checking

3.7.6.8 Using @declared_attr
............................

The declared_attr class allows Declarative mapped attributes
to be declared in class level functions, and is particularly useful when
using declarative mixins(1).  For these functions, the return type of
the function should be annotated using either the ‘Mapped[]’ construct
or by indicating the exact kind of object returned by the function:

     from sqlalchemy.orm.decl_api import declared_attr

     class HasUpdatedAt:
         @declared_attr
         def updated_at(cls) -> Column[DateTime]:  # uses Column
             return Column(DateTime)

     class HasCompany:

         @declared_attr
         def company_id(cls) -> Mapped[int]:  # uses Mapped
             return Column(ForeignKey("company.id"))

         @declared_attr
         def company(cls) -> Mapped["Company"]:
             return relationship("Company")

     class Employee(HasUpdatedAt, HasCompany, Base):
         __tablename__ = 'employee'

         id = Column(Integer, primary_key=True)
         name = Column(String)

Note the mismatch between the actual return type of a method like
‘HasCompany.company’ vs.  what is annotated.  The Mypy plugin converts
all ‘@declared_attr’ functions into simple annotated attributes to avoid
this complexity:

     # what Mypy sees
     class HasCompany:
         company_id: Mapped[int]
         company: Mapped["Company"]

   ---------- Footnotes ----------

   (1) orm_mixins_toplevel

3.7.6.9 Combining with Dataclasses or Other Type-Sensitive Attribute Systems
............................................................................

The examples of Python dataclasses integration at Declarative Mapping with Dataclasses and Attrs
presents a problem; Python
dataclasses expect an explicit type that it will use to build the class,
and the value given in each assignment statement is significant.  That
is, a class as follows has to be stated exactly as it is in order to be
accepted by dataclasses:

     mapper_registry : registry = registry()

     @mapper_registry.mapped
     @dataclass
     class User:
         __table__ = Table(
             "user",
             mapper_registry.metadata,
             Column("id", Integer, primary_key=True),
             Column("name", String(50)),
             Column("fullname", String(50)),
             Column("nickname", String(12)),
         )
         id: int = field(init=False)
         name: Optional[str] = None
         fullname: Optional[str] = None
         nickname: Optional[str] = None
         addresses: List[Address] = field(default_factory=list)

         __mapper_args__ = {  # type: ignore
             "properties" : {
                 "addresses": relationship("Address")
             }
         }

We can’t apply our ‘Mapped[]’ types to the attributes ‘id’, ‘name’, etc.
because they will be rejected by the ‘@dataclass’ decorator.
Additionally, Mypy has another plugin for dataclasses explicitly which
can also get in the way of what we’re doing.

The above class will actually pass Mypy’s type checking without issue;
the only thing we are missing is the ability for attributes on ‘User’ to
be used in SQL expressions, such as:

     stmt = select(User.name).where(User.id.in_([1, 2, 3]))

To provide a workaround for this, the Mypy plugin has an additional
feature whereby we can specify an extra attribute ‘_mypy_mapped_attrs’,
that is a list that encloses the class-level objects or their string
names.  This attribute can be conditional within the ‘TYPE_CHECKING’
variable:

     @mapper_registry.mapped
     @dataclass
     class User:
         __table__ = Table(
             "user",
             mapper_registry.metadata,
             Column("id", Integer, primary_key=True),
             Column("name", String(50)),
             Column("fullname", String(50)),
             Column("nickname", String(12)),
         )
         id: int = field(init=False)
         name: Optional[str] = None
         fullname: Optional[str]
         nickname: Optional[str]
         addresses: List[Address] = field(default_factory=list)

         if TYPE_CHECKING:
             _mypy_mapped_attrs = [id, name, "fullname", "nickname", addresses]

         __mapper_args__ = {  # type: ignore
             "properties" : {
                 "addresses": relationship("Address")
             }
         }

With the above recipe, the attributes listed in ‘_mypy_mapped_attrs’
will be applied with the Mapped typing information so that
the ‘User’ class will behave as a SQLAlchemy mapped class when used in a
class-bound context.

3.7.7 Mutation Tracking
-----------------------

Provide support for tracking of in-place changes to scalar values, which
are propagated into ORM change events on owning parent objects.

3.7.7.1 Establishing Mutability on Scalar Column Values
.......................................................

A typical example of a “mutable” structure is a Python dictionary.
Following the example introduced in Column and Data Types, we
begin with a custom type that marshals Python dictionaries into JSON
strings before being persisted:

     from sqlalchemy.types import TypeDecorator, VARCHAR
     import json

     class JSONEncodedDict(TypeDecorator):
         "Represents an immutable structure as a json-encoded string."

         impl = VARCHAR

         def process_bind_param(self, value, dialect):
             if value is not None:
                 value = json.dumps(value)
             return value

         def process_result_value(self, value, dialect):
             if value is not None:
                 value = json.loads(value)
             return value

The usage of ‘json’ is only for the purposes of example.  The
sqlalchemy.ext.mutable extension can be used with any type whose
target Python type may be mutable, including PickleType,
ARRAY, etc.

When using the sqlalchemy.ext.mutable extension, the value
itself tracks all parents which reference it.  Below, we illustrate a
simple version of the MutableDict dictionary object, which
applies the Mutable mixin to a plain Python dictionary:

     from sqlalchemy.ext.mutable import Mutable

     class MutableDict(Mutable, dict):
         @classmethod
         def coerce(cls, key, value):
             "Convert plain dictionaries to MutableDict."

             if not isinstance(value, MutableDict):
                 if isinstance(value, dict):
                     return MutableDict(value)

                 # this call will raise ValueError
                 return Mutable.coerce(key, value)
             else:
                 return value

         def __setitem__(self, key, value):
             "Detect dictionary set events and emit change events."

             dict.__setitem__(self, key, value)
             self.changed()

         def __delitem__(self, key):
             "Detect dictionary del events and emit change events."

             dict.__delitem__(self, key)
             self.changed()

The above dictionary class takes the approach of subclassing the Python
built-in ‘dict’ to produce a dict subclass which routes all mutation
events through ‘__setitem__’.  There are variants on this approach, such
as subclassing ‘UserDict.UserDict’ or ‘collections.MutableMapping’; the
part that’s important to this example is that the
Mutable.changed() method is called whenever an in-place change to
the datastructure takes place.

We also redefine the Mutable.coerce() method which will be
used to convert any values that are not instances of ‘MutableDict’, such
as the plain dictionaries returned by the ‘json’ module, into the
appropriate type.  Defining this method is optional; we could just as
well created our ‘JSONEncodedDict’ such that it always returns an
instance of ‘MutableDict’, and additionally ensured that all calling
code uses ‘MutableDict’ explicitly.  When Mutable.coerce()
is not overridden, any values applied to a parent object which are not
instances of the mutable type will raise a ‘ValueError’.

Our new ‘MutableDict’ type offers a class method
Mutable.as_mutable() which we can use within column metadata to
associate with types.  This method grabs the given type object or class
and associates a listener that will detect all future mappings of this
type, applying event listening instrumentation to the mapped attribute.
Such as, with classical table metadata:

     from sqlalchemy import Table, Column, Integer

     my_data = Table('my_data', metadata,
         Column('id', Integer, primary_key=True),
         Column('data', MutableDict.as_mutable(JSONEncodedDict))
     )

Above, see Mutable.as_mutable() returns an instance of
‘JSONEncodedDict’ (if the type object was not an instance already),
which will intercept any attributes which are mapped against this type.
Below we establish a simple mapping against the ‘my_data’ table:

     from sqlalchemy import mapper

     class MyDataClass(object):
         pass

     # associates mutation listeners with MyDataClass.data
     mapper(MyDataClass, my_data)

The ‘MyDataClass.data’ member will now be notified of in place changes
to its value.

There’s no difference in usage when using declarative:

     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class MyDataClass(Base):
         __tablename__ = 'my_data'
         id = Column(Integer, primary_key=True)
         data = Column(MutableDict.as_mutable(JSONEncodedDict))

Any in-place changes to the ‘MyDataClass.data’ member will flag the
attribute as “dirty” on the parent object:

     >>> from sqlalchemy.orm import Session

     >>> sess = Session()
     >>> m1 = MyDataClass(data={'value1':'foo'})
     >>> sess.add(m1)
     >>> sess.commit()

     >>> m1.data['value1'] = 'bar'
     >>> assert m1 in sess.dirty
     True

The ‘MutableDict’ can be associated with all future instances of
‘JSONEncodedDict’ in one step, using Mutable.associate_with().
This is similar to Mutable.as_mutable() except it will
intercept all occurrences of ‘MutableDict’ in all mappings
unconditionally, without the need to declare it individually:

     MutableDict.associate_with(JSONEncodedDict)

     class MyDataClass(Base):
         __tablename__ = 'my_data'
         id = Column(Integer, primary_key=True)
         data = Column(JSONEncodedDict)

3.7.7.2 Supporting Pickling
...........................

The key to the sqlalchemy.ext.mutable extension relies upon
the placement of a ‘weakref.WeakKeyDictionary’ upon the value object,
which stores a mapping of parent mapped objects keyed to the attribute
name under which they are associated with this value.
‘WeakKeyDictionary’ objects are not picklable, due to the fact that they
contain weakrefs and function callbacks.  In our case, this is a good
thing, since if this dictionary were picklable, it could lead to an
excessively large pickle size for our value objects that are pickled by
themselves outside of the context of the parent.  The developer
responsibility here is only to provide a ‘__getstate__’ method that
excludes the MutableBase._parents() collection from the
pickle stream:

     class MyMutableType(Mutable):
         def __getstate__(self):
             d = self.__dict__.copy()
             d.pop('_parents', None)
             return d

With our dictionary example, we need to return the contents of the dict
itself (and also restore them on __setstate__):

     class MutableDict(Mutable, dict):
         # ....

         def __getstate__(self):
             return dict(self)

         def __setstate__(self, state):
             self.update(state)

In the case that our mutable value object is pickled as it is attached
to one or more parent objects that are also part of the pickle, the
Mutable mixin will re-establish the Mutable._parents
collection on each value object as the owning parents themselves
are unpickled.

3.7.7.3 Receiving Events
........................

The AttributeEvents.modified() event handler may be used to
receive an event when a mutable scalar emits a change event.  This event
handler is called when the flag_modified() function is
called from within the mutable extension:

     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy import event

     Base = declarative_base()

     class MyDataClass(Base):
         __tablename__ = 'my_data'
         id = Column(Integer, primary_key=True)
         data = Column(MutableDict.as_mutable(JSONEncodedDict))

     @event.listens_for(MyDataClass.data, "modified")
     def modified_json(instance):
         print("json value modified:", instance.data)

3.7.7.4 Establishing Mutability on Composites
.............................................

Composites are a special ORM feature which allow a single scalar
attribute to be assigned an object value which represents information
“composed” from one or more columns from the underlying mapped table.
The usual example is that of a geometric “point”, and is introduced in
Composite Column Types.

As is the case with Mutable, the user-defined composite class
subclasses MutableComposite as a mixin, and detects and
delivers change events to its parents via the
MutableComposite.changed() method.  In the case of a composite
class, the detection is usually via the usage of Python descriptors
(i.e.  ‘@property’), or alternatively via the special Python method
‘__setattr__()’.  Below we expand upon the ‘Point’ class introduced in
Composite Column Types to subclass MutableComposite
and to also route attribute set events via ‘__setattr__’ to the
MutableComposite.changed() method:

     from sqlalchemy.ext.mutable import MutableComposite

     class Point(MutableComposite):
         def __init__(self, x, y):
             self.x = x
             self.y = y

         def __setattr__(self, key, value):
             "Intercept set events"

             # set the attribute
             object.__setattr__(self, key, value)

             # alert all parents to the change
             self.changed()

         def __composite_values__(self):
             return self.x, self.y

         def __eq__(self, other):
             return isinstance(other, Point) and \
                 other.x == self.x and \
                 other.y == self.y

         def __ne__(self, other):
             return not self.__eq__(other)

The MutableComposite class uses a Python metaclass to
automatically establish listeners for any usage of composite()
that specifies our ‘Point’ type.  Below, when ‘Point’ is mapped to
the ‘Vertex’ class, listeners are established which will route change
events from ‘Point’ objects to each of the ‘Vertex.start’ and
‘Vertex.end’ attributes:

     from sqlalchemy.orm import composite, mapper
     from sqlalchemy import Table, Column

     vertices = Table('vertices', metadata,
         Column('id', Integer, primary_key=True),
         Column('x1', Integer),
         Column('y1', Integer),
         Column('x2', Integer),
         Column('y2', Integer),
         )

     class Vertex(object):
         pass

     mapper(Vertex, vertices, properties={
         'start': composite(Point, vertices.c.x1, vertices.c.y1),
         'end': composite(Point, vertices.c.x2, vertices.c.y2)
     })

Any in-place changes to the ‘Vertex.start’ or ‘Vertex.end’ members will
flag the attribute as “dirty” on the parent object:

     >>> from sqlalchemy.orm import Session

     >>> sess = Session()
     >>> v1 = Vertex(start=Point(3, 4), end=Point(12, 15))
     >>> sess.add(v1)
     >>> sess.commit()

     >>> v1.end.x = 8
     >>> assert v1 in sess.dirty
     True

3.7.7.5 Coercing Mutable Composites
...................................

The MutableBase.coerce() method is also supported on
composite types.  In the case of MutableComposite, the
MutableBase.coerce() method is only called for attribute set
operations, not load operations.  Overriding the
MutableBase.coerce() method is essentially equivalent to using a
validates() validation routine for all attributes which make
use of the custom composite type:

     class Point(MutableComposite):
         # other Point methods
         # ...

         def coerce(cls, key, value):
             if isinstance(value, tuple):
                 value = Point(*value)
             elif not isinstance(value, Point):
                 raise ValueError("tuple or Point expected")
             return value

3.7.7.6 Supporting Pickling
...........................

As is the case with Mutable, the MutableComposite
helper class uses a ‘weakref.WeakKeyDictionary’ available via the
MutableBase._parents() attribute which isn’t picklable.  If we
need to pickle instances of ‘Point’ or its owning class ‘Vertex’, we at
least need to define a ‘__getstate__’ that doesn’t include the
‘_parents’ dictionary.  Below we define both a ‘__getstate__’ and a
‘__setstate__’ that package up the minimal form of our ‘Point’ class:

     class Point(MutableComposite):
         # ...

         def __getstate__(self):
             return self.x, self.y

         def __setstate__(self, state):
             self.x, self.y = state

As with Mutable, the MutableComposite augments
the pickling process of the parent’s object-relational state so that the
MutableBase._parents() collection is restored to all ‘Point’
objects.

3.7.7.7 API Reference
.....................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See Mutable.Mixin that defines transparent propagation of change events to a parent object.

See MutableBase.Common base class to Mutable and MutableComposite.

See MutableComposite.Mixin that defines transparent propagation of change events on a SQLAlchemy “composite”
               object to its owning parent or parents.

See MutableDict.A dictionary type that implements Mutable.

See MutableList.A list type that implements Mutable.

See MutableSet.A set type that implements Mutable.

 -- Class: sqlalchemy.ext.mutable.MutableBase

     Common base class to Mutable and
     MutableComposite.

      -- Attribute: sqlalchemy.ext.mutable.MutableBase..
               _parents

          Dictionary of parent object’s InstanceState.
          ->attribute name on the parent.

          This attribute is a so-called “memoized” property.  It
          initializes itself with a new ‘weakref.WeakKeyDictionary’ the
          first time it is accessed, returning the same object upon
          subsequent access.

          Changed in version 1.4: the InstanceState is now
          used as the key in the weak dictionary rather than the
          instance itself.

      -- Method: sqlalchemy.ext.mutable.MutableBase..
               classmethod coerce (key, value)

          Given a value, coerce it into the target type.

          Can be overridden by custom subclasses to coerce incoming data
          into a particular type.

          By default, raises ‘ValueError’.

          This method is called in different scenarios depending on if
          the parent class is of type Mutable or of type
          MutableComposite.  In the case of the former, it is
          called for both attribute-set operations as well as during ORM
          loading operations.  For the latter, it is only called during
          attribute-set operations; the mechanics of the
          composite() construct handle coercion during load
          operations.

          Parameters:

             * ‘key’ – string name of the ORM-mapped attribute being
               set.

             * ‘value’ – the incoming value.

          Returns: the method should return the coerced value, or raise
          ‘ValueError’ if the coercion cannot be completed.

 -- Class: sqlalchemy.ext.mutable.Mutable

     Mixin that defines transparent propagation of change events to a
     parent object.

     See the example in Establishing Mutability on Scalar Column Values
     for usage information.

     `Class signature'

     class sqlalchemy.ext.mutable.Mutable. (see
     sqlalchemy.ext.mutable.MutableBase)

      -- Method: sqlalchemy.ext.mutable.Mutable..classmethod
               _get_listen_keys (attribute)

          `inherited from the'
          ‘sqlalchemy.ext.mutable.MutableBase._get_listen_keys’ `method
          of' MutableBase.

          Given a descriptor attribute, return a ‘set()’ of the
          attribute keys which indicate a change in the state of this
          attribute.

          This is normally just ‘set([attribute.key])’, but can be
          overridden to provide for additional keys.  E.g.  a
          MutableComposite augments this set with the attribute
          keys associated with the columns that comprise the composite
          value.

          This collection is consulted in the case of intercepting the
          InstanceEvents.refresh() and
          InstanceEvents.refresh_flush() events, which pass along
          a list of attribute names that have been refreshed; the list
          is compared against this set to determine if action needs to
          be taken.

          New in version 1.0.5.

      -- Method: sqlalchemy.ext.mutable.Mutable..classmethod
               _listen_on_attribute (attribute, coerce, parent_cls)

          `inherited from the'
          ‘sqlalchemy.ext.mutable.MutableBase._listen_on_attribute’
          `method of' MutableBase.

          Establish this type as a mutation listener for the given
          mapped descriptor.

      -- Attribute: sqlalchemy.ext.mutable.Mutable.._parents

          `inherited from the'
          ‘sqlalchemy.ext.mutable.MutableBase._parents’ `attribute of'
          MutableBase.

          Dictionary of parent object’s InstanceState.
          ->attribute name on the parent.

          This attribute is a so-called “memoized” property.  It
          initializes itself with a new ‘weakref.WeakKeyDictionary’ the
          first time it is accessed, returning the same object upon
          subsequent access.

          Changed in version 1.4: the InstanceState is now
          used as the key in the weak dictionary rather than the
          instance itself.

      -- Method: sqlalchemy.ext.mutable.Mutable..classmethod
               as_mutable (sqltype)

          Associate a SQL type with this mutable Python type.

          This establishes listeners that will detect ORM mappings
          against the given type, adding mutation event trackers to
          those mappings.

          The type is returned, unconditionally as an instance, so that
          as_mutable() can be used inline:

               Table('mytable', metadata,
                   Column('id', Integer, primary_key=True),
                   Column('data', MyMutableType.as_mutable(PickleType))
               )

          Note that the returned type is always an instance, even if a
          class is given, and that only columns which are declared
          specifically with that type instance receive additional
          instrumentation.

          To associate a particular mutable type with all occurrences of
          a particular type, use the Mutable.associate_with()
          classmethod of the particular Mutable
          subclass to establish a global association.

               Warning: The listeners established by this method are
               `global' to all mappers, and are `not' garbage collected.
               Only use as_mutable() for types that are
               permanent to an application, not with ad-hoc types else
               this will cause unbounded growth in memory usage.

      -- Method: sqlalchemy.ext.mutable.Mutable..classmethod
               associate_with (sqltype)

          Associate this wrapper with all future mapped columns of the
          given type.

          This is a convenience method that calls
          ‘associate_with_attribute’ automatically.

               Warning: The listeners established by this method are
               `global' to all mappers, and are `not' garbage collected.
               Only use associate_with() for types that are
               permanent to an application, not with ad-hoc types else
               this will cause unbounded growth in memory usage.

      -- Method: sqlalchemy.ext.mutable.Mutable..classmethod
               associate_with_attribute (attribute)

          Establish this type as a mutation listener for the given
          mapped descriptor.

      -- Method: sqlalchemy.ext.mutable.Mutable..changed ()

          Subclasses should call this method whenever change events
          occur.

      -- Method: sqlalchemy.ext.mutable.Mutable..classmethod
               coerce (key, value)

          `inherited from the' MutableBase.coerce(). `method
          of' MutableBase.

          Given a value, coerce it into the target type.

          Can be overridden by custom subclasses to coerce incoming data
          into a particular type.

          By default, raises ‘ValueError’.

          This method is called in different scenarios depending on if
          the parent class is of type Mutable or of type
          MutableComposite.  In the case of the former, it is
          called for both attribute-set operations as well as during ORM
          loading operations.  For the latter, it is only called during
          attribute-set operations; the mechanics of the
          composite() construct handle coercion during load
          operations.

          Parameters:

             * ‘key’ – string name of the ORM-mapped attribute being
               set.

             * ‘value’ – the incoming value.

          Returns: the method should return the coerced value, or raise
          ‘ValueError’ if the coercion cannot be completed.

 -- Class: sqlalchemy.ext.mutable.MutableComposite

     Mixin that defines transparent propagation of change events on a
     SQLAlchemy “composite” object to its owning parent or parents.

     See the example in Establishing Mutability on Composites
     for usage information.

     `Class signature'

     class sqlalchemy.ext.mutable.MutableComposite. (see
     sqlalchemy.ext.mutable.MutableBase)

      -- Method: sqlalchemy.ext.mutable.MutableComposite..
               changed ()

          Subclasses should call this method whenever change events
          occur.

 -- Class: sqlalchemy.ext.mutable.MutableDict

     A dictionary type that implements Mutable.

     The MutableDict object implements a dictionary that
     will emit change events to the underlying mapping when the contents
     of the dictionary are altered, including when values are added or
     removed.

     Note that MutableDict does `not' apply mutable tracking
     to the `values themselves' inside the dictionary.  Therefore it is
     not a sufficient solution for the use case of tracking deep changes
     to a `recursive' dictionary structure, such as a JSON structure.
     To support this use case, build a subclass of MutableDict
     that provides appropriate coercion to the values placed in the
     dictionary so that they too are “mutable”, and emit events up to
     their parent structure.

     See also
     ........

     See MutableList.

     See MutableSet.

     `Class signature'

     class sqlalchemy.ext.mutable.MutableDict. (see
     sqlalchemy.ext.mutable.Mutable, ‘builtins.dict’)

      -- Method: sqlalchemy.ext.mutable.MutableDict..clear ()
               -> None. Remove all items from D.

      -- Method: sqlalchemy.ext.mutable.MutableDict..
               classmethod coerce (key, value)

          Convert plain dictionary to instance of this class.

      -- Method: sqlalchemy.ext.mutable.MutableDict..pop (k[,
               d]) -> v, remove specified key and return the
               corresponding value.

          If key is not found, d is returned if given, otherwise
          KeyError is raised

      -- Method: sqlalchemy.ext.mutable.MutableDict..popitem
               ()

          Remove and return a (key, value) pair as a 2-tuple.

          Pairs are returned in LIFO (last-in, first-out) order.  Raises
          KeyError if the dict is empty.

      -- Method: sqlalchemy.ext.mutable.MutableDict..
               setdefault (key, value)

          Insert key with a value of default if key is not in the
          dictionary.

          Return the value for key if key is in the dictionary, else
          default.

      -- Method: sqlalchemy.ext.mutable.MutableDict..update
               ([E], **F) -> None. Update D from dict/iterable E and F.

          If E is present and has a .keys() method, then does: for k in
          E: D[k] = E[k] If E is present and lacks a .keys() method,
          then does: for k, v in E: D[k] = v In either case, this is
          followed by: for k in F: D[k] = F[k]

 -- Class: sqlalchemy.ext.mutable.MutableList (iterable=(), /)

     A list type that implements Mutable.

     The MutableList object implements a list that will emit
     change events to the underlying mapping when the contents of the
     list are altered, including when values are added or removed.

     Note that MutableList does `not' apply mutable tracking
     to the `values themselves' inside the list.  Therefore it is not a
     sufficient solution for the use case of tracking deep changes to a
     `recursive' mutable structure, such as a JSON structure.  To
     support this use case, build a subclass of MutableList
     that provides appropriate coercion to the values placed in the
     dictionary so that they too are “mutable”, and emit events up to
     their parent structure.

     New in version 1.1.

     See also
     ........

     See MutableDict.

     See MutableSet.

     `Class signature'

     class sqlalchemy.ext.mutable.MutableList. (see
     sqlalchemy.ext.mutable.Mutable, ‘builtins.list’)

      -- Method: sqlalchemy.ext.mutable.MutableList..append
               (x)

          Append object to the end of the list.

      -- Method: sqlalchemy.ext.mutable.MutableList..clear ()

          Remove all items from list.

      -- Method: sqlalchemy.ext.mutable.MutableList..
               classmethod coerce (index, value)

          Convert plain list to instance of this class.

      -- Method: sqlalchemy.ext.mutable.MutableList..extend
               (x)

          Extend list by appending elements from the iterable.

      -- Method: sqlalchemy.ext.mutable.MutableList..insert
               (i, x)

          Insert object before index.

      -- Method: sqlalchemy.ext.mutable.MutableList..pop
               (*arg)

          Remove and return item at index (default last).

          Raises IndexError if list is empty or index is out of range.

      -- Method: sqlalchemy.ext.mutable.MutableList..remove
               (i)

          Remove first occurrence of value.

          Raises ValueError if the value is not present.

      -- Method: sqlalchemy.ext.mutable.MutableList..reverse
               ()

          Reverse `IN PLACE'.

      -- Method: sqlalchemy.ext.mutable.MutableList..sort
               (**kw)

          Sort the list in ascending order and return None.

          The sort is in-place (i.e.  the list itself is modified) and
          stable (i.e.  the order of two equal elements is maintained).

          If a key function is given, apply it once to each list item
          and sort them, ascending or descending, according to their
          function values.

          The reverse flag can be set to sort in descending order.

 -- Class: sqlalchemy.ext.mutable.MutableSet

     A set type that implements Mutable.

     The MutableSet object implements a set that will emit
     change events to the underlying mapping when the contents of the
     set are altered, including when values are added or removed.

     Note that MutableSet does `not' apply mutable tracking
     to the `values themselves' inside the set.  Therefore it is not a
     sufficient solution for the use case of tracking deep changes to a
     `recursive' mutable structure.  To support this use case, build a
     subclass of MutableSet that provides appropriate
     coercion to the values placed in the dictionary so that they too
     are “mutable”, and emit events up to their parent structure.

     New in version 1.1.

     See also
     ........

     See MutableDict.

     See MutableList.

     `Class signature'

     class sqlalchemy.ext.mutable.MutableSet. (see
     sqlalchemy.ext.mutable.Mutable, ‘builtins.set’)

      -- Method: sqlalchemy.ext.mutable.MutableSet..add
               (elem)

          Add an element to a set.

          This has no effect if the element is already present.

      -- Method: sqlalchemy.ext.mutable.MutableSet..clear ()

          Remove all elements from this set.

      -- Method: sqlalchemy.ext.mutable.MutableSet..
               classmethod coerce (index, value)

          Convert plain set to instance of this class.

      -- Method: sqlalchemy.ext.mutable.MutableSet..
               difference_update (*arg)

          Remove all elements of another set from this set.

      -- Method: sqlalchemy.ext.mutable.MutableSet..discard
               (elem)

          Remove an element from a set if it is a member.

          If the element is not a member, do nothing.

      -- Method: sqlalchemy.ext.mutable.MutableSet..
               intersection_update (*arg)

          Update a set with the intersection of itself and another.

      -- Method: sqlalchemy.ext.mutable.MutableSet..pop
               (*arg)

          Remove and return an arbitrary set element.  Raises KeyError
          if the set is empty.

      -- Method: sqlalchemy.ext.mutable.MutableSet..remove
               (elem)

          Remove an element from a set; it must be a member.

          If the element is not a member, raise a KeyError.

      -- Method: sqlalchemy.ext.mutable.MutableSet..
               symmetric_difference_update (*arg)

          Update a set with the symmetric difference of itself and
          another.

      -- Method: sqlalchemy.ext.mutable.MutableSet..update
               (*arg)

          Update a set with the union of itself and others.

3.7.8 Ordering List
-------------------

A custom list that manages index/position information for contained
elements.

author: Jason Kirtland

‘orderinglist’ is a helper for mutable ordered relationships.  It will
intercept list operations performed on a relationship().
-managed collection and automatically synchronize changes in list
position onto a target scalar attribute.

Example: A ‘slide’ table, where each row refers to zero or more entries
in a related ‘bullet’ table.  The bullets within a slide are displayed
in order based on the value of the ‘position’ column in the ‘bullet’
table.  As entries are reordered in memory, the value of the ‘position’
attribute should be updated to reflect the new sort order:

     Base = declarative_base()

     class Slide(Base):
         __tablename__ = 'slide'

         id = Column(Integer, primary_key=True)
         name = Column(String)

         bullets = relationship("Bullet", order_by="Bullet.position")

     class Bullet(Base):
         __tablename__ = 'bullet'
         id = Column(Integer, primary_key=True)
         slide_id = Column(Integer, ForeignKey('slide.id'))
         position = Column(Integer)
         text = Column(String)

The standard relationship mapping will produce a list-like attribute on
each ‘Slide’ containing all related ‘Bullet’ objects, but coping with
changes in ordering is not handled automatically.  When appending a
‘Bullet’ into ‘Slide.bullets’, the ‘Bullet.position’ attribute will
remain unset until manually assigned.  When the ‘Bullet’ is inserted
into the middle of the list, the following ‘Bullet’ objects will also
need to be renumbered.

The OrderingList object automates this task, managing the
‘position’ attribute on all ‘Bullet’ objects in the collection.  It is
constructed using the ordering_list() factory:

     from sqlalchemy.ext.orderinglist import ordering_list

     Base = declarative_base()

     class Slide(Base):
         __tablename__ = 'slide'

         id = Column(Integer, primary_key=True)
         name = Column(String)

         bullets = relationship("Bullet", order_by="Bullet.position",
                                 collection_class=ordering_list('position'))

     class Bullet(Base):
         __tablename__ = 'bullet'
         id = Column(Integer, primary_key=True)
         slide_id = Column(Integer, ForeignKey('slide.id'))
         position = Column(Integer)
         text = Column(String)

With the above mapping the ‘Bullet.position’ attribute is managed:

     s = Slide()
     s.bullets.append(Bullet())
     s.bullets.append(Bullet())
     s.bullets[1].position
     >>> 1
     s.bullets.insert(1, Bullet())
     s.bullets[2].position
     >>> 2

The OrderingList construct only works with `changes' to a
collection, and not the initial load from the database, and requires
that the list be sorted when loaded.  Therefore, be sure to specify
‘order_by’ on the relationship() against the target ordering
attribute, so that the ordering is correct when first loaded.

     Warning: OrderingList only provides limited
     functionality when a primary key column or unique column is the
     target of the sort.  Operations that are unsupported or are
     problematic include:

             * two entries must trade values.  This is not supported
               directly in the case of a primary key or unique
               constraint because it means at least one row would need
               to be temporarily removed first, or changed to a third,
               neutral value while the switch occurs.

             * an entry must be deleted in order to make room for a new
               entry.  SQLAlchemy’s unit of work performs all INSERTs
               before DELETEs within a single flush.  In the case of a
               primary key, it will trade an INSERT/DELETE of the same
               primary key for an UPDATE statement in order to lessen
               the impact of this limitation, however this does not take
               place for a UNIQUE column.  A future feature will allow
               the “DELETE before INSERT” behavior to be possible,
               alleviating this limitation, though this feature will
               require explicit configuration at the mapper level for
               sets of columns that are to be handled in this way.

ordering_list() takes the name of the related object’s
ordering attribute as an argument.  By default, the zero-based integer
index of the object’s position in the ordering_list() is
synchronized with the ordering attribute: index 0 will get position 0,
index 1 position 1, etc.  To start numbering at 1 or some other integer,
provide ‘count_from=1’.

3.7.8.1 API Reference
.....................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See count_from_0.(index,Numbering function: consecutive integers starting at 0.
collection)

See count_from_1.(index,Numbering function: consecutive integers starting at 1.
collection)

See count_from_n_factory.(start)Numbering function: consecutive integers starting at arbitrary start.

See ordering_list.(attr[,Prepares an OrderingList factory for use in mapper definitions.
count_from],
**kw)

See OrderingList.A custom list that manages position information for its children.

 -- Function: sqlalchemy.ext.orderinglist.ordering_list (attr,
          count_from=None, **kw)

     Prepares an OrderingList factory for use in mapper
     definitions.

     Returns an object suitable for use as an argument to a Mapper
     relationship’s ‘collection_class’ option.  e.g.:

          from sqlalchemy.ext.orderinglist import ordering_list

          class Slide(Base):
              __tablename__ = 'slide'

              id = Column(Integer, primary_key=True)
              name = Column(String)

              bullets = relationship("Bullet", order_by="Bullet.position",
                                      collection_class=ordering_list('position'))

     Parameters:

        * ‘attr’ – Name of the mapped attribute to use for storage and
          retrieval of ordering information

        * ‘count_from’ – Set up an integer-based ordering, starting at
          ‘count_from’.  For example, ‘ordering_list('pos',
          count_from=1)’ would create a 1-based list in SQL, storing the
          value in the ‘pos’ column.  Ignored if ‘ordering_func’ is
          supplied.

     Additional arguments are passed to the OrderingList
     constructor.

 -- Function: sqlalchemy.ext.orderinglist.count_from_0 (index,
          collection)

     Numbering function: consecutive integers starting at 0.

 -- Function: sqlalchemy.ext.orderinglist.count_from_1 (index,
          collection)

     Numbering function: consecutive integers starting at 1.

 -- Function: sqlalchemy.ext.orderinglist.count_from_n_factory (start)

     Numbering function: consecutive integers starting at arbitrary
     start.

 -- Class: sqlalchemy.ext.orderinglist.OrderingList (ordering_attr=None,
          ordering_func=None, reorder_on_append=False)

     A custom list that manages position information for its children.

     The OrderingList object is normally set up using the
     ordering_list() factory function, used in conjunction
     with the relationship() function.

     `Class signature'

     class sqlalchemy.ext.orderinglist.OrderingList.
     (‘builtins.list’)

      -- Method: sqlalchemy.ext.orderinglist.OrderingList..
               __init__ (ordering_attr=None, ordering_func=None,
               reorder_on_append=False)

          A custom list that manages position information for its
          children.

          ‘OrderingList’ is a ‘collection_class’ list implementation
          that syncs position in a Python list with a position attribute
          on the mapped objects.

          This implementation relies on the list starting in the proper
          order, so be `sure' to put an ‘order_by’ on your relationship.

          Parameters:

             * ‘ordering_attr’ – Name of the attribute that stores the
               object’s order in the relationship.

             * ‘ordering_func’ – Optional.  A function that maps the
               position in the Python list to a value to store in the
               ‘ordering_attr’.  Values returned are usually (but need
               not be!)  integers.

               An ‘ordering_func’ is called with two positional
               parameters: the index of the element in the list, and the
               list itself.

               If omitted, Python list indexes are used for the
               attribute values.  Two basic pre-built numbering
               functions are provided in this module: ‘count_from_0’ and
               ‘count_from_1’.  For more exotic examples like stepped
               numbering, alphabetical and Fibonacci numbering, see the
               unit tests.

             * ‘reorder_on_append’ – Default False.  When appending an
               object with an existing (non-None) ordering value, that
               value will be left untouched unless ‘reorder_on_append’
               is true.  This is an optimization to avoid a variety of
               dangerous unexpected database writes.

               SQLAlchemy will add instances to the list via append()
               when your object loads.  If for some reason the result
               set from the database skips a step in the ordering (say,
               row ‘1’ is missing but you get ‘2’, ‘3’, and ‘4’),
               reorder_on_append=True would immediately renumber the
               items to ‘1’, ‘2’, ‘3’.  If you have multiple sessions
               making changes, any of whom happen to load this
               collection even in passing, all of the sessions would try
               to “clean up” the numbering in their commits, possibly
               causing all but one to fail with a concurrent
               modification error.

               Recommend leaving this with the default of False, and
               just call ‘reorder()’ if you’re doing ‘append()’
               operations with previously ordered instances or when
               doing some housekeeping after manual sql operations.

      -- Method: sqlalchemy.ext.orderinglist.OrderingList..
               append (entity)

          Append object to the end of the list.

      -- Method: sqlalchemy.ext.orderinglist.OrderingList..
               insert (index, entity)

          Insert object before index.

      -- Method: sqlalchemy.ext.orderinglist.OrderingList..
               pop (index=- 1)

          Remove and return item at index (default last).

          Raises IndexError if list is empty or index is out of range.

      -- Method: sqlalchemy.ext.orderinglist.OrderingList..
               remove (entity)

          Remove first occurrence of value.

          Raises ValueError if the value is not present.

      -- Method: sqlalchemy.ext.orderinglist.OrderingList..
               reorder ()

          Synchronize ordering for the entire collection.

          Sweeps through the list and ensures that each object has
          accurate ordering information set.

3.7.9 Horizontal Sharding
-------------------------

Horizontal sharding support.

Defines a rudimental ‘horizontal sharding’ system which allows a Session
to distribute queries and persistence operations across multiple
databases.

For a usage example, see the Horizontal Sharding example
included in the source distribution.

3.7.9.1 API Documentation
.........................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See ShardedQuery.

See ShardedSession.

 -- Class: sqlalchemy.ext.horizontal_shard.ShardedSession
          (shard_chooser, id_chooser, execute_chooser=None, shards=None,
          query_cls=<class
          'sqlalchemy.ext.horizontal_shard.ShardedQuery'>, **kwargs)

     `Class signature'

     class sqlalchemy.ext.horizontal_shard.ShardedSession.
     (‘sqlalchemy.orm.session.Session’)

      -- Method: sqlalchemy.ext.horizontal_shard.ShardedSession..
               __init__ (shard_chooser, id_chooser,
               execute_chooser=None, shards=None, query_cls=<class
               'sqlalchemy.ext.horizontal_shard.ShardedQuery'>,
               **kwargs)

          Construct a ShardedSession.

          Parameters:

             * ‘shard_chooser’ – A callable which, passed a Mapper, a
               mapped instance, and possibly a SQL clause, returns a
               shard ID. This id may be based off of the attributes
               present within the object, or on some round-robin scheme.
               If the scheme is based on a selection, it should set
               whatever state on the instance to mark it in the future
               as participating in that shard.

             * ‘id_chooser’ – A callable, passed a query and a tuple of
               identity values, which should return a list of shard ids
               where the ID might reside.  The databases will be queried
               in the order of this listing.

             * ‘execute_chooser’ – For a given ORMExecuteState,
               returns the list of shard_ids where the query should
               be issued.  Results from all shards returned will be
               combined together into a single listing.

               Changed in version 1.4: The ‘execute_chooser’ parameter
               supersedes the ‘query_chooser’ parameter.

             * ‘shards’ – A dictionary of string shard names to
               Engine objects.

      -- Method: sqlalchemy.ext.horizontal_shard.ShardedSession..
               connection_callable (mapper=None, instance=None,
               shard_id=None, **kwargs)

          Provide a Connection to use in the unit of work
          flush process.

      -- Method: sqlalchemy.ext.horizontal_shard.ShardedSession..
               get_bind (mapper=None, shard_id=None, instance=None,
               clause=None, **kw)

          Return a “bind” to which this Session is bound.

          The “bind” is usually an instance of Engine, except
          in the case where the Session has been explicitly
          bound directly to a Connection.

          For a multiply-bound or unbound Session, the
          ‘mapper’ or ‘clause’ arguments are used to determine the
          appropriate bind to return.

          Note that the “mapper” argument is usually present when
          Session.get_bind() is called via an ORM operation such
          as a Session.query(), each individual
          INSERT/UPDATE/DELETE operation within a Session.flush(),
          call, etc.

          The order of resolution is:

            1. if mapper given and Session.binds is present,
               locate a bind based first on the mapper in use, then on
               the mapped class in use, then on any base classes that
               are present in the ‘__mro__’ of the mapped class, from
               more specific superclasses to more general.

            2. if clause given and ‘Session.binds’ is present, locate a
               bind based on Table objects found in the given
               clause present in ‘Session.binds’.

            3. if ‘Session.binds’ is present, return that.

            4. if clause given, attempt to return a bind linked to the
               MetaData ultimately associated with the
               clause.

            5. if mapper given, attempt to return a bind linked to the
               MetaData ultimately associated with the
               Table or other selectable to which the mapper is
               mapped.

            6. No bind can be found, see UnboundExecutionError.
               is raised.

          Note that the Session.get_bind() method can be
          overridden on a user-defined subclass of Session to
          provide any kind of bind resolution scheme.  See the example
          at Custom Vertical Partitioning.

          Parameters:

             * ‘mapper’ – Optional mapper() mapped class or
               instance of Mapper.  The bind can be derived
               from a Mapper first by consulting the “binds”
               map associated with this Session, and secondly
               by consulting the MetaData associated with the
               Table to which the Mapper is
               mapped for a bind.

             * ‘clause’ – A ClauseElement. (i.e.  see
               select(), text(), etc.).  If the ‘mapper’
               argument is not present or could not produce a bind, the
               given expression construct will be searched for a bound
               element, typically a Table associated with
               bound MetaData.

          See also
          ........

          See Partitioning Strategies (e.g. multiple database backends per Session).

          See Session.binds.

          See Session.bind_mapper().

          See Session.bind_table().

 -- Class: sqlalchemy.ext.horizontal_shard.ShardedQuery (*args,
          **kwargs)

     `Class signature'

     class sqlalchemy.ext.horizontal_shard.ShardedQuery.
     (see sqlalchemy.orm.Query)

      -- Method: sqlalchemy.ext.horizontal_shard.ShardedQuery..
               set_shard (shard_id)

          Return a new query, limited to a single shard ID.

          All subsequent operations with the returned query will be
          against the single shard regardless of other state.

          The shard_id can be passed for a 2.0 style execution to the
          bind_arguments dictionary of Session.execute():

               results = session.execute(
                   stmt,
                   bind_arguments={"shard_id": "my_shard"}
               )

3.7.10 Hybrid Attributes
------------------------

Define attributes on ORM-mapped classes that have “hybrid” behavior.

“hybrid” means the attribute has distinct behaviors defined at the class
level and at the instance level.

The hybrid extension provides a special form of method
decorator, is around 50 lines of code and has almost no dependencies on
the rest of SQLAlchemy.  It can, in theory, work with any
descriptor-based expression system.

Consider a mapping ‘Interval’, representing integer ‘start’ and ‘end’
values.  We can define higher level functions on mapped classes that
produce SQL expressions at the class level, and Python expression
evaluation at the instance level.  Below, each function decorated with
hybrid_method or hybrid_property may receive
‘self’ as an instance of the class, or as the class itself:

     from sqlalchemy import Column, Integer
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.orm import Session, aliased
     from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method

     Base = declarative_base()

     class Interval(Base):
         __tablename__ = 'interval'

         id = Column(Integer, primary_key=True)
         start = Column(Integer, nullable=False)
         end = Column(Integer, nullable=False)

         def __init__(self, start, end):
             self.start = start
             self.end = end

         @hybrid_property
         def length(self):
             return self.end - self.start

         @hybrid_method
         def contains(self, point):
             return (self.start <= point) & (point <= self.end)

         @hybrid_method
         def intersects(self, other):
             return self.contains(other.start) | self.contains(other.end)

Above, the ‘length’ property returns the difference between the ‘end’
and ‘start’ attributes.  With an instance of ‘Interval’, this
subtraction occurs in Python, using normal Python descriptor mechanics:

     >>> i1 = Interval(5, 10)
     >>> i1.length
     5

When dealing with the ‘Interval’ class itself, the
hybrid_property descriptor evaluates the function body given the
‘Interval’ class as the argument, which when evaluated with SQLAlchemy
expression mechanics (here using the
QueryableAttribute.expression accessor) returns a new SQL
expression:

     >>> print(Interval.length.expression)
     interval."end" - interval.start

     >>> print(Session().query(Interval).filter(Interval.length > 10))
     SELECT interval.id AS interval_id, interval.start AS interval_start,
     interval."end" AS interval_end
     FROM interval
     WHERE interval."end" - interval.start > :param_1

ORM methods such as Query.filter_by() generally use
‘getattr()’ to locate attributes, so can also be used with hybrid
attributes:

     >>> print(Session().query(Interval).filter_by(length=5))
     SELECT interval.id AS interval_id, interval.start AS interval_start,
     interval."end" AS interval_end
     FROM interval
     WHERE interval."end" - interval.start = :param_1

The ‘Interval’ class example also illustrates two methods, ‘contains()’
and ‘intersects()’, decorated with hybrid_method.  This
decorator applies the same idea to methods that hybrid_property
applies to attributes.  The methods return boolean values, and take
advantage of the Python ‘|’ and ‘&’ bitwise operators to produce
equivalent instance-level and SQL expression-level boolean behavior:

     >>> i1.contains(6)
     True
     >>> i1.contains(15)
     False
     >>> i1.intersects(Interval(7, 18))
     True
     >>> i1.intersects(Interval(25, 29))
     False

     >>> print(Session().query(Interval).filter(Interval.contains(15)))
     SELECT interval.id AS interval_id, interval.start AS interval_start,
     interval."end" AS interval_end
     FROM interval
     WHERE interval.start <= :start_1 AND interval."end" > :end_1

     >>> ia = aliased(Interval)
     >>> print(Session().query(Interval, ia).filter(Interval.intersects(ia)))
     SELECT interval.id AS interval_id, interval.start AS interval_start,
     interval."end" AS interval_end, interval_1.id AS interval_1_id,
     interval_1.start AS interval_1_start, interval_1."end" AS interval_1_end
     FROM interval, interval AS interval_1
     WHERE interval.start <= interval_1.start
         AND interval."end" > interval_1.start
         OR interval.start <= interval_1."end"
         AND interval."end" > interval_1."end"

3.7.10.1 Defining Expression Behavior Distinct from Attribute Behavior
......................................................................

Our usage of the ‘&’ and ‘|’ bitwise operators above was fortunate,
considering our functions operated on two boolean values to return a new
one.  In many cases, the construction of an in-Python function and a
SQLAlchemy SQL expression have enough differences that two separate
Python expressions should be defined.  The hybrid decorators
define the hybrid_property.expression() modifier for this
purpose.  As an example we’ll define the radius of the interval, which
requires the usage of the absolute value function:

     from sqlalchemy import func

     class Interval(object):
         # ...

         @hybrid_property
         def radius(self):
             return abs(self.length) / 2

         @radius.expression
         def radius(cls):
             return func.abs(cls.length) / 2

Above the Python function ‘abs()’ is used for instance-level operations,
the SQL function ‘ABS()’ is used via the func object for
class-level expressions:

     >>> i1.radius
     2

     >>> print(Session().query(Interval).filter(Interval.radius > 5))
     SELECT interval.id AS interval_id, interval.start AS interval_start,
         interval."end" AS interval_end
     FROM interval
     WHERE abs(interval."end" - interval.start) / :abs_1 > :param_1

     Note: When defining an expression for a hybrid property or method,
     the expression method `must' retain the name of the original
     hybrid, else the new hybrid with the additional state will be
     attached to the class with the non-matching name.  To use the
     example above:

          class Interval(object):
              # ...

              @hybrid_property
              def radius(self):
                  return abs(self.length) / 2

              # WRONG - the non-matching name will cause this function to be
              # ignored
              @radius.expression
              def radius_expression(cls):
                  return func.abs(cls.length) / 2

     This is also true for other mutator methods, such as
     hybrid_property.update_expression().  This is the same
     behavior as that of the ‘@property’ construct that is part of
     standard Python.

3.7.10.2 Defining Setters
.........................

Hybrid properties can also define setter methods.  If we wanted ‘length’
above, when set, to modify the endpoint value:

     class Interval(object):
         # ...

         @hybrid_property
         def length(self):
             return self.end - self.start

         @length.setter
         def length(self, value):
             self.end = self.start + value

The ‘length(self, value)’ method is now called upon set:

     >>> i1 = Interval(5, 10)
     >>> i1.length
     5
     >>> i1.length = 12
     >>> i1.end
     17

3.7.10.3 Allowing Bulk ORM Update
.................................

A hybrid can define a custom “UPDATE” handler for when using the
Query.update() method, allowing the hybrid to be used in the SET
clause of the update.

Normally, when using a hybrid with Query.update(), the SQL
expression is used as the column that’s the target of the SET. If our
‘Interval’ class had a hybrid ‘start_point’ that linked to
‘Interval.start’, this could be substituted directly:

     session.query(Interval).update({Interval.start_point: 10})

However, when using a composite hybrid like ‘Interval.length’, this
hybrid represents more than one column.  We can set up a handler that
will accommodate a value passed to Query.update() which can
affect this, using the hybrid_property.update_expression()
decorator.  A handler that works similarly to our setter would be:

     class Interval(object):
         # ...

         @hybrid_property
         def length(self):
             return self.end - self.start

         @length.setter
         def length(self, value):
             self.end = self.start + value

         @length.update_expression
         def length(cls, value):
             return [
                 (cls.end, cls.start + value)
             ]

Above, if we use ‘Interval.length’ in an UPDATE expression as:

     session.query(Interval).update(
         {Interval.length: 25}, synchronize_session='fetch')

We’ll get an UPDATE statement along the lines of:

     UPDATE interval SET end=start + :value

In some cases, the default “evaluate” strategy can’t perform the SET
expression in Python; while the addition operator we’re using above is
supported, for more complex SET expressions it will usually be necessary
to use either the “fetch” or False synchronization strategy as
illustrated above.

New in version 1.2: added support for bulk updates to hybrid properties.

3.7.10.4 Working with Relationships
...................................

There’s no essential difference when creating hybrids that work with
related objects as opposed to column-based data.  The need for distinct
expressions tends to be greater.  The two variants we’ll illustrate are
the “join-dependent” hybrid, and the “correlated subquery” hybrid.

3.7.10.5 Join-Dependent Relationship Hybrid
...........................................

Consider the following declarative mapping which relates a ‘User’ to a
‘SavingsAccount’:

     from sqlalchemy import Column, Integer, ForeignKey, Numeric, String
     from sqlalchemy.orm import relationship
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.ext.hybrid import hybrid_property

     Base = declarative_base()

     class SavingsAccount(Base):
         __tablename__ = 'account'
         id = Column(Integer, primary_key=True)
         user_id = Column(Integer, ForeignKey('user.id'), nullable=False)
         balance = Column(Numeric(15, 5))

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         name = Column(String(100), nullable=False)

         accounts = relationship("SavingsAccount", backref="owner")

         @hybrid_property
         def balance(self):
             if self.accounts:
                 return self.accounts[0].balance
             else:
                 return None

         @balance.setter
         def balance(self, value):
             if not self.accounts:
                 account = Account(owner=self)
             else:
                 account = self.accounts[0]
             account.balance = value

         @balance.expression
         def balance(cls):
             return SavingsAccount.balance

The above hybrid property ‘balance’ works with the first
‘SavingsAccount’ entry in the list of accounts for this user.  The
in-Python getter/setter methods can treat ‘accounts’ as a Python list
available on ‘self’.

However, at the expression level, it’s expected that the ‘User’ class
will be used in an appropriate context such that an appropriate join to
‘SavingsAccount’ will be present:

     >>> print(Session().query(User, User.balance).
     ...       join(User.accounts).filter(User.balance > 5000))
     SELECT "user".id AS user_id, "user".name AS user_name,
     account.balance AS account_balance
     FROM "user" JOIN account ON "user".id = account.user_id
     WHERE account.balance > :balance_1

Note however, that while the instance level accessors need to worry
about whether ‘self.accounts’ is even present, this issue expresses
itself differently at the SQL expression level, where we basically would
use an outer join:

     >>> from sqlalchemy import or_
     >>> print (Session().query(User, User.balance).outerjoin(User.accounts).
     ...         filter(or_(User.balance < 5000, User.balance == None)))
     SELECT "user".id AS user_id, "user".name AS user_name,
     account.balance AS account_balance
     FROM "user" LEFT OUTER JOIN account ON "user".id = account.user_id
     WHERE account.balance <  :balance_1 OR account.balance IS NULL

3.7.10.6 Correlated Subquery Relationship Hybrid
................................................

We can, of course, forego being dependent on the enclosing query’s usage
of joins in favor of the correlated subquery, which can portably be
packed into a single column expression.  A correlated subquery is more
portable, but often performs more poorly at the SQL level.  Using the
same technique illustrated at Using column_property, we can
adjust our ‘SavingsAccount’ example to aggregate the balances for `all'
accounts, and use a correlated subquery for the column expression:

     from sqlalchemy import Column, Integer, ForeignKey, Numeric, String
     from sqlalchemy.orm import relationship
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.ext.hybrid import hybrid_property
     from sqlalchemy import select, func

     Base = declarative_base()

     class SavingsAccount(Base):
         __tablename__ = 'account'
         id = Column(Integer, primary_key=True)
         user_id = Column(Integer, ForeignKey('user.id'), nullable=False)
         balance = Column(Numeric(15, 5))

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         name = Column(String(100), nullable=False)

         accounts = relationship("SavingsAccount", backref="owner")

         @hybrid_property
         def balance(self):
             return sum(acc.balance for acc in self.accounts)

         @balance.expression
         def balance(cls):
             return select(func.sum(SavingsAccount.balance)).\
                     where(SavingsAccount.user_id==cls.id).\
                     label('total_balance')

The above recipe will give us the ‘balance’ column which renders a
correlated SELECT:

     >>> print(s.query(User).filter(User.balance > 400))
     SELECT "user".id AS user_id, "user".name AS user_name
     FROM "user"
     WHERE (SELECT sum(account.balance) AS sum_1
     FROM account
     WHERE account.user_id = "user".id) > :param_1

3.7.10.7 Building Custom Comparators
....................................

The hybrid property also includes a helper that allows construction of
custom comparators.  A comparator object allows one to customize the
behavior of each SQLAlchemy expression operator individually.  They are
useful when creating custom types that have some highly idiosyncratic
behavior on the SQL side.

     Note: The hybrid_property.comparator() decorator
     introduced in this section `replaces' the use of the
     hybrid_property.expression() decorator.  They cannot be used
     together.

The example class below allows case-insensitive comparisons on the
attribute named ‘word_insensitive’:

     from sqlalchemy.ext.hybrid import Comparator, hybrid_property
     from sqlalchemy import func, Column, Integer, String
     from sqlalchemy.orm import Session
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class CaseInsensitiveComparator(Comparator):
         def __eq__(self, other):
             return func.lower(self.__clause_element__()) == func.lower(other)

     class SearchWord(Base):
         __tablename__ = 'searchword'
         id = Column(Integer, primary_key=True)
         word = Column(String(255), nullable=False)

         @hybrid_property
         def word_insensitive(self):
             return self.word.lower()

         @word_insensitive.comparator
         def word_insensitive(cls):
             return CaseInsensitiveComparator(cls.word)

Above, SQL expressions against ‘word_insensitive’ will apply the
‘LOWER()’ SQL function to both sides:

     >>> print(Session().query(SearchWord).filter_by(word_insensitive="Trucks"))
     SELECT searchword.id AS searchword_id, searchword.word AS searchword_word
     FROM searchword
     WHERE lower(searchword.word) = lower(:lower_1)

The ‘CaseInsensitiveComparator’ above implements part of the
ColumnOperators interface.  A “coercion” operation like
lowercasing can be applied to all comparison operations (i.e.  ‘eq’,
‘lt’, ‘gt’, etc.)  using Operators.operate():

     class CaseInsensitiveComparator(Comparator):
         def operate(self, op, other):
             return op(func.lower(self.__clause_element__()), func.lower(other))

3.7.10.8 Reusing Hybrid Properties across Subclasses
....................................................

A hybrid can be referred to from a superclass, to allow modifying
methods like hybrid_property.getter(),
hybrid_property.setter() to be used to redefine those methods on a
subclass.  This is similar to how the standard Python ‘@property’ object
works:

     class FirstNameOnly(Base):
         # ...

         first_name = Column(String)

         @hybrid_property
         def name(self):
             return self.first_name

         @name.setter
         def name(self, value):
             self.first_name = value

     class FirstNameLastName(FirstNameOnly):
         # ...

         last_name = Column(String)

         @FirstNameOnly.name.getter
         def name(self):
             return self.first_name + ' ' + self.last_name

         @name.setter
         def name(self, value):
             self.first_name, self.last_name = value.split(' ', 1)

Above, the ‘FirstNameLastName’ class refers to the hybrid from
‘FirstNameOnly.name’ to repurpose its getter and setter for the
subclass.

When overriding hybrid_property.expression() and
hybrid_property.comparator() alone as the first reference to the
superclass, these names conflict with the same-named accessors on the
class- level QueryableAttribute object returned at the class
level.  To override these methods when referring directly to the parent
class descriptor, add the special qualifier
hybrid_property.overrides, which will de- reference the
instrumented attribute back to the hybrid object:

     class FirstNameLastName(FirstNameOnly):
         # ...

         last_name = Column(String)

         @FirstNameOnly.name.overrides.expression
         def name(cls):
             return func.concat(cls.first_name, ' ', cls.last_name)

New in version 1.2: Added hybrid_property.getter() as well
as the ability to redefine accessors per-subclass.

3.7.10.9 Hybrid Value Objects
.............................

Note in our previous example, if we were to compare the
‘word_insensitive’ attribute of a ‘SearchWord’ instance to a plain
Python string, the plain Python string would not be coerced to lower
case - the ‘CaseInsensitiveComparator’ we built, being returned by
‘@word_insensitive.comparator’, only applies to the SQL side.

A more comprehensive form of the custom comparator is to construct a
`Hybrid Value Object'.  This technique applies the target value or
expression to a value object which is then returned by the accessor in
all cases.  The value object allows control of all operations upon the
value as well as how compared values are treated, both on the SQL
expression side as well as the Python value side.  Replacing the
previous ‘CaseInsensitiveComparator’ class with a new
‘CaseInsensitiveWord’ class:

     class CaseInsensitiveWord(Comparator):
         "Hybrid value representing a lower case representation of a word."

         def __init__(self, word):
             if isinstance(word, basestring):
                 self.word = word.lower()
             elif isinstance(word, CaseInsensitiveWord):
                 self.word = word.word
             else:
                 self.word = func.lower(word)

         def operate(self, op, other):
             if not isinstance(other, CaseInsensitiveWord):
                 other = CaseInsensitiveWord(other)
             return op(self.word, other.word)

         def __clause_element__(self):
             return self.word

         def __str__(self):
             return self.word

         key = 'word'
         "Label to apply to Query tuple results"

Above, the ‘CaseInsensitiveWord’ object represents ‘self.word’, which
may be a SQL function, or may be a Python native.  By overriding
‘operate()’ and ‘__clause_element__()’ to work in terms of ‘self.word’,
all comparison operations will work against the “converted” form of
‘word’, whether it be SQL side or Python side.  Our ‘SearchWord’ class
can now deliver the ‘CaseInsensitiveWord’ object unconditionally from a
single hybrid call:

     class SearchWord(Base):
         __tablename__ = 'searchword'
         id = Column(Integer, primary_key=True)
         word = Column(String(255), nullable=False)

         @hybrid_property
         def word_insensitive(self):
             return CaseInsensitiveWord(self.word)

The ‘word_insensitive’ attribute now has case-insensitive comparison
behavior universally, including SQL expression vs.  Python expression
(note the Python value is converted to lower case on the Python side
here):

     >>> print(Session().query(SearchWord).filter_by(word_insensitive="Trucks"))
     SELECT searchword.id AS searchword_id, searchword.word AS searchword_word
     FROM searchword
     WHERE lower(searchword.word) = :lower_1

SQL expression versus SQL expression:

     >>> sw1 = aliased(SearchWord)
     >>> sw2 = aliased(SearchWord)
     >>> print(Session().query(
     ...                    sw1.word_insensitive,
     ...                    sw2.word_insensitive).\
     ...                        filter(
     ...                            sw1.word_insensitive > sw2.word_insensitive
     ...                        ))
     SELECT lower(searchword_1.word) AS lower_1,
     lower(searchword_2.word) AS lower_2
     FROM searchword AS searchword_1, searchword AS searchword_2
     WHERE lower(searchword_1.word) > lower(searchword_2.word)

Python only expression:

     >>> ws1 = SearchWord(word="SomeWord")
     >>> ws1.word_insensitive == "sOmEwOrD"
     True
     >>> ws1.word_insensitive == "XOmEwOrX"
     False
     >>> print(ws1.word_insensitive)
     someword

The Hybrid Value pattern is very useful for any kind of value that may
have multiple representations, such as timestamps, time deltas, units of
measurement, currencies and encrypted passwords.

See also
........

Hybrids and Value Agnostic Types(1) - on the techspot.zzzeek.org blog

Value Agnostic Types, Part II(2) - on the techspot.zzzeek.org blog

   ---------- Footnotes ----------

   (1)
http://techspot.zzzeek.org/2011/10/21/hybrids-and-value-agnostic-types/

   (2)
http://techspot.zzzeek.org/2011/10/29/value-agnostic-types-part-ii/

3.7.10.10 Building Transformers
...............................

A `transformer' is an object which can receive a Query
object and return a new one.  The Query object includes a
method with_transformation() that returns a new Query
transformed by the given function.

We can combine this with the Comparator class to produce one
type of recipe which can both set up the FROM clause of a query as well
as assign filtering criterion.

Consider a mapped class ‘Node’, which assembles using adjacency list
into a hierarchical tree pattern:

     from sqlalchemy import Column, Integer, ForeignKey
     from sqlalchemy.orm import relationship
     from sqlalchemy.ext.declarative import declarative_base
     Base = declarative_base()

     class Node(Base):
         __tablename__ = 'node'
         id = Column(Integer, primary_key=True)
         parent_id = Column(Integer, ForeignKey('node.id'))
         parent = relationship("Node", remote_side=id)

Suppose we wanted to add an accessor ‘grandparent’.  This would return
the ‘parent’ of ‘Node.parent’.  When we have an instance of ‘Node’, this
is simple:

     from sqlalchemy.ext.hybrid import hybrid_property

     class Node(Base):
         # ...

         @hybrid_property
         def grandparent(self):
             return self.parent.parent

For the expression, things are not so clear.  We’d need to construct a
Query where we Query.join() twice along
‘Node.parent’ to get to the ‘grandparent’.  We can instead return a
transforming callable that we’ll combine with the Comparator
class to receive any Query object, and return a new one
that’s joined to the ‘Node.parent’ attribute and filtered based on the
given criterion:

     from sqlalchemy.ext.hybrid import Comparator

     class GrandparentTransformer(Comparator):
         def operate(self, op, other):
             def transform(q):
                 cls = self.__clause_element__()
                 parent_alias = aliased(cls)
                 return q.join(parent_alias, cls.parent).\
                             filter(op(parent_alias.parent, other))
             return transform

     Base = declarative_base()

     class Node(Base):
         __tablename__ = 'node'
         id = Column(Integer, primary_key=True)
         parent_id = Column(Integer, ForeignKey('node.id'))
         parent = relationship("Node", remote_side=id)

         @hybrid_property
         def grandparent(self):
             return self.parent.parent

         @grandparent.comparator
         def grandparent(cls):
             return GrandparentTransformer(cls)

The ‘GrandparentTransformer’ overrides the core
Operators.operate() method at the base of the Comparator
hierarchy to return a query- transforming callable, which then runs
the given comparison operation in a particular context.  Such as, in the
example above, the ‘operate’ method is called, given the ‘Operators.eq’
callable as well as the right side of the comparison ‘Node(id=5)’.  A
function ‘transform’ is then returned which will transform a
Query first to join to ‘Node.parent’, then to compare
‘parent_alias’ using ‘Operators.eq’ against the left and right sides,
passing into Query.filter():

     >>> from sqlalchemy.orm import Session
     >>> session = Session()
     {sql}>>> session.query(Node).\
     ...        with_transformation(Node.grandparent==Node(id=5)).\
     ...        all()
     SELECT node.id AS node_id, node.parent_id AS node_parent_id
     FROM node JOIN node AS node_1 ON node_1.id = node.parent_id
     WHERE :param_1 = node_1.parent_id
     {stop}

We can modify the pattern to be more verbose but flexible by separating
the “join” step from the “filter” step.  The tricky part here is
ensuring that successive instances of ‘GrandparentTransformer’ use the
same AliasedClass object against ‘Node’.  Below we use a
simple memoizing approach that associates a ‘GrandparentTransformer’
with each class:

     class Node(Base):

         # ...

         @grandparent.comparator
         def grandparent(cls):
             # memoize a GrandparentTransformer
             # per class
             if '_gp' not in cls.__dict__:
                 cls._gp = GrandparentTransformer(cls)
             return cls._gp

     class GrandparentTransformer(Comparator):

         def __init__(self, cls):
             self.parent_alias = aliased(cls)

         @property
         def join(self):
             def go(q):
                 return q.join(self.parent_alias, Node.parent)
             return go

         def operate(self, op, other):
             return op(self.parent_alias.parent, other)

     {sql}>>> session.query(Node).\
     ...            with_transformation(Node.grandparent.join).\
     ...            filter(Node.grandparent==Node(id=5))
     SELECT node.id AS node_id, node.parent_id AS node_parent_id
     FROM node JOIN node AS node_1 ON node_1.id = node.parent_id
     WHERE :param_1 = node_1.parent_id
     {stop}

The “transformer” pattern is an experimental pattern that starts to make
usage of some functional programming paradigms.  While it’s only
recommended for advanced and/or patient developers, there’s probably a
whole lot of amazing things it can be used for.

3.7.10.11 API Reference
.......................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See Comparator.A helper class that allows easy construction of custom ‘PropComparator’ classes for usage
               with hybrids.

See hybrid_method.A decorator which allows definition of a Python object method with both instance-level and
               class-level behavior.

See HYBRID_METHOD.Symbol indicating an ‘InspectionAttr’ that’s of type hybrid_method.

See hybrid_property.A decorator which allows definition of a Python descriptor with both instance-level and
               class-level behavior.

See HYBRID_PROPERTY.

 -- Class: sqlalchemy.ext.hybrid.hybrid_method (func, expr=None)

     A decorator which allows definition of a Python object method with
     both instance-level and class-level behavior.

     `Class signature'

     class sqlalchemy.ext.hybrid.hybrid_method.
     (‘sqlalchemy.orm.base.InspectionAttrInfo’)

      -- Method: sqlalchemy.ext.hybrid.hybrid_method..
               __init__ (func, expr=None)

          Create a new hybrid_method.

          Usage is typically via decorator:

               from sqlalchemy.ext.hybrid import hybrid_method

               class SomeClass(object):
                   @hybrid_method
                   def value(self, x, y):
                       return self._value + x + y

                   @value.expression
                   def value(self, x, y):
                       return func.some_function(self._value, x, y)

      -- Method: sqlalchemy.ext.hybrid.hybrid_method..
               expression (expr)

          Provide a modifying decorator that defines a SQL-expression
          producing method.

 -- Class: sqlalchemy.ext.hybrid.hybrid_property (fget, fset=None,
          fdel=None, expr=None, custom_comparator=None,
          update_expr=None)

     A decorator which allows definition of a Python descriptor with
     both instance-level and class-level behavior.

     `Class signature'

     class sqlalchemy.ext.hybrid.hybrid_property.
     (‘sqlalchemy.orm.base.InspectionAttrInfo’)

      -- Method: sqlalchemy.ext.hybrid.hybrid_property..
               __init__ (fget, fset=None, fdel=None, expr=None,
               custom_comparator=None, update_expr=None)

          Create a new hybrid_property.

          Usage is typically via decorator:

               from sqlalchemy.ext.hybrid import hybrid_property

               class SomeClass(object):
                   @hybrid_property
                   def value(self):
                       return self._value

                   @value.setter
                   def value(self, value):
                       self._value = value

      -- Method: sqlalchemy.ext.hybrid.hybrid_property..
               comparator (comparator)

          Provide a modifying decorator that defines a custom comparator
          producing method.

          The return value of the decorated method should be an instance
          of Comparator.

               Note: The hybrid_property.comparator()
               decorator `replaces' the use of the
               hybrid_property.expression() decorator.  They
               cannot be used together.

          When a hybrid is invoked at the class level, the
          Comparator object given here is wrapped inside of a
          specialized QueryableAttribute, which is the same
          kind of object used by the ORM to represent other mapped
          attributes.  The reason for this is so that other class-level
          attributes such as docstrings and a reference to the hybrid
          itself may be maintained within the structure that’s returned,
          without any modifications to the original comparator object
          passed in.

               Note: When referring to a hybrid property from an owning
               class (e.g.  ‘SomeClass.some_hybrid’), an instance of
               QueryableAttribute is returned, representing
               the expression or comparator object as this hybrid
               object.  However, that object itself has accessors called
               ‘expression’ and ‘comparator’; so when attempting to
               override these decorators on a subclass, it may be
               necessary to qualify it using the
               hybrid_property.overrides modifier first.  See that
               modifier for details.

      -- Method: sqlalchemy.ext.hybrid.hybrid_property..
               deleter (fdel)

          Provide a modifying decorator that defines a deletion method.

      -- Method: sqlalchemy.ext.hybrid.hybrid_property..
               expression (expr)

          Provide a modifying decorator that defines a SQL-expression
          producing method.

          When a hybrid is invoked at the class level, the SQL
          expression given here is wrapped inside of a specialized
          QueryableAttribute, which is the same kind of object used
          by the ORM to represent other mapped attributes.  The reason
          for this is so that other class-level attributes such as
          docstrings and a reference to the hybrid itself may be
          maintained within the structure that’s returned, without any
          modifications to the original SQL expression passed in.

               Note: When referring to a hybrid property from an owning
               class (e.g.  ‘SomeClass.some_hybrid’), an instance of
               QueryableAttribute is returned, representing
               the expression or comparator object as well as this
               hybrid object.  However, that object itself has accessors
               called ‘expression’ and ‘comparator’; so when attempting
               to override these decorators on a subclass, it may be
               necessary to qualify it using the
               hybrid_property.overrides modifier first.  See that
               modifier for details.

          See also
          ........

          See Defining Expression Behavior Distinct from Attribute Behavior.

      -- Method: sqlalchemy.ext.hybrid.hybrid_property..
               getter (fget)

          Provide a modifying decorator that defines a getter method.

          New in version 1.2.

      -- Attribute: sqlalchemy.ext.hybrid.hybrid_property..
               overrides

          Prefix for a method that is overriding an existing attribute.

          The hybrid_property.overrides accessor just
          returns this hybrid object, which when called at the class
          level from a parent class, will de-reference the “instrumented
          attribute” normally returned at this level, and allow
          modifying decorators like hybrid_property.expression()
          and hybrid_property.comparator() to be used
          without conflicting with the same-named attributes normally
          present on the QueryableAttribute:

               class SuperClass(object):
                   # ...

                   @hybrid_property
                   def foobar(self):
                       return self._foobar

               class SubClass(SuperClass):
                   # ...

                   @SuperClass.foobar.overrides.expression
                   def foobar(cls):
                       return func.subfoobar(self._foobar)

          New in version 1.2.

          See also
          ........

          See Reusing Hybrid Properties across Subclasses.

      -- Method: sqlalchemy.ext.hybrid.hybrid_property..
               setter (fset)

          Provide a modifying decorator that defines a setter method.

      -- Method: sqlalchemy.ext.hybrid.hybrid_property..
               update_expression (meth)

          Provide a modifying decorator that defines an UPDATE tuple
          producing method.

          The method accepts a single value, which is the value to be
          rendered into the SET clause of an UPDATE statement.  The
          method should then process this value into individual column
          expressions that fit into the ultimate SET clause, and return
          them as a sequence of 2-tuples.  Each tuple contains a column
          expression as the key and a value to be rendered.

          E.g.:

               class Person(Base):
                   # ...

                   first_name = Column(String)
                   last_name = Column(String)

                   @hybrid_property
                   def fullname(self):
                       return first_name + " " + last_name

                   @fullname.update_expression
                   def fullname(cls, value):
                       fname, lname = value.split(" ", 1)
                       return [
                           (cls.first_name, fname),
                           (cls.last_name, lname)
                       ]

          New in version 1.2.

 -- Class: sqlalchemy.ext.hybrid.Comparator (expression)

     A helper class that allows easy construction of custom
     ‘PropComparator’ classes for usage with hybrids.

     `Class signature'

     class sqlalchemy.ext.hybrid.Comparator. (see
     sqlalchemy.orm.PropComparator)

 -- Data: sqlalchemy.ext.hybrid.HYBRID_METHOD = symbol('HYBRID_METHOD')

     Symbol indicating an ‘InspectionAttr’ that’s of type
     hybrid_method.

     Is assigned to the InspectionAttr.extension_type
     attribute.

     See also
     ........

     ‘Mapper.all_orm_attributes’

 -- Data: sqlalchemy.ext.hybrid.HYBRID_PROPERTY =
          symbol('HYBRID_PROPERTY')

     Symbol indicating an ‘InspectionAttr’ that’s

          of type hybrid_method.

     Is assigned to the InspectionAttr.extension_type
     attribute.

     See also
     ........

     ‘Mapper.all_orm_attributes’

3.7.11 Indexable
----------------

Define attributes on ORM-mapped classes that have “index” attributes for
columns with Indexable types.

“index” means the attribute is associated with an element of an
Indexable column with the predefined index to access it.  The
Indexable types include types such as ARRAY,
JSON and HSTORE.

The indexable extension provides Column.-like
interface for any element of an Indexable typed column.  In
simple cases, it can be treated as a Column. - mapped
attribute.

New in version 1.1.

3.7.11.1 Synopsis
.................

Given ‘Person’ as a model with a primary key and JSON data field.  While
this field may have any number of elements encoded within it, we would
like to refer to the element called ‘name’ individually as a dedicated
attribute which behaves like a standalone column:

     from sqlalchemy import Column, JSON, Integer
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.ext.indexable import index_property

     Base = declarative_base()

     class Person(Base):
         __tablename__ = 'person'

         id = Column(Integer, primary_key=True)
         data = Column(JSON)

         name = index_property('data', 'name')

Above, the ‘name’ attribute now behaves like a mapped column.  We can
compose a new ‘Person’ and set the value of ‘name’:

     >>> person = Person(name='Alchemist')

The value is now accessible:

     >>> person.name
     'Alchemist'

Behind the scenes, the JSON field was initialized to a new blank
dictionary and the field was set:

     >>> person.data
     {"name": "Alchemist'}

The field is mutable in place:

     >>> person.name = 'Renamed'
     >>> person.name
     'Renamed'
     >>> person.data
     {'name': 'Renamed'}

When using index_property, the change that we make to the
indexable structure is also automatically tracked as history; we no
longer need to use MutableDict in order to track this change
for the unit of work.

Deletions work normally as well:

     >>> del person.name
     >>> person.data
     {}

Above, deletion of ‘person.name’ deletes the value from the dictionary,
but not the dictionary itself.

A missing key will produce ‘AttributeError’:

     >>> person = Person()
     >>> person.name
     ...
     AttributeError: 'name'

Unless you set a default value:

     >>> class Person(Base):
     >>>     __tablename__ = 'person'
     >>>
     >>>     id = Column(Integer, primary_key=True)
     >>>     data = Column(JSON)
     >>>
     >>>     name = index_property('data', 'name', default=None)  # See default

     >>> person = Person()
     >>> print(person.name)
     None

The attributes are also accessible at the class level.  Below, we
illustrate ‘Person.name’ used to generate an indexed SQL criteria:

     >>> from sqlalchemy.orm import Session
     >>> session = Session()
     >>> query = session.query(Person).filter(Person.name == 'Alchemist')

The above query is equivalent to:

     >>> query = session.query(Person).filter(Person.data['name'] == 'Alchemist')

Multiple index_property objects can be chained to produce
multiple levels of indexing:

     from sqlalchemy import Column, JSON, Integer
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.ext.indexable import index_property

     Base = declarative_base()

     class Person(Base):
         __tablename__ = 'person'

         id = Column(Integer, primary_key=True)
         data = Column(JSON)

         birthday = index_property('data', 'birthday')
         year = index_property('birthday', 'year')
         month = index_property('birthday', 'month')
         day = index_property('birthday', 'day')

Above, a query such as:

     q = session.query(Person).filter(Person.year == '1980')

On a PostgreSQL backend, the above query will render as:

     SELECT person.id, person.data
     FROM person
     WHERE person.data -> %(data_1)s -> %(param_1)s = %(param_2)s

3.7.11.2 Default Values
.......................

index_property includes special behaviors for when the
indexed data structure does not exist, and a set operation is called:

   * For an index_property that is given an integer index
     value, the default data structure will be a Python list of ‘None’
     values, at least as long as the index value; the value is then set
     at its place in the list.  This means for an index value of zero,
     the list will be initialized to ‘[None]’ before setting the given
     value, and for an index value of five, the list will be initialized
     to ‘[None, None, None, None, None]’ before setting the fifth
     element to the given value.  Note that an existing list is `not'
     extended in place to receive a value.

   * for an index_property that is given any other kind of
     index value (e.g.  strings usually), a Python dictionary is used as
     the default data structure.

   * The default data structure can be set to any Python callable using
     the index_property.datatype parameter, overriding the
     previous rules.

3.7.11.3 Subclassing
....................

index_property can be subclassed, in particular for the
common use case of providing coercion of values or SQL expressions as
they are accessed.  Below is a common recipe for use with a PostgreSQL
JSON type, where we want to also include automatic casting plus
‘astext()’:

     class pg_json_property(index_property):
         def __init__(self, attr_name, index, cast_type):
             super(pg_json_property, self).__init__(attr_name, index)
             self.cast_type = cast_type

         def expr(self, model):
             expr = super(pg_json_property, self).expr(model)
             return expr.astext.cast(self.cast_type)

The above subclass can be used with the PostgreSQL-specific version of
JSON:

     from sqlalchemy import Column, Integer
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.dialects.postgresql import JSON

     Base = declarative_base()

     class Person(Base):
         __tablename__ = 'person'

         id = Column(Integer, primary_key=True)
         data = Column(JSON)

         age = pg_json_property('data', 'age', Integer)

The ‘age’ attribute at the instance level works as before; however when
rendering SQL, PostgreSQL’s ‘->>’ operator will be used for indexed
access, instead of the usual index operator of ‘->’:

     >>> query = session.query(Person).filter(Person.age < 20)

The above query will render:

     SELECT person.id, person.data
     FROM person
     WHERE CAST(person.data ->> %(data_1)s AS INTEGER) < %(param_1)s

3.7.11.4 API Reference
......................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See index_property.A property generator.  The generated property describes an object attribute that corresponds
               to an Indexable column.

 -- Class: sqlalchemy.ext.indexable.index_property (attr_name, index,
          default=<object object>, datatype=None, mutable=True,
          onebased=True)

     A property generator.  The generated property describes an object
     attribute that corresponds to an Indexable column.

     New in version 1.1.

     See also
     ........

     See sqlalchemy.ext.indexable.

     `Class signature'

     class sqlalchemy.ext.indexable.index_property. (see
     sqlalchemy.ext.hybrid.hybrid_property)

      -- Method: sqlalchemy.ext.indexable.index_property..
               __init__ (attr_name, index, default=<object object>,
               datatype=None, mutable=True, onebased=True)

          Create a new index_property.

          Parameters:

             * ‘attr_name’ – An attribute name of an ‘Indexable’ typed
               column, or other attribute that returns an indexable
               structure.

             * ‘index’ – The index to be used for getting and setting
               this value.  This should be the Python-side index value
               for integers.

             * ‘default’ – A value which will be returned instead of
               ‘AttributeError’ when there is not a value at given
               index.

             * ‘datatype’ – default datatype to use when the field is
               empty.  By default, this is derived from the type of
               index used; a Python list for an integer index, or a
               Python dictionary for any other style of index.  For a
               list, the list will be initialized to a list of None
               values that is at least ‘index’ elements long.

             * ‘mutable’ – if False, writes and deletes to the attribute
               will be disallowed.

             * ‘onebased’ – assume the SQL representation of this value
               is one-based; that is, the first index in SQL is 1, not
               zero.

3.7.12 Alternate Class Instrumentation
--------------------------------------

Extensible class instrumentation.

The sqlalchemy.ext.instrumentation package provides for
alternate systems of class instrumentation within the ORM. Class
instrumentation refers to how the ORM places attributes on the class
which maintain data and track changes to that data, as well as event
hooks installed on the class.

     Note: The extension package is provided for the benefit of
     integration with other object management packages, which already
     perform their own instrumentation.  It is not intended for general
     use.

For examples of how the instrumentation extension is used, see the
example Attribute Instrumentation.

3.7.12.1 API Reference
......................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See ExtendedInstrumentationRegistry.Extends InstrumentationFactory with additional bookkeeping, to accommodate
               multiple types of class managers.

See instrumentation_finders.An extensible sequence of callables which return instrumentation implementations

See INSTRUMENTATION_MANAGER.Attribute, elects custom instrumentation when present on a mapped class.

See InstrumentationFactory.Factory for new ClassManager instances.

See InstrumentationManager.User-defined class instrumentation extension.

 -- Data: sqlalchemy.ext.instrumentation.INSTRUMENTATION_MANAGER =
          '__sa_instrumentation_manager__'

     Attribute, elects custom instrumentation when present on a mapped
     class.

     Allows a class to specify a slightly or wildly different technique
     for tracking changes made to mapped attributes and collections.

     Only one instrumentation implementation is allowed in a given
     object inheritance hierarchy.

     The value of this attribute must be a callable and will be passed a
     class object.  The callable must return one of:

             - An instance of an InstrumentationManager or
               subclass

             - An object implementing all or some of
               InstrumentationManager (TODO)

             - A dictionary of callables, implementing all or some of
               the above (TODO)

             - An instance of a ClassManager or subclass

     This attribute is consulted by SQLAlchemy instrumentation
     resolution, once the sqlalchemy.ext.instrumentation
     module has been imported.  If custom finders are installed in the
     global instrumentation_finders list, they may or may not choose to
     honor this attribute.

 -- Class: sqlalchemy.orm.instrumentation.InstrumentationFactory

     Factory for new ClassManager instances.

 -- Class: sqlalchemy.ext.instrumentation.InstrumentationManager
          (class_)

     User-defined class instrumentation extension.

     InstrumentationManager can be subclassed in order to
     change how class instrumentation proceeds.  This class exists for
     the purposes of integration with other object management frameworks
     which would like to entirely modify the instrumentation methodology
     of the ORM, and is not intended for regular usage.  For
     interception of class instrumentation events, see
     InstrumentationEvents.

     The API for this class should be considered as semi-stable, and may
     change slightly with new releases.

      -- Method:
               sqlalchemy.ext.instrumentation.InstrumentationManager..
               dict_getter (class_)

      -- Method:
               sqlalchemy.ext.instrumentation.InstrumentationManager..
               dispose (class_, manager)

      -- Method:
               sqlalchemy.ext.instrumentation.InstrumentationManager..
               get_instance_dict (class_, instance)

      -- Method:
               sqlalchemy.ext.instrumentation.InstrumentationManager..
               initialize_instance_dict (class_, instance)

      -- Method:
               sqlalchemy.ext.instrumentation.InstrumentationManager..
               install_descriptor (class_, key, inst)

      -- Method:
               sqlalchemy.ext.instrumentation.InstrumentationManager..
               install_member (class_, key, implementation)

      -- Method:
               sqlalchemy.ext.instrumentation.InstrumentationManager..
               install_state (class_, instance, state)

      -- Method:
               sqlalchemy.ext.instrumentation.InstrumentationManager..
               instrument_attribute (class_, key, inst)

      -- Method:
               sqlalchemy.ext.instrumentation.InstrumentationManager..
               instrument_collection_class (class_, key,
               collection_class)

      -- Method:
               sqlalchemy.ext.instrumentation.InstrumentationManager..
               manage (class_, manager)

      -- Method:
               sqlalchemy.ext.instrumentation.InstrumentationManager..
               manager_getter (class_)

      -- Method:
               sqlalchemy.ext.instrumentation.InstrumentationManager..
               post_configure_attribute (class_, key, inst)

      -- Method:
               sqlalchemy.ext.instrumentation.InstrumentationManager..
               remove_state (class_, instance)

      -- Method:
               sqlalchemy.ext.instrumentation.InstrumentationManager..
               state_getter (class_)

      -- Method:
               sqlalchemy.ext.instrumentation.InstrumentationManager..
               uninstall_descriptor (class_, key)

      -- Method:
               sqlalchemy.ext.instrumentation.InstrumentationManager..
               uninstall_member (class_, key)

 -- Data: sqlalchemy.ext.instrumentation.instrumentation_finders =
          [<function find_native_user_instrumentation_hook>]

     An extensible sequence of callables which return instrumentation
     implementations

     When a class is registered, each callable will be passed a class
     object.  If None is returned, the next finder in the sequence is
     consulted.  Otherwise the return must be an instrumentation factory
     that follows the same guidelines as
     sqlalchemy.ext.instrumentation.INSTRUMENTATION_MANAGER.

     By default, the only finder is
     find_native_user_instrumentation_hook, which searches for
     INSTRUMENTATION_MANAGER. If all finders return None, standard
     ClassManager instrumentation is used.

 -- Class:
          sqlalchemy.ext.instrumentation.ExtendedInstrumentationRegistry

     Extends InstrumentationFactory with additional
     bookkeeping, to accommodate multiple types of class managers.

     `Class signature'

     class
     sqlalchemy.ext.instrumentation.ExtendedInstrumentationRegistry.
     (see sqlalchemy.orm.instrumentation.InstrumentationFactory)

3.8 ORM Examples
================

The SQLAlchemy distribution includes a variety of code examples
illustrating a select set of patterns, some typical and some not so
typical.  All are runnable and can be found in the ‘/examples’ directory
of the distribution.  Descriptions and source code for all can be found
here.

Additional SQLAlchemy examples, some user contributed, are available on
the wiki at ‘http://www.sqlalchemy.org/trac/wiki/UsageRecipes’.

3.8.1 Mapping Recipes
---------------------

3.8.1.1 Adjacency List
......................

An example of a dictionary-of-dictionaries structure mapped using an
adjacency list model.

E.g.:

     node = TreeNode('rootnode')
     node.append('node1')
     node.append('node3')
     session.add(node)
     session.commit()

     dump_tree(node)

Listing of files:

   * adjacency_list.py

3.8.1.2 Associations
....................

Examples illustrating the usage of the “association object” pattern,
where an intermediary class mediates the relationship between two
classes that are associated in a many-to-many pattern.

Listing of files:

   *
     basic_association.py - Illustrate a many-to-many relationship
     between an “Order” and a collection of “Item” objects, associating
     a purchase price with each via an association object called
     “OrderItem”

   *
     dict_of_sets_with_default.py - An advanced association proxy
     example which illustrates nesting of association proxies to produce
     multi-level Python collections, in this case a dictionary with
     string keys and sets of integers as values, which conceal the
     underlying mapped classes.

   *
     proxied_association.py - Same example as basic_association, adding
     in usage of sqlalchemy.ext.associationproxy to make
     explicit references to ‘OrderItem’ optional.

3.8.1.3 Asyncio Integration
...........................

Examples illustrating the asyncio engine feature of SQLAlchemy.

Listing of files:

   *
     async_orm.py - Illustrates use of the
     sqlalchemy.ext.asyncio.AsyncSession object for asynchronous ORM
     use.

   *
     basic.py - Illustrates the asyncio engine / connection interface.

   *
     greenlet_orm.py - Illustrates use of the
     sqlalchemy.ext.asyncio.AsyncSession object for asynchronous ORM
     use, including the optional run_sync() method.

3.8.1.4 Directed Graphs
.......................

An example of persistence for a directed graph structure.  The graph is
stored as a collection of edges, each referencing both a “lower” and an
“upper” node in a table of nodes.  Basic persistence and querying for
lower- and upper- neighbors are illustrated:

     n2 = Node(2)
     n5 = Node(5)
     n2.add_neighbor(n5)
     print(n2.higher_neighbors())

Listing of files:

   * directed_graph.py

3.8.1.5 Dynamic Relations as Dictionaries
.........................................

Illustrates how to place a dictionary-like facade on top of a “dynamic”
relation, so that dictionary operations (assuming simple string keys)
can operate upon a large collection without loading the full collection
at once.

Listing of files:

   * dynamic_dict.py

3.8.1.6 Generic Associations
............................

Illustrates various methods of associating multiple types of parents
with a particular child object.

The examples all use the declarative extension along with declarative
mixins.  Each one presents the identical use case at the end - two
classes, ‘Customer’ and ‘Supplier’, both subclassing the ‘HasAddresses’
mixin, which ensures that the parent class is provided with an
‘addresses’ collection which contains ‘Address’ objects.

The discriminator_on_association.py and generic_fk.py scripts are
modernized versions of recipes presented in the 2007 blog post
Polymorphic Associations with SQLAlchemy(1).

Listing of files:

   *
     discriminator_on_association.py - Illustrates a mixin which
     provides a generic association using a single target table and a
     single association table, referred to by all parent tables.  The
     association table contains a “discriminator” column which
     determines what type of parent object associates to each particular
     row in the association table.

   *
     generic_fk.py - Illustrates a so-called “generic foreign key”, in a
     similar fashion to that of popular frameworks such as Django, ROR,
     etc.  This approach bypasses standard referential integrity
     practices, in that the “foreign key” column is not actually
     constrained to refer to any particular table; instead,
     in-application logic is used to determine which table is
     referenced.

   *
     table_per_association.py - Illustrates a mixin which provides a
     generic association via a individually generated association tables
     for each parent class.  The associated objects themselves are
     persisted in a single table shared among all parents.

   *
     table_per_related.py - Illustrates a generic association which
     persists association objects within individual tables, each one
     generated to persist those objects on behalf of a particular parent
     class.

   ---------- Footnotes ----------

   (1)
http://techspot.zzzeek.org/2007/05/29/polymorphic-associations-with-sqlalchemy/

3.8.1.7 Large Collections
.........................

Large collection example.

Illustrates the options to use with relationship() when the
list of related objects is very large, including:

   * “dynamic” relationships which query slices of data as accessed

   * how to use ON DELETE CASCADE in conjunction with
     ‘passive_deletes=True’ to greatly improve the performance of
     related collection deletion.

Listing of files:

   * large_collection.py

3.8.1.8 Materialized Paths
..........................

Illustrates the “materialized paths” pattern for hierarchical data using
the SQLAlchemy ORM.

Listing of files:

   *
     materialized_paths.py - Illustrates the “materialized paths”
     pattern.

3.8.1.9 Nested Sets
...................

Illustrates a rudimentary way to implement the “nested sets” pattern for
hierarchical data using the SQLAlchemy ORM.

Listing of files:

   *
     nested_sets.py - Celko’s “Nested Sets” Tree Structure.

3.8.1.10 Performance
....................

A performance profiling suite for a variety of SQLAlchemy use cases.

Each suite focuses on a specific use case with a particular performance
profile and associated implications:

   * bulk inserts

   * individual inserts, with or without transactions

   * fetching large numbers of rows

   * running lots of short queries

All suites include a variety of use patterns illustrating both Core and
ORM use, and are generally sorted in order of performance from worst to
greatest, inversely based on amount of functionality provided by
SQLAlchemy, greatest to least (these two things generally correspond
perfectly).

A command line tool is presented at the package level which allows
individual suites to be run:

     $ python -m examples.performance --help
     usage: python -m examples.performance [-h] [--test TEST] [--dburl DBURL]
                                           [--num NUM] [--profile] [--dump]
                                           [--echo]

                                           {bulk_inserts,large_resultsets,single_inserts}

     positional arguments:
       {bulk_inserts,large_resultsets,single_inserts}
                             suite to run

     optional arguments:
       -h, --help            show this help message and exit
       --test TEST           run specific test name
       --dburl DBURL         database URL, default sqlite:///profile.db
       --num NUM             Number of iterations/items/etc for tests;
                             default is module-specific
       --profile             run profiling and dump call counts
       --dump                dump full call profile (implies --profile)
       --echo                Echo SQL output

An example run looks like:

     $ python -m examples.performance bulk_inserts

Or with options:

     $ python -m examples.performance bulk_inserts \
         --dburl mysql+mysqldb://scott:tiger@localhost/test \
         --profile --num 1000

See also
........

See How can I profile a SQLAlchemy powered application?.

3.8.1.11 File Listing
.....................

Listing of files:

   *
     __main__.py - Allows the examples/performance package to be run as
     a script.

   *
     bulk_inserts.py - This series of tests illustrates different ways
     to INSERT a large number of rows in bulk.

   *
     bulk_updates.py - This series of tests illustrates different ways
     to UPDATE a large number of rows in bulk.

   *
     large_resultsets.py - In this series of tests, we are looking at
     time to load a large number of very small and simple rows.

   *
     short_selects.py - This series of tests illustrates different ways
     to SELECT a single record by primary key

   *
     single_inserts.py - In this series of tests, we’re looking at a
     method that inserts a row within a distinct transaction, and
     afterwards returns to essentially a “closed” state.  This would be
     analogous to an API call that starts up a database connection,
     inserts the row, commits and closes.

3.8.1.12 Running all tests with time
....................................

This is the default form of run:

     $ python -m examples.performance single_inserts
     Tests to run: test_orm_commit, test_bulk_save,
                   test_bulk_insert_dictionaries, test_core,
                   test_core_query_caching, test_dbapi_raw_w_connect,
                   test_dbapi_raw_w_pool

     test_orm_commit : Individual INSERT/COMMIT pairs via the
         ORM (10000 iterations); total time 13.690218 sec
     test_bulk_save : Individual INSERT/COMMIT pairs using
         the "bulk" API  (10000 iterations); total time 11.290371 sec
     test_bulk_insert_dictionaries : Individual INSERT/COMMIT pairs using
         the "bulk" API with dictionaries (10000 iterations);
         total time 10.814626 sec
     test_core : Individual INSERT/COMMIT pairs using Core.
         (10000 iterations); total time 9.665620 sec
     test_core_query_caching : Individual INSERT/COMMIT pairs using Core
         with query caching (10000 iterations); total time 9.209010 sec
     test_dbapi_raw_w_connect : Individual INSERT/COMMIT pairs w/ DBAPI +
         connection each time (10000 iterations); total time 9.551103 sec
     test_dbapi_raw_w_pool : Individual INSERT/COMMIT pairs w/ DBAPI +
         connection pool (10000 iterations); total time 8.001813 sec

3.8.1.13 Dumping Profiles for Individual Tests
..............................................

A Python profile output can be dumped for all tests, or more commonly
individual tests:

     $ python -m examples.performance single_inserts --test test_core --num 1000 --dump
     Tests to run: test_core
     test_core : Individual INSERT/COMMIT pairs using Core. (1000 iterations); total fn calls 186109
              186109 function calls (186102 primitive calls) in 1.089 seconds

        Ordered by: internal time, call count

        ncalls  tottime  percall  cumtime  percall filename:lineno(function)
          1000    0.634    0.001    0.634    0.001 {method 'commit' of 'sqlite3.Connection' objects}
          1000    0.154    0.000    0.154    0.000 {method 'execute' of 'sqlite3.Cursor' objects}
          1000    0.021    0.000    0.074    0.000 /Users/classic/dev/sqlalchemy/lib/sqlalchemy/sql/compiler.py:1950(_get_colparams)
          1000    0.015    0.000    0.034    0.000 /Users/classic/dev/sqlalchemy/lib/sqlalchemy/engine/default.py:503(_init_compiled)
             1    0.012    0.012    1.091    1.091 examples/performance/single_inserts.py:79(test_core)

         ...

3.8.1.14 Writing your Own Suites
................................

The profiler suite system is extensible, and can be applied to your own
set of tests.  This is a valuable technique to use in deciding upon the
proper approach for some performance-critical set of routines.  For
example, if we wanted to profile the difference between several kinds of
loading, we can create a file ‘test_loads.py’, with the following
content:

     from examples.performance import Profiler
     from sqlalchemy import Integer, Column, create_engine, ForeignKey
     from sqlalchemy.orm import relationship, joinedload, subqueryload, Session
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()
     engine = None
     session = None

     class Parent(Base):
         __tablename__ = 'parent'
         id = Column(Integer, primary_key=True)
         children = relationship("Child")

     class Child(Base):
         __tablename__ = 'child'
         id = Column(Integer, primary_key=True)
         parent_id = Column(Integer, ForeignKey('parent.id'))

     # Init with name of file, default number of items
     Profiler.init("test_loads", 1000)

     @Profiler.setup_once
     def setup_once(dburl, echo, num):
         "setup once.  create an engine, insert fixture data"
         global engine
         engine = create_engine(dburl, echo=echo)
         Base.metadata.drop_all(engine)
         Base.metadata.create_all(engine)
         sess = Session(engine)
         sess.add_all([
             Parent(children=[Child() for j in range(100)])
             for i in range(num)
         ])
         sess.commit()

     @Profiler.setup
     def setup(dburl, echo, num):
         "setup per test.  create a new Session."
         global session
         session = Session(engine)
         # pre-connect so this part isn't profiled (if we choose)
         session.connection()

     @Profiler.profile
     def test_lazyload(n):
         "load everything, no eager loading."

         for parent in session.query(Parent):
             parent.children

     @Profiler.profile
     def test_joinedload(n):
         "load everything, joined eager loading."

         for parent in session.query(Parent).options(joinedload("children")):
             parent.children

     @Profiler.profile
     def test_subqueryload(n):
         "load everything, subquery eager loading."

         for parent in session.query(Parent).options(subqueryload("children")):
             parent.children

     if __name__ == '__main__':
         Profiler.main()

We can run our new script directly:

     $ python test_loads.py  --dburl postgresql+psycopg2://scott:tiger@localhost/test
     Running setup once...
     Tests to run: test_lazyload, test_joinedload, test_subqueryload
     test_lazyload : load everything, no eager loading. (1000 iterations); total time 11.971159 sec
     test_joinedload : load everything, joined eager loading. (1000 iterations); total time 2.754592 sec
     test_subqueryload : load everything, subquery eager loading. (1000 iterations); total time 2.977696 sec

3.8.1.15 Relationship Join Conditions
.....................................

Examples of various relationship() configurations, which make
use of the ‘primaryjoin’ argument to compose special types of join
conditions.

Listing of files:

   *
     cast.py - Illustrate a relationship() that joins two
     columns where those columns are not of the same type, and a CAST
     must be used on the SQL side in order to match them.

   *
     threeway.py - Illustrate a “three way join” - where a primary table
     joins to a remote table via an association table, but then the
     primary table also needs to refer to some columns in the remote
     table directly.

3.8.1.16 Space Invaders
.......................

A Space Invaders game using SQLite as the state machine.

Originally developed in 2012.  Adapted to work in Python 3.

Runs in a textual console using ASCII art.

To run:

     python -m examples.space_invaders.space_invaders

While it runs, watch the SQL output in the log:

     tail -f space_invaders.log

enjoy!

Listing of files:

   * space_invaders.py

3.8.1.17 XML Persistence
........................

Illustrates three strategies for persisting and querying XML documents
as represented by ElementTree in a relational database.  The techniques
do not apply any mappings to the ElementTree objects directly, so are
compatible with the native cElementTree as well as lxml, and can be
adapted to suit any kind of DOM representation system.  Querying along
xpath-like strings is illustrated as well.

E.g.:

     # parse an XML file and persist in the database
     doc = ElementTree.parse("test.xml")
     session.add(Document(file, doc))
     session.commit()

     # locate documents with a certain path/attribute structure
     for document in find_document('/somefile/header/field2[@attr=foo]'):
         # dump the XML
         print(document)

Listing of files:

   *
     pickle_type.py - illustrates a quick and dirty way to persist an
     XML document expressed using ElementTree and pickle.

   *
     adjacency_list.py - Illustrates an explicit way to persist an XML
     document expressed using ElementTree.

   *
     optimized_al.py - Uses the same strategy as ‘adjacency_list.py’,
     but associates each DOM row with its owning document row, so that a
     full document of DOM nodes can be loaded using O(1) queries - the
     construction of the “hierarchy” is performed after the load in a
     non-recursive fashion and is more efficient.

3.8.1.18 Versioning Objects
...........................

3.8.1.19 Versioning with a History Table
........................................

Illustrates an extension which creates version tables for entities and
stores records for each change.  The given extensions generate an
anonymous “history” class which represents historical versions of the
target object.

Compare to the Versioning using Temporal Rows examples which
write updates as new rows in the same table, without using a separate
history table.

Usage is illustrated via a unit test module ‘test_versioning.py’, which
can be run via ‘pytest’:

     # assume SQLAlchemy is installed where pytest is

     cd examples/versioned_history
     pytest test_versioning.py

A fragment of example usage, using declarative:

     from history_meta import Versioned, versioned_session

     Base = declarative_base()

     class SomeClass(Versioned, Base):
         __tablename__ = 'sometable'

         id = Column(Integer, primary_key=True)
         name = Column(String(50))

         def __eq__(self, other):
             assert type(other) is SomeClass and other.id == self.id

     Session = sessionmaker(bind=engine)
     versioned_session(Session)

     sess = Session()
     sc = SomeClass(name='sc1')
     sess.add(sc)
     sess.commit()

     sc.name = 'sc1modified'
     sess.commit()

     assert sc.version == 2

     SomeClassHistory = SomeClass.__history_mapper__.class_

     assert sess.query(SomeClassHistory).\
                 filter(SomeClassHistory.version == 1).\
                 all() \
                 == [SomeClassHistory(version=1, name='sc1')]

The ‘Versioned’ mixin is designed to work with declarative.  To use the
extension with classical mappers, the ‘_history_mapper’ function can be
applied:

     from history_meta import _history_mapper

     m = mapper(SomeClass, sometable)
     _history_mapper(m)

     SomeHistoryClass = SomeClass.__history_mapper__.class_

The versioning example also integrates with the ORM optimistic
concurrency feature documented at Configuring a Version Counter.
To enable this feature, set the flag
‘Versioned.use_mapper_versioning’ to True:

     class SomeClass(Versioned, Base):
         __tablename__ = 'sometable'

         use_mapper_versioning = True

         id = Column(Integer, primary_key=True)
         name = Column(String(50))

         def __eq__(self, other):
             assert type(other) is SomeClass and other.id == self.id

Above, if two instance of ‘SomeClass’ with the same version identifier
are updated and sent to the database for UPDATE concurrently, if the
database isolation level allows the two UPDATE statements to proceed,
one will fail because it no longer is against the last known version
identifier.

Listing of files:

   *
     history_meta.py - Versioned mixin class and other utilities.

   *
     test_versioning.py - Unit tests illustrating usage of the
     ‘history_meta.py’ module functions.

3.8.1.20 Versioning using Temporal Rows
.......................................

Several examples that illustrate the technique of intercepting changes
that would be first interpreted as an UPDATE on a row, and instead
turning it into an INSERT of a new row, leaving the previous row intact
as a historical version.

Compare to the Versioning with a History Table example which
writes a history row to a separate history table.

Listing of files:

   *
     versioned_map.py - A variant of the versioned_rows example built
     around the concept of a “vertical table” structure, like those
     illustrated in Vertical Attribute Mapping examples.

   *
     versioned_rows.py - Illustrates a method to intercept changes on
     objects, turning an UPDATE statement on a single row into an INSERT
     statement, so that a new row is inserted with the new data, keeping
     the old row intact.

   *
     versioned_rows_w_versionid.py - Illustrates a method to intercept
     changes on objects, turning an UPDATE statement on a single row
     into an INSERT statement, so that a new row is inserted with the
     new data, keeping the old row intact.

   *
     versioned_update_old_row.py - Illustrates the same UPDATE into
     INSERT technique of ‘versioned_rows.py’, but also emits an UPDATE
     on the `old' row to affect a change in timestamp.  Also includes a
     QueryEvents.before_compile() hook to limit queries to
     only the most recent version.

3.8.1.21 Vertical Attribute Mapping
...................................

Illustrates “vertical table” mappings.

A “vertical table” refers to a technique where individual attributes of
an object are stored as distinct rows in a table.  The “vertical table”
technique is used to persist objects which can have a varied set of
attributes, at the expense of simple query control and brevity.  It is
commonly found in content/document management systems in order to
represent user-created structures flexibly.

Two variants on the approach are given.  In the second, each row
references a “datatype” which contains information about the type of
information stored in the attribute, such as integer, string, or date.

Example:

     shrew = Animal(u'shrew')
     shrew[u'cuteness'] = 5
     shrew[u'weasel-like'] = False
     shrew[u'poisonous'] = True

     session.add(shrew)
     session.flush()

     q = (session.query(Animal).
          filter(Animal.facts.any(
            and_(AnimalFact.key == u'weasel-like',
                 AnimalFact.value == True))))
     print('weasel-like animals', q.all())

Listing of files:

   *
     dictlike-polymorphic.py - Mapping a polymorphic-valued vertical
     table as a dictionary.

   *
     dictlike.py - Mapping a vertical table as a dictionary.

3.8.2 Inheritance Mapping Recipes
---------------------------------

3.8.2.1 Basic Inheritance Mappings
..................................

Working examples of single-table, joined-table, and concrete-table
inheritance as described in Mapping Class Inheritance Hierarchies.

Listing of files:

   *
     concrete.py - Concrete-table (table-per-class) inheritance example.

   *
     joined.py - Joined-table (table-per-subclass) inheritance example.

   *
     single.py - Single-table (table-per-hierarchy) inheritance example.

3.8.3 Special APIs
------------------

3.8.3.1 Attribute Instrumentation
.................................

Examples illustrating modifications to SQLAlchemy’s attribute management
system.

Listing of files:

   *
     active_column_defaults.py - Illustrates use of the
     AttributeEvents.init_scalar() event, in conjunction with Core
     column defaults to provide ORM objects that automatically produce
     the default value when an un-set attribute is accessed.

   *
     custom_management.py - Illustrates customized class
     instrumentation, using the sqlalchemy.ext.instrumentation
     extension package.

   *
     listen_for_events.py - Illustrates how to attach events to all
     instrumented attributes and listen for change events.

3.8.3.2 Horizontal Sharding
...........................

A basic example of using the SQLAlchemy Sharding API. Sharding refers to
horizontally scaling data across multiple databases.

The basic components of a “sharded” mapping are:

   * multiple Engine instances, each assigned a “shard id”.
     These Engine instances may refer to different
     databases, or different schemas / accounts within the same
     database, or they can even be differentiated only by options that
     will cause them to access different schemas or tables when used.

   * a function which can return a single shard id, given an instance to
     be saved; this is called “shard_chooser”

   * a function which can return a list of shard ids which apply to a
     particular instance identifier; this is called “id_chooser”.If it
     returns all shard ids, all shards will be searched.

   * a function which can return a list of shard ids to try, given a
     particular Query (“query_chooser”).  If it returns all shard ids,
     all shards will be queried and the results joined together.

In these examples, different kinds of shards are used against the same
basic example which accommodates weather data on a per-continent basis.
We provide example shard_chooser, id_chooser and query_chooser
functions.  The query_chooser illustrates inspection of the SQL
expression element in order to attempt to determine a single shard being
requested.

The construction of generic sharding routines is an ambitious approach
to the issue of organizing instances among multiple databases.  For a
more plain-spoken alternative, the “distinct entity” approach is a
simple method of assigning objects to different tables (and potentially
database nodes) in an explicit way - described on the wiki at
EntityName(1).

Listing of files:

   *
     separate_databases.py - Illustrates sharding using distinct SQLite
     databases.

   *
     separate_tables.py - Illustrates sharding using a single SQLite
     database, that will however have multiple tables using a naming
     convention.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/wiki/UsageRecipes/EntityName

3.8.4 Extending the ORM
-----------------------

3.8.4.1 ORM Query Events
........................

Recipes which illustrate augmentation of ORM SELECT behavior as used by
Session.execute() with 2.0 style use of select(),
as well as the 1.x style Query object.

Examples include demonstrations of the with_loader_criteria()
option as well as the SessionEvents.do_orm_execute()
hook.

As of SQLAlchemy 1.4, the Query construct is unified with
the Select construct, so that these two objects are mostly
the same.

Listing of files:

   *
     filter_public.py - Illustrates a global criteria applied to
     entities of a particular type.

   *
     temporal_range.py - Illustrates a custom per-query criteria that
     will be applied to selected entities.

3.8.4.2 Dogpile Caching
.......................

Illustrates how to embed dogpile.cache(1) functionality with ORM
queries, allowing full cache control as well as the ability to pull
“lazy loaded” attributes from long term cache.

In this demo, the following techniques are illustrated:

   * Using the SessionEvents.do_orm_execute() event hook

   * Basic technique of circumventing Session.execute() to
     pull from a custom cache source instead of the database.

   * Rudimental caching with dogpile.cache, using “regions” which allow
     global control over a fixed set of configurations.

   * Using custom ‘UserDefinedOption’ objects to configure options in a
     statement object.

See also
........

See Re-Executing Statements. - includes a general example of the
technique presented here.

E.g.:

     # query for Person objects, specifying cache
     stmt = select(Person).options(FromCache("default"))

     # specify that each Person's "addresses" collection comes from
     # cache too
     stmt = stmt.options(RelationshipCache(Person.addresses, "default"))

     # execute and results
     result = session.execute(stmt)

     print(result.scalars.all())

To run, both SQLAlchemy and dogpile.cache must be installed or on the
current PYTHONPATH. The demo will create a local directory for
datafiles, insert initial data, and run.  Running the demo a second time
will utilize the cache files already present, and exactly one SQL
statement against two tables will be emitted - the displayed result
however will utilize dozens of lazyloads that all pull from cache.

The demo scripts themselves, in order of complexity, are run as Python
modules so that relative imports work:

     python -m examples.dogpile_caching.helloworld

     python -m examples.dogpile_caching.relationship_caching

     python -m examples.dogpile_caching.advanced

     python -m examples.dogpile_caching.local_session_caching

Listing of files:

   *
     environment.py - Establish data / cache file paths, and
     configurations, bootstrap fixture data if necessary.

   *
     caching_query.py - Represent functions and classes which allow the
     usage of Dogpile caching with SQLAlchemy.  Introduces a query
     option called FromCache.

   *
     model.py - The datamodel, which represents Person that has multiple
     Address objects, each with PostalCode, City, Country.

   *
     fixture_data.py - Installs some sample data.  Here we have a
     handful of postal codes for a few US/Canadian cities.  Then, 100
     Person records are installed, each with a randomly selected postal
     code.

   *
     helloworld.py - Illustrate how to load some data, and cache the
     results.

   *
     relationship_caching.py - Illustrates how to add cache options on
     relationship endpoints, so that lazyloads load from cache.

   *
     advanced.py - Illustrate usage of Query combined with the FromCache
     option, including front-end loading, cache invalidation and
     collection caching.

   *
     local_session_caching.py - This example creates a new dogpile.cache
     backend that will persist data in a dictionary which is local to
     the current session.  remove() the session and the cache is gone.

   ---------- Footnotes ----------

   (1) https://dogpilecache.sqlalchemy.org/

3.8.4.3 PostGIS Integration
...........................

A naive example illustrating techniques to help embed PostGIS
functionality.

This example was originally developed in the hopes that it would be
extrapolated into a comprehensive PostGIS integration layer.  We are
pleased to announce that this has come to fruition as GeoAlchemy(1).

The example illustrates:

   * a DDL extension which allows CREATE/DROP to work in conjunction
     with AddGeometryColumn/DropGeometryColumn

   * a Geometry type, as well as a few subtypes, which convert result
     row values to a GIS-aware object, and also integrates with the DDL
     extension.

   * a GIS-aware object which stores a raw geometry value and provides a
     factory for functions such as AsText().

   * an ORM comparator which can override standard column methods on
     mapped objects to produce GIS operators.

   * an attribute event listener that intercepts strings and converts to
     GeomFromText().

   * a standalone operator example.

The implementation is limited to only public, well known and simple to
use extension points.

E.g.:

     print(session.query(Road).filter(
         Road.road_geom.intersects(r1.road_geom)).all())

Listing of files:

   * postgis.py

   ---------- Footnotes ----------

   (1) http://www.geoalchemy.org/

4 SQLAlchemy Core
*****************

The breadth of SQLAlchemy’s SQL rendering engine, DBAPI integration,
transaction integration, and schema description services are documented
here.  In contrast to the ORM’s domain-centric mode of usage, the SQL
Expression Language provides a schema-centric usage paradigm.

4.1 SQL Expression Language Tutorial (1.x API)
==============================================

     About this document: This tutorial covers the well known SQLAlchemy
     Core API that has been in use for many years.  As of SQLAlchemy
     1.4, there are two distinct styles of Core use known as 1.x style
     and 2.0 style, the latter of which makes some adjustments mostly in
     the area of how transactions are controlled as well as narrows down
     the patterns for how SQL statement constructs are executed.

     The plan is that in SQLAlchemy 2.0, those elements of 1.x style
     Core use will be removed, after a deprecation phase that continues
     throughout the 1.4 series.  For ORM use, some elements of 1.x style
     will still be available; see the Migrating to SQLAlchemy 2.0
     document for a complete overview.

     The tutorial here is applicable to users who want to learn how
     SQLAlchemy Core has been used for many years, particularly those
     users working with existing applications or related learning
     material that is in 1.x style.

     For an introduction to SQLAlchemy Core from the new 1.4/2.0
     perspective, see SQLAlchemy 1.4 / 2.0 Tutorial.

     See also
     ........

     See Migrating to SQLAlchemy 2.0.

     See SQLAlchemy 1.4 / 2.0 Tutorial.

The SQLAlchemy Expression Language presents a system of representing
relational database structures and expressions using Python constructs.
These constructs are modeled to resemble those of the underlying
database as closely as possible, while providing a modicum of
abstraction of the various implementation differences between database
backends.  While the constructs attempt to represent equivalent concepts
between backends with consistent structures, they do not conceal useful
concepts that are unique to particular subsets of backends.  The
Expression Language therefore presents a method of writing
backend-neutral SQL expressions, but does not attempt to enforce that
expressions are backend-neutral.

The Expression Language is in contrast to the Object Relational Mapper,
which is a distinct API that builds on top of the Expression Language.
Whereas the ORM, introduced in Object Relational Tutorial (1.x API),
presents a high level and abstracted pattern of usage, which
itself is an example of applied usage of the Expression Language, the
Expression Language presents a system of representing the primitive
constructs of the relational database directly without opinion.

While there is overlap among the usage patterns of the ORM and the
Expression Language, the similarities are more superficial than they may
at first appear.  One approaches the structure and content of data from
the perspective of a user-defined domain model(1) which is transparently
persisted and refreshed from its underlying storage model.  The other
approaches it from the perspective of literal schema and SQL expression
representations which are explicitly composed into messages consumed
individually by the database.

A successful application may be constructed using the Expression
Language exclusively, though the application will need to define its own
system of translating application concepts into individual database
messages and from individual database result sets.  Alternatively, an
application constructed with the ORM may, in advanced scenarios, make
occasional usage of the Expression Language directly in certain areas
where specific database interactions are required.

The following tutorial is in doctest format, meaning each ‘>>>’ line
represents something you can type at a Python command prompt, and the
following text represents the expected return value.  The tutorial has
no prerequisites.

   ---------- Footnotes ----------

   (1) http://en.wikipedia.org/wiki/Domain_model

4.1.1 Version Check
-------------------

A quick check to verify that we are on at least `version 1.4' of
SQLAlchemy:

     >>> import sqlalchemy
     >>> sqlalchemy.__version__  # doctest: +SKIP
     1.4.0

4.1.2 Connecting
----------------

For this tutorial we will use an in-memory-only SQLite database.  This
is an easy way to test things without needing to have an actual database
defined anywhere.  To connect we use create_engine():

     >>> from sqlalchemy import create_engine
     >>> engine = create_engine('sqlite:///:memory:', echo=True)

The ‘echo’ flag is a shortcut to setting up SQLAlchemy logging, which is
accomplished via Python’s standard ‘logging’ module.  With it enabled,
we’ll see all the generated SQL produced.  If you are working through
this tutorial and want less output generated, set it to ‘False’.  This
tutorial will format the SQL behind a popup window so it doesn’t get in
our way; just click the “SQL” links to see what’s being generated.

The return value of create_engine() is an instance of
Engine, and it represents the core interface to the database,
adapted through a dialect that handles the details of the database and
DBAPI in use.  In this case the SQLite dialect will interpret
instructions to the Python built-in ‘sqlite3’ module.

Lazy Connecting
...............

The Engine, when first returned by create_engine(),
has not actually tried to connect to the database yet; that happens only
the first time it is asked to perform a task against the database.

The first time a method like Engine.execute() or
Engine.connect() is called, the Engine establishes a
real DBAPI connection to the database, which is then used to emit the
SQL.

See also
........

See Database Urls. - includes examples of create_engine()
connecting to several kinds of databases with links to more
information.

4.1.3 Define and Create Tables
------------------------------

The SQL Expression Language constructs its expressions in most cases
against table columns.  In SQLAlchemy, a column is most often
represented by an object called Column, and in all cases a
Column is associated with a Table.  A collection of
Table objects and their associated child objects is referred
to as `database metadata'.  In this tutorial we will explicitly lay out
several Table objects, but note that SA can also “import”
whole sets of Table objects automatically from an existing
database (this process is called `table reflection').

We define our tables all within a catalog called MetaData,
using the Table construct, which resembles regular SQL CREATE
TABLE statements.  We’ll make two tables, one of which represents
“users” in an application, and another which represents zero or more
“email addresses” for each row in the “users” table:

     >>> from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey
     >>> metadata = MetaData()
     >>> users = Table('users', metadata,
     ...     Column('id', Integer, primary_key=True),
     ...     Column('name', String),
     ...     Column('fullname', String),
     ... )

     >>> addresses = Table('addresses', metadata,
     ...   Column('id', Integer, primary_key=True),
     ...   Column('user_id', None, ForeignKey('users.id')),
     ...   Column('email_address', String, nullable=False)
     ...  )

All about how to define Table objects, as well as how to
create them from an existing database automatically, is described in
Describing Databases with MetaData.

Next, to tell the MetaData we’d actually like to create our
selection of tables for real inside the SQLite database, we use
create_all(), passing it the ‘engine’ instance which points to our
database.  This will check for the presence of each table first before
creating, so it’s safe to call multiple times:

     {sql}>>> metadata.create_all(engine)
     BEGIN...
     CREATE TABLE users (
         id INTEGER NOT NULL,
         name VARCHAR,
         fullname VARCHAR,
         PRIMARY KEY (id)
     )
     [...] ()
     CREATE TABLE addresses (
         id INTEGER NOT NULL,
         user_id INTEGER,
         email_address VARCHAR NOT NULL,
         PRIMARY KEY (id),
         FOREIGN KEY(user_id) REFERENCES users (id)
     )
     [...] ()
     COMMIT

     Note: Users familiar with the syntax of CREATE TABLE may notice
     that the VARCHAR columns were generated without a length; on SQLite
     and PostgreSQL, this is a valid datatype, but on others, it’s not
     allowed.  So if running this tutorial on one of those databases,
     and you wish to use SQLAlchemy to issue CREATE TABLE, a “length”
     may be provided to the String type as below:

          Column('name', String(50))

     The length field on String, as well as similar
     precision/scale fields available on Integer,
     Numeric, etc.  are not referenced by SQLAlchemy other than
     when creating tables.

     Additionally, Firebird and Oracle require sequences to generate new
     primary key identifiers, and SQLAlchemy doesn’t generate or assume
     these without being instructed.  For that, you use the
     Sequence construct:

          from sqlalchemy import Sequence
          Column('id', Integer, Sequence('user_id_seq'), primary_key=True)

     A full, foolproof Table is therefore:

          users = Table('users', metadata,
             Column('id', Integer, Sequence('user_id_seq'), primary_key=True),
             Column('name', String(50)),
             Column('fullname', String(50)),
             Column('nickname', String(50))
          )

     We include this more verbose Table construct separately
     to highlight the difference between a minimal construct geared
     primarily towards in-Python usage only, versus one that will be
     used to emit CREATE TABLE statements on a particular set of
     backends with more stringent requirements.

4.1.4 Insert Expressions
------------------------

The first SQL expression we’ll create is the Insert
construct, which represents an INSERT statement.  This is typically
created relative to its target table:

     >>> ins = users.insert()

To see a sample of the SQL this construct produces, use the ‘str()’
function:

     >>> str(ins)
     'INSERT INTO users (id, name, fullname) VALUES (:id, :name, :fullname)'

Notice above that the INSERT statement names every column in the ‘users’
table.  This can be limited by using the ‘values()’ method, which
establishes the VALUES clause of the INSERT explicitly:

     >>> ins = users.insert().values(name='jack', fullname='Jack Jones')
     >>> str(ins)
     'INSERT INTO users (name, fullname) VALUES (:name, :fullname)'

Above, while the ‘values’ method limited the VALUES clause to just two
columns, the actual data we placed in ‘values’ didn’t get rendered into
the string; instead we got named bind parameters.  As it turns out, our
data `is' stored within our Insert construct, but it
typically only comes out when the statement is actually executed; since
the data consists of literal values, SQLAlchemy automatically generates
bind parameters for them.  We can peek at this data for now by looking
at the compiled form of the statement:

     >>> ins.compile().params
     {'fullname': 'Jack Jones', 'name': 'jack'}

4.1.5 Executing
---------------

The interesting part of an Insert is executing it.  This is
performed using a database connection, which is represented by the
Connection object.  To acquire a connection, we will use the
Engine.connect() method:

     >>> conn = engine.connect()
     >>> conn
     <sqlalchemy.engine.base.Connection object at 0x...>

The Connection object represents an actively checked out
DBAPI connection resource.  Lets feed it our Insert object
and see what happens:

     >>> result = conn.execute(ins)
     {opensql}INSERT INTO users (name, fullname) VALUES (?, ?)
     [...] ('jack', 'Jack Jones')
     COMMIT

So the INSERT statement was now issued to the database.  Although we got
positional “qmark” bind parameters instead of “named” bind parameters in
the output.  How come ?  Because when executed, the Connection
used the SQLite `dialect' to help generate the statement; when we
use the ‘str()’ function, the statement isn’t aware of this dialect, and
falls back onto a default which uses named parameters.  We can view this
manually as follows:

     >>> ins.bind = engine
     >>> str(ins)
     'INSERT INTO users (name, fullname) VALUES (?, ?)'

What about the ‘result’ variable we got when we called ‘execute()’ ?  As
the SQLAlchemy Connection object references a DBAPI
connection, the result, known as a CursorResult object, is
analogous to the DBAPI cursor object.  In the case of an INSERT, we can
get important information from it, such as the primary key values which
were generated from our statement using
CursorResult.inserted_primary_key:

     >>> result.inserted_primary_key
     (1,)

The value of ‘1’ was automatically generated by SQLite, but only because
we did not specify the ‘id’ column in our Insert statement;
otherwise, our explicit value would have been used.  In either case,
SQLAlchemy always knows how to get at a newly generated primary key
value, even though the method of generating them is different across
different databases; each database’s ‘Dialect’ knows the specific steps
needed to determine the correct value (or values; note that
CursorResult.inserted_primary_key returns a list so that it
supports composite primary keys).  Methods here range from using
‘cursor.lastrowid’, to selecting from a database-specific function, to
using ‘INSERT..RETURNING’ syntax; this all occurs transparently.

4.1.6 Executing Multiple Statements
-----------------------------------

Our insert example above was intentionally a little drawn out to show
some various behaviors of expression language constructs.  In the usual
case, an Insert statement is usually compiled against the
parameters sent to the ‘execute()’ method on Connection, so
that there’s no need to use the ‘values’ keyword with Insert.
Lets create a generic Insert statement again and use it in
the “normal” way:

     >>> ins = users.insert()
     >>> conn.execute(ins, {"id": 2, "name":"wendy", "fullname": "Wendy Williams"})
     {opensql}INSERT INTO users (id, name, fullname) VALUES (?, ?, ?)
     [...] (2, 'wendy', 'Wendy Williams')
     COMMIT
     {stop}<sqlalchemy.engine.cursor.LegacyCursorResult object at 0x...>

Above, because we specified all three columns in the ‘execute()’ method,
the compiled Insert included all three columns.  The
Insert statement is compiled at execution time based on the
parameters we specified; if we specified fewer parameters, the
Insert would have fewer entries in its VALUES clause.

To issue many inserts using DBAPI’s ‘executemany()’ method, we can send
in a list of dictionaries each containing a distinct set of parameters
to be inserted, as we do here to add some email addresses:

     >>> conn.execute(addresses.insert(), [
     ...    {'user_id': 1, 'email_address' : 'jack@yahoo.com'},
     ...    {'user_id': 1, 'email_address' : 'jack@msn.com'},
     ...    {'user_id': 2, 'email_address' : 'www@www.org'},
     ...    {'user_id': 2, 'email_address' : 'wendy@aol.com'},
     ... ])
     {opensql}INSERT INTO addresses (user_id, email_address) VALUES (?, ?)
     [...] ((1, 'jack@yahoo.com'), (1, 'jack@msn.com'), (2, 'www@www.org'), (2, 'wendy@aol.com'))
     COMMIT
     {stop}<sqlalchemy.engine.cursor.LegacyCursorResult object at 0x...>

Above, we again relied upon SQLite’s automatic generation of primary key
identifiers for each ‘addresses’ row.

When executing multiple sets of parameters, each dictionary must have
the `same' set of keys; i.e.  you cant have fewer keys in some
dictionaries than others.  This is because the Insert
statement is compiled against the `first' dictionary in the list, and
it’s assumed that all subsequent argument dictionaries are compatible
with that statement.

The “executemany” style of invocation is available for each of the
insert(), update() and delete() constructs.

4.1.7 Selecting
---------------

We began with inserts just so that our test database had some data in
it.  The more interesting part of the data is selecting it!  We’ll cover
UPDATE and DELETE statements later.  The primary construct used to
generate SELECT statements is the select() function:

     >>> from sqlalchemy.sql import select
     >>> s = select(users)
     >>> result = conn.execute(s)
     {opensql}SELECT users.id, users.name, users.fullname
     FROM users
     [...] ()

Above, we issued a basic select() call, placing the ‘users’
table within the COLUMNS clause of the select, and then executing.
SQLAlchemy expanded the ‘users’ table into the set of each of its
columns, and also generated a FROM clause for us.

Changed in version 1.4: The select() construct now accepts
column arguments positionally, as ‘select(*args)’.  The previous style
of ‘select()’ accepting a list of column elements is now deprecated.
See select(), case() now accept positional expressions.

The result returned is again a CursorResult object, which
acts much like a DBAPI cursor, including methods such as
fetchone() and fetchall().  These methods return row
objects, which are provided via the Row class.  The result
object can be iterated directly in order to provide an iterator of
Row objects:

     >>> for row in result:
     ...     print(row)
     (1, u'jack', u'Jack Jones')
     (2, u'wendy', u'Wendy Williams')

Above, we see that printing each Row produces a simple
tuple-like result.  The most canonical way in Python to access the
values of these tuples as rows are fetched is through tuple assignment:

     {sql}>>> result = conn.execute(s)
     SELECT users.id, users.name, users.fullname
     FROM users
     [...] ()

     {stop}>>> for id, name, fullname in result:
     ...     print("name:", name, "; fullname: ", fullname)
     name: jack ; fullname:  Jack Jones
     name: wendy ; fullname:  Wendy Williams

The Row object actually behaves like a Python named tuple, so
we may also access these attributes from the row itself using attribute
access:

     {sql}>>> result = conn.execute(s)
     SELECT users.id, users.name, users.fullname
     FROM users
     [...] ()

     {stop}>>> for row in result:
     ...     print("name:", row.name, "; fullname: ", row.fullname)
     name: jack ; fullname:  Jack Jones
     name: wendy ; fullname:  Wendy Williams

To access columns via name using strings, either when the column name is
programmatically generated, or contains non-ascii characters, the
Row._mapping view may be used that provides dictionary-like
access:

     {sql}>>> result = conn.execute(s)
     SELECT users.id, users.name, users.fullname
     FROM users
     [...] ()

     {stop}>>> row = result.fetchone()
     >>> print("name:", row._mapping['name'], "; fullname:", row._mapping['fullname'])
     name: jack ; fullname: Jack Jones

Deprecated since version 1.4: In versions of SQLAlchemy prior to 1.4,
the above access using Row._mapping would proceed against
the row object itself, that is:

     row = result.fetchone()
     name, fullname = row["name"], row["fullname"]

This pattern is now deprecated and will be removed in SQLAlchemy 2.0, so
that the Row object may now behave fully like a Python named
tuple.

Changed in version 1.4: Added Row._mapping which provides
for dictionary-like access to a Row, superseding the use of
string/ column keys against the Row object directly.

As the Row is a tuple, sequence (i.e.  integer or slice)
access may be used as well:

     >>> row = result.fetchone()
     >>> print("name:", row[1], "; fullname:", row[2])
     name: wendy ; fullname: Wendy Williams

A more specialized method of column access is to use the SQL construct
that directly corresponds to a particular column as the mapping key; in
this example, it means we would use the Column objects
selected in our SELECT directly as keys in conjunction with the
Row._mapping collection:

     {sql}>>> for row in conn.execute(s):
     ...     print("name:", row._mapping[users.c.name], "; fullname:", row._mapping[users.c.fullname])
     SELECT users.id, users.name, users.fullname
     FROM users
     [...] ()
     {stop}name: jack ; fullname: Jack Jones
     name: wendy ; fullname: Wendy Williams

Results and Rows are changing
.............................

The Row class was known as ‘RowProxy’ and the
CursorResult class was known as ‘ResultProxy’, for all SQLAlchemy
versions through 1.3.  In 1.4, the objects returned by
CursorResult are actually a subclass of Row known as
LegacyRow.  See RowProxy is no longer a “proxy”; is now called Row and behaves like an enhanced named tuple
for background
on this change.

The CursorResult object features “auto-close” behavior that
closes the underlying DBAPI ‘cursor’ object when all pending result rows
have been fetched.  If a CursorResult is to be discarded
before such an autoclose has occurred, it can be explicitly closed using
the CursorResult.close() method:

     >>> result.close()

4.1.8 Selecting Specific Columns
--------------------------------

If we’d like to more carefully control the columns which are placed in
the COLUMNS clause of the select, we reference individual Column
objects from our Table.  These are available as named
attributes off the ‘c’ attribute of the Table object:

     >>> s = select(users.c.name, users.c.fullname)
     {sql}>>> result = conn.execute(s)
     SELECT users.name, users.fullname
     FROM users
     [...] ()
     {stop}>>> for row in result:
     ...     print(row)
     (u'jack', u'Jack Jones')
     (u'wendy', u'Wendy Williams')

Lets observe something interesting about the FROM clause.  Whereas the
generated statement contains two distinct sections, a “SELECT columns”
part and a “FROM table” part, our select() construct only has
a list containing columns.  How does this work ?  Let’s try putting
`two' tables into our select() statement:

     {sql}>>> for row in conn.execute(select(users, addresses)):
     ...     print(row)
     SELECT users.id, users.name, users.fullname, addresses.id AS id_1, addresses.user_id, addresses.email_address
     FROM users, addresses
     [...] ()
     {stop}(1, u'jack', u'Jack Jones', 1, 1, u'jack@yahoo.com')
     (1, u'jack', u'Jack Jones', 2, 1, u'jack@msn.com')
     (1, u'jack', u'Jack Jones', 3, 2, u'www@www.org')
     (1, u'jack', u'Jack Jones', 4, 2, u'wendy@aol.com')
     (2, u'wendy', u'Wendy Williams', 1, 1, u'jack@yahoo.com')
     (2, u'wendy', u'Wendy Williams', 2, 1, u'jack@msn.com')
     (2, u'wendy', u'Wendy Williams', 3, 2, u'www@www.org')
     (2, u'wendy', u'Wendy Williams', 4, 2, u'wendy@aol.com')

It placed `both' tables into the FROM clause.  But also, it made a real
mess.  Those who are familiar with SQL joins know that this is a
`Cartesian product'; each row from the ‘users’ table is produced against
each row from the ‘addresses’ table.  So to put some sanity into this
statement, we need a WHERE clause.  We do that using
Select.where():

     >>> s = select(users, addresses).where(users.c.id == addresses.c.user_id)
     {sql}>>> for row in conn.execute(s):
     ...     print(row)
     SELECT users.id, users.name, users.fullname, addresses.id AS id_1,
        addresses.user_id, addresses.email_address
     FROM users, addresses
     WHERE users.id = addresses.user_id
     [...] ()
     {stop}(1, u'jack', u'Jack Jones', 1, 1, u'jack@yahoo.com')
     (1, u'jack', u'Jack Jones', 2, 1, u'jack@msn.com')
     (2, u'wendy', u'Wendy Williams', 3, 2, u'www@www.org')
     (2, u'wendy', u'Wendy Williams', 4, 2, u'wendy@aol.com')

So that looks a lot better, we added an expression to our
select() which had the effect of adding ‘WHERE users.id =
addresses.user_id’ to our statement, and our results were managed down
so that the join of ‘users’ and ‘addresses’ rows made sense.  But let’s
look at that expression?  It’s using just a Python equality operator
between two different Column objects.  It should be clear
that something is up.  Saying ‘1 == 1’ produces ‘True’, and ‘1 == 2’
produces ‘False’, not a WHERE clause.  So lets see exactly what that
expression is doing:

     >>> users.c.id == addresses.c.user_id
     <sqlalchemy.sql.elements.BinaryExpression object at 0x...>

Wow, surprise !  This is neither a ‘True’ nor a ‘False’.  Well what is
it ?

     >>> str(users.c.id == addresses.c.user_id)
     'users.id = addresses.user_id'

As you can see, the ‘==’ operator is producing an object that is very
much like the Insert and select() objects we’ve
made so far, thanks to Python’s ‘__eq__()’ builtin; you call ‘str()’ on
it and it produces SQL. By now, one can see that everything we are
working with is ultimately the same type of object.  SQLAlchemy terms
the base class of all of these expressions as ColumnElement.

4.1.9 Operators
---------------

Since we’ve stumbled upon SQLAlchemy’s operator paradigm, let’s go
through some of its capabilities.  We’ve seen how to equate two columns
to each other:

     >>> print(users.c.id == addresses.c.user_id)
     users.id = addresses.user_id

If we use a literal value (a literal meaning, not a SQLAlchemy clause
object), we get a bind parameter:

     >>> print(users.c.id == 7)
     users.id = :id_1

The ‘7’ literal is embedded the resulting ColumnElement; we
can use the same trick we did with the Insert object to see
it:

     >>> (users.c.id == 7).compile().params
     {u'id_1': 7}

Most Python operators, as it turns out, produce a SQL expression here,
like equals, not equals, etc.:

     >>> print(users.c.id != 7)
     users.id != :id_1

     >>> # None converts to IS NULL
     >>> print(users.c.name == None)
     users.name IS NULL

     >>> # reverse works too
     >>> print('fred' > users.c.name)
     users.name < :name_1

If we add two integer columns together, we get an addition expression:

     >>> print(users.c.id + addresses.c.id)
     users.id + addresses.id

Interestingly, the type of the Column is important!  If we
use ‘+’ with two string based columns (recall we put types like
Integer and String on our Column objects at
the beginning), we get something different:

     >>> print(users.c.name + users.c.fullname)
     users.name || users.fullname

Where ‘||’ is the string concatenation operator used on most databases.
But not all of them.  MySQL users, fear not:

     >>> print((users.c.name + users.c.fullname).
     ...      compile(bind=create_engine('mysql://'))) # doctest: +SKIP
     concat(users.name, users.fullname)

The above illustrates the SQL that’s generated for an Engine
that’s connected to a MySQL database; the ‘||’ operator now compiles as
MySQL’s ‘concat()’ function.

If you have come across an operator which really isn’t available, you
can always use the Operators.op() method; this generates
whatever operator you need:

     >>> print(users.c.name.op('tiddlywinks')('foo'))
     users.name tiddlywinks :name_1

This function can also be used to make bitwise operators explicit.  For
example:

     somecolumn.op('&')(0xff)

is a bitwise AND of the value in ‘somecolumn’.

When using Operators.op(), the return type of the expression
may be important, especially when the operator is used in an expression
that will be sent as a result column.  For this case, be sure to make
the type explicit, if not what’s normally expected, using
type_coerce():

     from sqlalchemy import type_coerce
     expr = type_coerce(somecolumn.op('-%>')('foo'), MySpecialType())
     stmt = select(expr)

For boolean operators, use the Operators.bool_op() method,
which will ensure that the return type of the expression is handled as
boolean:

     somecolumn.bool_op('-->')('some value')

4.1.9.1 Commonly Used Operators
...............................

Here’s a rundown of some of the most common operators used in both the
Core expression language as well as in the ORM. Here we see expressions
that are most commonly present when using the Select.where()
method, but can be used in other scenarios as well.

A listing of all the column-level operations common to all column-like
objects is at ColumnOperators.

   * ColumnOperators.__eq__():

          statement.where(users.c.name == 'ed')

   * ColumnOperators.__ne__():

          statement.where(users.c.name != 'ed')

   * ColumnOperators.like():

          statement.where(users.c.name.like('%ed%'))

          Note: ColumnOperators.like() renders the LIKE
          operator, which is case insensitive on some backends, and case
          sensitive on others.  For guaranteed case-insensitive
          comparisons, use ColumnOperators.ilike().

   * ColumnOperators.ilike(). (case-insensitive LIKE):

          statement.where(users.c.name.ilike('%ed%'))

          Note: most backends don’t support ILIKE directly.  For those,
          the ColumnOperators.ilike() operator renders an
          expression combining LIKE with the LOWER SQL function applied
          to each operand.

   * ColumnOperators.in_():

          statement.where(users.c.name.in_(['ed', 'wendy', 'jack']))

          # works with Select objects too:
          statement.where.filter(users.c.name.in_(
              select(users.c.name).where(users.c.name.like('%ed%'))
          ))

          # use tuple_() for composite (multi-column) queries
          from sqlalchemy import tuple_
          statement.where(
              tuple_(users.c.name, users.c.nickname).\
              in_([('ed', 'edsnickname'), ('wendy', 'windy')])
          )

   * ColumnOperators.not_in():

          statement.where(~users.c.name.in_(['ed', 'wendy', 'jack']))

   * ColumnOperators.is_():

          statement.where(users.c. == None)

          # alternatively, if pep8/linters are a concern
          statement.where(users.c.name.is_(None))

   * ColumnOperators.is_not():

          statement.where(users.c.name != None)

          # alternatively, if pep8/linters are a concern
          statement.where(users.c.name.is_not(None))

   * AND:

          # use and_()
          from sqlalchemy import and_
          statement.where(and_(users.c.name == 'ed', users.c.fullname == 'Ed Jones'))

          # or send multiple expressions to .where()
          statement.where(users.c.name == 'ed', users.c.fullname == 'Ed Jones')

          # or chain multiple where() calls
          statement.where(users.c.name == 'ed').where(users.c.fullname == 'Ed Jones')

          Note: Make sure you use and_() and `not' the Python
          ‘and’ operator!

   * OR:

          from sqlalchemy import or_
          statement.where(or_(users.c.name == 'ed', users.c.name == 'wendy'))

          Note: Make sure you use or_() and `not' the Python
          ‘or’ operator!

   * ColumnOperators.match():

          statement.where(users.c.name.match('wendy'))

          Note: ColumnOperators.match() uses a
          database-specific ‘MATCH’ or ‘CONTAINS’ function; its behavior
          will vary by backend and is not available on some backends
          such as SQLite.

4.1.9.2 Operator Customization
..............................

While Operators.op() is handy to get at a custom operator in
a hurry, the Core supports fundamental customization and extension of
the operator system at the type level.  The behavior of existing
operators can be modified on a per-type basis, and new operations can be
defined which become available for all column expressions that are part
of that particular type.  See the section Redefining and Creating New Operators
for a description.

4.1.10 Conjunctions
-------------------

We’d like to show off some of our operators inside of select()
constructs.  But we need to lump them together a little more, so
let’s first introduce some conjunctions.  Conjunctions are those little
words like AND and OR that put things together.  We’ll also hit upon
NOT. See and_(), or_(), and not_() can work
from the corresponding functions SQLAlchemy provides (notice we also
throw in a ColumnOperators.like()):

     >>> from sqlalchemy.sql import and_, or_, not_
     >>> print(and_(
     ...         users.c.name.like('j%'),
     ...         users.c.id == addresses.c.user_id,
     ...         or_(
     ...              addresses.c.email_address == 'wendy@aol.com',
     ...              addresses.c.email_address == 'jack@yahoo.com'
     ...         ),
     ...         not_(users.c.id > 5)
     ...       )
     ...  )
     users.name LIKE :name_1 AND users.id = addresses.user_id AND
     (addresses.email_address = :email_address_1
        OR addresses.email_address = :email_address_2)
     AND users.id <= :id_1

And you can also use the re-jiggered bitwise AND, OR and NOT operators,
although because of Python operator precedence you have to watch your
parenthesis:

     >>> print(users.c.name.like('j%') & (users.c.id == addresses.c.user_id) &
     ...     (
     ...       (addresses.c.email_address == 'wendy@aol.com') | \
     ...       (addresses.c.email_address == 'jack@yahoo.com')
     ...     ) \
     ...     & ~(users.c.id>5)
     ... )
     users.name LIKE :name_1 AND users.id = addresses.user_id AND
     (addresses.email_address = :email_address_1
         OR addresses.email_address = :email_address_2)
     AND users.id <= :id_1

So with all of this vocabulary, let’s select all users who have an email
address at AOL or MSN, whose name starts with a letter between “m” and
“z”, and we’ll also generate a column containing their full name
combined with their email address.  We will add two new constructs to
this statement, see ColumnOperators.between() and
ColumnElement.label().  ColumnOperators.between()
produces a BETWEEN clause, and ColumnElement.label() is used
in a column expression to produce labels using the ‘AS’ keyword; it’s
recommended when selecting from expressions that otherwise would not
have a name:

     >>> s = select((users.c.fullname +
     ...               ", " + addresses.c.email_address).
     ...                label('title')).\
     ...        where(
     ...           and_(
     ...               users.c.id == addresses.c.user_id,
     ...               users.c.name.between('m', 'z'),
     ...               or_(
     ...                  addresses.c.email_address.like('%@aol.com'),
     ...                  addresses.c.email_address.like('%@msn.com')
     ...               )
     ...           )
     ...        )
     >>> conn.execute(s).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
     (addresses.email_address LIKE ? OR addresses.email_address LIKE ?)
     [...] (', ', 'm', 'z', '%@aol.com', '%@msn.com')
     {stop}[(u'Wendy Williams, wendy@aol.com',)]

Once again, SQLAlchemy figured out the FROM clause for our statement.
In fact it will determine the FROM clause based on all of its other
bits; the columns clause, the where clause, and also some other elements
which we haven’t covered yet, which include ORDER BY, GROUP BY, and
HAVING.

A shortcut to using and_() is to chain together multiple
Select.where() clauses.  The above can also be written as:

     >>> s = select((users.c.fullname +
     ...               ", " + addresses.c.email_address).
     ...                label('title')).\
     ...        where(users.c.id == addresses.c.user_id).\
     ...        where(users.c.name.between('m', 'z')).\
     ...        where(
     ...               or_(
     ...                  addresses.c.email_address.like('%@aol.com'),
     ...                  addresses.c.email_address.like('%@msn.com')
     ...               )
     ...        )
     >>> conn.execute(s).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
     (addresses.email_address LIKE ? OR addresses.email_address LIKE ?)
     [...] (', ', 'm', 'z', '%@aol.com', '%@msn.com')
     {stop}[(u'Wendy Williams, wendy@aol.com',)]

The way that we can build up a select() construct through
successive method calls is called method chaining.

4.1.11 Using Textual SQL
------------------------

Our last example really became a handful to type.  Going from what one
understands to be a textual SQL expression into a Python construct which
groups components together in a programmatic style can be hard.  That’s
why SQLAlchemy lets you just use strings, for those cases when the SQL
is already known and there isn’t a strong need for the statement to
support dynamic features.  The text() construct is used to
compose a textual statement that is passed to the database mostly
unchanged.  Below, we create a text() object and execute it:

     >>> from sqlalchemy.sql import text
     >>> s = text(
     ...     "SELECT users.fullname || ', ' || addresses.email_address AS title "
     ...         "FROM users, addresses "
     ...         "WHERE users.id = addresses.user_id "
     ...         "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()
     {opensql}SELECT users.fullname || ', ' || addresses.email_address AS title
     FROM users, addresses
     WHERE users.id = addresses.user_id AND users.name BETWEEN ? AND ? AND
     (addresses.email_address LIKE ? OR addresses.email_address LIKE ?)
     [...] ('m', 'z', '%@aol.com', '%@msn.com')
     {stop}[(u'Wendy Williams, wendy@aol.com',)]

Above, we can see that bound parameters are specified in text()
using the named colon format; this format is consistent regardless
of database backend.  To send values in for the parameters, we passed
them into the Connection.execute() method as additional
arguments.

4.1.11.1 Specifying Bound Parameter Behaviors
.............................................

The text() construct supports pre-established bound values
using the TextClause.bindparams() method:

     stmt = text("SELECT * FROM users WHERE users.name BETWEEN :x AND :y")
     stmt = stmt.bindparams(x="m", y="z")

The parameters can also be explicitly typed:

     stmt = stmt.bindparams(bindparam("x", type_=String), bindparam("y", type_=String))
     result = conn.execute(stmt, {"x": "m", "y": "z"})

Typing for bound parameters is necessary when the type requires
Python-side or special SQL-side processing provided by the datatype.

See also
........

See TextClause.bindparams(). - full method description

4.1.11.2 Specifying Result-Column Behaviors
...........................................

We may also specify information about the result columns using the
TextClause.columns() method; this method can be used to specify
the return types, based on name:

     stmt = stmt.columns(id=Integer, name=String)

or it can be passed full column expressions positionally, either typed
or untyped.  In this case it’s a good idea to list out the columns
explicitly within our textual SQL, since the correlation of our column
expressions to the SQL will be done positionally:

     stmt = text("SELECT id, name FROM users")
     stmt = stmt.columns(users.c.id, users.c.name)

When we call the TextClause.columns() method, we get back a
‘TextAsFrom’ object that supports the full suite of ‘TextAsFrom.c’ and
other “selectable” operations:

     j = stmt.join(addresses, stmt.c.id == addresses.c.user_id)

     new_stmt = select(stmt.c.id, addresses.c.id).\
         select_from(j).where(stmt.c.name == 'x')

The positional form of TextClause.columns() is particularly
useful when relating textual SQL to existing Core or ORM models, because
we can use column expressions directly without worrying about name
conflicts or other issues with the result column names in the textual
SQL:

     >>> stmt = text("SELECT users.id, addresses.id, users.id, "
     ...     "users.name, addresses.email_address AS email "
     ...     "FROM users JOIN addresses ON users.id=addresses.user_id "
     ...     "WHERE users.id = 1").columns(
     ...        users.c.id,
     ...        addresses.c.id,
     ...        addresses.c.user_id,
     ...        users.c.name,
     ...        addresses.c.email_address
     ...     )
     >>> result = conn.execute(stmt)
     {opensql}SELECT users.id, addresses.id, users.id, users.name,
         addresses.email_address AS email
     FROM users JOIN addresses ON users.id=addresses.user_id WHERE users.id = 1
     [...] ()
     {stop}

Above, there’s three columns in the result that are named “id”, but
since we’ve associated these with column expressions positionally, the
names aren’t an issue when the result-columns are fetched using the
actual column object as a key.  Fetching the ‘email_address’ column
would be:

     >>> row = result.fetchone()
     >>> row._mapping[addresses.c.email_address]
     'jack@yahoo.com'

If on the other hand we used a string column key, the usual rules of
name-based matching still apply, and we’d get an ambiguous column error
for the ‘id’ value:

     >>> row._mapping["id"]
     Traceback (most recent call last):
     ...
     InvalidRequestError: Ambiguous column name 'id' in result set column descriptions

It’s important to note that while accessing columns from a result set
using Column objects may seem unusual, it is in fact the only
system used by the ORM, which occurs transparently beneath the facade of
the ‘Query’ object; in this way, the TextClause.columns()
method is typically very applicable to textual statements to be used in
an ORM context.  The example at Using Textual SQL
illustrates a simple usage.

New in version 1.1: The TextClause.columns() method now
accepts column expressions which will be matched positionally to a plain
text SQL result set, eliminating the need for column names to match or
even be unique in the SQL statement when matching table metadata or ORM
models to textual SQL.

See also
........

See TextClause.columns(). - full method description

See Using Textual SQL. - integrating ORM-level queries with
text().

4.1.11.3 Using text() fragments inside bigger statements
........................................................

text() can also be used to produce fragments of SQL that can
be freely within a select() object, which accepts
text() objects as an argument for most of its builder functions.
Below, we combine the usage of text() within a
select() object.  The select() construct provides the
“geometry” of the statement, and the text() construct
provides the textual content within this form.  We can build a statement
without the need to refer to any pre-established Table
metadata:

     >>> s = select(
     ...        text("users.fullname || ', ' || addresses.email_address AS title")
     ...     ).\
     ...         where(
     ...             and_(
     ...                 text("users.id = addresses.user_id"),
     ...                 text("users.name BETWEEN 'm' AND 'z'"),
     ...                 text(
     ...                     "(addresses.email_address LIKE :x "
     ...                     "OR addresses.email_address LIKE :y)")
     ...             )
     ...         ).select_from(text('users, addresses'))
     >>> 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'
     AND (addresses.email_address LIKE ? OR addresses.email_address LIKE ?)
     [...] ('%@aol.com', '%@msn.com')
     {stop}[(u'Wendy Williams, wendy@aol.com',)]

Changed in version 1.0.0: The select() construct emits
warnings when string SQL fragments are coerced to text(), and
text() should be used explicitly.  See Warnings emitted when coercing full SQL fragments into text()
for background.

4.1.11.4 Using More Specific Text with ‘table()’, ‘literal_column()’, and ‘column()’
....................................................................................

We can move our level of structure back in the other direction too, by
using column(), literal_column(), and
table() for some of the key elements of our statement.  Using
these constructs, we can get some more expression capabilities than if
we used text() directly, as they provide to the Core more
information about how the strings they store are to be used, but still
without the need to get into full Table based metadata.
Below, we also specify the String datatype for two of the key
literal_column() objects, so that the string-specific
concatenation operator becomes available.  We also use
literal_column() in order to use table-qualified expressions, e.g.
‘users.fullname’, that will be rendered as is; using column()
implies an individual column name that may be quoted:

     >>> from sqlalchemy import select, and_, text, String
     >>> from sqlalchemy.sql import table, literal_column
     >>> s = select(
     ...    literal_column("users.fullname", String) +
     ...    ', ' +
     ...    literal_column("addresses.email_address").label("title")
     ... ).\
     ...    where(
     ...        and_(
     ...            literal_column("users.id") == literal_column("addresses.user_id"),
     ...            text("users.name BETWEEN 'm' AND 'z'"),
     ...            text(
     ...                "(addresses.email_address LIKE :x OR "
     ...                "addresses.email_address LIKE :y)")
     ...        )
     ...    ).select_from(table('users')).select_from(table('addresses'))

     >>> 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
     AND users.name BETWEEN 'm' AND 'z'
     AND (addresses.email_address LIKE ? OR addresses.email_address LIKE ?)
     [...] (', ', '%@aol.com', '%@msn.com')
     {stop}[(u'Wendy Williams, wendy@aol.com',)]

4.1.11.5 Ordering or Grouping by a Label
........................................

One place where we sometimes want to use a string as a shortcut is when
our statement has some labeled column element that we want to refer to
in a place such as the “ORDER BY” or “GROUP BY” clause; other candidates
include fields within an “OVER” or “DISTINCT” clause.  If we have such a
label in our select() construct, we can refer to it directly
by passing the string straight into ‘select.order_by()’ or
‘select.group_by()’, among others.  This will refer to the named label
and also prevent the expression from being rendered twice.  Label names
that resolve to columns are rendered fully:

     >>> from sqlalchemy import func
     >>> stmt = select(
     ...         addresses.c.user_id,
     ...         func.count(addresses.c.id).label('num_addresses')).\
     ...         group_by("user_id").order_by("user_id", "num_addresses")

     {sql}>>> conn.execute(stmt).fetchall()
     SELECT addresses.user_id, count(addresses.id) AS num_addresses
     FROM addresses GROUP BY addresses.user_id ORDER BY addresses.user_id, num_addresses
     [...] ()
     {stop}[(1, 2), (2, 2)]

We can use modifiers like asc() or desc() by
passing the string name:

     >>> from sqlalchemy import func, desc
     >>> stmt = select(
     ...         addresses.c.user_id,
     ...         func.count(addresses.c.id).label('num_addresses')).\
     ...         group_by("user_id").order_by("user_id", desc("num_addresses"))

     {sql}>>> conn.execute(stmt).fetchall()
     SELECT addresses.user_id, count(addresses.id) AS num_addresses
     FROM addresses GROUP BY addresses.user_id ORDER BY addresses.user_id, num_addresses DESC
     [...] ()
     {stop}[(1, 2), (2, 2)]

Note that the string feature here is very much tailored to when we have
already used the ColumnElement.label() method to create a
specifically-named label.  In other cases, we always want to refer to
the ColumnElement object directly so that the expression
system can make the most effective choices for rendering.  Below, we
illustrate how using the ColumnElement eliminates ambiguity
when we want to order by a column name that appears more than once:

     >>> u1a, u1b = users.alias(), users.alias()
     >>> stmt = select(u1a, u1b).\
     ...             where(u1a.c.name > u1b.c.name).\
     ...             order_by(u1a.c.name)  # using "name" here would be ambiguous

     {sql}>>> conn.execute(stmt).fetchall()
     SELECT users_1.id, users_1.name, users_1.fullname, users_2.id AS id_1,
     users_2.name AS name_1, users_2.fullname AS fullname_1
     FROM users AS users_1, users AS users_2
     WHERE users_1.name > users_2.name ORDER BY users_1.name
     [...] ()
     {stop}[(2, u'wendy', u'Wendy Williams', 1, u'jack', u'Jack Jones')]

4.1.12 Using Aliases and Subqueries
-----------------------------------

The alias in SQL corresponds to a “renamed” version of a table or SELECT
statement, which occurs anytime you say “SELECT ..  FROM sometable AS
someothername”.  The ‘AS’ creates a new name for the table.  Aliases are
a key construct as they allow any table or subquery to be referenced by
a unique name.  In the case of a table, this allows the same table to be
named in the FROM clause multiple times.  In the case of a SELECT
statement, it provides a parent name for the columns represented by the
statement, allowing them to be referenced relative to this name.

In SQLAlchemy, any Table or other FromClause based
selectable can be turned into an alias using FromClause.alias()
method, which produces an Alias construct.
Alias is a FromClause object that refers to a mapping
of Column objects via its FromClause.c
collection, and can be used within the FROM clause of any subsequent
SELECT statement, by referring to its column elements in the columns or
WHERE clause of the statement, or through explicit placement in the FROM
clause, either directly or within a join.

As an example, suppose we know that our user ‘jack’ has two particular
email addresses.  How can we locate jack based on the combination of
those two addresses?  To accomplish this, we’d use a join to the
‘addresses’ table, once for each address.  We create two Alias
constructs against ‘addresses’, and then use them both within a
select() construct:

     >>> a1 = addresses.alias()
     >>> a2 = addresses.alias()
     >>> s = select(users).\
     ...        where(and_(
     ...            users.c.id == a1.c.user_id,
     ...            users.c.id == a2.c.user_id,
     ...            a1.c.email_address == 'jack@msn.com',
     ...            a2.c.email_address == 'jack@yahoo.com'
     ...        ))
     >>> conn.execute(s).fetchall()
     {opensql}SELECT users.id, users.name, users.fullname
     FROM users, addresses AS addresses_1, addresses AS addresses_2
     WHERE users.id = addresses_1.user_id
         AND users.id = addresses_2.user_id
         AND addresses_1.email_address = ?
         AND addresses_2.email_address = ?
     [...] ('jack@msn.com', 'jack@yahoo.com')
     {stop}[(1, u'jack', u'Jack Jones')]

Note that the Alias construct generated the names
‘addresses_1’ and ‘addresses_2’ in the final SQL result.  The generation
of these names is determined by the position of the construct within the
statement.  If we created a query using only the second ‘a2’ alias, the
name would come out as ‘addresses_1’.  The generation of the names is
also `deterministic', meaning the same SQLAlchemy statement construct
will produce the identical SQL string each time it is rendered for a
particular dialect.

Since on the outside, we refer to the alias using the Alias
construct itself, we don’t need to be concerned about the generated
name.  However, for the purposes of debugging, it can be specified by
passing a string name to the FromClause.alias() method:

     >>> a1 = addresses.alias('a1')

SELECT-oriented constructs which extend from SelectBase may
be turned into aliased subqueries using the SelectBase.subquery()
method, which produces a Subquery construct; for ease
of use, there is also a SelectBase.alias() method that is
synonymous with SelectBase.subquery().  Like Alias,
see Subquery is also a FromClause object that
may be part of any enclosing SELECT using the same techniques one would
use for a Alias.

We can self-join the ‘users’ table back to the select() we’ve
created by making Subquery of the entire statement:

     >>> address_subq = s.subquery()
     >>> s = select(users.c.name).where(users.c.id == address_subq.c.id)
     >>> conn.execute(s).fetchall()
     {opensql}SELECT users.name
     FROM users,
         (SELECT users.id AS id, users.name AS name, users.fullname AS fullname
             FROM users, addresses AS addresses_1, addresses AS addresses_2
             WHERE users.id = addresses_1.user_id AND users.id = addresses_2.user_id
             AND addresses_1.email_address = ?
             AND addresses_2.email_address = ?) AS anon_1
     WHERE users.id = anon_1.id
     [...] ('jack@msn.com', 'jack@yahoo.com')
     {stop}[(u'jack',)]

Changed in version 1.4: Added the Subquery object and
created more of a separation between an “alias” of a FROM clause and a
named subquery of a SELECT. See A SELECT statement is no longer implicitly considered to be a FROM clause.

4.1.13 Using Joins
------------------

We’re halfway along to being able to construct any SELECT expression.
The next cornerstone of the SELECT is the JOIN expression.  We’ve
already been doing joins in our examples, by just placing two tables in
either the columns clause or the where clause of the select()
construct.  But if we want to make a real “JOIN” or “OUTERJOIN”
construct, we use the FromClause.join() and
FromClause.outerjoin() methods, most commonly accessed from the
left table in the join:

     >>> print(users.join(addresses))
     users JOIN addresses ON users.id = addresses.user_id

The alert reader will see more surprises; SQLAlchemy figured out how to
JOIN the two tables !  The ON condition of the join, as it’s called, was
automatically generated based on the ForeignKey object which
we placed on the ‘addresses’ table way at the beginning of this
tutorial.  Already the ‘join()’ construct is looking like a much better
way to join tables.

Of course you can join on whatever expression you want, such as if we
want to join on all users who use the same name in their email address
as their username:

     >>> print(users.join(addresses,
     ...                 addresses.c.email_address.like(users.c.name + '%')
     ...             )
     ...  )
     users JOIN addresses ON addresses.email_address LIKE users.name || :name_1

When we create a select() construct, SQLAlchemy looks around
at the tables we’ve mentioned and then places them in the FROM clause of
the statement.  When we use JOINs however, we know what FROM clause we
want, so here we make use of the Select.select_from()
method:

     >>> s = select(users.c.fullname).select_from(
     ...    users.join(addresses,
     ...             addresses.c.email_address.like(users.c.name + '%'))
     ...    )
     {sql}>>> conn.execute(s).fetchall()
     SELECT users.fullname
     FROM users JOIN addresses ON addresses.email_address LIKE users.name || ?
     [...] ('%',)
     {stop}[(u'Jack Jones',), (u'Jack Jones',), (u'Wendy Williams',)]

The FromClause.outerjoin() method creates ‘LEFT OUTER JOIN’
constructs, and is used in the same way as FromClause.join():

     >>> s = select(users.c.fullname).select_from(users.outerjoin(addresses))
     >>> print(s)
     SELECT users.fullname
         FROM users
         LEFT OUTER JOIN addresses ON users.id = addresses.user_id

That’s the output ‘outerjoin()’ produces, unless, of course, you’re
stuck in a gig using Oracle prior to version 9, and you’ve set up your
engine (which would be using ‘OracleDialect’) to use Oracle-specific
SQL:

     >>> from sqlalchemy.dialects.oracle import dialect as OracleDialect
     >>> print(s.compile(dialect=OracleDialect(use_ansi=False)))
     SELECT users.fullname
     FROM users, addresses
     WHERE users.id = addresses.user_id(+)

If you don’t know what that SQL means, don’t worry !  The secret tribe
of Oracle DBAs don’t want their black magic being found out ;).

See also
........

See join().

See outerjoin().

See Join.

4.1.14 Common Table Expressions (CTE)
-------------------------------------

Common table expressions are now supported by every major database,
including modern MySQL, MariaDB, SQLite, PostgreSQL, Oracle and MS SQL
Server.  SQLAlchemy supports this construct via the CTE
object, which one typically acquires using the Select.cte()
method on a Select construct:

     >>> users_cte = select(users.c.id, users.c.name).where(users.c.name == 'wendy').cte()
     >>> stmt = select(addresses).where(addresses.c.user_id == users_cte.c.id).order_by(addresses.c.id)
     >>> conn.execute(stmt).fetchall()
     {opensql}WITH anon_1 AS
     (SELECT users.id AS id, users.name AS name
     FROM users
     WHERE users.name = ?)
      SELECT addresses.id, addresses.user_id, addresses.email_address
     FROM addresses, anon_1
     WHERE addresses.user_id = anon_1.id ORDER BY addresses.id
     [...] ('wendy',)
     {stop}[(3, 2, 'www@www.org'), (4, 2, 'wendy@aol.com')]

The CTE construct is a great way to provide a source of rows that is
semantically similar to using a subquery, but with a much simpler format
where the source of rows is neatly tucked away at the top of the query
where it can be referenced anywhere in the main statement like a regular
table.

When we construct a CTE object, we make use of it like any
other table in the statement.  However instead of being added to the
FROM clause as a subquery, it comes out on top, which has the additional
benefit of not causing surprise cartesian products.

The RECURSIVE format of CTE is available when one uses the
Select.cte.recursive parameter.  A recursive CTE typically
requires that we are linking to ourselves as an alias.  The general form
of this kind of operation involves a UNION of the original CTE against
itself.  Noting that our example tables are not well suited to producing
an actually useful query with this feature, this form looks like:

     >>> users_cte = select(users.c.id, users.c.name).cte(recursive=True)
     >>> users_recursive = users_cte.alias()
     >>> users_cte = users_cte.union(select(users.c.id, users.c.name).where(users.c.id > users_recursive.c.id))
     >>> stmt = select(addresses).where(addresses.c.user_id == users_cte.c.id).order_by(addresses.c.id)
     >>> conn.execute(stmt).fetchall()
     {opensql}WITH RECURSIVE anon_1(id, name) AS
     (SELECT users.id AS id, users.name AS name
     FROM users UNION SELECT users.id AS id, users.name AS name
     FROM users, anon_1 AS anon_2
     WHERE users.id > anon_2.id)
      SELECT addresses.id, addresses.user_id, addresses.email_address
     FROM addresses, anon_1
     WHERE addresses.user_id = anon_1.id ORDER BY addresses.id
     [...] ()
     {stop}[(1, 1, 'jack@yahoo.com'), (2, 1, 'jack@msn.com'), (3, 2, 'www@www.org'), (4, 2, 'wendy@aol.com')]

4.1.15 Everything Else
----------------------

The concepts of creating SQL expressions have been introduced.  What’s
left are more variants of the same themes.  So now we’ll catalog the
rest of the important things we’ll need to know.

4.1.15.1 Bind Parameter Objects
...............................

Throughout all these examples, SQLAlchemy is busy creating bind
parameters wherever literal expressions occur.  You can also specify
your own bind parameters with your own names, and use the same statement
repeatedly.  The bindparam() construct is used to produce a
bound parameter with a given name.  While SQLAlchemy always refers to
bound parameters by name on the API side, the database dialect converts
to the appropriate named or positional style at execution time, as here
where it converts to positional for SQLite:

     >>> from sqlalchemy.sql import bindparam
     >>> s = users.select().where(users.c.name == bindparam('username'))
     {sql}>>> conn.execute(s, {"username": "wendy"}).fetchall()
     SELECT users.id, users.name, users.fullname
     FROM users
     WHERE users.name = ?
     [...] ('wendy',)
     {stop}[(2, u'wendy', u'Wendy Williams')]

Another important aspect of bindparam() is that it may be
assigned a type.  The type of the bind parameter will determine its
behavior within expressions and also how the data bound to it is
processed before being sent off to the database:

     >>> s = users.select().where(users.c.name.like(bindparam('username', type_=String) + text("'%'")))
     {sql}>>> conn.execute(s, {"username": "wendy"}).fetchall()
     SELECT users.id, users.name, users.fullname
     FROM users
     WHERE users.name LIKE ? || '%'
     [...] ('wendy',)
     {stop}[(2, u'wendy', u'Wendy Williams')]

bindparam() constructs of the same name can also be used
multiple times, where only a single named value is needed in the execute
parameters:

     >>> s = select(users, addresses).\
     ...     where(
     ...        or_(
     ...          users.c.name.like(
     ...                 bindparam('name', type_=String) + text("'%'")),
     ...          addresses.c.email_address.like(
     ...                 bindparam('name', type_=String) + text("'@%'"))
     ...        )
     ...     ).\
     ...     select_from(users.outerjoin(addresses)).\
     ...     order_by(addresses.c.id)
     {sql}>>> conn.execute(s, {"name": "jack"}).fetchall()
     SELECT users.id, users.name, users.fullname, addresses.id AS id_1,
         addresses.user_id, addresses.email_address
     FROM users LEFT OUTER JOIN addresses ON users.id = addresses.user_id
     WHERE users.name LIKE ? || '%' OR addresses.email_address LIKE ? || '@%'
     ORDER BY addresses.id
     [...] ('jack', 'jack')
     {stop}[(1, u'jack', u'Jack Jones', 1, 1, u'jack@yahoo.com'), (1, u'jack', u'Jack Jones', 2, 1, u'jack@msn.com')]

See also
........

See bindparam().

4.1.15.2 Functions
..................

SQL functions are created using the func keyword, which
generates functions using attribute access:

     >>> from sqlalchemy.sql import func
     >>> print(func.now())
     now()

     >>> print(func.concat('x', 'y'))
     concat(:concat_1, :concat_2)

By “generates”, we mean that `any' SQL function is created based on the
word you choose:

     >>> print(func.xyz_my_goofy_function())
     xyz_my_goofy_function()

Certain function names are known by SQLAlchemy, allowing special
behavioral rules to be applied.  Some for example are “ANSI” functions,
which mean they don’t get the parenthesis added after them, such as
CURRENT_TIMESTAMP:

     >>> print(func.current_timestamp())
     CURRENT_TIMESTAMP

A function, like any other column expression, has a type, which
indicates the type of expression as well as how SQLAlchemy will
interpret result columns that are returned from this expression.  The
default type used for an arbitrary function name derived from ‘func’ is
simply a “null” datatype.  However, in order for the column expression
generated by the function to have type-specific operator behavior as
well as result-set behaviors, such as date and numeric coercions, the
type may need to be specified explicitly:

     stmt = select(func.date(some_table.c.date_string, type_=Date))

Functions are most typically used in the columns clause of a select
statement, and can also be labeled as well as given a type.  Labeling a
function is recommended so that the result can be targeted in a result
row based on a string name, and assigning it a type is required when you
need result-set processing to occur, such as for Unicode conversion and
date conversions.  Below, we use the result function ‘scalar()’ to just
read the first column of the first row and then close the result; the
label, even though present, is not important in this case:

     >>> conn.execute(
     ...     select(
     ...            func.max(addresses.c.email_address, type_=String).
     ...                label('maxemail')
     ...           )
     ...     ).scalar()
     {opensql}SELECT max(addresses.email_address) AS maxemail
     FROM addresses
     [...] ()
     {stop}u'www@www.org'

Databases such as PostgreSQL and Oracle which support functions that
return whole result sets can be assembled into selectable units, which
can be used in statements.  Such as, a database function ‘calculate()’
which takes the parameters ‘x’ and ‘y’, and returns three columns which
we’d like to name ‘q’, ‘z’ and ‘r’, we can construct using “lexical”
column objects as well as bind parameters:

     >>> from sqlalchemy.sql import column
     >>> calculate = select(column('q'), column('z'), column('r')).\
     ...        select_from(
     ...             func.calculate(
     ...                    bindparam('x'),
     ...                    bindparam('y')
     ...                )
     ...             )
     >>> calc = calculate.alias()
     >>> print(select(users).where(users.c.id > calc.c.z))
     SELECT users.id, users.name, users.fullname
     FROM users, (SELECT q, z, r
     FROM calculate(:x, :y)) AS anon_1
     WHERE users.id > anon_1.z

If we wanted to use our ‘calculate’ statement twice with different bind
parameters, the unique_params() function will create copies
for us, and mark the bind parameters as “unique” so that conflicting
names are isolated.  Note we also make two separate aliases of our
selectable:

     >>> calc1 = calculate.alias('c1').unique_params(x=17, y=45)
     >>> calc2 = calculate.alias('c2').unique_params(x=5, y=12)
     >>> s = select(users).\
     ...         where(users.c.id.between(calc1.c.z, calc2.c.z))
     >>> print(s)
     SELECT users.id, users.name, users.fullname
     FROM users,
         (SELECT q, z, r FROM calculate(:x_1, :y_1)) AS c1,
         (SELECT q, z, r FROM calculate(:x_2, :y_2)) AS c2
     WHERE users.id BETWEEN c1.z AND c2.z

     >>> s.compile().params # doctest: +SKIP
     {u'x_2': 5, u'y_2': 12, u'y_1': 45, u'x_1': 17}

See also
........

See func.

4.1.15.3 Window Functions
.........................

Any FunctionElement, including functions generated by
func, can be turned into a “window function”, that is an OVER
clause, using the FunctionElement.over() method:

     >>> s = select(
     ...         users.c.id,
     ...         func.row_number().over(order_by=users.c.name)
     ...     )
     >>> print(s)
     SELECT users.id, row_number() OVER (ORDER BY users.name) AS anon_1
     FROM users

FunctionElement.over() also supports range specification
using either the over.rows or over.range
parameters:

     >>> s = select(
     ...         users.c.id,
     ...         func.row_number().over(
     ...                 order_by=users.c.name,
     ...                 rows=(-2, None))
     ...     )
     >>> print(s)
     SELECT users.id, row_number() OVER
     (ORDER BY users.name ROWS BETWEEN :param_1 PRECEDING AND UNBOUNDED FOLLOWING) AS anon_1
     FROM users

over.rows and over.range each accept a two-tuple
which contains a combination of negative and positive integers for
ranges, zero to indicate “CURRENT ROW” and ‘None’ to indicate
“UNBOUNDED”.  See the examples at over() for more detail.

New in version 1.1: support for “rows” and “range” specification for
window functions

See also
........

See over().

See FunctionElement.over().

4.1.15.4 Data Casts and Type Coercion
.....................................

In SQL, we often need to indicate the datatype of an element explicitly,
or we need to convert between one datatype and another within a SQL
statement.  The CAST SQL function performs this.  In SQLAlchemy, the
cast() function renders the SQL CAST keyword.  It accepts a
column expression and a data type object as arguments:

     >>> from sqlalchemy import cast
     >>> s = select(cast(users.c.id, String))
     >>> conn.execute(s).fetchall()
     {opensql}SELECT CAST(users.id AS VARCHAR) AS id
     FROM users
     [...] ()
     {stop}[('1',), ('2',)]

The cast() function is used not just when converting between
datatypes, but also in cases where the database needs to know that some
particular value should be considered to be of a particular datatype
within an expression.

The cast() function also tells SQLAlchemy itself that an
expression should be treated as a particular type as well.  The datatype
of an expression directly impacts the behavior of Python operators upon
that object, such as how the ‘+’ operator may indicate integer addition
or string concatenation, and it also impacts how a literal Python value
is transformed or handled before being passed to the database as well as
how result values of that expression should be transformed or handled.

Sometimes there is the need to have SQLAlchemy know the datatype of an
expression, for all the reasons mentioned above, but to not render the
CAST expression itself on the SQL side, where it may interfere with a
SQL operation that already works without it.  For this fairly common use
case there is another function type_coerce() which is
closely related to cast(), in that it sets up a Python
expression as having a specific SQL database type, but does not render
the ‘CAST’ keyword or datatype on the database side.
type_coerce() is particularly important when dealing with the
JSON datatype, which typically has an intricate relationship
with string-oriented datatypes on different platforms and may not even
be an explicit datatype, such as on SQLite and MariaDB. Below, we use
type_coerce() to deliver a Python structure as a JSON string
into one of MySQL’s JSON functions:

     >>> import json
     >>> from sqlalchemy import JSON
     >>> from sqlalchemy import type_coerce
     >>> from sqlalchemy.dialects import mysql
     >>> s = select(
     ... type_coerce(
     ...        {'some_key': {'foo': 'bar'}}, JSON
     ...    )['some_key']
     ... )
     >>> print(s.compile(dialect=mysql.dialect()))
     SELECT JSON_EXTRACT(%s, %s) AS anon_1

Above, MySQL’s ‘JSON_EXTRACT’ SQL function was invoked because we used
type_coerce() to indicate that our Python dictionary should
be treated as JSON.  The Python ‘__getitem__’ operator,
‘['some_key']’ in this case, became available as a result and allowed a
‘JSON_EXTRACT’ path expression (not shown, however in this case it would
ultimately be ‘'$."some_key"'’) to be rendered.

4.1.15.5 Unions and Other Set Operations
........................................

Unions come in two flavors, UNION and UNION ALL, which are available via
module level functions union() and union_all():

     >>> from sqlalchemy.sql import union
     >>> u = union(
     ...     addresses.select().
     ...             where(addresses.c.email_address == 'foo@bar.com'),
     ...    addresses.select().
     ...             where(addresses.c.email_address.like('%@yahoo.com')),
     ... ).order_by(addresses.c.email_address)

     {sql}>>> conn.execute(u).fetchall()
     SELECT addresses.id, addresses.user_id, addresses.email_address
     FROM addresses
     WHERE addresses.email_address = ?
     UNION
     SELECT addresses.id, addresses.user_id, addresses.email_address
     FROM addresses
     WHERE addresses.email_address LIKE ? ORDER BY email_address
     [...] ('foo@bar.com', '%@yahoo.com')
     {stop}[(1, 1, u'jack@yahoo.com')]

Also available, though not supported on all databases, are
intersect(), intersect_all(), except_(), and
except_all():

     >>> from sqlalchemy.sql import except_
     >>> u = except_(
     ...    addresses.select().
     ...             where(addresses.c.email_address.like('%@%.com')),
     ...    addresses.select().
     ...             where(addresses.c.email_address.like('%@msn.com'))
     ... )

     {sql}>>> conn.execute(u).fetchall()
     SELECT addresses.id, addresses.user_id, addresses.email_address
     FROM addresses
     WHERE addresses.email_address LIKE ?
     EXCEPT
     SELECT addresses.id, addresses.user_id, addresses.email_address
     FROM addresses
     WHERE addresses.email_address LIKE ?
     [...] ('%@%.com', '%@msn.com')
     {stop}[(1, 1, u'jack@yahoo.com'), (4, 2, u'wendy@aol.com')]

A common issue with so-called “compound” selectables arises due to the
fact that they nest with parenthesis.  SQLite in particular doesn’t like
a statement that starts with parenthesis.  So when nesting a “compound”
inside a “compound”, it’s often necessary to apply
‘.subquery().select()’ to the first element of the outermost compound,
if that element is also a compound.  For example, to nest a “union” and
a “select” inside of “except_”, SQLite will want the “union” to be
stated as a subquery:

     >>> u = except_(
     ...    union(
     ...         addresses.select().
     ...             where(addresses.c.email_address.like('%@yahoo.com')),
     ...         addresses.select().
     ...             where(addresses.c.email_address.like('%@msn.com'))
     ...     ).subquery().select(),   # apply subquery here
     ...    addresses.select().where(addresses.c.email_address.like('%@msn.com'))
     ... )
     {sql}>>> conn.execute(u).fetchall()
     SELECT anon_1.id, anon_1.user_id, anon_1.email_address
     FROM (SELECT addresses.id AS id, addresses.user_id AS user_id,
         addresses.email_address AS email_address
         FROM addresses
         WHERE addresses.email_address LIKE ?
         UNION
         SELECT addresses.id AS id,
             addresses.user_id AS user_id,
             addresses.email_address AS email_address
         FROM addresses
         WHERE addresses.email_address LIKE ?) AS anon_1
     EXCEPT
     SELECT addresses.id, addresses.user_id, addresses.email_address
     FROM addresses
     WHERE addresses.email_address LIKE ?
     [...] ('%@yahoo.com', '%@msn.com', '%@msn.com')
     {stop}[(1, 1, u'jack@yahoo.com')]

See also
........

See union().

See union_all().

See intersect().

See intersect_all().

See except_().

See except_all().

4.1.15.6 Ordering Unions
........................

UNION and other set constructs have a special case when it comes to
ordering the results.  As the UNION consists of several SELECT
statements, to ORDER the whole result usually requires that an ORDER BY
clause refer to column names but not specific tables.  As in the
previous examples, we used ‘.order_by(addresses.c.email_address)’ but
SQLAlchemy rendered the ORDER BY without using the table name.  A
generalized way to apply ORDER BY to a union is also to refer to the
‘CompoundSelect.selected_columns’ collection in order to access the
column expressions which are synonymous with the columns selected from
the first SELECT; the SQLAlchemy compiler will ensure these will be
rendered without table names:

     >>> u = union(
     ...     addresses.select().
     ...             where(addresses.c.email_address == 'foo@bar.com'),
     ...    addresses.select().
     ...             where(addresses.c.email_address.like('%@yahoo.com')),
     ... )
     >>> u = u.order_by(u.selected_columns.email_address)
     >>> print(u)
     SELECT addresses.id, addresses.user_id, addresses.email_address
     FROM addresses
     WHERE addresses.email_address = :email_address_1
     UNION SELECT addresses.id, addresses.user_id, addresses.email_address
     FROM addresses
     WHERE addresses.email_address LIKE :email_address_2 ORDER BY email_address

4.1.15.7 Scalar Selects
.......................

A scalar select is a SELECT that returns exactly one row and one column.
It can then be used as a column expression.  A scalar select is often a
correlated subquery, which relies upon the enclosing SELECT statement in
order to acquire at least one of its FROM clauses.

The select() construct can be modified to act as a column
expression by calling either the SelectBase.scalar_subquery()
or SelectBase.label() method:

     >>> subq = select(func.count(addresses.c.id)).\
     ...             where(users.c.id == addresses.c.user_id).\
     ...             scalar_subquery()

The above construct is now a ScalarSelect object, which is
an adapter around the original ‘Select’ object; it participates within
the ColumnElement family of expression constructs.  We can
place this construct the same as any other column within another
select():

     >>> conn.execute(select(users.c.name, subq)).fetchall()
     {opensql}SELECT users.name, (SELECT count(addresses.id) AS count_1
     FROM addresses
     WHERE users.id = addresses.user_id) AS anon_1
     FROM users
     [...] ()
     {stop}[(u'jack', 2), (u'wendy', 2)]

To apply a non-anonymous column name to our scalar select, we create it
using SelectBase.label() instead:

     >>> subq = select(func.count(addresses.c.id)).\
     ...             where(users.c.id == addresses.c.user_id).\
     ...             label("address_count")
     >>> conn.execute(select(users.c.name, subq)).fetchall()
     {opensql}SELECT users.name, (SELECT count(addresses.id) AS count_1
     FROM addresses
     WHERE users.id = addresses.user_id) AS address_count
     FROM users
     [...] ()
     {stop}[(u'jack', 2), (u'wendy', 2)]

See also
........

See Select.scalar_subquery().

See Select.label().

4.1.15.8 Correlated Subqueries
..............................

In the examples on Scalar Selects, the FROM clause of each
embedded select did not contain the ‘users’ table in its FROM clause.
This is because SQLAlchemy automatically correlates embedded FROM
objects to that of an enclosing query, if present, and if the inner
SELECT statement would still have at least one FROM clause of its own.
For example:

     >>> stmt = select(addresses.c.user_id).\
     ...             where(addresses.c.user_id == users.c.id).\
     ...             where(addresses.c.email_address == 'jack@yahoo.com')
     >>> enclosing_stmt = select(users.c.name).\
     ...             where(users.c.id == stmt.scalar_subquery())
     >>> conn.execute(enclosing_stmt).fetchall()
     {opensql}SELECT users.name
     FROM users
     WHERE users.id = (SELECT addresses.user_id
         FROM addresses
         WHERE addresses.user_id = users.id
         AND addresses.email_address = ?)
     [...] ('jack@yahoo.com',)
     {stop}[(u'jack',)]

Auto-correlation will usually do what’s expected, however it can also be
controlled.  For example, if we wanted a statement to correlate only to
the ‘addresses’ table but not the ‘users’ table, even if both were
present in the enclosing SELECT, we use the Select.correlate()
method to specify those FROM clauses that may be correlated:

     >>> stmt = select(users.c.id).\
     ...             where(users.c.id == addresses.c.user_id).\
     ...             where(users.c.name == 'jack').\
     ...             correlate(addresses)
     >>> enclosing_stmt = select(
     ...         users.c.name, addresses.c.email_address).\
     ...     select_from(users.join(addresses)).\
     ...     where(users.c.id == stmt.scalar_subquery())
     >>> conn.execute(enclosing_stmt).fetchall()
     {opensql}SELECT users.name, addresses.email_address
      FROM users JOIN addresses ON users.id = addresses.user_id
      WHERE users.id = (SELECT users.id
      FROM users
      WHERE users.id = addresses.user_id AND users.name = ?)
      [...] ('jack',)
      {stop}[(u'jack', u'jack@yahoo.com'), (u'jack', u'jack@msn.com')]

To entirely disable a statement from correlating, we can pass ‘None’ as
the argument:

     >>> stmt = select(users.c.id).\
     ...             where(users.c.name == 'wendy').\
     ...             correlate(None)
     >>> enclosing_stmt = select(users.c.name).\
     ...     where(users.c.id == stmt.scalar_subquery())
     >>> conn.execute(enclosing_stmt).fetchall()
     {opensql}SELECT users.name
      FROM users
      WHERE users.id = (SELECT users.id
       FROM users
       WHERE users.name = ?)
     [...] ('wendy',)
     {stop}[(u'wendy',)]

We can also control correlation via exclusion, using the
Select.correlate_except() method.  Such as, we can write our
SELECT for the ‘users’ table by telling it to correlate all FROM clauses
except for ‘users’:

     >>> stmt = select(users.c.id).\
     ...             where(users.c.id == addresses.c.user_id).\
     ...             where(users.c.name == 'jack').\
     ...             correlate_except(users)
     >>> enclosing_stmt = select(
     ...         users.c.name, addresses.c.email_address).\
     ...     select_from(users.join(addresses)).\
     ...     where(users.c.id == stmt.scalar_subquery())
     >>> conn.execute(enclosing_stmt).fetchall()
     {opensql}SELECT users.name, addresses.email_address
      FROM users JOIN addresses ON users.id = addresses.user_id
      WHERE users.id = (SELECT users.id
      FROM users
      WHERE users.id = addresses.user_id AND users.name = ?)
      [...] ('jack',)
      {stop}[(u'jack', u'jack@yahoo.com'), (u'jack', u'jack@msn.com')]

4.1.15.9 LATERAL correlation
............................

LATERAL correlation is a special sub-category of SQL correlation which
allows a selectable unit to refer to another selectable unit within a
single FROM clause.  This is an extremely special use case which, while
part of the SQL standard, is only known to be supported by recent
versions of PostgreSQL.

Normally, if a SELECT statement refers to ‘table1 JOIN (some SELECT) AS
subquery’ in its FROM clause, the subquery on the right side may not
refer to the “table1” expression from the left side; correlation may
only refer to a table that is part of another SELECT that entirely
encloses this SELECT. The LATERAL keyword allows us to turn this
behavior around, allowing an expression such as:

     SELECT people.people_id, people.age, people.name
     FROM people JOIN LATERAL (SELECT books.book_id AS book_id
     FROM books WHERE books.owner_id = people.people_id)
     AS book_subq ON true

Where above, the right side of the JOIN contains a subquery that refers
not just to the “books” table but also the “people” table, correlating
to the left side of the JOIN. SQLAlchemy Core supports a statement like
the above using the Select.lateral() method as follows:

     >>> from sqlalchemy import table, column, select, true
     >>> people = table('people', column('people_id'), column('age'), column('name'))
     >>> books = table('books', column('book_id'), column('owner_id'))
     >>> subq = select(books.c.book_id).\
     ...      where(books.c.owner_id == people.c.people_id).lateral("book_subq")
     >>> print(select(people).select_from(people.join(subq, true())))
     SELECT people.people_id, people.age, people.name
     FROM people JOIN LATERAL (SELECT books.book_id AS book_id
     FROM books WHERE books.owner_id = people.people_id)
     AS book_subq ON true

Above, we can see that the Select.lateral() method acts a
lot like the Select.alias() method, including that we can
specify an optional name.  However the construct is the Lateral
construct instead of an Alias which provides for the
LATERAL keyword as well as special instructions to allow correlation
from inside the FROM clause of the enclosing statement.

The Select.lateral() method interacts normally with the
Select.correlate() and Select.correlate_except()
methods, except that the correlation rules also apply to any other
tables present in the enclosing statement’s FROM clause.  Correlation is
“automatic” to these tables by default, is explicit if the table is
specified to Select.correlate(), and is explicit to all
tables except those specified to Select.correlate_except().

New in version 1.1: Support for the LATERAL keyword and lateral
correlation.

See also
........

See Lateral.

See Select.lateral().

4.1.15.10 Ordering, Grouping, Limiting, Offset…ing…
...................................................

Ordering is done by passing column expressions to the
‘SelectBase.order_by()’ method:

     >>> stmt = select(users.c.name).order_by(users.c.name)
     >>> conn.execute(stmt).fetchall()
     {opensql}SELECT users.name
     FROM users ORDER BY users.name
     [...] ()
     {stop}[(u'jack',), (u'wendy',)]

Ascending or descending can be controlled using the
ColumnElement.asc() and ColumnElement.desc()
modifiers:

     >>> stmt = select(users.c.name).order_by(users.c.name.desc())
     >>> conn.execute(stmt).fetchall()
     {opensql}SELECT users.name
     FROM users ORDER BY users.name DESC
     [...] ()
     {stop}[(u'wendy',), (u'jack',)]

Grouping refers to the GROUP BY clause, and is usually used in
conjunction with aggregate functions to establish groups of rows to be
aggregated.  This is provided via the ‘SelectBase.group_by()’ method:

     >>> stmt = select(users.c.name, func.count(addresses.c.id)).\
     ...             select_from(users.join(addresses)).\
     ...             group_by(users.c.name)
     >>> conn.execute(stmt).fetchall()
     {opensql}SELECT users.name, count(addresses.id) AS count_1
     FROM users JOIN addresses
         ON users.id = addresses.user_id
     GROUP BY users.name
     [...] ()
     {stop}[(u'jack', 2), (u'wendy', 2)]

HAVING can be used to filter results on an aggregate value, after GROUP
BY has been applied.  It’s available here via the Select.having()
method:

     >>> stmt = select(users.c.name, func.count(addresses.c.id)).\
     ...             select_from(users.join(addresses)).\
     ...             group_by(users.c.name).\
     ...             having(func.length(users.c.name) > 4)
     >>> conn.execute(stmt).fetchall()
     {opensql}SELECT users.name, count(addresses.id) AS count_1
     FROM users JOIN addresses
         ON users.id = addresses.user_id
     GROUP BY users.name
     HAVING length(users.name) > ?
     [...] (4,)
     {stop}[(u'wendy', 2)]

A common system of dealing with duplicates in composed SELECT statements
is the DISTINCT modifier.  A simple DISTINCT clause can be added using
the Select.distinct() method:

     >>> stmt = select(users.c.name).\
     ...             where(addresses.c.email_address.
     ...                    contains(users.c.name)).\
     ...             distinct()
     >>> conn.execute(stmt).fetchall()
     {opensql}SELECT DISTINCT users.name
     FROM users, addresses
     WHERE (addresses.email_address LIKE '%' || users.name || '%')
     [...] ()
     {stop}[(u'jack',), (u'wendy',)]

Most database backends support a system of limiting how many rows are
returned, and the majority also feature a means of starting to return
rows after a given “offset”.  While common backends like PostgreSQL,
MySQL and SQLite support LIMIT and OFFSET keywords, other backends need
to refer to more esoteric features such as “window functions” and row
ids to achieve the same effect.  The Select.limit() and
Select.offset() methods provide an easy abstraction into the
current backend’s methodology:

     >>> stmt = select(users.c.name, addresses.c.email_address).\
     ...             select_from(users.join(addresses)).\
     ...             limit(1).offset(1)
     >>> conn.execute(stmt).fetchall()
     {opensql}SELECT users.name, addresses.email_address
     FROM users JOIN addresses ON users.id = addresses.user_id
      LIMIT ? OFFSET ?
     [...] (1, 1)
     {stop}[(u'jack', u'jack@msn.com')]

4.1.16 Inserts, Updates and Deletes
-----------------------------------

We’ve seen TableClause.insert() demonstrated earlier in this
tutorial.  Where TableClause.insert() produces INSERT, the
TableClause.update() method produces UPDATE. Both of these
constructs feature a method called ValuesBase.values() which
specifies the VALUES or SET clause of the statement.

The ValuesBase.values() method accommodates any column
expression as a value:

     >>> stmt = users.update().\
     ...             values(fullname="Fullname: " + users.c.name)
     >>> conn.execute(stmt)
     {opensql}UPDATE users SET fullname=(? || users.name)
     [...] ('Fullname: ',)
     COMMIT
     {stop}<sqlalchemy.engine.cursor.LegacyCursorResult object at 0x...>

When using TableClause.insert() or
TableClause.update() in an “execute many” context, we may also
want to specify named bound parameters which we can refer to in the
argument list.  The two constructs will automatically generate bound
placeholders for any column names passed in the dictionaries sent to
Connection.execute() at execution time.  However, if we wish
to use explicitly targeted named parameters with composed expressions,
we need to use the bindparam() construct.  When using
bindparam() with TableClause.insert() or
TableClause.update(), the names of the table’s columns themselves
are reserved for the “automatic” generation of bind names.  We can
combine the usage of implicitly available bind names and explicitly
named parameters as in the example below:

     >>> stmt = users.insert().\
     ...         values(name=bindparam('_name') + " .. name")
     >>> conn.execute(stmt, [
     ...        {'id':4, '_name':'name1'},
     ...        {'id':5, '_name':'name2'},
     ...        {'id':6, '_name':'name3'},
     ...     ])
     {opensql}INSERT INTO users (id, name) VALUES (?, (? || ?))
     [...] ((4, 'name1', ' .. name'), (5, 'name2', ' .. name'), (6, 'name3', ' .. name'))
     COMMIT
     <sqlalchemy.engine.cursor.LegacyCursorResult object at 0x...>

An UPDATE statement is emitted using the TableClause.update()
construct.  This works much like an INSERT, except there is an
additional WHERE clause that can be specified:

     >>> stmt = users.update().\
     ...             where(users.c.name == 'jack').\
     ...             values(name='ed')

     >>> conn.execute(stmt)
     {opensql}UPDATE users SET name=? WHERE users.name = ?
     [...] ('ed', 'jack')
     COMMIT
     {stop}<sqlalchemy.engine.cursor.LegacyCursorResult object at 0x...>

When using TableClause.update() in an “executemany” context,
we may wish to also use explicitly named bound parameters in the WHERE
clause.  Again, see bindparam() is the construct used to achieve
this:

     >>> stmt = users.update().\
     ...             where(users.c.name == bindparam('oldname')).\
     ...             values(name=bindparam('newname'))
     >>> conn.execute(stmt, [
     ...     {'oldname':'jack', 'newname':'ed'},
     ...     {'oldname':'wendy', 'newname':'mary'},
     ...     {'oldname':'jim', 'newname':'jake'},
     ...     ])
     {opensql}UPDATE users SET name=? WHERE users.name = ?
     [...] (('ed', 'jack'), ('mary', 'wendy'), ('jake', 'jim'))
     COMMIT
     {stop}<sqlalchemy.engine.cursor.LegacyCursorResult object at 0x...>

4.1.16.1 Correlated Updates
...........................

A correlated update lets you update a table using selection from another
table, or the same table; the SELECT statement is passed as a scalar
subquery using Select.scalar_subquery():

     >>> stmt = select(addresses.c.email_address).\
     ...             where(addresses.c.user_id == users.c.id).\
     ...             limit(1)
     >>> conn.execute(users.update().values(fullname=stmt.scalar_subquery()))
     {opensql}UPDATE users SET fullname=(SELECT addresses.email_address
         FROM addresses
         WHERE addresses.user_id = users.id
         LIMIT ? OFFSET ?)
     [...] (1, 0)
     COMMIT
     {stop}<sqlalchemy.engine.cursor.LegacyCursorResult object at 0x...>

4.1.16.2 Multiple Table Updates
...............................

The PostgreSQL, Microsoft SQL Server, and MySQL backends all support
UPDATE statements that refer to multiple tables.  For PG and MSSQL, this
is the “UPDATE FROM” syntax, which updates one table at a time, but can
reference additional tables in an additional “FROM” clause that can then
be referenced in the WHERE clause directly.  On MySQL, multiple tables
can be embedded into a single UPDATE statement separated by a comma.
The SQLAlchemy update() construct supports both of these
modes implicitly, by specifying multiple tables in the WHERE clause:

     stmt = users.update().\
             values(name='ed wood').\
             where(users.c.id == addresses.c.id).\
             where(addresses.c.email_address.startswith('ed%'))
     conn.execute(stmt)

The resulting SQL from the above statement would render as:

     UPDATE users SET name=:name FROM addresses
     WHERE users.id = addresses.id AND
     addresses.email_address LIKE :email_address_1 || '%'

When using MySQL, columns from each table can be assigned to in the SET
clause directly, using the dictionary form passed to
Update.values():

     stmt = users.update().\
             values({
                 users.c.name:'ed wood',
                 addresses.c.email_address:'ed.wood@foo.com'
             }).\
             where(users.c.id == addresses.c.id).\
             where(addresses.c.email_address.startswith('ed%'))

The tables are referenced explicitly in the SET clause:

     UPDATE users, addresses SET addresses.email_address=%s,
             users.name=%s WHERE users.id = addresses.id
             AND addresses.email_address LIKE concat(%s, '%')

When the construct is used on a non-supporting database, the compiler
will raise ‘NotImplementedError’.  For convenience, when a statement is
printed as a string without specification of a dialect, the “string SQL”
compiler will be invoked which provides a non-working SQL representation
of the construct.

4.1.16.3 Parameter-Ordered Updates
..................................

The default behavior of the update() construct when
rendering the SET clauses is to render them using the column ordering
given in the originating Table object.  This is an important
behavior, since it means that the rendering of a particular UPDATE
statement with particular columns will be rendered the same each time,
which has an impact on query caching systems that rely on the form of
the statement, either client side or server side.  Since the parameters
themselves are passed to the Update.values() method as
Python dictionary keys, there is no other fixed ordering available.

However in some cases, the order of parameters rendered in the SET
clause of an UPDATE statement may need to be explicitly stated.  The
main example of this is when using MySQL and providing updates to column
values based on that of other column values.  The end result of the
following statement:

     UPDATE some_table SET x = y + 10, y = 20

Will have a different result than:

     UPDATE some_table SET y = 20, x = y + 10

This because on MySQL, the individual SET clauses are fully evaluated on
a per-value basis, as opposed to on a per-row basis, and as each SET
clause is evaluated, the values embedded in the row are changing.

To suit this specific use case, the ‘update.ordered_values()’ method may
be used.  When using this method, we supply a `series of 2-tuples' as
the argument to the method:

     stmt = some_table.update().\
         ordered_values((some_table.c.y, 20), (some_table.c.x, some_table.c.y + 10))

The series of 2-tuples is essentially the same structure as a Python
dictionary, except that it explicitly suggests a specific ordering.
Using the above form, we are assured that the “y” column’s SET clause
will render first, then the “x” column’s SET clause.

Changed in version 1.4: Added the Update.ordered_values()
method which supersedes the update.preserve_parameter_order
flag that will be removed in SQLAlchemy 2.0.

See also
........

See INSERT…ON DUPLICATE KEY UPDATE (Upsert). - background on the
MySQL ‘ON DUPLICATE KEY UPDATE’ clause and how to support parameter
ordering.

4.1.16.4 Deletes
................

Finally, a delete.  This is accomplished easily enough using the
TableClause.delete() construct:

     >>> conn.execute(addresses.delete())
     {opensql}DELETE FROM addresses
     [...] ()
     COMMIT
     {stop}<sqlalchemy.engine.cursor.LegacyCursorResult object at 0x...>

     >>> conn.execute(users.delete().where(users.c.name > 'm'))
     {opensql}DELETE FROM users WHERE users.name > ?
     [...] ('m',)
     COMMIT
     {stop}<sqlalchemy.engine.cursor.LegacyCursorResult object at 0x...>

4.1.16.5 Multiple Table Deletes
...............................

New in version 1.2.

The PostgreSQL, Microsoft SQL Server, and MySQL backends all support
DELETE statements that refer to multiple tables within the WHERE
criteria.  For PG and MySQL, this is the “DELETE USING” syntax, and for
SQL Server, it’s a “DELETE FROM” that refers to more than one table.
The SQLAlchemy delete() construct supports both of these
modes implicitly, by specifying multiple tables in the WHERE clause:

     stmt = users.delete().\
             where(users.c.id == addresses.c.id).\
             where(addresses.c.email_address.startswith('ed%'))
     conn.execute(stmt)

On a PostgreSQL backend, the resulting SQL from the above statement
would render as:

     DELETE FROM users USING addresses
     WHERE users.id = addresses.id
     AND (addresses.email_address LIKE %(email_address_1)s || '%%')

When the construct is used on a non-supporting database, the compiler
will raise ‘NotImplementedError’.  For convenience, when a statement is
printed as a string without specification of a dialect, the “string SQL”
compiler will be invoked which provides a non-working SQL representation
of the construct.

4.1.16.6 Matched Row Counts
...........................

Both of TableClause.update() and TableClause.delete()
are associated with `matched row counts'.  This is a number
indicating the number of rows that were matched by the WHERE clause.
Note that by “matched”, this includes rows where no UPDATE actually took
place.  The value is available as CursorResult.rowcount:

     >>> result = conn.execute(users.delete())
     {opensql}DELETE FROM users
     [...] ()
     COMMIT
     {stop}>>> result.rowcount
     1

4.1.17 Further Reference
------------------------

Expression Language Reference: SQL Statements and Expressions API.

Database Metadata Reference: Describing Databases with MetaData.

Engine Reference: Engine Configuration.

Connection Reference: Working with Engines and Connections.

Types Reference: Column and Data Types.

4.2 SQL Statements and Expressions API
======================================

This section presents the API reference for the SQL Expression Language.
For a full introduction to its usage, see SQL Expression Language Tutorial (1.x API).

4.2.1 Column Elements and Expressions
-------------------------------------

The expression API consists of a series of classes each of which
represents a specific lexical element within a SQL string.  Composed
together into a larger structure, they form a statement construct that
may be `compiled' into a string representation that can be passed to a
database.  The classes are organized into a hierarchy that begins at the
basemost ClauseElement class.  Key subclasses include
ColumnElement, which represents the role of any column-based
expression in a SQL statement, such as in the columns clause, WHERE
clause, and ORDER BY clause, and FromClause, which represents
the role of a token that is placed in the FROM clause of a SELECT
statement.

4.2.1.1 Column Element Foundational Constructors
................................................

Standalone functions imported from the ‘sqlalchemy’ namespace which are
used when building up SQLAlchemy Expression Language constructs.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See and_.(*clauses)Produce a conjunction of expressions joined by ‘AND’.

See bindparam.(key[,Produce a “bound expression”.
value,
type_,
unique,
...])

See case.(*whens,Produce a ‘CASE’ expression.
**kw)

See cast.(expression,Produce a ‘CAST’ expression.
type_)

See column.(text[,Produce a ColumnClause object.
type_,
is_literal,
_selectable])

See custom_op.Represent a ‘custom’ operator.

See distinct.(expr)Produce an column-expression-level unary ‘DISTINCT’ clause.

See extract.(field,Return a Extract construct.
expr,
**kwargs)

See false.()Return a False_ construct.

See func.Generate SQL function expressions.

See lambda_stmt.(lmb[,Produce a SQL statement that is cached as a lambda.
enable_tracking,
track_closure_variables,
track_on,
...])

See literal.(value[,Return a literal clause, bound to a bind parameter.
type_])

See literal_column.(text[,Produce a ColumnClause object that has the column.is_literal flag
type_])        set to True.

See not_.(clause)Return a negation of the given clause, i.e.  ‘NOT(clause)’.

See null.()Return a constant Null construct.

See or_.(*clauses)Produce a conjunction of expressions joined by ‘OR’.

See outparam.(key[,Create an ‘OUT’ parameter for usage in functions (stored procedures), for databases which
type_])        support them.

See quoted_name.Represent a SQL identifier combined with quoting preferences.

See text.(text[,Construct a new TextClause clause, representing a textual SQL string directly.
bind])

See true.()Return a constant True_ construct.

See tuple_.(*clauses,Return a Tuple.
**kw)

See type_coerce.(expression,Associate a SQL expression with a particular type, without rendering ‘CAST’.
type_)

 -- Function: sqlalchemy.sql.expression.and_ (*clauses)

     Produce a conjunction of expressions joined by ‘AND’.

     E.g.:

          from sqlalchemy import and_

          stmt = select(users_table).where(
                          and_(
                              users_table.c.name == 'wendy',
                              users_table.c.enrolled == True
                          )
                      )

     The and_() conjunction is also available using the
     Python ‘&’ operator (though note that compound expressions need to
     be parenthesized in order to function with Python operator
     precedence behavior):

          stmt = select(users_table).where(
                          (users_table.c.name == 'wendy') &
                          (users_table.c.enrolled == True)
                      )

     The and_() operation is also implicit in some cases; the
     Select.where() method for example can be invoked
     multiple times against a statement, which will have the effect of
     each clause being combined using and_():

          stmt = select(users_table).\
                  where(users_table.c.name == 'wendy').\
                  where(users_table.c.enrolled == True)

     The and_() construct must be given at least one
     positional argument in order to be valid; a and_()
     construct with no arguments is ambiguous.  To produce an “empty” or
     dynamically generated and_() expression, from a given
     list of expressions, a “default” element of ‘True’ should be
     specified:

          criteria = and_(True, *expressions)

     The above expression will compile to SQL as the expression ‘true’
     or ‘1 = 1’, depending on backend, if no other expressions are
     present.  If expressions are present, then the ‘True’ value is
     ignored as it does not affect the outcome of an AND expression that
     has other elements.

     Deprecated since version 1.4: The and_() element now
     requires that at least one argument is passed; creating the
     and_() construct with no arguments is deprecated, and will
     emit a deprecation warning while continuing to produce a blank SQL
     string.

     See also
     ........

     See or_().

 -- Function: sqlalchemy.sql.expression.bindparam (key,
          value=symbol('NO_ARG'), type_=None, unique=False,
          required=symbol('NO_ARG'), quote=None, callable_=None,
          expanding=False, isoutparam=False, literal_execute=False,
          _compared_to_operator=None, _compared_to_type=None,
          _is_crud=False)

     Produce a “bound expression”.

     The return value is an instance of BindParameter; this
     is a ColumnElement subclass which represents a
     so-called “placeholder” value in a SQL expression, the value of
     which is supplied at the point at which the statement in executed
     against a database connection.

     In SQLAlchemy, the bindparam() construct has the ability
     to carry along the actual value that will be ultimately used at
     expression time.  In this way, it serves not just as a
     “placeholder” for eventual population, but also as a means of
     representing so-called “unsafe” values which should not be rendered
     directly in a SQL statement, but rather should be passed along to
     the DBAPI as values which need to be correctly escaped and
     potentially handled for type-safety.

     When using bindparam() explicitly, the use case is
     typically one of traditional deferment of parameters; the
     bindparam() construct accepts a name which can then be
     referred to at execution time:

          from sqlalchemy import bindparam

          stmt = select(users_table).\
                      where(users_table.c.name == bindparam('username'))

     The above statement, when rendered, will produce SQL similar to:

          SELECT id, name FROM user WHERE name = :username

     In order to populate the value of ‘:username’ above, the value
     would typically be applied at execution time to a method like
     Connection.execute():

          result = connection.execute(stmt, username='wendy')

     Explicit use of bindparam() is also common when
     producing UPDATE or DELETE statements that are to be invoked
     multiple times, where the WHERE criterion of the statement is to
     change on each invocation, such as:

          stmt = (users_table.update().
                  where(user_table.c.name == bindparam('username')).
                  values(fullname=bindparam('fullname'))
                  )

          connection.execute(
              stmt, [{"username": "wendy", "fullname": "Wendy Smith"},
                     {"username": "jack", "fullname": "Jack Jones"},
                     ]
          )

     SQLAlchemy’s Core expression system makes wide use of
     bindparam() in an implicit sense.  It is typical that Python
     literal values passed to virtually all SQL expression functions are
     coerced into fixed bindparam() constructs.  For example,
     given a comparison operation such as:

          expr = users_table.c.name == 'Wendy'

     The above expression will produce a BinaryExpression
     construct, where the left side is the Column object
     representing the ‘name’ column, and the right side is a
     BindParameter representing the literal value:

          print(repr(expr.right))
          BindParameter('%(4327771088 name)s', 'Wendy', type_=String())

     The expression above will render SQL such as:

          user.name = :name_1

     Where the ‘:name_1’ parameter name is an anonymous name.  The
     actual string ‘Wendy’ is not in the rendered string, but is carried
     along where it is later used within statement execution.  If we
     invoke a statement like the following:

          stmt = select(users_table).where(users_table.c.name == 'Wendy')
          result = connection.execute(stmt)

     We would see SQL logging output as:

          SELECT "user".id, "user".name
          FROM "user"
          WHERE "user".name = %(name_1)s
          {'name_1': 'Wendy'}

     Above, we see that ‘Wendy’ is passed as a parameter to the
     database, while the placeholder ‘:name_1’ is rendered in the
     appropriate form for the target database, in this case the
     PostgreSQL database.

     Similarly, see bindparam() is invoked automatically when
     working with CRUD statements as far as the “VALUES” portion is
     concerned.  The insert() construct produces an ‘INSERT’
     expression which will, at statement execution time, generate bound
     placeholders based on the arguments passed, as in:

          stmt = users_table.insert()
          result = connection.execute(stmt, name='Wendy')

     The above will produce SQL output as:

          INSERT INTO "user" (name) VALUES (%(name)s)
          {'name': 'Wendy'}

     The Insert construct, at compilation/execution time,
     rendered a single bindparam() mirroring the column name
     ‘name’ as a result of the single ‘name’ parameter we passed to the
     Connection.execute() method.

     Parameters:

        * ‘key’ – the key (e.g.  the name) for this bind param.  Will be
          used in the generated SQL statement for dialects that use
          named parameters.  This value may be modified when part of a
          compilation operation, if other BindParameter
          objects exist with the same key, or if its length is too long
          and truncation is required.

        * ‘value’ – Initial value for this bind param.  Will be used at
          statement execution time as the value for this parameter
          passed to the DBAPI, if no other value is indicated to the
          statement execution method for this particular parameter name.
          Defaults to ‘None’.

        * ‘callable_’ – A callable function that takes the place of
          “value”.  The function will be called at statement execution
          time to determine the ultimate value.  Used for scenarios
          where the actual bind value cannot be determined at the point
          at which the clause construct is created, but embedded bind
          values are still desirable.

        * ‘type_’ – A TypeEngine class or instance
          representing an optional datatype for this bindparam().
          If not passed, a type may be determined automatically for
          the bind, based on the given value; for example, trivial
          Python types such as ‘str’, ‘int’, ‘bool’ may result in the
          String, Integer or Boolean
          types being automatically selected.

          The type of a bindparam() is significant especially
          in that the type will apply pre-processing to the value before
          it is passed to the database.  For example, a
          bindparam() which refers to a datetime value, and is
          specified as holding the DateTime type, may apply
          conversion needed to the value (such as stringification on
          SQLite) before passing the value to the database.

        * ‘unique’ – if True, the key name of this BindParameter
          will be modified if another BindParameter of
          the same name already has been located within the containing
          expression.  This flag is used generally by the internals when
          producing so-called “anonymous” bound expressions, it isn’t
          generally applicable to explicitly-named bindparam()
          constructs.

        * ‘required’ – If ‘True’, a value is required at execution time.
          If not passed, it defaults to ‘True’ if neither
          bindparam.value or bindparam.callable were
          passed.  If either of these parameters are present, then
          bindparam.required defaults to ‘False’.

        * ‘quote’ – True if this parameter name requires quoting and is
          not currently known as a SQLAlchemy reserved word; this
          currently only applies to the Oracle backend, where bound
          names must sometimes be quoted.

        * ‘isoutparam’ – if True, the parameter should be treated like a
          stored procedure “OUT” parameter.  This applies to backends
          such as Oracle which support OUT parameters.

        * ‘expanding’ – if True, this parameter will be treated as an
          “expanding” parameter at execution time; the parameter value
          is expected to be a sequence, rather than a scalar value, and
          the string SQL statement will be transformed on a
          per-execution basis to accommodate the sequence with a
          variable number of parameter slots passed to the DBAPI. This
          is to allow statement caching to be used in conjunction with
          an IN clause.

          See also
          ........

          See ColumnOperators.in_().

          See Using IN expressions. - with baked queries

               Note: The “expanding” feature does not support
               “executemany”- style parameter sets.

          New in version 1.2.

          Changed in version 1.3: the “expanding” bound parameter
          feature now supports empty lists.

     See also
     ........

     See Bind Parameter Objects.

     See Insert Expressions.

     See outparam().

     Parameters: ‘literal_execute’ – if True, the bound parameter will
     be rendered in the compile phase with a special “POSTCOMPILE”
     token, and the SQLAlchemy compiler will render the final value of
     the parameter into the SQL statement at statement execution time,
     omitting the value from the parameter dictionary / list passed to
     DBAPI ‘cursor.execute()’.  This produces a similar effect as that
     of using the ‘literal_binds’, compilation flag, however takes place
     as the statement is sent to the DBAPI ‘cursor.execute()’ method,
     rather than when the statement is compiled.  The primary use of
     this capability is for rendering LIMIT / OFFSET clauses for
     database drivers that can’t accommodate for bound parameters in
     these contexts, while allowing SQL constructs to be cacheable at
     the compilation level.

     New in version 1.4: Added “post compile” bound parameters

     See also
     ........

     See New “post compile” bound parameters used for LIMIT/OFFSET in Oracle, SQL Server.

 -- Function: sqlalchemy.sql.expression.case (*whens, **kw)

     Produce a ‘CASE’ expression.

     The ‘CASE’ construct in SQL is a conditional object that acts
     somewhat analogously to an “if/then” construct in other languages.
     It returns an instance of Case.

     case() in its usual form is passed a series of “when”
     constructs, that is, a list of conditions and results as tuples:

          from sqlalchemy import case

          stmt = select(users_table).\
                      where(
                          case(
                              (users_table.c.name == 'wendy', 'W'),
                              (users_table.c.name == 'jack', 'J'),
                              else_='E'
                          )
                      )

     The above statement will produce SQL resembling:

          SELECT id, name FROM user
          WHERE CASE
              WHEN (name = :name_1) THEN :param_1
              WHEN (name = :name_2) THEN :param_2
              ELSE :param_3
          END

     When simple equality expressions of several values against a single
     parent column are needed, see case() also has a “shorthand”
     format used via the case.value parameter, which is
     passed a column expression to be compared.  In this form, the
     case.whens parameter is passed as a dictionary containing
     expressions to be compared against keyed to result expressions.
     The statement below is equivalent to the preceding statement:

          stmt = select(users_table).\
                      where(
                          case(
                              whens={"wendy": "W", "jack": "J"},
                              value=users_table.c.name,
                              else_='E'
                          )
                      )

     The values which are accepted as result values in case.whens
     as well as with case.else_ are coerced from Python
     literals into bindparam() constructs.  SQL expressions,
     e.g.  see ColumnElement constructs, are accepted as well.
     To coerce a literal string expression into a constant expression
     rendered inline, use the literal_column() construct, as
     in:

          from sqlalchemy import case, literal_column

          case(
              (
                  orderline.c.qty > 100,
                  literal_column("'greaterthan100'")
              ),
              (
                  orderline.c.qty > 10,
                  literal_column("'greaterthan10'")
              ),
              else_=literal_column("'lessthan10'")
          )

     The above will render the given constants without using bound
     parameters for the result values (but still for the comparison
     values), as in:

          CASE
              WHEN (orderline.qty > :qty_1) THEN 'greaterthan100'
              WHEN (orderline.qty > :qty_2) THEN 'greaterthan10'
              ELSE 'lessthan10'
          END

     Parameters:

        * ‘*whens’ – The criteria to be compared against, see
          case.whens accepts two different forms, based on whether
          or not case.value is used.

          Changed in version 1.4: the case() function now
          accepts the series of WHEN conditions positionally; passing
          the expressions within a list is deprecated.

          In the first form, it accepts a list of 2-tuples; each 2-tuple
          consists of ‘(<sql expression>, <value>)’, where the SQL
          expression is a boolean expression and “value” is a resulting
          value, e.g.:

               case(
                   (users_table.c.name == 'wendy', 'W'),
                   (users_table.c.name == 'jack', 'J')
               )

          In the second form, it accepts a Python dictionary of
          comparison values mapped to a resulting value; this form
          requires case.value to be present, and values will
          be compared using the ‘==’ operator, e.g.:

               case(
                   {"wendy": "W", "jack": "J"},
                   value=users_table.c.name
               )

        * ‘value’ – An optional SQL expression which will be used as a
          fixed “comparison point” for candidate values within a
          dictionary passed to case.whens.

        * ‘else_’ – An optional SQL expression which will be the
          evaluated result of the ‘CASE’ construct if all expressions
          within case.whens evaluate to false.  When
          omitted, most databases will produce a result of NULL if none
          of the “when” expressions evaluate to true.

 -- Function: sqlalchemy.sql.expression.cast (expression, type_)

     Produce a ‘CAST’ expression.

     cast() returns an instance of Cast.

     E.g.:

          from sqlalchemy import cast, Numeric

          stmt = select(cast(product_table.c.unit_price, Numeric(10, 4)))

     The above statement will produce SQL resembling:

          SELECT CAST(unit_price AS NUMERIC(10, 4)) FROM product

     The cast() function performs two distinct functions
     when used.  The first is that it renders the ‘CAST’ expression
     within the resulting SQL string.  The second is that it associates
     the given type (e.g.  see TypeEngine class or instance)
     with the column expression on the Python side, which means the
     expression will take on the expression operator behavior associated
     with that type, as well as the bound-value handling and
     result-row-handling behavior of the type.

     Changed in version 0.9.0: cast() now applies the given
     type to the expression such that it takes effect on the
     bound-value, e.g.  the Python-to-database direction, in addition to
     the result handling, e.g.  database-to-Python, direction.

     An alternative to cast() is the type_coerce()
     function.  This function performs the second task of
     associating an expression with a specific type, but does not render
     the ‘CAST’ expression in SQL.

     Parameters:

        * ‘expression’ – A SQL expression, such as a
          ColumnElement expression or a Python string which will
          be coerced into a bound literal value.

        * ‘type_’ – A TypeEngine class or instance
          indicating the type to which the ‘CAST’ should apply.

     See also
     ........

     See Data Casts and Type Coercion.

     See type_coerce(). - an alternative to CAST that coerces the
     type on the Python side only, which is often sufficient to generate
     the correct SQL and data coercion.

 -- Function: sqlalchemy.sql.expression.column (text, type_=None,
          is_literal=False, _selectable=None)

     Produce a ColumnClause object.

     The ColumnClause is a lightweight analogue to the
     Column class.  The column() function can be
     invoked with just a name alone, as in:

          from sqlalchemy import column

          id, name = column("id"), column("name")
          stmt = select(id, name).select_from("user")

     The above statement would produce SQL like:

          SELECT id, name FROM user

     Once constructed, see column() may be used like any other
     SQL expression element such as within select()
     constructs:

          from sqlalchemy.sql import column

          id, name = column("id"), column("name")
          stmt = select(id, name).select_from("user")

     The text handled by column() is assumed to be handled
     like the name of a database column; if the string contains mixed
     case, special characters, or matches a known reserved word on the
     target backend, the column expression will render using the quoting
     behavior determined by the backend.  To produce a textual SQL
     expression that is rendered exactly without any quoting, use
     literal_column() instead, or pass ‘True’ as the value of
     column.is_literal.  Additionally, full SQL statements
     are best handled using the text() construct.

     column() can be used in a table-like fashion by
     combining it with the table() function (which is the
     lightweight analogue to Table. ) to produce a working
     table construct with minimal boilerplate:

          from sqlalchemy import table, column, select

          user = table("user",
                  column("id"),
                  column("name"),
                  column("description"),
          )

          stmt = select(user.c.description).where(user.c.name == 'wendy')

     A column(). / see table() construct like that
     illustrated above can be created in an ad-hoc fashion and is not
     associated with any MetaData, DDL, or events, unlike its
     Table counterpart.

     Changed in version 1.0.0: column() can now be imported
     from the plain ‘sqlalchemy’ namespace like any other SQL element.

     Parameters:

        * ‘text’ – the text of the element.

        * ‘type’ – see TypeEngine object which can associate
          this ColumnClause with a type.

        * ‘is_literal’ – if True, the ColumnClause is
          assumed to be an exact expression that will be delivered to
          the output with no quoting rules applied regardless of case
          sensitive settings.  the literal_column() function
          essentially invokes column() while passing
          ‘is_literal=True’.

     See also
     ........

     See Column.

     See literal_column().

     See table().

     See text().

     See Using More Specific Text with table(), _expression.literal_column(), and _expression.column().

 -- Class: sqlalchemy.sql.expression.custom_op (opstring, precedence=0,
          is_comparison=False, return_type=None,
          natural_self_precedent=False, eager_grouping=False)

     Represent a ‘custom’ operator.

     custom_op is normally instantiated when the
     Operators.op() or Operators.bool_op() methods are
     used to create a custom operator callable.  The class can also be
     used directly when programmatically constructing expressions.  E.g.
     to represent the “factorial” operation:

          from sqlalchemy.sql import UnaryExpression
          from sqlalchemy.sql import operators
          from sqlalchemy import Numeric

          unary = UnaryExpression(table.c.somecolumn,
                  modifier=operators.custom_op("!"),
                  type_=Numeric)

     See also
     ........

     See Operators.op().

     See Operators.bool_op().

 -- Function: sqlalchemy.sql.expression.distinct (expr)

     Produce an column-expression-level unary ‘DISTINCT’ clause.

     This applies the ‘DISTINCT’ keyword to an individual column
     expression, and is typically contained within an aggregate
     function, as in:

          from sqlalchemy import distinct, func
          stmt = select(func.count(distinct(users_table.c.name)))

     The above would produce an expression resembling:

          SELECT COUNT(DISTINCT name) FROM user

     The distinct() function is also available as a
     column-level method, e.g.  see ColumnElement.distinct(), as
     in:

          stmt = select(func.count(users_table.c.name.distinct()))

     The distinct() operator is different from the
     Select.distinct() method of Select, which produces
     a ‘SELECT’ statement with ‘DISTINCT’ applied to the result set as a
     whole, e.g.  a ‘SELECT DISTINCT’ expression.  See that method for
     further information.

     See also
     ........

     See ColumnElement.distinct().

     See Select.distinct().

     See func.

 -- Function: sqlalchemy.sql.expression.extract (field, expr, **kwargs)

     Return a Extract construct.

     This is typically available as extract() as well as
     ‘func.extract’ from the func namespace.

 -- Function: sqlalchemy.sql.expression.false ()

     Return a False_ construct.

     E.g.:

          >>> from sqlalchemy import false
          >>> print(select(t.c.x).where(false()))
          SELECT x FROM t WHERE false

     A backend which does not support true/false constants will render
     as an expression against 1 or 0:

          >>> print(select(t.c.x).where(false()))
          SELECT x FROM t WHERE 0 = 1

     The true() and false() constants also
     feature “short circuit” operation within an and_() or
     or_() conjunction:

          >>> print(select(t.c.x).where(or_(t.c.x > 5, true())))
          SELECT x FROM t WHERE true

          >>> print(select(t.c.x).where(and_(t.c.x > 5, false())))
          SELECT x FROM t WHERE false

     Changed in version 0.9: true() and false()
     feature better integrated behavior within conjunctions and on
     dialects that don’t support true/false constants.

     See also
     ........

     See true().

 -- Data: sqlalchemy.sql.expression.func =
          <sqlalchemy.sql.functions._FunctionGenerator object>

     Generate SQL function expressions.

     func is a special object instance which generates SQL
     functions based on name-based attributes, e.g.:

          >>> print(func.count(1))
          count(:param_1)

     The returned object is an instance of Function, and is a
     column-oriented SQL element like any other, and is used in that
     way:

          >>> print(select(func.count(table.c.id)))
          SELECT count(sometable.id) FROM sometable

     Any name can be given to func.  If the function name is
     unknown to SQLAlchemy, it will be rendered exactly as is.  For
     common SQL functions which SQLAlchemy is aware of, the name may be
     interpreted as a `generic function' which will be compiled
     appropriately to the target database:

          >>> print(func.current_timestamp())
          CURRENT_TIMESTAMP

     To call functions which are present in dot-separated packages,
     specify them in the same manner:

          >>> print(func.stats.yield_curve(5, 10))
          stats.yield_curve(:yield_curve_1, :yield_curve_2)

     SQLAlchemy can be made aware of the return type of functions to
     enable type-specific lexical and result-based behavior.  For
     example, to ensure that a string-based function returns a Unicode
     value and is similarly treated as a string in expressions, specify
     Unicode as the type:

          >>> print(func.my_string(u'hi', type_=Unicode) + ' ' +
          ...       func.my_string(u'there', type_=Unicode))
          my_string(:my_string_1) || :my_string_2 || my_string(:my_string_3)

     The object returned by a func call is usually an
     instance of Function.  This object meets the “column”
     interface, including comparison and labeling functions.  The object
     can also be passed the ‘Connectable.execute()’ method of a
     Connection or Engine, where it will be wrapped
     inside of a SELECT statement first:

          print(connection.execute(func.current_timestamp()).scalar())

     In a few exception cases, the func accessor will
     redirect a name to a built-in expression such as cast()
     or extract(), as these names have well-known meaning but
     are not exactly the same as “functions” from a SQLAlchemy
     perspective.

     Functions which are interpreted as “generic” functions know how to
     calculate their return type automatically.  For a listing of known
     generic functions, see SQL and Generic Functions.

          Note: The func construct has only limited support
          for calling standalone “stored procedures”, especially those
          with special parameterization concerns.

          See the section Calling Stored Procedures for
          details on how to use the DBAPI-level ‘callproc()’ method for
          fully traditional stored procedures.

     See also
     ........

     See Functions. - in the Core Tutorial

     See Function.

 -- Function: sqlalchemy.sql.expression.lambda_stmt (lmb,
          enable_tracking=True, track_closure_variables=True,
          track_on=None, global_track_bound_values=True,
          track_bound_values=True, lambda_cache=None)

     Produce a SQL statement that is cached as a lambda.

     The Python code object within the lambda is scanned for both Python
     literals that will become bound parameters as well as closure
     variables that refer to Core or ORM constructs that may vary.  The
     lambda itself will be invoked only once per particular set of
     constructs detected.

     E.g.:

          from sqlalchemy import lambda_stmt

          stmt = lambda_stmt(lambda: table.select())
          stmt += lambda s: s.where(table.c.id == 5)

          result = connection.execute(stmt)

     The object returned is an instance of StatementLambdaElement.

     New in version 1.4.

     Parameters:

        * ‘lmb’ – a Python function, typically a lambda, which takes no
          arguments and returns a SQL expression construct

        * ‘enable_tracking’ – when False, all scanning of the given
          lambda for changes in closure variables or bound parameters is
          disabled.  Use for a lambda that produces the identical
          results in all cases with no parameterization.

        * ‘track_closure_variables’ – when False, changes in closure
          variables within the lambda will not be scanned.  Use for a
          lambda where the state of its closure variables will never
          change the SQL structure returned by the lambda.

        * ‘track_bound_values’ – when False, bound parameter tracking
          will be disabled for the given lambda.  Use for a lambda that
          either does not produce any bound values, or where the initial
          bound values never change.

        * ‘global_track_bound_values’ – when False, bound parameter
          tracking will be disabled for the entire statement including
          additional links added via the
          StatementLambdaElement.add_criteria() method.

        * ‘lambda_cache’ – a dictionary or other mapping-like object
          where information about the lambda’s Python code as well as
          the tracked closure variables in the lambda itself will be
          stored.  Defaults to a global LRU cache.  This cache is
          independent of the “compiled_cache” used by the
          Connection object.

     See also
     ........

     See Using Lambdas to add significant speed gains to statement production.

 -- Function: sqlalchemy.sql.expression.literal (value, type_=None)

     Return a literal clause, bound to a bind parameter.

     Literal clauses are created automatically when non- see
     ClauseElement objects (such as strings, ints, dates, etc.)
     are used in a comparison operation with a ColumnElement
     subclass, such as a Column object.  Use this function to
     force the generation of a literal clause, which will be created as
     a BindParameter with a bound value.

     Parameters:

        * ‘value’ – the value to be bound.  Can be any Python object
          supported by the underlying DB-API, or is translatable via the
          given type argument.

        * ‘type_’ – an optional TypeEngine which will
          provide bind-parameter translation for this literal.

 -- Function: sqlalchemy.sql.expression.literal_column (text,
          type_=None)

     Produce a ColumnClause object that has the
     column.is_literal flag set to True.

     literal_column() is similar to column(),
     except that it is more often used as a “standalone” column
     expression that renders exactly as stated; while column()
     stores a string name that will be assumed to be part of a
     table and may be quoted as such, see literal_column() can
     be that, or any other arbitrary column-oriented expression.

     Parameters:

        * ‘text’ – the text of the expression; can be any SQL
          expression.  Quoting rules will not be applied.  To specify a
          column-name expression which should be subject to quoting
          rules, use the column() function.

        * ‘type_’ – an optional TypeEngine object which will
          provide result-set translation and additional expression
          semantics for this column.  If left as ‘None’ the type will be
          NullType.

     See also
     ........

     See column().

     See text().

     See Using More Specific Text with table(), _expression.literal_column(), and _expression.column().

 -- Function: sqlalchemy.sql.expression.not_ (clause)

     Return a negation of the given clause, i.e.  ‘NOT(clause)’.

     The ‘~’ operator is also overloaded on all ColumnElement
     subclasses to produce the same result.

 -- Function: sqlalchemy.sql.expression.null ()

     Return a constant Null construct.

 -- Function: sqlalchemy.sql.expression.or_ (*clauses)

     Produce a conjunction of expressions joined by ‘OR’.

     E.g.:

          from sqlalchemy import or_

          stmt = select(users_table).where(
                          or_(
                              users_table.c.name == 'wendy',
                              users_table.c.name == 'jack'
                          )
                      )

     The or_() conjunction is also available using the Python
     ‘|’ operator (though note that compound expressions need to be
     parenthesized in order to function with Python operator precedence
     behavior):

          stmt = select(users_table).where(
                          (users_table.c.name == 'wendy') |
                          (users_table.c.name == 'jack')
                      )

     The or_() construct must be given at least one
     positional argument in order to be valid; a or_()
     construct with no arguments is ambiguous.  To produce an “empty” or
     dynamically generated or_() expression, from a given
     list of expressions, a “default” element of ‘False’ should be
     specified:

          or_criteria = or_(False, *expressions)

     The above expression will compile to SQL as the expression ‘false’
     or ‘0 = 1’, depending on backend, if no other expressions are
     present.  If expressions are present, then the ‘False’ value is
     ignored as it does not affect the outcome of an OR expression which
     has other elements.

     Deprecated since version 1.4: The or_() element now
     requires that at least one argument is passed; creating the
     or_() construct with no arguments is deprecated, and will emit
     a deprecation warning while continuing to produce a blank SQL
     string.

     See also
     ........

     See and_().

 -- Function: sqlalchemy.sql.expression.outparam (key, type_=None)

     Create an ‘OUT’ parameter for usage in functions (stored
     procedures), for databases which support them.

     The ‘outparam’ can be used like a regular function parameter.  The
     “output” value will be available from the CursorResult
     object via its ‘out_parameters’ attribute, which returns a
     dictionary containing the values.

 -- Function: sqlalchemy.sql.expression.text (text, bind=None)

     Construct a new TextClause clause, representing a
     textual SQL string directly.

     E.g.:

          from sqlalchemy import text

          t = text("SELECT * FROM users")
          result = connection.execute(t)

     The advantages text() provides over a plain string are
     backend-neutral support for bind parameters, per-statement
     execution options, as well as bind parameter and result-column
     typing behavior, allowing SQLAlchemy type constructs to play a role
     when executing a statement that is specified literally.  The
     construct can also be provided with a ‘.c’ collection of column
     elements, allowing it to be embedded in other SQL expression
     constructs as a subquery.

     Bind parameters are specified by name, using the format ‘:name’.
     E.g.:

          t = text("SELECT * FROM users WHERE id=:user_id")
          result = connection.execute(t, user_id=12)

     For SQL statements where a colon is required verbatim, as within an
     inline string, use a backslash to escape:

          t = text("SELECT * FROM users WHERE name='\:username'")

     The TextClause construct includes methods which can
     provide information about the bound parameters as well as the
     column values which would be returned from the textual statement,
     assuming it’s an executable SELECT type of statement.  The
     TextClause.bindparams() method is used to provide bound
     parameter detail, and TextClause.columns() method
     allows specification of return columns including names and types:

          t = text("SELECT * FROM users WHERE id=:user_id").\
                  bindparams(user_id=7).\
                  columns(id=Integer, name=String)

          for id, name in connection.execute(t):
              print(id, name)

     The text() construct is used in cases when a literal
     string SQL fragment is specified as part of a larger query, such as
     for the WHERE clause of a SELECT statement:

          s = select(users.c.id, users.c.name).where(text("id=:user_id"))
          result = connection.execute(s, user_id=12)

     text() is also used for the construction of a full,
     standalone statement using plain text.  As such, SQLAlchemy refers
     to it as an Executable object, and it supports the
     Executable.execution_options() method.  For example, a
     text() construct that should be subject to “autocommit”
     can be set explicitly so using the
     Connection.execution_options.autocommit option:

          t = text("EXEC my_procedural_thing()").\
                  execution_options(autocommit=True)

     Deprecated since version 1.4: The “autocommit” execution option is
     deprecated and will be removed in SQLAlchemy 2.0.  See
     Library-level (but not driver level) “Autocommit” removed from both Core and ORM
     for discussion.

     Parameters:

        * ‘text’ – the text of the SQL statement to be created.  Use
          ‘:<param>’ to specify bind parameters; they will be compiled
          to their engine-specific format.

               Warning: The text.text argument to
               text() can be passed as a Python string argument,
               which will be treated as `trusted SQL text' and rendered
               as given.  `DO NOT PASS UNTRUSTED INPUT TO THIS
               PARAMETER'.

        * ‘bind’ – an optional connection or engine to be used for this
          text query.

          Deprecated since version 1.4: The text.bind
          argument is deprecated and will be removed in SQLAlchemy 2.0.

     See also
     ........

     See Using Textual SQL. - in the Core tutorial

 -- Function: sqlalchemy.sql.expression.true ()

     Return a constant True_ construct.

     E.g.:

          >>> from sqlalchemy import true
          >>> print(select(t.c.x).where(true()))
          SELECT x FROM t WHERE true

     A backend which does not support true/false constants will render
     as an expression against 1 or 0:

          >>> print(select(t.c.x).where(true()))
          SELECT x FROM t WHERE 1 = 1

     The true() and false() constants also
     feature “short circuit” operation within an and_() or
     or_() conjunction:

          >>> print(select(t.c.x).where(or_(t.c.x > 5, true())))
          SELECT x FROM t WHERE true

          >>> print(select(t.c.x).where(and_(t.c.x > 5, false())))
          SELECT x FROM t WHERE false

     Changed in version 0.9: true() and false()
     feature better integrated behavior within conjunctions and on
     dialects that don’t support true/false constants.

     See also
     ........

     See false().

 -- Function: sqlalchemy.sql.expression.tuple_ (*clauses, **kw)

     Return a Tuple.

     Main usage is to produce a composite IN construct using
     ColumnOperators.in_().

          from sqlalchemy import tuple_

          tuple_(table.c.col1, table.c.col2).in_(
              [(1, 2), (5, 12), (10, 19)]
          )

     Changed in version 1.3.6: Added support for SQLite IN tuples.

          Warning: The composite IN construct is not supported by all
          backends, and is currently known to work on PostgreSQL, MySQL,
          and SQLite.  Unsupported backends will raise a subclass of
          DBAPIError when such an expression is invoked.

 -- Function: sqlalchemy.sql.expression.type_coerce (expression, type_)

     Associate a SQL expression with a particular type, without
     rendering ‘CAST’.

     E.g.:

          from sqlalchemy import type_coerce

          stmt = select(type_coerce(log_table.date_string, StringDateTime()))

     The above construct will produce a TypeCoerce object,
     which does not modify the rendering in any way on the SQL side,
     with the possible exception of a generated label if used in a
     columns clause context:

          SELECT date_string AS date_string FROM log

     When result rows are fetched, the ‘StringDateTime’ type processor
     will be applied to result rows on behalf of the ‘date_string’
     column.

          Note: the type_coerce() construct does not render
          any SQL syntax of its own, including that it does not imply
          parenthesization.  Please use TypeCoerce.self_group()
          if explicit parenthesization is required.

     In order to provide a named label for the expression, use
     ColumnElement.label():

          stmt = select(
              type_coerce(log_table.date_string, StringDateTime()).label('date')
          )

     A type that features bound-value handling will also have that
     behavior take effect when literal values or bindparam()
     constructs are passed to type_coerce() as targets.  For
     example, if a type implements the
     TypeEngine.bind_expression() method or
     TypeEngine.bind_processor() method or equivalent, these
     functions will take effect at statement compilation/execution time
     when a literal value is passed, as in:

          # bound-value handling of MyStringType will be applied to the
          # literal value "some string"
          stmt = select(type_coerce("some string", MyStringType))

     When using type_coerce() with composed expressions,
     note that `parenthesis are not applied'.  If type_coerce()
     is being used in an operator context where the parenthesis
     normally present from CAST are necessary, use the
     TypeCoerce.self_group() method:

          >>> some_integer = column("someint", Integer)
          >>> some_string = column("somestr", String)
          >>> expr = type_coerce(some_integer + 5, String) + some_string
          >>> print(expr)
          someint + :someint_1 || somestr
          >>> expr = type_coerce(some_integer + 5, String).self_group() + some_string
          >>> print(expr)
          (someint + :someint_1) || somestr

     Parameters:

        * ‘expression’ – A SQL expression, such as a
          ColumnElement expression or a Python string which will
          be coerced into a bound literal value.

        * ‘type_’ – A TypeEngine class or instance
          indicating the type to which the expression is coerced.

     See also
     ........

     See Data Casts and Type Coercion.

     See cast().

 -- Class: sqlalchemy.sql.expression.quoted_name (value, quote)

     Represent a SQL identifier combined with quoting preferences.

     quoted_name is a Python unicode/str subclass which
     represents a particular identifier name along with a ‘quote’ flag.
     This ‘quote’ flag, when set to ‘True’ or ‘False’, overrides
     automatic quoting behavior for this identifier in order to either
     unconditionally quote or to not quote the name.  If left at its
     default of ‘None’, quoting behavior is applied to the identifier on
     a per-backend basis based on an examination of the token itself.

     A quoted_name object with ‘quote=True’ is also
     prevented from being modified in the case of a so-called “name
     normalize” option.  Certain database backends, such as Oracle,
     Firebird, and DB2 “normalize” case-insensitive names as uppercase.
     The SQLAlchemy dialects for these backends convert from
     SQLAlchemy’s lower-case-means-insensitive convention to the
     upper-case-means-insensitive conventions of those backends.  The
     ‘quote=True’ flag here will prevent this conversion from occurring
     to support an identifier that’s quoted as all lower case against
     such a backend.

     The quoted_name object is normally created
     automatically when specifying the name for key schema constructs
     such as Table, Column, and others.  The class
     can also be passed explicitly as the name to any function that
     receives a name which can be quoted.  Such as to use the
     Engine.has_table() method with an unconditionally quoted
     name:

          from sqlalchemy import create_engine
          from sqlalchemy.sql import quoted_name

          engine = create_engine("oracle+cx_oracle://some_dsn")
          engine.has_table(quoted_name("some_table", True))

     The above logic will run the “has table” logic against the Oracle
     backend, passing the name exactly as ‘"some_table"’ without
     converting to upper case.

     New in version 0.9.0.

     Changed in version 1.2: The quoted_name construct is
     now importable from ‘sqlalchemy.sql’, in addition to the previous
     location of ‘sqlalchemy.sql.elements’.

     `Class signature'

     class sqlalchemy.sql.expression.quoted_name.
     (‘sqlalchemy.util.langhelpers.MemoizedSlots’, ‘builtins.str’)

      -- Attribute: sqlalchemy.sql.expression.quoted_name..
               quote

          whether the string should be unconditionally quoted

4.2.1.2 Column Element Modifier Constructors
............................................

Functions listed here are more commonly available as methods from any
ColumnElement construct, for example, the label()
function is usually invoked via the ColumnElement.label()
method.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See all_.(expr)Produce an ALL expression.

See any_.(expr)Produce an ANY expression.

See asc.(column)Produce an ascending ‘ORDER BY’ clause element.

See between.(expr,Produce a ‘BETWEEN’ predicate clause.
lower_bound,
upper_bound[,
symmetric])

See collate.(expression,Return the clause ‘expression COLLATE collation’.
collation)

See desc.(column)Produce a descending ‘ORDER BY’ clause element.

See funcfilter.(func,Produce a FunctionFilter object against a function.
*criterion)

See label.(name,Return a Label object for the given ColumnElement
element[,
type_])

See nulls_first.(column)Produce the ‘NULLS FIRST’ modifier for an ‘ORDER BY’ expression.

See nulls_last.(column)Produce the ‘NULLS LAST’ modifier for an ‘ORDER BY’ expression.

See over.(element[,Produce an Over object against a function.
partition_by,
order_by,
range_,
...])

See within_group.(element,Produce a WithinGroup object against a function.
*order_by)

 -- Function: sqlalchemy.sql.expression.all_ (expr)

     Produce an ALL expression.

     This may apply to an array type for some dialects (e.g.
     postgresql), or to a subquery for others (e.g.  mysql).  e.g.:

          # postgresql '5 = ALL (somearray)'
          expr = 5 == all_(mytable.c.somearray)

          # mysql '5 = ALL (SELECT value FROM table)'
          expr = 5 == all_(select(table.c.value))

     The operator is more conveniently available from any
     ColumnElement object that makes use of the ARRAY
     datatype:

          expr = mytable.c.somearray.all(5)

     See also
     ........

     See any_().

     See Comparator.all().

 -- Function: sqlalchemy.sql.expression.any_ (expr)

     Produce an ANY expression.

     This may apply to an array type for some dialects (e.g.
     postgresql), or to a subquery for others (e.g.  mysql).  e.g.:

          # postgresql '5 = ANY (somearray)'
          expr = 5 == any_(mytable.c.somearray)

          # mysql '5 = ANY (SELECT value FROM table)'
          expr = 5 == any_(select(table.c.value))

     The operator is more conveniently available from any
     ColumnElement object that makes use of the ARRAY
     datatype:

          expr = mytable.c.somearray.any(5)

     See also
     ........

     See all_().

     ‘ARRAY.any()’

 -- Function: sqlalchemy.sql.expression.asc (column)

     Produce an ascending ‘ORDER BY’ clause element.

     e.g.:

          from sqlalchemy import asc
          stmt = select(users_table).order_by(asc(users_table.c.name))

     will produce SQL as:

          SELECT id, name FROM user ORDER BY name ASC

     The asc() function is a standalone version of the
     ColumnElement.asc() method available on all SQL expressions,
     e.g.:

          stmt = select(users_table).order_by(users_table.c.name.asc())

     Parameters: ‘column’ – A ColumnElement. (e.g.  scalar
     SQL expression) with which to apply the asc()
     operation.

     See also
     ........

     See desc().

     See nulls_first().

     See nulls_last().

     See Select.order_by().

 -- Function: sqlalchemy.sql.expression.between (expr, lower_bound,
          upper_bound, symmetric=False)

     Produce a ‘BETWEEN’ predicate clause.

     E.g.:

          from sqlalchemy import between
          stmt = select(users_table).where(between(users_table.c.id, 5, 7))

     Would produce SQL resembling:

          SELECT id, name FROM user WHERE id BETWEEN :id_1 AND :id_2

     The between() function is a standalone version of the
     ColumnElement.between() method available on all SQL
     expressions, as in:

          stmt = select(users_table).where(users_table.c.id.between(5, 7))

     All arguments passed to between(), including the left
     side column expression, are coerced from Python scalar values if a
     the value is not a ColumnElement subclass.  For
     example, three fixed values can be compared as in:

          print(between(5, 3, 7))

     Which would produce:

          :param_1 BETWEEN :param_2 AND :param_3

     Parameters:

        * ‘expr’ – a column expression, typically a ColumnElement
          instance or alternatively a Python scalar expression to
          be coerced into a column expression, serving as the left side
          of the ‘BETWEEN’ expression.

        * ‘lower_bound’ – a column or Python scalar expression serving
          as the lower bound of the right side of the ‘BETWEEN’
          expression.

        * ‘upper_bound’ – a column or Python scalar expression serving
          as the upper bound of the right side of the ‘BETWEEN’
          expression.

        * ‘symmetric’ – if True, will render ” BETWEEN SYMMETRIC “.
          Note that not all databases support this syntax.

          New in version 0.9.5.

     See also
     ........

     See ColumnElement.between().

 -- Function: sqlalchemy.sql.expression.collate (expression, collation)

     Return the clause ‘expression COLLATE collation’.

     e.g.:

          collate(mycolumn, 'utf8_bin')

     produces:

          mycolumn COLLATE utf8_bin

     The collation expression is also quoted if it is a case sensitive
     identifier, e.g.  contains uppercase characters.

     Changed in version 1.2: quoting is automatically applied to COLLATE
     expressions if they are case sensitive.

 -- Function: sqlalchemy.sql.expression.desc (column)

     Produce a descending ‘ORDER BY’ clause element.

     e.g.:

          from sqlalchemy import desc

          stmt = select(users_table).order_by(desc(users_table.c.name))

     will produce SQL as:

          SELECT id, name FROM user ORDER BY name DESC

     The desc() function is a standalone version of the
     ColumnElement.desc() method available on all SQL
     expressions, e.g.:

          stmt = select(users_table).order_by(users_table.c.name.desc())

     Parameters: ‘column’ – A ColumnElement. (e.g.  scalar
     SQL expression) with which to apply the desc()
     operation.

     See also
     ........

     See asc().

     See nulls_first().

     See nulls_last().

     See Select.order_by().

 -- Function: sqlalchemy.sql.expression.funcfilter (func, *criterion)

     Produce a FunctionFilter object against a function.

     Used against aggregate and window functions, for database backends
     that support the “FILTER” clause.

     E.g.:

          from sqlalchemy import funcfilter
          funcfilter(func.count(1), MyClass.name == 'some name')

     Would produce “COUNT(1) FILTER (WHERE myclass.name = ‘some name’)”.

     This function is also available from the func construct
     itself via the FunctionElement.filter() method.

     New in version 1.0.0.

     See also
     ........

     See Special Modifiers WITHIN GROUP, FILTER. - in the
     SQLAlchemy 1.4 / 2.0 Tutorial.

     See FunctionElement.filter().

 -- Function: sqlalchemy.sql.expression.label (name, element,
          type_=None)

     Return a Label object for the given
     ColumnElement.

     A label changes the name of an element in the columns clause of a
     ‘SELECT’ statement, typically via the ‘AS’ SQL keyword.

     This functionality is more conveniently available via the
     ColumnElement.label() method on ColumnElement.

     Parameters:

        * ‘name’ – label name

        * ‘obj’ – a ColumnElement.

 -- Function: sqlalchemy.sql.expression.nulls_first (column)

     Produce the ‘NULLS FIRST’ modifier for an ‘ORDER BY’ expression.

     nulls_first() is intended to modify the expression
     produced by asc() or desc(), and indicates
     how NULL values should be handled when they are encountered during
     ordering:

          from sqlalchemy import desc, nulls_first

          stmt = select(users_table).order_by(
              nulls_first(desc(users_table.c.name)))

     The SQL expression from the above would resemble:

          SELECT id, name FROM user ORDER BY name DESC NULLS FIRST

     Like asc() and desc(), nulls_first()
     is typically invoked from the column expression itself using
     ColumnElement.nulls_first(), rather than as its
     standalone function version, as in:

          stmt = select(users_table).order_by(
              users_table.c.name.desc().nulls_first())

     Changed in version 1.4: nulls_first() is renamed from
     ‘nullsfirst()’ in previous releases.  The previous name remains
     available for backwards compatibility.

     See also
     ........

     See asc().

     See desc().

     See nulls_last().

     See Select.order_by().

 -- Function: sqlalchemy.sql.expression.nulls_last (column)

     Produce the ‘NULLS LAST’ modifier for an ‘ORDER BY’ expression.

     nulls_last() is intended to modify the expression
     produced by asc() or desc(), and indicates
     how NULL values should be handled when they are encountered during
     ordering:

          from sqlalchemy import desc, nulls_last

          stmt = select(users_table).order_by(
              nulls_last(desc(users_table.c.name)))

     The SQL expression from the above would resemble:

          SELECT id, name FROM user ORDER BY name DESC NULLS LAST

     Like asc() and desc(), nulls_last()
     is typically invoked from the column expression itself using
     ColumnElement.nulls_last(), rather than as its
     standalone function version, as in:

          stmt = select(users_table).order_by(
              users_table.c.name.desc().nulls_last())

     Changed in version 1.4: nulls_last() is renamed from
     ‘nullslast()’ in previous releases.  The previous name remains
     available for backwards compatibility.

     See also
     ........

     See asc().

     See desc().

     See nulls_first().

     See Select.order_by().

 -- Function: sqlalchemy.sql.expression.over (element,
          partition_by=None, order_by=None, range_=None, rows=None)

     Produce an Over object against a function.

     Used against aggregate or so-called “window” functions, for
     database backends that support window functions.

     over() is usually called using the
     FunctionElement.over() method, e.g.:

          func.row_number().over(order_by=mytable.c.some_column)

     Would produce:

          ROW_NUMBER() OVER(ORDER BY some_column)

     Ranges are also possible using the over.range_ and
     over.rows parameters.  These mutually-exclusive
     parameters each accept a 2-tuple, which contains a combination of
     integers and None:

          func.row_number().over(
              order_by=my_table.c.some_column, range_=(None, 0))

     The above would produce:

          ROW_NUMBER() OVER(ORDER BY some_column
          RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)

     A value of ‘None’ indicates “unbounded”, a value of zero indicates
     “current row”, and negative / positive integers indicate
     “preceding” and “following”:

        * RANGE BETWEEN 5 PRECEDING AND 10 FOLLOWING:

               func.row_number().over(order_by='x', range_=(-5, 10))

        * ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW:

               func.row_number().over(order_by='x', rows=(None, 0))

        * RANGE BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING:

               func.row_number().over(order_by='x', range_=(-2, None))

        * RANGE BETWEEN 1 FOLLOWING AND 3 FOLLOWING:

               func.row_number().over(order_by='x', range_=(1, 3))

     New in version 1.1: support for RANGE / ROWS within a window

     Parameters:

        * ‘element’ – a FunctionElement, WithinGroup,
          or other compatible construct.

        * ‘partition_by’ – a column element or string, or a list of
          such, that will be used as the PARTITION BY clause of the OVER
          construct.

        * ‘order_by’ – a column element or string, or a list of such,
          that will be used as the ORDER BY clause of the OVER
          construct.

        * ‘range_’ – optional range clause for the window.  This is a
          tuple value which can contain integer values or ‘None’, and
          will render a RANGE BETWEEN PRECEDING / FOLLOWING clause.

          New in version 1.1.

        * ‘rows’ – optional rows clause for the window.  This is a tuple
          value which can contain integer values or None, and will
          render a ROWS BETWEEN PRECEDING / FOLLOWING clause.

          New in version 1.1.

     This function is also available from the func construct
     itself via the FunctionElement.over() method.

     See also
     ........

     See Using Window Functions. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

     See func.

     See within_group().

 -- Function: sqlalchemy.sql.expression.within_group (element,
          *order_by)

     Produce a WithinGroup object against a function.

     Used against so-called “ordered set aggregate” and “hypothetical
     set aggregate” functions, including percentile_cont,
     rank, dense_rank, etc.

     within_group() is usually called using the
     FunctionElement.within_group() method, e.g.:

          from sqlalchemy import within_group
          stmt = select(
              department.c.id,
              func.percentile_cont(0.5).within_group(
                  department.c.salary.desc()
              )
          )

     The above statement would produce SQL similar to ‘SELECT
     department.id, percentile_cont(0.5) WITHIN GROUP (ORDER BY
     department.salary DESC)’.

     Parameters:

        * ‘element’ – a FunctionElement construct, typically
          generated by func.

        * ‘*order_by’ – one or more column elements that will be used as
          the ORDER BY clause of the WITHIN GROUP construct.

     New in version 1.1.

     See also
     ........

     See Special Modifiers WITHIN GROUP, FILTER. - in the
     SQLAlchemy 1.4 / 2.0 Tutorial.

     See func.

     See over().

4.2.1.3 Column Element Class Documentation
..........................................

The classes here are generated using the constructors listed at
Column Element Foundational Constructors and Column Element Modifier Constructors.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See BinaryExpression.Represent an expression that is ‘LEFT <operator> RIGHT’.

See BindParameter.Represent a “bound expression”.

See CacheKey.

See Case.Represent a ‘CASE’ expression.

See Cast.Represent a ‘CAST’ expression.

See ClauseElement.Base class for elements of a programmatically constructed SQL expression.

See ClauseList.Describe a list of clauses, separated by an operator.

See ColumnClause.Represents a column expression from any textual string.

See ColumnCollection.Collection of ColumnElement instances, typically for selectables.

See ColumnElement.Represent a column-oriented SQL expression suitable for usage in the “columns” clause, WHERE
               clause etc.  of a statement.

See ColumnOperators.Defines boolean, comparison, and other operators for ColumnElement expressions.

See DialectKWArgs.Establish the ability for a class to have dialect-specific arguments with defaults and
               constructor validation.

See Extract.Represent a SQL EXTRACT clause, ‘extract(field FROM expr)’.

See False_.Represent the ‘false’ keyword, or equivalent, in a SQL statement.

See FunctionFilter.Represent a function FILTER clause.

See Label.Represents a column label (AS).

See LambdaElement.A SQL construct where the state is stored as an un-invoked lambda.

See Null.Represent the NULL keyword in a SQL statement.

See Operators.Base of comparison and logical operators.

See Over.Represent an OVER clause.

See StatementLambdaElement.Represent a composable SQL statement as a LambdaElement.

See TextClause.Represent a literal SQL text fragment.

See True_.Represent the ‘true’ keyword, or equivalent, in a SQL statement.

See Tuple.Represent a SQL tuple.

See TypeCoerce.Represent a Python-side type-coercion wrapper.

See UnaryExpression.Define a ‘unary’ expression.

See WithinGroup.Represent a WITHIN GROUP (ORDER BY) clause.

See WrapsColumnExpression.Mixin that defines a ColumnElement as a wrapper with special labeling behavior
               for an expression that already has a name.

 -- Class: sqlalchemy.sql.expression.BinaryExpression (left, right,
          operator, type_=None, negate=None, modifiers=None)

     Represent an expression that is ‘LEFT <operator> RIGHT’.

     A BinaryExpression is generated automatically whenever
     two column expressions are used in a Python binary expression:

          >>> from sqlalchemy.sql import column
          >>> column('a') + column('b')
          <sqlalchemy.sql.expression.BinaryExpression object at 0x101029dd0>
          >>> print(column('a') + column('b'))
          a + b

     `Class signature'

     class sqlalchemy.sql.expression.BinaryExpression. (see
     sqlalchemy.sql.expression.ColumnElement)

      -- Method: sqlalchemy.sql.expression.BinaryExpression..
               self_group (against: Optional[Any] = None) ->
               ClauseElement

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

 -- Class: sqlalchemy.sql.expression.BindParameter (key,
          value=symbol('NO_ARG'), type_=None, unique=False,
          required=symbol('NO_ARG'), quote=None, callable_=None,
          expanding=False, isoutparam=False, literal_execute=False,
          _compared_to_operator=None, _compared_to_type=None,
          _is_crud=False)

     Represent a “bound expression”.

     BindParameter is invoked explicitly using the
     bindparam() function, as in:

          from sqlalchemy import bindparam

          stmt = select(users_table).\
                      where(users_table.c.name == bindparam('username'))

     Detailed discussion of how BindParameter is used is at
     bindparam().

     See also
     ........

     See bindparam().

     `Class signature'

     class sqlalchemy.sql.expression.BindParameter.
     (‘sqlalchemy.sql.roles.InElementRole’, see
     sqlalchemy.sql.expression.ColumnElement)

      -- Method: sqlalchemy.sql.expression.BindParameter..
               __init__ (key, value=symbol('NO_ARG'), type_=None,
               unique=False, required=symbol('NO_ARG'), quote=None,
               callable_=None, expanding=False, isoutparam=False,
               literal_execute=False, _compared_to_operator=None,
               _compared_to_type=None, _is_crud=False)

          Construct a new BindParameter object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.sql.expression.bindparam() for a full
          usage and argument description.

      -- Attribute: sqlalchemy.sql.expression.BindParameter..
               effective_value

          Return the value of this bound parameter, taking into account
          if the ‘callable’ parameter was set.

          The ‘callable’ value will be evaluated and returned if
          present, else ‘value’.

 -- Class: sqlalchemy.sql.expression.CacheKey (key, bindparams)

     `Class signature'

     class sqlalchemy.sql.expression.CacheKey.
     (‘sqlalchemy.sql.traversals.CacheKey’)

      -- Method: sqlalchemy.sql.expression.CacheKey..
               to_offline_string (statement_cache, statement,
               parameters)

          Generate an “offline string” form of this CacheKey.

          The “offline string” is basically the string SQL for the
          statement plus a repr of the bound parameter values in series.
          Whereas the CacheKey object is dependent on
          in-memory identities in order to work as a cache key, the
          “offline” version is suitable for a cache that will work for
          other processes as well.

          The given ‘statement_cache’ is a dictionary-like object where
          the string form of the statement itself will be cached.  This
          dictionary should be in a longer lived scope in order to
          reduce the time spent stringifying statements.

 -- Class: sqlalchemy.sql.expression.Case (*whens, **kw)

     Represent a ‘CASE’ expression.

     Case is produced using the case() factory
     function, as in:

          from sqlalchemy import case

          stmt = select(users_table).                    where(
                          case(
                              (users_table.c.name == 'wendy', 'W'),
                              (users_table.c.name == 'jack', 'J'),
                              else_='E'
                          )
                      )

     Details on Case usage is at case().

     See also
     ........

     See case().

     `Class signature'

     class sqlalchemy.sql.expression.Case. (see
     sqlalchemy.sql.expression.ColumnElement)

      -- Method: sqlalchemy.sql.expression.Case..__init__
               (*whens, **kw)

          Construct a new Case object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.sql.expression.case() for a full usage
          and argument description.

 -- Class: sqlalchemy.sql.expression.Cast (expression, type_)

     Represent a ‘CAST’ expression.

     Cast is produced using the cast() factory
     function, as in:

          from sqlalchemy import cast, Numeric

          stmt = select(cast(product_table.c.unit_price, Numeric(10, 4)))

     Details on Cast usage is at cast().

     See also
     ........

     See Data Casts and Type Coercion.

     See cast().

     See type_coerce(). - an alternative to CAST that coerces the
     type on the Python side only, which is often sufficient to generate
     the correct SQL and data coercion.

     `Class signature'

     class sqlalchemy.sql.expression.Cast.
     (‘sqlalchemy.sql.expression.WrapsColumnExpression’, see
     sqlalchemy.sql.expression.ColumnElement)

      -- Method: sqlalchemy.sql.expression.Cast..__init__
               (expression, type_)

          Construct a new Cast object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.sql.expression.cast() for a full usage
          and argument description.

 -- Class: sqlalchemy.sql.expression.ClauseElement

     Base class for elements of a programmatically constructed SQL
     expression.

     `Class signature'

     class sqlalchemy.sql.expression.ClauseElement.
     (‘sqlalchemy.sql.roles.SQLRole’,
     ‘sqlalchemy.sql.annotation.SupportsWrappingAnnotations’,
     ‘sqlalchemy.sql.traversals.MemoizedHasCacheKey’,
     ‘sqlalchemy.sql.traversals.HasCopyInternals’, see
     sqlalchemy.sql.visitors.Traversible)

      -- Method: sqlalchemy.sql.expression.ClauseElement..
               compare (other, **kw)

          Compare this ClauseElement to the given
          ClauseElement.

          Subclasses should override the default behavior, which is a
          straight identity comparison.

          **kw are arguments consumed by subclass ‘compare()’ methods
          and may be used to modify the criteria for comparison (see
          ColumnElement).

      -- Method: sqlalchemy.sql.expression.ClauseElement..
               compile (bind=None, dialect=None, **kw)

          Compile this SQL expression.

          The return value is a Compiled object.  Calling
          ‘str()’ or ‘unicode()’ on the returned value will yield a
          string representation of the result.  The Compiled
          object also can return a dictionary of bind parameter names
          and values using the ‘params’ accessor.

          Parameters:

             * ‘bind’ – An ‘Engine’ or ‘Connection’ from which a
               ‘Compiled’ will be acquired.  This argument takes
               precedence over this ClauseElement.’s bound
               engine, if any.

             * ‘column_keys’ – Used for INSERT and UPDATE statements, a
               list of column names which should be present in the
               VALUES clause of the compiled statement.  If ‘None’, all
               columns from the target table object are rendered.

             * ‘dialect’ – A ‘Dialect’ instance from which a ‘Compiled’
               will be acquired.  This argument takes precedence over
               the ‘bind’ argument as well as this ClauseElement.
               ‘s bound engine, if any.

             * ‘compile_kwargs’ – optional dictionary of additional
               parameters that will be passed through to the compiler
               within all “visit” methods.  This allows any custom flag
               to be passed through to a custom compilation construct,
               for example.  It is also used for the case of passing the
               ‘literal_binds’ flag through:

                    from sqlalchemy.sql import table, column, select

                    t = table('t', column('x'))

                    s = select(t).where(t.c.x == 5)

                    print(s.compile(compile_kwargs={"literal_binds": True}))

               New in version 0.9.0.

          See also
          ........

          See How do I render SQL expressions as strings, possibly with bound parameters inlined?.

      -- Method: sqlalchemy.sql.expression.ClauseElement..
               get_children (omit_attrs=(), **kw)

          Return immediate child Traversible elements of
          this Traversible.

          This is used for visit traversal.

          **kw may contain flags that change the collection that is
          returned, for example to return a subset of items in order to
          cut down on larger traversals, or to return child items from a
          different context (such as schema-level collections instead of
          clause-level).

      -- Class: memoized_attribute (fget, doc=None)

          A read-only @property that is only evaluated once.

      -- Method: sqlalchemy.sql.expression.ClauseElement..
               classmethod memoized_instancemethod (fn)

          `inherited from the' ‘HasMemoized.memoized_instancemethod()’
          `method of' ‘HasMemoized’

          Decorate a method memoize its return value.

      -- Method: sqlalchemy.sql.expression.ClauseElement..
               params (*optionaldict, **kwargs)

          Return a copy with bindparam() elements replaced.

          Returns a copy of this ClauseElement with bindparam()
          elements replaced with values taken from the given
          dictionary:

               >>> clause = column('x') + bindparam('foo')
               >>> print(clause.compile().params)
               {'foo':None}
               >>> print(clause.params({'foo':7}).compile().params)
               {'foo':7}

      -- Method: sqlalchemy.sql.expression.ClauseElement..
               self_group (against: Optional[Any] = None) ->
               ClauseElement

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

      -- Method: sqlalchemy.sql.expression.ClauseElement..
               unique_params (*optionaldict, **kwargs)

          Return a copy with bindparam() elements replaced.

          Same functionality as ClauseElement.params(),
          except adds ‘unique=True’ to affected bind parameters so that
          multiple statements can be used.

 -- Class: sqlalchemy.sql.expression.ClauseList (*clauses, **kwargs)

     Describe a list of clauses, separated by an operator.

     By default, is comma-separated, such as a column listing.

     `Class signature'

     class sqlalchemy.sql.expression.ClauseList.
     (‘sqlalchemy.sql.roles.InElementRole’,
     ‘sqlalchemy.sql.roles.OrderByRole’,
     ‘sqlalchemy.sql.roles.ColumnsClauseRole’,
     ‘sqlalchemy.sql.roles.DMLColumnRole’, see
     sqlalchemy.sql.expression.ClauseElement)

      -- Method: sqlalchemy.sql.expression.ClauseList..
               self_group (against: Optional[Any] = None) ->
               ClauseElement

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

 -- Class: sqlalchemy.sql.expression.ColumnClause (text, type_=None,
          is_literal=False, _selectable=None)

     Represents a column expression from any textual string.

     The ColumnClause, a lightweight analogue to the
     Column class, is typically invoked using the column()
     function, as in:

          from sqlalchemy import column

          id, name = column("id"), column("name")
          stmt = select(id, name).select_from("user")

     The above statement would produce SQL like:

          SELECT id, name FROM user

     ColumnClause is the immediate superclass of the
     schema-specific Column object.  While the Column
     class has all the same capabilities as ColumnClause,
     the ColumnClause class is usable by itself in those
     cases where behavioral requirements are limited to simple SQL
     expression generation.  The object has none of the associations
     with schema-level metadata or with execution-time behavior that
     Column does, so in that sense is a “lightweight” version
     of Column.

     Full details on ColumnClause usage is at
     column().

     See also
     ........

     See column().

     See Column.

     `Class signature'

     class sqlalchemy.sql.expression.ColumnClause.
     (‘sqlalchemy.sql.roles.DDLReferredColumnRole’,
     ‘sqlalchemy.sql.roles.LabeledColumnExprRole’,
     ‘sqlalchemy.sql.roles.StrAsPlainColumnRole’,
     ‘sqlalchemy.sql.expression.Immutable’,
     ‘sqlalchemy.sql.expression.NamedColumn’)

      -- Method: sqlalchemy.sql.expression.ColumnClause..
               __init__ (text, type_=None, is_literal=False,
               _selectable=None)

          Construct a new ColumnClause object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.sql.expression.column() for a full
          usage and argument description.

      -- Method: sqlalchemy.sql.expression.ColumnClause..
               get_children (column_tables=False, **kw)

          Return immediate child Traversible elements of
          this Traversible.

          This is used for visit traversal.

          **kw may contain flags that change the collection that is
          returned, for example to return a subset of items in order to
          cut down on larger traversals, or to return child items from a
          different context (such as schema-level collections instead of
          clause-level).

 -- Class: sqlalchemy.sql.expression.ColumnCollection (columns=None)

     Collection of ColumnElement instances, typically for
     selectables.

     The ColumnCollection has both mapping- and sequence-
     like behaviors.  A ColumnCollection usually stores
     Column objects, which are then accessible both via
     mapping style access as well as attribute access style.  The name
     for which a Column would be present is normally that of
     the Column.key parameter, however depending on the
     context, it may be stored under a special label name:

          >>> from sqlalchemy import Column, Integer
          >>> from sqlalchemy.sql import ColumnCollection
          >>> x, y = Column('x', Integer), Column('y', Integer)
          >>> cc = ColumnCollection(columns=[(x.name, x), (y.name, y)])
          >>> cc.x
          Column('x', Integer(), table=None)
          >>> cc.y
          Column('y', Integer(), table=None)
          >>> cc['x']
          Column('x', Integer(), table=None)
          >>> cc['y']

     ColumnCollection also indexes the columns in order and
     allows them to be accessible by their integer position:

          >>> cc[0]
          Column('x', Integer(), table=None)
          >>> cc[1]
          Column('y', Integer(), table=None)

     New in version 1.4: ColumnCollection allows
     integer-based index access to the collection.

     Iterating the collection yields the column expressions in order:

          >>> list(cc)
          [Column('x', Integer(), table=None),
           Column('y', Integer(), table=None)]

     The base ColumnCollection object can store duplicates,
     which can mean either two columns with the same key, in which case
     the column returned by key access is `arbitrary':

          >>> x1, x2 = Column('x', Integer), Column('x', Integer)
          >>> cc = ColumnCollection(columns=[(x1.name, x1), (x2.name, x2)])
          >>> list(cc)
          [Column('x', Integer(), table=None),
           Column('x', Integer(), table=None)]
          >>> cc['x'] is x1
          False
          >>> cc['x'] is x2
          True

     Or it can also mean the same column multiple times.  These cases
     are supported as ColumnCollection is used to represent
     the columns in a SELECT statement which may include duplicates.

     A special subclass ‘DedupeColumnCollection’ exists which instead
     maintains SQLAlchemy’s older behavior of not allowing duplicates;
     this collection is used for schema level objects like Table
     and PrimaryKeyConstraint where this deduping is
     helpful.  The ‘DedupeColumnCollection’ class also has additional
     mutation methods as the schema constructs have more use cases that
     require removal and replacement of columns.

     Changed in version 1.4: ColumnCollection now stores
     duplicate column keys as well as the same column in multiple
     positions.  The ‘DedupeColumnCollection’ class is added to maintain
     the former behavior in those cases where deduplication as well as
     additional replace/remove operations are needed.

      -- Method: sqlalchemy.sql.expression.ColumnCollection..
               contains_column (col)

          Checks if a column object exists in this collection

      -- Method: sqlalchemy.sql.expression.ColumnCollection..
               corresponding_column (column, require_embedded=False)

          Given a ColumnElement, return the exported
          ColumnElement object from this ColumnCollection
          which corresponds to that original ColumnElement
          via a common ancestor column.

          Parameters:

             * ‘column’ – the target ColumnElement to be
               matched.

             * ‘require_embedded’ – only return corresponding columns
               for the given ColumnElement, if the given
               ColumnElement is actually present within a
               sub-element of this Selectable.  Normally the
               column will match if it merely shares a common ancestor
               with one of the exported columns of this
               Selectable.

          See also
          ........

          See Selectable.corresponding_column(). - invokes this
          method against the collection returned by
          Selectable.exported_columns.

          Changed in version 1.4: the implementation for
          ‘corresponding_column’ was moved onto the
          ColumnCollection itself.

 -- Class: sqlalchemy.sql.expression.ColumnElement

     Represent a column-oriented SQL expression suitable for usage in
     the “columns” clause, WHERE clause etc.  of a statement.

     While the most familiar kind of ColumnElement is the
     Column object, see ColumnElement serves as the
     basis for any unit that may be present in a SQL expression,
     including the expressions themselves, SQL functions, bound
     parameters, literal expressions, keywords such as ‘NULL’, etc.
     see ColumnElement is the ultimate base class for all such
     elements.

     A wide variety of SQLAlchemy Core functions work at the SQL
     expression level, and are intended to accept instances of
     ColumnElement as arguments.  These functions will typically
     document that they accept a “SQL expression” as an argument.  What
     this means in terms of SQLAlchemy usually refers to an input which
     is either already in the form of a ColumnElement
     object, or a value which can be `coerced' into one.  The coercion
     rules followed by most, but not all, SQLAlchemy Core functions with
     regards to SQL expressions are as follows:

             * a literal Python value, such as a string, integer or
               floating point value, boolean, datetime, ‘Decimal’
               object, or virtually any other Python object, will be
               coerced into a “literal bound value”.  This generally
               means that a bindparam() will be produced
               featuring the given value embedded into the construct;
               the resulting BindParameter object is an
               instance of ColumnElement.  The Python value
               will ultimately be sent to the DBAPI at execution time as
               a parameterized argument to the ‘execute()’ or
               ‘executemany()’ methods, after SQLAlchemy type-specific
               converters (e.g.  those provided by any associated
               TypeEngine objects) are applied to the value.

             * any special object value, typically ORM-level constructs,
               which feature an accessor called ‘__clause_element__()’.
               The Core expression system looks for this method when an
               object of otherwise unknown type is passed to a function
               that is looking to coerce the argument into a
               ColumnElement and sometimes a SelectBase
               expression.  It is used within the ORM to convert
               from ORM-specific objects like mapped classes and mapped
               attributes into Core expression objects.

             * The Python ‘None’ value is typically interpreted as
               ‘NULL’, which in SQLAlchemy Core produces an instance of
               null().

     A ColumnElement provides the ability to generate new
     ColumnElement objects using Python expressions.  This
     means that Python operators such as ‘==’, ‘!=’ and ‘<’ are
     overloaded to mimic SQL operations, and allow the instantiation of
     further ColumnElement instances which are composed from
     other, more fundamental ColumnElement objects.  For
     example, two ColumnClause objects can be added together
     with the addition operator ‘+’ to produce a BinaryExpression.
     Both ColumnClause and BinaryExpression
     are subclasses of ColumnElement:

          >>> from sqlalchemy.sql import column
          >>> column('a') + column('b')
          <sqlalchemy.sql.expression.BinaryExpression object at 0x101029dd0>
          >>> print(column('a') + column('b'))
          a + b

     See also
     ........

     See Column.

     See column().

     `Class signature'

     class sqlalchemy.sql.expression.ColumnElement.
     (‘sqlalchemy.sql.roles.ColumnArgumentOrKeyRole’,
     ‘sqlalchemy.sql.roles.StatementOptionRole’,
     ‘sqlalchemy.sql.roles.WhereHavingRole’,
     ‘sqlalchemy.sql.roles.BinaryElementRole’,
     ‘sqlalchemy.sql.roles.OrderByRole’,
     ‘sqlalchemy.sql.roles.ColumnsClauseRole’,
     ‘sqlalchemy.sql.roles.LimitOffsetRole’,
     ‘sqlalchemy.sql.roles.DMLColumnRole’,
     ‘sqlalchemy.sql.roles.DDLConstraintColumnRole’,
     ‘sqlalchemy.sql.roles.DDLExpressionRole’, see
     sqlalchemy.sql.expression.ColumnOperators,
     sqlalchemy.sql.expression.ClauseElement)

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               __eq__ (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__eq__’ `method of'
          ColumnOperators.

          Implement the ‘==’ operator.

          In a column context, produces the clause ‘a = b’.  If the
          target is ‘None’, produces ‘a IS NULL’.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               __le__ (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__le__’ `method of'
          ColumnOperators.

          Implement the ‘<=’ operator.

          In a column context, produces the clause ‘a <= b’.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               __lt__ (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__lt__’ `method of'
          ColumnOperators.

          Implement the ‘<’ operator.

          In a column context, produces the clause ‘a < b’.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               __ne__ (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__ne__’ `method of'
          ColumnOperators.

          Implement the ‘!=’ operator.

          In a column context, produces the clause ‘a != b’.  If the
          target is ‘None’, produces ‘a IS NOT NULL’.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               all_ ()

          `inherited from the' ColumnOperators.all_().
          `method of' ColumnOperators.

          Produce a all_() clause against the parent object.

          This operator is only appropriate against a scalar subquery
          object, or for some backends an column expression that is
          against the ARRAY type, e.g.:

               # postgresql '5 = ALL (somearray)'
               expr = 5 == mytable.c.somearray.all_()

               # mysql '5 = ALL (SELECT value FROM table)'
               expr = 5 == select(table.c.value).scalar_subquery().all_()

          See also
          ........

          See all_(). - standalone version

          See any_(). - ANY operator

          New in version 1.1.

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               allows_lambda = True

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               anon_key_label

          Provides a constant ‘anonymous key label’ for this
          ColumnElement.

          Compare to ‘anon_label’, except that the “key” of the column,
          if available, is used to generate the label.

          This is used when a deduplicating key is placed into the
          columns collection of a selectable.

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               anon_label

          Provides a constant ‘anonymous label’ for this ColumnElement.

          This is a label() expression which will be named at compile
          time.  The same label() is returned each time ‘anon_label’ is
          called so that expressions can reference ‘anon_label’ multiple
          times, producing the same label name at compile time.

          The compiler uses this function automatically at compile time
          for expressions that are known to be ‘unnamed’ like binary
          expressions and function calls.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               any_ ()

          `inherited from the' ColumnOperators.any_().
          `method of' ColumnOperators.

          Produce a any_() clause against the parent object.

          This operator is only appropriate against a scalar subquery
          object, or for some backends an column expression that is
          against the ARRAY type, e.g.:

               # postgresql '5 = ANY (somearray)'
               expr = 5 == mytable.c.somearray.any_()

               # mysql '5 = ANY (SELECT value FROM table)'
               expr = 5 == select(table.c.value).scalar_subquery().any_()

          See also
          ........

          See any_(). - standalone version

          See all_(). - ALL operator

          New in version 1.1.

      -- Method: sqlalchemy.sql.expression.ColumnElement..asc
               ()

          `inherited from the' ColumnOperators.asc(). `method
          of' ColumnOperators.

          Produce a asc() clause against the parent object.

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               base_columns

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               between (cleft, cright, symmetric=False)

          `inherited from the' ColumnOperators.between().
          `method of' ColumnOperators.

          Produce a between() clause against the parent
          object, given the lower and upper range.

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               bind = None

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               bool_op (opstring, precedence=0)

          `inherited from the' Operators.bool_op(). `method
          of' Operators.

          Return a custom boolean operator.

          This method is shorthand for calling Operators.op()
          and passing the Operators.op.is_comparison
          flag with True.

          See also
          ........

          See Operators.op().

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               cast (type_)

          Produce a type cast, i.e.  ‘CAST(<expression> AS <type>)’.

          This is a shortcut to the cast() function.

          See also
          ........

          See Data Casts and Type Coercion.

          See cast().

          See type_coerce().

          New in version 1.0.7.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               collate (collation)

          `inherited from the' ColumnOperators.collate().
          `method of' ColumnOperators.

          Produce a collate() clause against the parent
          object, given the collation string.

          See also
          ........

          See collate().

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               comparator

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               compare (other, **kw)

          `inherited from the' ClauseElement.compare().
          `method of' ClauseElement.

          Compare this ClauseElement to the given
          ClauseElement.

          Subclasses should override the default behavior, which is a
          straight identity comparison.

          **kw are arguments consumed by subclass ‘compare()’ methods
          and may be used to modify the criteria for comparison (see
          ColumnElement).

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               compile (bind=None, dialect=None, **kw)

          `inherited from the' ClauseElement.compile().
          `method of' ClauseElement.

          Compile this SQL expression.

          The return value is a Compiled object.  Calling
          ‘str()’ or ‘unicode()’ on the returned value will yield a
          string representation of the result.  The Compiled
          object also can return a dictionary of bind parameter names
          and values using the ‘params’ accessor.

          Parameters:

             * ‘bind’ – An ‘Engine’ or ‘Connection’ from which a
               ‘Compiled’ will be acquired.  This argument takes
               precedence over this ClauseElement.’s bound
               engine, if any.

             * ‘column_keys’ – Used for INSERT and UPDATE statements, a
               list of column names which should be present in the
               VALUES clause of the compiled statement.  If ‘None’, all
               columns from the target table object are rendered.

             * ‘dialect’ – A ‘Dialect’ instance from which a ‘Compiled’
               will be acquired.  This argument takes precedence over
               the ‘bind’ argument as well as this ClauseElement.
               ‘s bound engine, if any.

             * ‘compile_kwargs’ – optional dictionary of additional
               parameters that will be passed through to the compiler
               within all “visit” methods.  This allows any custom flag
               to be passed through to a custom compilation construct,
               for example.  It is also used for the case of passing the
               ‘literal_binds’ flag through:

                    from sqlalchemy.sql import table, column, select

                    t = table('t', column('x'))

                    s = select(t).where(t.c.x == 5)

                    print(s.compile(compile_kwargs={"literal_binds": True}))

               New in version 0.9.0.

          See also
          ........

          See How do I render SQL expressions as strings, possibly with bound parameters inlined?.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               concat (other)

          `inherited from the' ColumnOperators.concat().
          `method of' ColumnOperators.

          Implement the ‘concat’ operator.

          In a column context, produces the clause ‘a || b’, or uses the
          ‘concat()’ operator on MySQL.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               contains (other, **kwargs)

          `inherited from the' ColumnOperators.contains().
          `method of' ColumnOperators.

          Implement the ‘contains’ operator.

          Produces a LIKE expression that tests against a match for the
          middle of a string value:

               column LIKE '%' || <other> || '%'

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.contains("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.contains.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.contains.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.contains.autoescape flag is set to
               True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.contains("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE '%' || :param || '%' ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.contains("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE '%' || :param || '%' ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.contains.autoescape:

                    somecolumn.contains("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.startswith().

          See ColumnOperators.endswith().

          See ColumnOperators.like().

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               desc ()

          `inherited from the' ColumnOperators.desc().
          `method of' ColumnOperators.

          Produce a desc() clause against the parent object.

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               description = None

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               distinct ()

          `inherited from the' ColumnOperators.distinct().
          `method of' ColumnOperators.

          Produce a distinct() clause against the parent
          object.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               endswith (other, **kwargs)

          `inherited from the' ColumnOperators.endswith().
          `method of' ColumnOperators.

          Implement the ‘endswith’ operator.

          Produces a LIKE expression that tests against a match for the
          end of a string value:

               column LIKE '%' || <other>

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.endswith("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.endswith.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.endswith.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.endswith.autoescape flag is set to
               True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.endswith("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE '%' || :param ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.endswith("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE '%' || :param ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.endswith.autoescape:

                    somecolumn.endswith("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.startswith().

          See ColumnOperators.contains().

          See ColumnOperators.like().

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               expression

          Return a column expression.

          Part of the inspection interface; returns self.

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               foreign_keys = []

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               get_children (omit_attrs=(), **kw)

          `inherited from the' ClauseElement.get_children().
          `method of' ClauseElement.

          Return immediate child Traversible elements of
          this Traversible.

          This is used for visit traversal.

          **kw may contain flags that change the collection that is
          returned, for example to return a subset of items in order to
          cut down on larger traversals, or to return child items from a
          different context (such as schema-level collections instead of
          clause-level).

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               ilike (other, escape=None)

          `inherited from the' ColumnOperators.ilike().
          `method of' ColumnOperators.

          Implement the ‘ilike’ operator, e.g.  case insensitive LIKE.

          In a column context, produces an expression either of the
          form:

               lower(a) LIKE lower(other)

          Or on backends that support the ILIKE operator:

               a ILIKE other

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.ilike("%foobar%"))

          Parameters:

             * ‘other’ – expression to be compared

             * ‘escape’ – optional escape character, renders the
               ‘ESCAPE’ keyword, e.g.:

                    somecolumn.ilike("foo/%bar", escape="/")

          See also
          ........

          See ColumnOperators.like().

      -- Method: sqlalchemy.sql.expression.ColumnElement..in_
               (other)

          `inherited from the' ColumnOperators.in_(). `method
          of' ColumnOperators.

          Implement the ‘in’ operator.

          In a column context, produces the clause ‘column IN <other>’.

          The given parameter ‘other’ may be:

             * A list of literal values, e.g.:

                    stmt.where(column.in_([1, 2, 3]))

               In this calling form, the list of items is converted to a
               set of bound parameters the same length as the list
               given:

                    WHERE COL IN (?, ?, ?)

             * A list of tuples may be provided if the comparison is
               against a tuple_() containing multiple
               expressions:

                    from sqlalchemy import tuple_
                    stmt.where(tuple_(col1, col2).in_([(1, 10), (2, 20), (3, 30)]))

             * An empty list, e.g.:

                    stmt.where(column.in_([]))

               In this calling form, the expression renders an “empty
               set” expression.  These expressions are tailored to
               individual backends and are generally trying to get an
               empty SELECT statement as a subquery.  Such as on SQLite,
               the expression is:

                    WHERE col IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)

               Changed in version 1.4: empty IN expressions now use an
               execution-time generated SELECT subquery in all cases.

             * A bound parameter, e.g.  see bindparam(), may be
               used if it includes the bindparam.expanding
               flag:

                    stmt.where(column.in_(bindparam('value', expanding=True)))

               In this calling form, the expression renders a special
               non-SQL placeholder expression that looks like:

                    WHERE COL IN ([EXPANDING_value])

               This placeholder expression is intercepted at statement
               execution time to be converted into the variable number
               of bound parameter form illustrated earlier.  If the
               statement were executed as:

                    connection.execute(stmt, {"value": [1, 2, 3]})

               The database would be passed a bound parameter for each
               value:

                    WHERE COL IN (?, ?, ?)

               New in version 1.2: added “expanding” bound parameters

               If an empty list is passed, a special “empty list”
               expression, which is specific to the database in use, is
               rendered.  On SQLite this would be:

                    WHERE COL IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)

               New in version 1.3: “expanding” bound parameters now
               support empty lists

             * a select() construct, which is usually a
               correlated scalar select:

                    stmt.where(
                        column.in_(
                            select(othertable.c.y).
                            where(table.c.x == othertable.c.x)
                        )
                    )

               In this calling form, see ColumnOperators.in_()
               renders as given:

                    WHERE COL IN (SELECT othertable.y
                    FROM othertable WHERE othertable.x = table.x)

          Parameters: ‘other’ – a list of literals, a select()
          construct, or a bindparam() construct that
          includes the bindparam.expanding flag set to True.

      -- Method: sqlalchemy.sql.expression.ColumnElement..is_
               (other)

          `inherited from the' ColumnOperators.is_(). `method
          of' ColumnOperators.

          Implement the ‘IS’ operator.

          Normally, ‘IS’ is generated automatically when comparing to a
          value of ‘None’, which resolves to ‘NULL’.  However, explicit
          usage of ‘IS’ may be desirable if comparing to boolean values
          on certain platforms.

          See also
          ........

          See ColumnOperators.is_not().

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               is_clause_element = True

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               is_distinct_from (other)

          `inherited from the' ColumnOperators.is_distinct_from().
          `method of' ColumnOperators.

          Implement the ‘IS DISTINCT FROM’ operator.

          Renders “a IS DISTINCT FROM b” on most platforms; on some such
          as SQLite may render “a IS NOT b”.

          New in version 1.1.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               is_not (other)

          `inherited from the' ColumnOperators.is_not().
          `method of' ColumnOperators.

          Implement the ‘IS NOT’ operator.

          Normally, ‘IS NOT’ is generated automatically when comparing
          to a value of ‘None’, which resolves to ‘NULL’.  However,
          explicit usage of ‘IS NOT’ may be desirable if comparing to
          boolean values on certain platforms.

          Changed in version 1.4: The ‘is_not()’ operator is renamed
          from ‘isnot()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.is_().

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               is_not_distinct_from (other)

          `inherited from the'
          ColumnOperators.is_not_distinct_from(). `method of'
          ColumnOperators.

          Implement the ‘IS NOT DISTINCT FROM’ operator.

          Renders “a IS NOT DISTINCT FROM b” on most platforms; on some
          such as SQLite may render “a IS b”.

          Changed in version 1.4: The ‘is_not_distinct_from()’ operator
          is renamed from ‘isnot_distinct_from()’ in previous releases.
          The previous name remains available for backwards
          compatibility.

          New in version 1.1.

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               is_selectable = False

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               isnot (other)

          `inherited from the' ColumnOperators.isnot().
          `method of' ColumnOperators.

          Implement the ‘IS NOT’ operator.

          Normally, ‘IS NOT’ is generated automatically when comparing
          to a value of ‘None’, which resolves to ‘NULL’.  However,
          explicit usage of ‘IS NOT’ may be desirable if comparing to
          boolean values on certain platforms.

          Changed in version 1.4: The ‘is_not()’ operator is renamed
          from ‘isnot()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.is_().

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               isnot_distinct_from (other)

          `inherited from the'
          ColumnOperators.isnot_distinct_from(). `method of'
          ColumnOperators.

          Implement the ‘IS NOT DISTINCT FROM’ operator.

          Renders “a IS NOT DISTINCT FROM b” on most platforms; on some
          such as SQLite may render “a IS b”.

          Changed in version 1.4: The ‘is_not_distinct_from()’ operator
          is renamed from ‘isnot_distinct_from()’ in previous releases.
          The previous name remains available for backwards
          compatibility.

          New in version 1.1.

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               key = None

          The ‘key’ that in some circumstances refers to this object in
          a Python namespace.

          This typically refers to the “key” of the column as present in
          the ‘.c’ collection of a selectable, e.g.
          ‘sometable.c["somekey"]’ would return a Column with
          a ‘.key’ of “somekey”.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               label (name)

          Produce a column label, i.e.  ‘<columnname> AS <name>’.

          This is a shortcut to the label() function.

          If ‘name’ is ‘None’, an anonymous label name will be
          generated.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               like (other, escape=None)

          `inherited from the' ColumnOperators.like().
          `method of' ColumnOperators.

          Implement the ‘like’ operator.

          In a column context, produces the expression:

               a LIKE other

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.like("%foobar%"))

          Parameters:

             * ‘other’ – expression to be compared

             * ‘escape’ – optional escape character, renders the
               ‘ESCAPE’ keyword, e.g.:

                    somecolumn.like("foo/%bar", escape="/")

          See also
          ........

          See ColumnOperators.ilike().

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               match (other, **kwargs)

          `inherited from the' ColumnOperators.match().
          `method of' ColumnOperators.

          Implements a database-specific ‘match’ operator.

          ColumnOperators.match() attempts to resolve to a
          MATCH-like function or operator provided by the backend.
          Examples include:

             * PostgreSQL - renders ‘x @@ to_tsquery(y)’

             * MySQL - renders ‘MATCH (x) AGAINST (y IN BOOLEAN MODE)’

             * Oracle - renders ‘CONTAINS(x, y)’

             * other backends may provide special implementations.

             * Backends without any special implementation will emit the
               operator as “MATCH”.  This is compatible with SQLite, for
               example.

      -- Class: memoized_attribute (fget, doc=None)

          A read-only @property that is only evaluated once.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               classmethod memoized_instancemethod (fn)

          `inherited from the' ‘HasMemoized.memoized_instancemethod()’
          `method of' ‘HasMemoized’

          Decorate a method memoize its return value.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               not_ilike (other, escape=None)

          `inherited from the' ColumnOperators.not_ilike().
          `method of' ColumnOperators.

          implement the ‘NOT ILIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.ilike(), i.e.  ‘~x.ilike(y)’.

          Changed in version 1.4: The ‘not_ilike()’ operator is renamed
          from ‘notilike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.ilike().

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               not_in (other)

          `inherited from the' ColumnOperators.not_in().
          `method of' ColumnOperators.

          implement the ‘NOT IN’ operator.

          This is equivalent to using negation with
          ColumnOperators.in_(), i.e.  ‘~x.in_(y)’.

          In the case that ‘other’ is an empty sequence, the compiler
          produces an “empty not in” expression.  This defaults to the
          expression “1 = 1” to produce true in all cases.  The
          create_engine.empty_in_strategy may be used to alter
          this behavior.

          Changed in version 1.4: The ‘not_in()’ operator is renamed
          from ‘notin_()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          Changed in version 1.2: The ColumnOperators.in_()
          and ColumnOperators.not_in() operators now produce
          a “static” expression for an empty IN sequence by default.

          See also
          ........

          See ColumnOperators.in_().

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               not_like (other, escape=None)

          `inherited from the' ColumnOperators.not_like().
          `method of' ColumnOperators.

          implement the ‘NOT LIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.like(), i.e.  ‘~x.like(y)’.

          Changed in version 1.4: The ‘not_like()’ operator is renamed
          from ‘notlike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.like().

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               notilike (other, escape=None)

          `inherited from the' ColumnOperators.notilike().
          `method of' ColumnOperators.

          implement the ‘NOT ILIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.ilike(), i.e.  ‘~x.ilike(y)’.

          Changed in version 1.4: The ‘not_ilike()’ operator is renamed
          from ‘notilike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.ilike().

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               notin_ (other)

          `inherited from the' ColumnOperators.notin_().
          `method of' ColumnOperators.

          implement the ‘NOT IN’ operator.

          This is equivalent to using negation with
          ColumnOperators.in_(), i.e.  ‘~x.in_(y)’.

          In the case that ‘other’ is an empty sequence, the compiler
          produces an “empty not in” expression.  This defaults to the
          expression “1 = 1” to produce true in all cases.  The
          create_engine.empty_in_strategy may be used to alter
          this behavior.

          Changed in version 1.4: The ‘not_in()’ operator is renamed
          from ‘notin_()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          Changed in version 1.2: The ColumnOperators.in_()
          and ColumnOperators.not_in() operators now produce
          a “static” expression for an empty IN sequence by default.

          See also
          ........

          See ColumnOperators.in_().

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               notlike (other, escape=None)

          `inherited from the' ColumnOperators.notlike().
          `method of' ColumnOperators.

          implement the ‘NOT LIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.like(), i.e.  ‘~x.like(y)’.

          Changed in version 1.4: The ‘not_like()’ operator is renamed
          from ‘notlike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.like().

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               nulls_first ()

          `inherited from the' ColumnOperators.nulls_first().
          `method of' ColumnOperators.

          Produce a nulls_first() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_first()’ operator is
          renamed from ‘nullsfirst()’ in previous releases.  The
          previous name remains available for backwards compatibility.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               nulls_last ()

          `inherited from the' ColumnOperators.nulls_last().
          `method of' ColumnOperators.

          Produce a nulls_last() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_last()’ operator is renamed
          from ‘nullslast()’ in previous releases.  The previous name
          remains available for backwards compatibility.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               nullsfirst ()

          `inherited from the' ColumnOperators.nullsfirst().
          `method of' ColumnOperators.

          Produce a nulls_first() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_first()’ operator is
          renamed from ‘nullsfirst()’ in previous releases.  The
          previous name remains available for backwards compatibility.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               nullslast ()

          `inherited from the' ColumnOperators.nullslast().
          `method of' ColumnOperators.

          Produce a nulls_last() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_last()’ operator is renamed
          from ‘nullslast()’ in previous releases.  The previous name
          remains available for backwards compatibility.

      -- Method: sqlalchemy.sql.expression.ColumnElement..op
               (opstring, precedence=0, is_comparison=False,
               return_type=None)

          `inherited from the' Operators.op(). `method of'
          Operators.

          Produce a generic operator function.

          e.g.:

               somecolumn.op("*")(5)

          produces:

               somecolumn * 5

          This function can also be used to make bitwise operators
          explicit.  For example:

               somecolumn.op('&')(0xff)

          is a bitwise AND of the value in ‘somecolumn’.

          Parameters:

             * ‘operator’ – a string which will be output as the infix
               operator between this element and the expression passed
               to the generated function.

             * ‘precedence’ – precedence to apply to the operator, when
               parenthesizing expressions.  A lower number will cause
               the expression to be parenthesized when applied against
               another operator with higher precedence.  The default
               value of ‘0’ is lower than all operators except for the
               comma (‘,’) and ‘AS’ operators.  A value of 100 will be
               higher or equal to all operators, and -100 will be lower
               than or equal to all operators.

             * ‘is_comparison’ – if True, the operator will be
               considered as a “comparison” operator, that is which
               evaluates to a boolean true/false value, like ‘==’, ‘>’,
               etc.  This flag should be set so that ORM relationships
               can establish that the operator is a comparison operator
               when used in a custom join condition.

               New in version 0.9.2: - added the
               Operators.op.is_comparison flag.

             * ‘return_type’ – a TypeEngine class or object
               that will force the return type of an expression produced
               by this operator to be of that type.  By default,
               operators that specify Operators.op.is_comparison
               will resolve to Boolean, and those that
               do not will be of the same type as the left-hand operand.

          See also
          ........

          See Redefining and Creating New Operators.

          See Using custom operators in join conditions.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               operate (op, *other, **kwargs)

          Operate on an argument.

          This is the lowest level of operation, raises
          ‘NotImplementedError’ by default.

          Overriding this on a subclass can allow common behavior to be
          applied to all operations.  For example, overriding
          ColumnOperators to apply ‘func.lower()’ to the left and
          right side:

               class MyComparator(ColumnOperators):
                   def operate(self, op, other):
                       return op(func.lower(self), func.lower(other))

          Parameters:

             * ‘op’ – Operator callable.

             * ‘*other’ – the ‘other’ side of the operation.  Will be a
               single scalar for most operations.

             * ‘**kwargs’ – modifiers.  These may be passed by special
               operators such as ColumnOperators.contains().

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               params (*optionaldict, **kwargs)

          `inherited from the' ClauseElement.params().
          `method of' ClauseElement.

          Return a copy with bindparam() elements replaced.

          Returns a copy of this ClauseElement with bindparam()
          elements replaced with values taken from the given
          dictionary:

               >>> clause = column('x') + bindparam('foo')
               >>> print(clause.compile().params)
               {'foo':None}
               >>> print(clause.params({'foo':7}).compile().params)
               {'foo':7}

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               primary_key = False

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               proxy_set

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               regexp_match (pattern, flags=None)

          `inherited from the' ColumnOperators.regexp_match().
          `method of' ColumnOperators.

          Implements a database-specific ‘regexp match’ operator.

          E.g.:

               stmt = select(table.c.some_column).where(
                   table.c.some_column.regexp_match('^(b|c)')
               )

          ColumnOperators.regexp_match() attempts to resolve
          to a REGEXP-like function or operator provided by the backend,
          however the specific regular expression syntax and flags
          available are `not backend agnostic'.

          Examples include:

             * PostgreSQL - renders ‘x ~ y’ or ‘x !~ y’ when negated.

             * Oracle - renders ‘REGEXP_LIKE(x, y)’

             * SQLite - uses SQLite’s ‘REGEXP’ placeholder operator and
               calls into the Python ‘re.match()’ builtin.

             * other backends may provide special implementations.

             * Backends without any special implementation will emit the
               operator as “REGEXP” or “NOT REGEXP”.  This is compatible
               with SQLite and MySQL, for example.

          Regular expression support is currently implemented for
          Oracle, PostgreSQL, MySQL and MariaDB. Partial support is
          available for SQLite.  Support among third-party dialects may
          vary.

          Parameters:

             * ‘pattern’ – The regular expression pattern string or
               column clause.

             * ‘flags’ – Any regular expression string flags to apply.
               Flags tend to be backend specific.  It can be a string or
               a column clause.  Some backends, like PostgreSQL and
               MariaDB, may alternatively specify the flags as part of
               the pattern.  When using the ignore case flag ‘i’ in
               PostgreSQL, the ignore case regexp match operator ‘~*’ or
               ‘!~*’ will be used.

          New in version 1.4.

          See also
          ........

          See ColumnOperators.regexp_replace().

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               regexp_replace (pattern, replacement, flags=None)

          `inherited from the' ColumnOperators.regexp_replace().
          `method of' ColumnOperators.

          Implements a database-specific ‘regexp replace’ operator.

          E.g.:

               stmt = select(
                   table.c.some_column.regexp_replace(
                       'b(..)',
                       'X^AY',
                       flags='g'
                   )
               )

          ColumnOperators.regexp_replace() attempts to
          resolve to a REGEXP_REPLACE-like function provided by the
          backend, that usually emit the function ‘REGEXP_REPLACE()’.
          However, the specific regular expression syntax and flags
          available are `not backend agnostic'.

          Regular expression replacement support is currently
          implemented for Oracle, PostgreSQL, MySQL 8 or greater and
          MariaDB. Support among third-party dialects may vary.

          Parameters:

             * ‘pattern’ – The regular expression pattern string or
               column clause.

             * ‘pattern’ – The replacement string or column clause.

             * ‘flags’ – Any regular expression string flags to apply.
               Flags tend to be backend specific.  It can be a string or
               a column clause.  Some backends, like PostgreSQL and
               MariaDB, may alternatively specify the flags as part of
               the pattern.

          New in version 1.4.

          See also
          ........

          See ColumnOperators.regexp_match().

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               reverse_operate (op, other, **kwargs)

          Reverse operate on an argument.

          Usage is the same as operate().

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               self_group (against: Optional[Any] = None) ->
               ClauseElement

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               shares_lineage (othercolumn)

          Return True if the given ColumnElement has a
          common ancestor to this ColumnElement.

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               startswith (other, **kwargs)

          `inherited from the' ColumnOperators.startswith().
          `method of' ColumnOperators.

          Implement the ‘startswith’ operator.

          Produces a LIKE expression that tests against a match for the
          start of a string value:

               column LIKE <other> || '%'

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.startswith("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.startswith.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.startswith.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.startswith.autoescape flag is set
               to True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.startswith("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE :param || '%' ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.startswith("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE :param || '%' ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.startswith.autoescape:

                    somecolumn.startswith("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.endswith().

          See ColumnOperators.contains().

          See ColumnOperators.like().

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               stringify_dialect = 'default'

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               supports_execution = False

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               timetuple = None

          `inherited from the' ColumnOperators.timetuple.
          `attribute of' ColumnOperators.

          Hack, allows datetime objects to be compared on the LHS.

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               type

      -- Method: sqlalchemy.sql.expression.ColumnElement..
               unique_params (*optionaldict, **kwargs)

          `inherited from the' ClauseElement.unique_params().
          `method of' ClauseElement.

          Return a copy with bindparam() elements replaced.

          Same functionality as ClauseElement.params(),
          except adds ‘unique=True’ to affected bind parameters so that
          multiple statements can be used.

      -- Attribute: sqlalchemy.sql.expression.ColumnElement..
               uses_inspection = True

 -- Class: sqlalchemy.sql.expression.ColumnOperators

     Defines boolean, comparison, and other operators for
     ColumnElement expressions.

     By default, all methods call down to operate() or
     reverse_operate(), passing in the appropriate operator
     function from the Python builtin ‘operator’ module or a
     SQLAlchemy-specific operator function from
     ‘sqlalchemy.expression.operators’.  For example the ‘__eq__’
     function:

          def __eq__(self, other):
              return self.operate(operators.eq, other)

     Where ‘operators.eq’ is essentially:

          def eq(a, b):
              return a == b

     The core column expression unit ColumnElement overrides
     Operators.operate() and others to return further
     ColumnElement constructs, so that the ‘==’ operation above is
     replaced by a clause construct.

     See also
     ........

     See Redefining and Creating New Operators.

     See TypeEngine.comparator_factory.

     See ColumnOperators.

     See PropComparator.

     `Class signature'

     class sqlalchemy.sql.expression.ColumnOperators. (see
     sqlalchemy.sql.expression.Operators)

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __add__ (other)

          Implement the ‘+’ operator.

          In a column context, produces the clause ‘a + b’ if the parent
          object has non-string affinity.  If the parent object has a
          string affinity, produces the concatenation operator, ‘a || b’
          - see ColumnOperators.concat().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __and__ (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.Operators.__and__’ `method of'
          Operators.

          Implement the ‘&’ operator.

          When used with SQL expressions, results in an AND operation,
          equivalent to and_(), that is:

               a & b

          is equivalent to:

               from sqlalchemy import and_
               and_(a, b)

          Care should be taken when using ‘&’ regarding operator
          precedence; the ‘&’ operator has the highest precedence.  The
          operands should be enclosed in parenthesis if they contain
          further sub expressions:

               (a == 2) & (b == 4)

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __div__ (other)

          Implement the ‘/’ operator.

          In a column context, produces the clause ‘a / b’.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __eq__ (other)

          Implement the ‘==’ operator.

          In a column context, produces the clause ‘a = b’.  If the
          target is ‘None’, produces ‘a IS NULL’.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __ge__ (other)

          Implement the ‘>=’ operator.

          In a column context, produces the clause ‘a >= b’.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __getitem__ (index)

          Implement the [] operator.

          This can be used by some database-specific types such as
          PostgreSQL ARRAY and HSTORE.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __gt__ (other)

          Implement the ‘>’ operator.

          In a column context, produces the clause ‘a > b’.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __hash__ ()

          Return hash(self).

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __invert__ ()

          `inherited from the'
          ‘sqlalchemy.sql.expression.Operators.__invert__’ `method of'
          Operators.

          Implement the ‘~’ operator.

          When used with SQL expressions, results in a NOT operation,
          equivalent to not_(), that is:

               ~a

          is equivalent to:

               from sqlalchemy import not_
               not_(a)

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __le__ (other)

          Implement the ‘<=’ operator.

          In a column context, produces the clause ‘a <= b’.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __lshift__ (other)

          implement the << operator.

          Not used by SQLAlchemy core, this is provided for custom
          operator systems which want to use << as an extension point.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __lt__ (other)

          Implement the ‘<’ operator.

          In a column context, produces the clause ‘a < b’.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __mod__ (other)

          Implement the ‘%’ operator.

          In a column context, produces the clause ‘a % b’.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __mul__ (other)

          Implement the ‘*’ operator.

          In a column context, produces the clause ‘a * b’.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __ne__ (other)

          Implement the ‘!=’ operator.

          In a column context, produces the clause ‘a != b’.  If the
          target is ‘None’, produces ‘a IS NOT NULL’.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __neg__ ()

          Implement the ‘-’ operator.

          In a column context, produces the clause ‘-a’.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __or__ (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.Operators.__or__’ `method of'
          Operators.

          Implement the ‘|’ operator.

          When used with SQL expressions, results in an OR operation,
          equivalent to or_(), that is:

               a | b

          is equivalent to:

               from sqlalchemy import or_
               or_(a, b)

          Care should be taken when using ‘|’ regarding operator
          precedence; the ‘|’ operator has the highest precedence.  The
          operands should be enclosed in parenthesis if they contain
          further sub expressions:

               (a == 2) | (b == 4)

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __radd__ (other)

          Implement the ‘+’ operator in reverse.

          See ColumnOperators.__add__().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __rdiv__ (other)

          Implement the ‘/’ operator in reverse.

          See ColumnOperators.__div__().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __rmod__ (other)

          Implement the ‘%’ operator in reverse.

          See ColumnOperators.__mod__().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __rmul__ (other)

          Implement the ‘*’ operator in reverse.

          See ColumnOperators.__mul__().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __rshift__ (other)

          implement the >> operator.

          Not used by SQLAlchemy core, this is provided for custom
          operator systems which want to use >> as an extension point.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __rsub__ (other)

          Implement the ‘-’ operator in reverse.

          See ColumnOperators.__sub__().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __rtruediv__ (other)

          Implement the ‘//’ operator in reverse.

          See ColumnOperators.__truediv__().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __sub__ (other)

          Implement the ‘-’ operator.

          In a column context, produces the clause ‘a - b’.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               __truediv__ (other)

          Implement the ‘//’ operator.

          In a column context, produces the clause ‘a / b’.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               all_ ()

          Produce a all_() clause against the parent object.

          This operator is only appropriate against a scalar subquery
          object, or for some backends an column expression that is
          against the ARRAY type, e.g.:

               # postgresql '5 = ALL (somearray)'
               expr = 5 == mytable.c.somearray.all_()

               # mysql '5 = ALL (SELECT value FROM table)'
               expr = 5 == select(table.c.value).scalar_subquery().all_()

          See also
          ........

          See all_(). - standalone version

          See any_(). - ANY operator

          New in version 1.1.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               any_ ()

          Produce a any_() clause against the parent object.

          This operator is only appropriate against a scalar subquery
          object, or for some backends an column expression that is
          against the ARRAY type, e.g.:

               # postgresql '5 = ANY (somearray)'
               expr = 5 == mytable.c.somearray.any_()

               # mysql '5 = ANY (SELECT value FROM table)'
               expr = 5 == select(table.c.value).scalar_subquery().any_()

          See also
          ........

          See any_(). - standalone version

          See all_(). - ALL operator

          New in version 1.1.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               asc ()

          Produce a asc() clause against the parent object.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               between (cleft, cright, symmetric=False)

          Produce a between() clause against the parent
          object, given the lower and upper range.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               bool_op (opstring, precedence=0)

          `inherited from the' Operators.bool_op(). `method
          of' Operators.

          Return a custom boolean operator.

          This method is shorthand for calling Operators.op()
          and passing the Operators.op.is_comparison
          flag with True.

          See also
          ........

          See Operators.op().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               collate (collation)

          Produce a collate() clause against the parent
          object, given the collation string.

          See also
          ........

          See collate().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               concat (other)

          Implement the ‘concat’ operator.

          In a column context, produces the clause ‘a || b’, or uses the
          ‘concat()’ operator on MySQL.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               contains (other, **kwargs)

          Implement the ‘contains’ operator.

          Produces a LIKE expression that tests against a match for the
          middle of a string value:

               column LIKE '%' || <other> || '%'

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.contains("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.contains.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.contains.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.contains.autoescape flag is set to
               True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.contains("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE '%' || :param || '%' ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.contains("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE '%' || :param || '%' ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.contains.autoescape:

                    somecolumn.contains("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.startswith().

          See ColumnOperators.endswith().

          See ColumnOperators.like().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               desc ()

          Produce a desc() clause against the parent object.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               distinct ()

          Produce a distinct() clause against the parent
          object.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               endswith (other, **kwargs)

          Implement the ‘endswith’ operator.

          Produces a LIKE expression that tests against a match for the
          end of a string value:

               column LIKE '%' || <other>

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.endswith("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.endswith.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.endswith.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.endswith.autoescape flag is set to
               True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.endswith("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE '%' || :param ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.endswith("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE '%' || :param ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.endswith.autoescape:

                    somecolumn.endswith("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.startswith().

          See ColumnOperators.contains().

          See ColumnOperators.like().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               ilike (other, escape=None)

          Implement the ‘ilike’ operator, e.g.  case insensitive LIKE.

          In a column context, produces an expression either of the
          form:

               lower(a) LIKE lower(other)

          Or on backends that support the ILIKE operator:

               a ILIKE other

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.ilike("%foobar%"))

          Parameters:

             * ‘other’ – expression to be compared

             * ‘escape’ – optional escape character, renders the
               ‘ESCAPE’ keyword, e.g.:

                    somecolumn.ilike("foo/%bar", escape="/")

          See also
          ........

          See ColumnOperators.like().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               in_ (other)

          Implement the ‘in’ operator.

          In a column context, produces the clause ‘column IN <other>’.

          The given parameter ‘other’ may be:

             * A list of literal values, e.g.:

                    stmt.where(column.in_([1, 2, 3]))

               In this calling form, the list of items is converted to a
               set of bound parameters the same length as the list
               given:

                    WHERE COL IN (?, ?, ?)

             * A list of tuples may be provided if the comparison is
               against a tuple_() containing multiple
               expressions:

                    from sqlalchemy import tuple_
                    stmt.where(tuple_(col1, col2).in_([(1, 10), (2, 20), (3, 30)]))

             * An empty list, e.g.:

                    stmt.where(column.in_([]))

               In this calling form, the expression renders an “empty
               set” expression.  These expressions are tailored to
               individual backends and are generally trying to get an
               empty SELECT statement as a subquery.  Such as on SQLite,
               the expression is:

                    WHERE col IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)

               Changed in version 1.4: empty IN expressions now use an
               execution-time generated SELECT subquery in all cases.

             * A bound parameter, e.g.  see bindparam(), may be
               used if it includes the bindparam.expanding
               flag:

                    stmt.where(column.in_(bindparam('value', expanding=True)))

               In this calling form, the expression renders a special
               non-SQL placeholder expression that looks like:

                    WHERE COL IN ([EXPANDING_value])

               This placeholder expression is intercepted at statement
               execution time to be converted into the variable number
               of bound parameter form illustrated earlier.  If the
               statement were executed as:

                    connection.execute(stmt, {"value": [1, 2, 3]})

               The database would be passed a bound parameter for each
               value:

                    WHERE COL IN (?, ?, ?)

               New in version 1.2: added “expanding” bound parameters

               If an empty list is passed, a special “empty list”
               expression, which is specific to the database in use, is
               rendered.  On SQLite this would be:

                    WHERE COL IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)

               New in version 1.3: “expanding” bound parameters now
               support empty lists

             * a select() construct, which is usually a
               correlated scalar select:

                    stmt.where(
                        column.in_(
                            select(othertable.c.y).
                            where(table.c.x == othertable.c.x)
                        )
                    )

               In this calling form, see ColumnOperators.in_()
               renders as given:

                    WHERE COL IN (SELECT othertable.y
                    FROM othertable WHERE othertable.x = table.x)

          Parameters: ‘other’ – a list of literals, a select()
          construct, or a bindparam() construct that
          includes the bindparam.expanding flag set to True.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               is_ (other)

          Implement the ‘IS’ operator.

          Normally, ‘IS’ is generated automatically when comparing to a
          value of ‘None’, which resolves to ‘NULL’.  However, explicit
          usage of ‘IS’ may be desirable if comparing to boolean values
          on certain platforms.

          See also
          ........

          See ColumnOperators.is_not().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               is_distinct_from (other)

          Implement the ‘IS DISTINCT FROM’ operator.

          Renders “a IS DISTINCT FROM b” on most platforms; on some such
          as SQLite may render “a IS NOT b”.

          New in version 1.1.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               is_not (other)

          Implement the ‘IS NOT’ operator.

          Normally, ‘IS NOT’ is generated automatically when comparing
          to a value of ‘None’, which resolves to ‘NULL’.  However,
          explicit usage of ‘IS NOT’ may be desirable if comparing to
          boolean values on certain platforms.

          Changed in version 1.4: The ‘is_not()’ operator is renamed
          from ‘isnot()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.is_().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               is_not_distinct_from (other)

          Implement the ‘IS NOT DISTINCT FROM’ operator.

          Renders “a IS NOT DISTINCT FROM b” on most platforms; on some
          such as SQLite may render “a IS b”.

          Changed in version 1.4: The ‘is_not_distinct_from()’ operator
          is renamed from ‘isnot_distinct_from()’ in previous releases.
          The previous name remains available for backwards
          compatibility.

          New in version 1.1.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               isnot (other)

          Implement the ‘IS NOT’ operator.

          Normally, ‘IS NOT’ is generated automatically when comparing
          to a value of ‘None’, which resolves to ‘NULL’.  However,
          explicit usage of ‘IS NOT’ may be desirable if comparing to
          boolean values on certain platforms.

          Changed in version 1.4: The ‘is_not()’ operator is renamed
          from ‘isnot()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.is_().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               isnot_distinct_from (other)

          Implement the ‘IS NOT DISTINCT FROM’ operator.

          Renders “a IS NOT DISTINCT FROM b” on most platforms; on some
          such as SQLite may render “a IS b”.

          Changed in version 1.4: The ‘is_not_distinct_from()’ operator
          is renamed from ‘isnot_distinct_from()’ in previous releases.
          The previous name remains available for backwards
          compatibility.

          New in version 1.1.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               like (other, escape=None)

          Implement the ‘like’ operator.

          In a column context, produces the expression:

               a LIKE other

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.like("%foobar%"))

          Parameters:

             * ‘other’ – expression to be compared

             * ‘escape’ – optional escape character, renders the
               ‘ESCAPE’ keyword, e.g.:

                    somecolumn.like("foo/%bar", escape="/")

          See also
          ........

          See ColumnOperators.ilike().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               match (other, **kwargs)

          Implements a database-specific ‘match’ operator.

          ColumnOperators.match() attempts to resolve to a
          MATCH-like function or operator provided by the backend.
          Examples include:

             * PostgreSQL - renders ‘x @@ to_tsquery(y)’

             * MySQL - renders ‘MATCH (x) AGAINST (y IN BOOLEAN MODE)’

             * Oracle - renders ‘CONTAINS(x, y)’

             * other backends may provide special implementations.

             * Backends without any special implementation will emit the
               operator as “MATCH”.  This is compatible with SQLite, for
               example.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               not_ilike (other, escape=None)

          implement the ‘NOT ILIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.ilike(), i.e.  ‘~x.ilike(y)’.

          Changed in version 1.4: The ‘not_ilike()’ operator is renamed
          from ‘notilike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.ilike().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               not_in (other)

          implement the ‘NOT IN’ operator.

          This is equivalent to using negation with
          ColumnOperators.in_(), i.e.  ‘~x.in_(y)’.

          In the case that ‘other’ is an empty sequence, the compiler
          produces an “empty not in” expression.  This defaults to the
          expression “1 = 1” to produce true in all cases.  The
          create_engine.empty_in_strategy may be used to alter
          this behavior.

          Changed in version 1.4: The ‘not_in()’ operator is renamed
          from ‘notin_()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          Changed in version 1.2: The ColumnOperators.in_()
          and ColumnOperators.not_in() operators now produce
          a “static” expression for an empty IN sequence by default.

          See also
          ........

          See ColumnOperators.in_().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               not_like (other, escape=None)

          implement the ‘NOT LIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.like(), i.e.  ‘~x.like(y)’.

          Changed in version 1.4: The ‘not_like()’ operator is renamed
          from ‘notlike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.like().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               notilike (other, escape=None)

          implement the ‘NOT ILIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.ilike(), i.e.  ‘~x.ilike(y)’.

          Changed in version 1.4: The ‘not_ilike()’ operator is renamed
          from ‘notilike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.ilike().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               notin_ (other)

          implement the ‘NOT IN’ operator.

          This is equivalent to using negation with
          ColumnOperators.in_(), i.e.  ‘~x.in_(y)’.

          In the case that ‘other’ is an empty sequence, the compiler
          produces an “empty not in” expression.  This defaults to the
          expression “1 = 1” to produce true in all cases.  The
          create_engine.empty_in_strategy may be used to alter
          this behavior.

          Changed in version 1.4: The ‘not_in()’ operator is renamed
          from ‘notin_()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          Changed in version 1.2: The ColumnOperators.in_()
          and ColumnOperators.not_in() operators now produce
          a “static” expression for an empty IN sequence by default.

          See also
          ........

          See ColumnOperators.in_().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               notlike (other, escape=None)

          implement the ‘NOT LIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.like(), i.e.  ‘~x.like(y)’.

          Changed in version 1.4: The ‘not_like()’ operator is renamed
          from ‘notlike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.like().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               nulls_first ()

          Produce a nulls_first() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_first()’ operator is
          renamed from ‘nullsfirst()’ in previous releases.  The
          previous name remains available for backwards compatibility.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               nulls_last ()

          Produce a nulls_last() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_last()’ operator is renamed
          from ‘nullslast()’ in previous releases.  The previous name
          remains available for backwards compatibility.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               nullsfirst ()

          Produce a nulls_first() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_first()’ operator is
          renamed from ‘nullsfirst()’ in previous releases.  The
          previous name remains available for backwards compatibility.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               nullslast ()

          Produce a nulls_last() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_last()’ operator is renamed
          from ‘nullslast()’ in previous releases.  The previous name
          remains available for backwards compatibility.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               op (opstring, precedence=0, is_comparison=False,
               return_type=None)

          `inherited from the' Operators.op(). `method of'
          Operators.

          Produce a generic operator function.

          e.g.:

               somecolumn.op("*")(5)

          produces:

               somecolumn * 5

          This function can also be used to make bitwise operators
          explicit.  For example:

               somecolumn.op('&')(0xff)

          is a bitwise AND of the value in ‘somecolumn’.

          Parameters:

             * ‘operator’ – a string which will be output as the infix
               operator between this element and the expression passed
               to the generated function.

             * ‘precedence’ – precedence to apply to the operator, when
               parenthesizing expressions.  A lower number will cause
               the expression to be parenthesized when applied against
               another operator with higher precedence.  The default
               value of ‘0’ is lower than all operators except for the
               comma (‘,’) and ‘AS’ operators.  A value of 100 will be
               higher or equal to all operators, and -100 will be lower
               than or equal to all operators.

             * ‘is_comparison’ – if True, the operator will be
               considered as a “comparison” operator, that is which
               evaluates to a boolean true/false value, like ‘==’, ‘>’,
               etc.  This flag should be set so that ORM relationships
               can establish that the operator is a comparison operator
               when used in a custom join condition.

               New in version 0.9.2: - added the
               Operators.op.is_comparison flag.

             * ‘return_type’ – a TypeEngine class or object
               that will force the return type of an expression produced
               by this operator to be of that type.  By default,
               operators that specify Operators.op.is_comparison
               will resolve to Boolean, and those that
               do not will be of the same type as the left-hand operand.

          See also
          ........

          See Redefining and Creating New Operators.

          See Using custom operators in join conditions.

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               operate (op, *other, **kwargs)

          `inherited from the' Operators.operate(). `method
          of' Operators.

          Operate on an argument.

          This is the lowest level of operation, raises
          ‘NotImplementedError’ by default.

          Overriding this on a subclass can allow common behavior to be
          applied to all operations.  For example, overriding
          ColumnOperators to apply ‘func.lower()’ to the left and
          right side:

               class MyComparator(ColumnOperators):
                   def operate(self, op, other):
                       return op(func.lower(self), func.lower(other))

          Parameters:

             * ‘op’ – Operator callable.

             * ‘*other’ – the ‘other’ side of the operation.  Will be a
               single scalar for most operations.

             * ‘**kwargs’ – modifiers.  These may be passed by special
               operators such as ColumnOperators.contains().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               regexp_match (pattern, flags=None)

          Implements a database-specific ‘regexp match’ operator.

          E.g.:

               stmt = select(table.c.some_column).where(
                   table.c.some_column.regexp_match('^(b|c)')
               )

          ColumnOperators.regexp_match() attempts to resolve
          to a REGEXP-like function or operator provided by the backend,
          however the specific regular expression syntax and flags
          available are `not backend agnostic'.

          Examples include:

             * PostgreSQL - renders ‘x ~ y’ or ‘x !~ y’ when negated.

             * Oracle - renders ‘REGEXP_LIKE(x, y)’

             * SQLite - uses SQLite’s ‘REGEXP’ placeholder operator and
               calls into the Python ‘re.match()’ builtin.

             * other backends may provide special implementations.

             * Backends without any special implementation will emit the
               operator as “REGEXP” or “NOT REGEXP”.  This is compatible
               with SQLite and MySQL, for example.

          Regular expression support is currently implemented for
          Oracle, PostgreSQL, MySQL and MariaDB. Partial support is
          available for SQLite.  Support among third-party dialects may
          vary.

          Parameters:

             * ‘pattern’ – The regular expression pattern string or
               column clause.

             * ‘flags’ – Any regular expression string flags to apply.
               Flags tend to be backend specific.  It can be a string or
               a column clause.  Some backends, like PostgreSQL and
               MariaDB, may alternatively specify the flags as part of
               the pattern.  When using the ignore case flag ‘i’ in
               PostgreSQL, the ignore case regexp match operator ‘~*’ or
               ‘!~*’ will be used.

          New in version 1.4.

          See also
          ........

          See ColumnOperators.regexp_replace().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               regexp_replace (pattern, replacement, flags=None)

          Implements a database-specific ‘regexp replace’ operator.

          E.g.:

               stmt = select(
                   table.c.some_column.regexp_replace(
                       'b(..)',
                       'X^AY',
                       flags='g'
                   )
               )

          ColumnOperators.regexp_replace() attempts to
          resolve to a REGEXP_REPLACE-like function provided by the
          backend, that usually emit the function ‘REGEXP_REPLACE()’.
          However, the specific regular expression syntax and flags
          available are `not backend agnostic'.

          Regular expression replacement support is currently
          implemented for Oracle, PostgreSQL, MySQL 8 or greater and
          MariaDB. Support among third-party dialects may vary.

          Parameters:

             * ‘pattern’ – The regular expression pattern string or
               column clause.

             * ‘pattern’ – The replacement string or column clause.

             * ‘flags’ – Any regular expression string flags to apply.
               Flags tend to be backend specific.  It can be a string or
               a column clause.  Some backends, like PostgreSQL and
               MariaDB, may alternatively specify the flags as part of
               the pattern.

          New in version 1.4.

          See also
          ........

          See ColumnOperators.regexp_match().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               reverse_operate (op, other, **kwargs)

          `inherited from the' Operators.reverse_operate().
          `method of' Operators.

          Reverse operate on an argument.

          Usage is the same as operate().

      -- Method: sqlalchemy.sql.expression.ColumnOperators..
               startswith (other, **kwargs)

          Implement the ‘startswith’ operator.

          Produces a LIKE expression that tests against a match for the
          start of a string value:

               column LIKE <other> || '%'

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.startswith("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.startswith.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.startswith.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.startswith.autoescape flag is set
               to True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.startswith("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE :param || '%' ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.startswith("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE :param || '%' ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.startswith.autoescape:

                    somecolumn.startswith("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.endswith().

          See ColumnOperators.contains().

          See ColumnOperators.like().

      -- Attribute: sqlalchemy.sql.expression.ColumnOperators..
               timetuple = None

          Hack, allows datetime objects to be compared on the LHS.

 -- Class: sqlalchemy.sql.base.DialectKWArgs

     Establish the ability for a class to have dialect-specific
     arguments with defaults and constructor validation.

     The DialectKWArgs interacts with the
     DefaultDialect.construct_arguments present on a dialect.

     See also
     ........

     See DefaultDialect.construct_arguments.

      -- Method: sqlalchemy.sql.base.DialectKWArgs..
               classmethod argument_for (dialect_name,
               argument_name, default)

          Add a new kind of dialect-specific keyword argument for this
          class.

          E.g.:

               Index.argument_for("mydialect", "length", None)

               some_index = Index('a', 'b', mydialect_length=5)

          The DialectKWArgs.argument_for() method is a
          per-argument way adding extra arguments to the
          DefaultDialect.construct_arguments dictionary.  This
          dictionary provides a list of argument names accepted by
          various schema-level constructs on behalf of a dialect.

          New dialects should typically specify this dictionary all at
          once as a data member of the dialect class.  The use case for
          ad-hoc addition of argument names is typically for end-user
          code that is also using a custom compilation scheme which
          consumes the additional arguments.

          Parameters:

             * ‘dialect_name’ – name of a dialect.  The dialect must be
               locatable, else a NoSuchModuleError is
               raised.  The dialect must also include an existing
               DefaultDialect.construct_arguments collection,
               indicating that it participates in the keyword-argument
               validation and default system, else ArgumentError
               is raised.  If the dialect does not include this
               collection, then any keyword argument can be specified on
               behalf of this dialect already.  All dialects packaged
               within SQLAlchemy include this collection, however for
               third party dialects, support may vary.

             * ‘argument_name’ – name of the parameter.

             * ‘default’ – default value of the parameter.

          New in version 0.9.4.

      -- Attribute: sqlalchemy.sql.base.DialectKWArgs..
               dialect_kwargs

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          The arguments are present here in their original
          ‘<dialect>_<kwarg>’ format.  Only arguments that were actually
          passed are included; unlike the
          DialectKWArgs.dialect_options collection, which contains
          all options known by this dialect including defaults.

          The collection is also writable; keys are accepted of the form
          ‘<dialect>_<kwarg>’ where the value will be assembled into the
          list of options.

          New in version 0.9.2.

          Changed in version 0.9.4: The
          DialectKWArgs.dialect_kwargs collection is now writable.

          See also
          ........

          See DialectKWArgs.dialect_options. - nested dictionary
          form

      -- Attribute: sqlalchemy.sql.base.DialectKWArgs..
               dialect_options

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          This is a two-level nested registry, keyed to ‘<dialect_name>’
          and ‘<argument_name>’.  For example, the ‘postgresql_where’
          argument would be locatable as:

               arg = my_object.dialect_options['postgresql']['where']

          New in version 0.9.2.

          See also
          ........

          See DialectKWArgs.dialect_kwargs. - flat dictionary
          form

      -- Attribute: sqlalchemy.sql.base.DialectKWArgs..kwargs

          A synonym for DialectKWArgs.dialect_kwargs.

 -- Class: sqlalchemy.sql.expression.Extract (field, expr, **kwargs)

     Represent a SQL EXTRACT clause, ‘extract(field FROM expr)’.

     `Class signature'

     class sqlalchemy.sql.expression.Extract. (see
     sqlalchemy.sql.expression.ColumnElement)

      -- Method: sqlalchemy.sql.expression.Extract..__init__
               (field, expr, **kwargs)

          Construct a new Extract object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.sql.expression.extract() for a full
          usage and argument description.

 -- Class: sqlalchemy.sql.expression.False_ (*arg, **kw)

     Represent the ‘false’ keyword, or equivalent, in a SQL statement.

     False_ is accessed as a constant via the false()
     function.

     `Class signature'

     class sqlalchemy.sql.expression.False_.
     (‘sqlalchemy.sql.expression.SingletonConstant’,
     ‘sqlalchemy.sql.roles.ConstExprRole’, see
     sqlalchemy.sql.expression.ColumnElement)

 -- Class: sqlalchemy.sql.expression.FunctionFilter (func, *criterion)

     Represent a function FILTER clause.

     This is a special operator against aggregate and window functions,
     which controls which rows are passed to it.  It’s supported only by
     certain database backends.

     Invocation of FunctionFilter is via
     FunctionElement.filter():

          func.count(1).filter(True)

     New in version 1.0.0.

     See also
     ........

     See FunctionElement.filter().

     `Class signature'

     class sqlalchemy.sql.expression.FunctionFilter. (see
     sqlalchemy.sql.expression.ColumnElement)

      -- Method: sqlalchemy.sql.expression.FunctionFilter..
               __init__ (func, *criterion)

          Construct a new FunctionFilter object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.sql.expression.funcfilter() for a full
          usage and argument description.

      -- Method: sqlalchemy.sql.expression.FunctionFilter..
               filter (*criterion)

          Produce an additional FILTER against the function.

          This method adds additional criteria to the initial criteria
          set up by FunctionElement.filter().

          Multiple criteria are joined together at SQL render time via
          ‘AND’.

      -- Method: sqlalchemy.sql.expression.FunctionFilter..
               over (partition_by=None, order_by=None, range_=None,
               rows=None)

          Produce an OVER clause against this filtered function.

          Used against aggregate or so-called “window” functions, for
          database backends that support window functions.

          The expression:

               func.rank().filter(MyClass.y > 5).over(order_by='x')

          is shorthand for:

               from sqlalchemy import over, funcfilter
               over(funcfilter(func.rank(), MyClass.y > 5), order_by='x')

          See over() for a full description.

      -- Method: sqlalchemy.sql.expression.FunctionFilter..
               self_group (against=None)

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

 -- Class: sqlalchemy.sql.expression.Label (name, element, type_=None)

     Represents a column label (AS).

     Represent a label, as typically applied to any column-level element
     using the ‘AS’ sql keyword.

     `Class signature'

     class sqlalchemy.sql.expression.Label.
     (‘sqlalchemy.sql.roles.LabeledColumnExprRole’, see
     sqlalchemy.sql.expression.ColumnElement)

      -- Method: sqlalchemy.sql.expression.Label..__init__
               (name, element, type_=None)

          Construct a new Label object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.sql.expression.label() for a full usage
          and argument description.

      -- Attribute: sqlalchemy.sql.expression.Label..
               foreign_keys

      -- Attribute: sqlalchemy.sql.expression.Label..
               primary_key

      -- Method: sqlalchemy.sql.expression.Label..self_group
               (against: Optional[Any] = None) -> ClauseElement

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

 -- Class: sqlalchemy.sql.expression.LambdaElement (fn, role,
          opts=<class 'sqlalchemy.sql.lambdas.LambdaOptions'>,
          apply_propagate_attrs=None)

     A SQL construct where the state is stored as an un-invoked lambda.

     The LambdaElement is produced transparently whenever
     passing lambda expressions into SQL constructs, such as:

          stmt = select(table).where(lambda: table.c.col == parameter)

     The LambdaElement is the base of the
     StatementLambdaElement which represents a full statement
     within a lambda.

     New in version 1.4.

     See also
     ........

     See Using Lambdas to add significant speed gains to statement production.

     `Class signature'

     class sqlalchemy.sql.expression.LambdaElement. (see
     sqlalchemy.sql.expression.ClauseElement)

 -- Class: sqlalchemy.sql.expression.Null (*arg, **kw)

     Represent the NULL keyword in a SQL statement.

     Null is accessed as a constant via the null()
     function.

     `Class signature'

     class sqlalchemy.sql.expression.Null.
     (‘sqlalchemy.sql.expression.SingletonConstant’,
     ‘sqlalchemy.sql.roles.ConstExprRole’, see
     sqlalchemy.sql.expression.ColumnElement)

 -- Class: sqlalchemy.sql.expression.Operators

     Base of comparison and logical operators.

     Implements base methods ‘Operators.operate()’ and
     ‘Operators.reverse_operate()’, as well as ‘Operators.__and__()’,
     ‘Operators.__or__()’, ‘Operators.__invert__()’.

     Usually is used via its most common subclass ColumnOperators.

      -- Method: sqlalchemy.sql.expression.Operators..__and__
               (other)

          Implement the ‘&’ operator.

          When used with SQL expressions, results in an AND operation,
          equivalent to and_(), that is:

               a & b

          is equivalent to:

               from sqlalchemy import and_
               and_(a, b)

          Care should be taken when using ‘&’ regarding operator
          precedence; the ‘&’ operator has the highest precedence.  The
          operands should be enclosed in parenthesis if they contain
          further sub expressions:

               (a == 2) & (b == 4)

      -- Method: sqlalchemy.sql.expression.Operators..
               __invert__ ()

          Implement the ‘~’ operator.

          When used with SQL expressions, results in a NOT operation,
          equivalent to not_(), that is:

               ~a

          is equivalent to:

               from sqlalchemy import not_
               not_(a)

      -- Method: sqlalchemy.sql.expression.Operators..__or__
               (other)

          Implement the ‘|’ operator.

          When used with SQL expressions, results in an OR operation,
          equivalent to or_(), that is:

               a | b

          is equivalent to:

               from sqlalchemy import or_
               or_(a, b)

          Care should be taken when using ‘|’ regarding operator
          precedence; the ‘|’ operator has the highest precedence.  The
          operands should be enclosed in parenthesis if they contain
          further sub expressions:

               (a == 2) | (b == 4)

      -- Method: sqlalchemy.sql.expression.Operators..bool_op
               (opstring, precedence=0)

          Return a custom boolean operator.

          This method is shorthand for calling Operators.op()
          and passing the Operators.op.is_comparison
          flag with True.

          See also
          ........

          See Operators.op().

      -- Method: sqlalchemy.sql.expression.Operators..op
               (opstring, precedence=0, is_comparison=False,
               return_type=None)

          Produce a generic operator function.

          e.g.:

               somecolumn.op("*")(5)

          produces:

               somecolumn * 5

          This function can also be used to make bitwise operators
          explicit.  For example:

               somecolumn.op('&')(0xff)

          is a bitwise AND of the value in ‘somecolumn’.

          Parameters:

             * ‘operator’ – a string which will be output as the infix
               operator between this element and the expression passed
               to the generated function.

             * ‘precedence’ – precedence to apply to the operator, when
               parenthesizing expressions.  A lower number will cause
               the expression to be parenthesized when applied against
               another operator with higher precedence.  The default
               value of ‘0’ is lower than all operators except for the
               comma (‘,’) and ‘AS’ operators.  A value of 100 will be
               higher or equal to all operators, and -100 will be lower
               than or equal to all operators.

             * ‘is_comparison’ – if True, the operator will be
               considered as a “comparison” operator, that is which
               evaluates to a boolean true/false value, like ‘==’, ‘>’,
               etc.  This flag should be set so that ORM relationships
               can establish that the operator is a comparison operator
               when used in a custom join condition.

               New in version 0.9.2: - added the
               Operators.op.is_comparison flag.

             * ‘return_type’ – a TypeEngine class or object
               that will force the return type of an expression produced
               by this operator to be of that type.  By default,
               operators that specify Operators.op.is_comparison
               will resolve to Boolean, and those that
               do not will be of the same type as the left-hand operand.

          See also
          ........

          See Redefining and Creating New Operators.

          See Using custom operators in join conditions.

      -- Method: sqlalchemy.sql.expression.Operators..operate
               (op, *other, **kwargs)

          Operate on an argument.

          This is the lowest level of operation, raises
          ‘NotImplementedError’ by default.

          Overriding this on a subclass can allow common behavior to be
          applied to all operations.  For example, overriding
          ColumnOperators to apply ‘func.lower()’ to the left and
          right side:

               class MyComparator(ColumnOperators):
                   def operate(self, op, other):
                       return op(func.lower(self), func.lower(other))

          Parameters:

             * ‘op’ – Operator callable.

             * ‘*other’ – the ‘other’ side of the operation.  Will be a
               single scalar for most operations.

             * ‘**kwargs’ – modifiers.  These may be passed by special
               operators such as ColumnOperators.contains().

      -- Method: sqlalchemy.sql.expression.Operators..
               reverse_operate (op, other, **kwargs)

          Reverse operate on an argument.

          Usage is the same as operate().

 -- Class: sqlalchemy.sql.expression.Over (element, partition_by=None,
          order_by=None, range_=None, rows=None)

     Represent an OVER clause.

     This is a special operator against a so-called “window” function,
     as well as any aggregate function, which produces results relative
     to the result set itself.  It’s supported only by certain database
     backends.

     `Class signature'

     class sqlalchemy.sql.expression.Over. (see
     sqlalchemy.sql.expression.ColumnElement)

      -- Method: sqlalchemy.sql.expression.Over..__init__
               (element, partition_by=None, order_by=None, range_=None,
               rows=None)

          Construct a new Over object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.sql.expression.over() for a full usage
          and argument description.

      -- Attribute: sqlalchemy.sql.expression.Over..element =
               None

          The underlying expression object to which this Over
          object refers towards.

 -- Class: sqlalchemy.sql.expression.StatementLambdaElement (fn, role,
          opts=<class 'sqlalchemy.sql.lambdas.LambdaOptions'>,
          apply_propagate_attrs=None)

     Represent a composable SQL statement as a LambdaElement.

     The StatementLambdaElement is constructed using the
     lambda_stmt() function:

          from sqlalchemy import lambda_stmt

          stmt = lambda_stmt(lambda: select(table))

     Once constructed, additional criteria can be built onto the
     statement by adding subsequent lambdas, which accept the existing
     statement object as a single parameter:

          stmt += lambda s: s.where(table.c.col == parameter)

     New in version 1.4.

     See also
     ........

     See Using Lambdas to add significant speed gains to statement production.

     `Class signature'

     class sqlalchemy.sql.expression.StatementLambdaElement.
     (‘sqlalchemy.sql.roles.AllowsLambdaRole’,
     ‘sqlalchemy.sql.lambdas.LambdaElement’)

      -- Method:
               sqlalchemy.sql.expression.StatementLambdaElement..
               add_criteria (other, enable_tracking=True,
               track_on=None, track_closure_variables=True,
               track_bound_values=True)

          Add new criteria to this StatementLambdaElement.

          E.g.:

               >>> def my_stmt(parameter):
               ...     stmt = lambda_stmt(
               ...         lambda: select(table.c.x, table.c.y),
               ...     )
               ...     stmt = stmt.add_criteria(
               ...         lambda: table.c.x > parameter
               ...     )
               ...     return stmt

          The StatementLambdaElement.add_criteria() method
          is equivalent to using the Python addition operator to add a
          new lambda, except that additional arguments may be added
          including ‘track_closure_values’ and ‘track_on’:

               >>> def my_stmt(self, foo):
               ...     stmt = lambda_stmt(
               ...         lambda: select(func.max(foo.x, foo.y)),
               ...         track_closure_variables=False
               ...     )
               ...     stmt = stmt.add_criteria(
               ...         lambda: self.where_criteria,
               ...         track_on=[self]
               ...     )
               ...     return stmt

          See lambda_stmt() for a description of the
          parameters accepted.

      -- Method:
               sqlalchemy.sql.expression.StatementLambdaElement..
               spoil ()

          Return a new StatementLambdaElement that will run
          all lambdas unconditionally each time.

 -- Class: sqlalchemy.sql.expression.TextClause (text, bind=None)

     Represent a literal SQL text fragment.

     E.g.:

          from sqlalchemy import text

          t = text("SELECT * FROM users")
          result = connection.execute(t)

     The TextClause construct is produced using the
     text() function; see that function for full documentation.

     See also
     ........

     See text().

     `Class signature'

     class sqlalchemy.sql.expression.TextClause.
     (‘sqlalchemy.sql.roles.DDLConstraintColumnRole’,
     ‘sqlalchemy.sql.roles.DDLExpressionRole’,
     ‘sqlalchemy.sql.roles.StatementOptionRole’,
     ‘sqlalchemy.sql.roles.WhereHavingRole’,
     ‘sqlalchemy.sql.roles.OrderByRole’,
     ‘sqlalchemy.sql.roles.FromClauseRole’,
     ‘sqlalchemy.sql.roles.SelectStatementRole’,
     ‘sqlalchemy.sql.roles.BinaryElementRole’,
     ‘sqlalchemy.sql.roles.InElementRole’, see
     sqlalchemy.sql.expression.Executable,
     sqlalchemy.sql.expression.ClauseElement)

      -- Method: sqlalchemy.sql.expression.TextClause..
               bindparams (*binds, **names_to_values)

          Establish the values and/or types of bound parameters within
          this TextClause construct.

          Given a text construct such as:

               from sqlalchemy import text
               stmt = text("SELECT id, name FROM user WHERE name=:name "
                           "AND timestamp=:timestamp")

          the TextClause.bindparams() method can be used to
          establish the initial value of ‘:name’ and ‘:timestamp’, using
          simple keyword arguments:

               stmt = stmt.bindparams(name='jack',
                           timestamp=datetime.datetime(2012, 10, 8, 15, 12, 5))

          Where above, new BindParameter objects will be
          generated with the names ‘name’ and ‘timestamp’, and values of
          ‘jack’ and ‘datetime.datetime(2012, 10, 8, 15, 12, 5)’,
          respectively.  The types will be inferred from the values
          given, in this case String and DateTime.

          When specific typing behavior is needed, the positional
          ‘*binds’ argument can be used in which to specify
          bindparam() constructs directly.  These constructs must
          include at least the ‘key’ argument, then an optional value
          and type:

               from sqlalchemy import bindparam
               stmt = stmt.bindparams(
                               bindparam('name', value='jack', type_=String),
                               bindparam('timestamp', type_=DateTime)
                           )

          Above, we specified the type of DateTime for the
          ‘timestamp’ bind, and the type of String for the
          ‘name’ bind.  In the case of ‘name’ we also set the default
          value of ‘"jack"’.

          Additional bound parameters can be supplied at statement
          execution time, e.g.:

               result = connection.execute(stmt,
                           timestamp=datetime.datetime(2012, 10, 8, 15, 12, 5))

          The TextClause.bindparams() method can be called
          repeatedly, where it will re-use existing BindParameter
          objects to add new information.  For example, we can call
          TextClause.bindparams() first with typing
          information, and a second time with value information, and it
          will be combined:

               stmt = text("SELECT id, name FROM user WHERE name=:name "
                           "AND timestamp=:timestamp")
               stmt = stmt.bindparams(
                   bindparam('name', type_=String),
                   bindparam('timestamp', type_=DateTime)
               )
               stmt = stmt.bindparams(
                   name='jack',
                   timestamp=datetime.datetime(2012, 10, 8, 15, 12, 5)
               )

          The TextClause.bindparams() method also supports
          the concept of `unique' bound parameters.  These are
          parameters that are “uniquified” on name at statement
          compilation time, so that multiple text()
          constructs may be combined together without the names
          conflicting.  To use this feature, specify the
          BindParameter.unique flag on each bindparam()
          object:

               stmt1 = text("select id from table where name=:name").bindparams(
                   bindparam("name", value='name1', unique=True)
               )
               stmt2 = text("select id from table where name=:name").bindparams(
                   bindparam("name", value='name2', unique=True)
               )

               union = union_all(
                   stmt1.columns(column("id")),
                   stmt2.columns(column("id"))
               )

          The above statement will render as:

               select id from table where name=:name_1
               UNION ALL select id from table where name=:name_2

          New in version 1.3.11: Added support for the
          BindParameter.unique flag to work with text()
          constructs.

      -- Method: sqlalchemy.sql.expression.TextClause..
               columns (*cols, **types)

          Turn this TextClause object into a
          TextualSelect object that serves the same role as a
          SELECT statement.

          The TextualSelect is part of the SelectBase
          hierarchy and can be embedded into another statement by
          using the TextualSelect.subquery() method to
          produce a Subquery object, which can then be
          SELECTed from.

          This function essentially bridges the gap between an entirely
          textual SELECT statement and the SQL expression language
          concept of a “selectable”:

               from sqlalchemy.sql import column, text

               stmt = text("SELECT id, name FROM some_table")
               stmt = stmt.columns(column('id'), column('name')).subquery('st')

               stmt = select(mytable).\
                       select_from(
                           mytable.join(stmt, mytable.c.name == stmt.c.name)
                       ).where(stmt.c.id > 5)

          Above, we pass a series of column() elements to
          the TextClause.columns() method positionally.
          These column() elements now become first class
          elements upon the TextualSelect.selected_columns
          column collection, which then become part of the ‘Subquery.c’
          collection after TextualSelect.subquery() is
          invoked.

          The column expressions we pass to TextClause.columns()
          may also be typed; when we do so, these TypeEngine
          objects become the effective return type of the column,
          so that SQLAlchemy’s result-set-processing systems may be used
          on the return values.  This is often needed for types such as
          date or boolean types, as well as for unicode processing on
          some dialect configurations:

               stmt = text("SELECT id, name, timestamp FROM some_table")
               stmt = stmt.columns(
                           column('id', Integer),
                           column('name', Unicode),
                           column('timestamp', DateTime)
                       )

               for id, name, timestamp in connection.execute(stmt):
                   print(id, name, timestamp)

          As a shortcut to the above syntax, keyword arguments referring
          to types alone may be used, if only type conversion is needed:

               stmt = text("SELECT id, name, timestamp FROM some_table")
               stmt = stmt.columns(
                           id=Integer,
                           name=Unicode,
                           timestamp=DateTime
                       )

               for id, name, timestamp in connection.execute(stmt):
                   print(id, name, timestamp)

          The positional form of TextClause.columns() also
          provides the unique feature of `positional column targeting',
          which is particularly useful when using the ORM with complex
          textual queries.  If we specify the columns from our model to
          TextClause.columns(), the result set will match to
          those columns positionally, meaning the name or origin of the
          column in the textual SQL doesn’t matter:

               stmt = text("SELECT users.id, addresses.id, users.id, "
                    "users.name, addresses.email_address AS email "
                    "FROM users JOIN addresses ON users.id=addresses.user_id "
                    "WHERE users.id = 1").columns(
                       User.id,
                       Address.id,
                       Address.user_id,
                       User.name,
                       Address.email_address
                    )

               query = session.query(User).from_statement(stmt).options(
                   contains_eager(User.addresses))

          New in version 1.1: the TextClause.columns()
          method now offers positional column targeting in the result
          set when the column expressions are passed purely
          positionally.

          The TextClause.columns() method provides a direct
          route to calling ‘FromClause.subquery()’ as well as
          SelectBase.cte() against a textual SELECT statement:

               stmt = stmt.columns(id=Integer, name=String).cte('st')

               stmt = select(sometable).where(sometable.c.id == stmt.c.id)

          Parameters:

             * ‘*cols’ – A series of ColumnElement objects,
               typically Column objects from a Table
               or ORM level column-mapped attributes, representing a
               set of columns that this textual string will SELECT from.

             * ‘**types’ – A mapping of string names to
               TypeEngine type objects indicating the datatypes to
               use for names that are SELECTed from the textual string.
               Prefer to use the ‘*cols’ argument as it also indicates
               positional ordering.

      -- Method: sqlalchemy.sql.expression.TextClause..
               self_group (against: Optional[Any] = None) ->
               Union[Grouping, TextClause]

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

 -- Class: sqlalchemy.sql.expression.Tuple (*clauses, **kw)

     Represent a SQL tuple.

     `Class signature'

     class sqlalchemy.sql.expression.Tuple. (see
     sqlalchemy.sql.expression.ClauseList,
     sqlalchemy.sql.expression.ColumnElement)

      -- Method: sqlalchemy.sql.expression.Tuple..__init__
               (*clauses, **kw)

          Construct a new Tuple object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.sql.expression.tuple_() for a full
          usage and argument description.

      -- Method: sqlalchemy.sql.expression.Tuple..self_group
               (against=None)

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

 -- Class: sqlalchemy.sql.expression.WithinGroup (element, *order_by)

     Represent a WITHIN GROUP (ORDER BY) clause.

     This is a special operator against so-called “ordered set
     aggregate” and “hypothetical set aggregate” functions, including
     ‘percentile_cont()’, ‘rank()’, ‘dense_rank()’, etc.

     It’s supported only by certain database backends, such as
     PostgreSQL, Oracle and MS SQL Server.

     The WithinGroup construct extracts its type from the
     method FunctionElement.within_group_type().  If this
     returns ‘None’, the function’s ‘.type’ is used.

     `Class signature'

     class sqlalchemy.sql.expression.WithinGroup. (see
     sqlalchemy.sql.expression.ColumnElement)

      -- Method: sqlalchemy.sql.expression.WithinGroup..
               __init__ (element, *order_by)

          Construct a new WithinGroup object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.sql.expression.within_group() for a
          full usage and argument description.

      -- Method: sqlalchemy.sql.expression.WithinGroup..over
               (partition_by=None, order_by=None, range_=None,
               rows=None)

          Produce an OVER clause against this WithinGroup
          construct.

          This function has the same signature as that of
          FunctionElement.over().

 -- Class: sqlalchemy.sql.elements.WrapsColumnExpression

     Mixin that defines a ColumnElement as a wrapper with
     special labeling behavior for an expression that already has a
     name.

     New in version 1.4.

     See also
     ........

     See Improved column labeling for simple column expressions using CAST or similar.

 -- Class: sqlalchemy.sql.expression.True_ (*arg, **kw)

     Represent the ‘true’ keyword, or equivalent, in a SQL statement.

     True_ is accessed as a constant via the true()
     function.

     `Class signature'

     class sqlalchemy.sql.expression.True_.
     (‘sqlalchemy.sql.expression.SingletonConstant’,
     ‘sqlalchemy.sql.roles.ConstExprRole’, see
     sqlalchemy.sql.expression.ColumnElement)

 -- Class: sqlalchemy.sql.expression.TypeCoerce (expression, type_)

     Represent a Python-side type-coercion wrapper.

     TypeCoerce supplies the type_coerce()
     function; see that function for usage details.

     Changed in version 1.1: The type_coerce() function now
     produces a persistent TypeCoerce wrapper object rather
     than translating the given object in place.

     See also
     ........

     See type_coerce().

     See cast().

     `Class signature'

     class sqlalchemy.sql.expression.TypeCoerce.
     (‘sqlalchemy.sql.expression.WrapsColumnExpression’, see
     sqlalchemy.sql.expression.ColumnElement)

      -- Method: sqlalchemy.sql.expression.TypeCoerce..
               __init__ (expression, type_)

          Construct a new TypeCoerce object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.sql.expression.type_coerce() for a full
          usage and argument description.

      -- Method: sqlalchemy.sql.expression.TypeCoerce..
               self_group (against=None)

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

 -- Class: sqlalchemy.sql.expression.UnaryExpression (element,
          operator=None, modifier=None, type_=None,
          wraps_column_expression=False)

     Define a ‘unary’ expression.

     A unary expression has a single column expression and an operator.
     The operator can be placed on the left (where it is called the
     ‘operator’) or right (where it is called the ‘modifier’) of the
     column expression.

     UnaryExpression is the basis for several unary
     operators including those used by desc(), asc(),
     see distinct(), nulls_first() and
     nulls_last().

     `Class signature'

     class sqlalchemy.sql.expression.UnaryExpression. (see
     sqlalchemy.sql.expression.ColumnElement)

      -- Method: sqlalchemy.sql.expression.UnaryExpression..
               self_group (against: Optional[Any] = None) ->
               ClauseElement

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

4.2.2 Operator Reference
------------------------

This section details usage of the operators that are available to
construct SQL expressions.

These methods are presented in terms of the Operators and
ColumnOperators base classes.  The methods are then
available on descendants of these classes, including:

   * Column objects

   * ColumnElement objects more generally, which are the
     root of all Core SQL Expression language column-level expressions

   * InstrumentedAttribute objects, which are ORM level
     mapped attributes.

The operators are first introduced in the tutorial sections, including:

   * SQLAlchemy 1.4 / 2.0 Tutorial. - unified tutorial in 2.0
     style

   * Object Relational Tutorial (1.x API). - ORM tutorial in
     1.x style

   * SQL Expression Language Tutorial (1.x API). - Core
     tutorial in 1.x style

4.2.2.1 Comparison Operators
............................

Basic comparisons which apply to many datatypes, including numerics,
strings, dates, and many others:

   * ColumnOperators.__eq__(). (Python “‘==’” operator):

          >>> print(column('x') == 5)
          x = :x_1

   * ColumnOperators.__ne__(). (Python “‘!=’” operator):

          >>> print(column('x') != 5)
          x != :x_1

   * ColumnOperators.__gt__(). (Python “‘>’” operator):

          >>> print(column('x') > 5)
          x > :x_1

   * ColumnOperators.__lt__(). (Python “‘<’” operator):

          >>> print(column('x') < 5)
          x < :x_1

   * ColumnOperators.__ge__(). (Python “‘>=’” operator):

          >>> print(column('x') >= 5)
          x >= :x_1

   * ColumnOperators.__le__(). (Python “‘<=’” operator):

          >>> print(column('x') <= 5)
          x <= :x_1

   * ColumnOperators.between():

          >>> print(column('x').between(5, 10))
          x BETWEEN :x_1 AND :x_2

4.2.2.2 IN Comparisons
......................

The SQL IN operator is a subject all its own in SQLAlchemy.  As the IN
operator is usually used against a list of fixed values, SQLAlchemy’s
feature of bound parameter coercion makes use of a special form of SQL
compilation that renders an interim SQL string for compilation that’s
formed into the final list of bound parameters in a second step.  In
other words, “it just works”.

4.2.2.3 IN against a list of values
...................................

IN is available most typically by passing a list of values to the
ColumnOperators.in_() method:

     >>> print(column('x').in_([1, 2, 3]))
     x IN ([POSTCOMPILE_x_1])

The special bound form ‘POSTCOMPILE’ is rendered into individual
parameters at execution time, illustrated below:

     >>> stmt = select(User.id).where(User.id.in_([1, 2, 3]))
     >>> result = conn.execute(stmt)
     {opensql}SELECT user_account.id
     FROM user_account
     WHERE user_account.id IN (?, ?, ?)
     [...] (1, 2, 3){stop}

4.2.2.4 Empty IN Expressions
............................

SQLAlchemy produces a mathematically valid result for an empty IN
expression by rendering a backend-specific subquery that returns no
rows.  Again in other words, “it just works”:

     >>> stmt = select(User.id).where(User.id.in_([]))
     >>> result = conn.execute(stmt)
     {opensql}SELECT user_account.id
     FROM user_account
     WHERE user_account.id IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)
     [...] ()

The “empty set” subquery above generalizes correctly and is also
rendered in terms of the IN operator which remains in place.

4.2.2.5 NOT IN
..............

“NOT IN” is available via the ColumnOperators.not_in()
operator:

     >>> print(column('x').not_in([1, 2, 3]))
     x NOT IN ([POSTCOMPILE_x_1])

This is typically more easily available by negating with the ‘~’
operator:

     >>> print(~column('x').in_([1, 2, 3]))
     x NOT IN ([POSTCOMPILE_x_1])

4.2.2.6 Tuple IN Expressions
............................

Comparison of tuples to tuples is common with IN, as among other use
cases accommodates for the case when matching rows to a set of potential
composite primary key values.  The tuple_() construct
provides the basic building block for tuple comparisons.  The
‘Tuple.in_()’ operator then receives a list of tuples:

     >>> from sqlalchemy import tuple_
     >>> tup = tuple_(column('x', Integer), column('y', Integer))
     >>> expr = tup.in_([(1, 2), (3, 4)])
     >>> print(expr)
     (x, y) IN ([POSTCOMPILE_param_1])

To illustrate the parameters rendered:

     >>> tup = tuple_(User.id, Address.id)
     >>> stmt = select(User.name).join(Address).where(tup.in_([(1, 1), (2, 2)]))
     >>> conn.execute(stmt).all()
     {opensql}SELECT user_account.name
     FROM user_account JOIN address ON user_account.id = address.user_id
     WHERE (user_account.id, address.id) IN (VALUES (?, ?), (?, ?))
     [...] (1, 1, 2, 2){stop}
     [('spongebob',), ('sandy',)]

4.2.2.7 Subquery IN
...................

Finally, the ColumnOperators.in_() and
ColumnOperators.not_in() operators work with subqueries.  The form
provides that a Select construct is passed in directly,
without any explicit conversion to a named subquery:

     >>> print(column('x').in_(select(user_table.c.id)))
     x IN (SELECT user_account.id
     FROM user_account)

Tuples work as expected:

     >>> print(
     ...     tuple_(column('x'), column('y')).in_(
     ...         select(user_table.c.id, address_table.c.id).join(address_table)
     ...     )
     ... )
     (x, y) IN (SELECT user_account.id, address.id
     FROM user_account JOIN address ON user_account.id = address.user_id)

4.2.2.8 Identity Comparisons
............................

These operators involve testing for special SQL values such as ‘NULL’,
boolean constants such as ‘true’ or ‘false’ which some databases
support:

   * ColumnOperators.is_():

     This operator will provide exactly the SQL for “x IS y”, most often
     seen as “<expr> IS NULL”.  The ‘NULL’ constant is most easily
     acquired using regular Python ‘None’:

          >>> print(column('x').is_(None))
          x IS NULL

     SQL NULL is also explicitly available, if needed, using the
     null() construct:

          >>> from sqlalchemy import null
          >>> print(column('x').is_(null()))
          x IS NULL

     The ColumnOperators.is_() operator is automatically
     invoked when using the ColumnOperators.__eq__()
     overloaded operator, i.e.  ‘==’, in conjunction with the ‘None’ or
     null() value.  In this way, there’s typically not a
     need to use ColumnOperators.is_() explicitly,
     paricularly when used with a dynamic value:

          >>> a = None
          >>> print(column('x') == a)
          x IS NULL

     Note that the Python ‘is’ operator is `not overloaded'.  Even
     though Python provides hooks to overload operators such as ‘==’ and
     ‘!=’, it does `not' provide any way to redefine ‘is’.

   * ColumnOperators.is_not():

     Similar to ColumnOperators.is_(), produces “IS NOT”:

          >>> print(column('x').is_not(None))
          x IS NOT NULL

     Is similarly equivalent to ‘!= None’:

          >>> print(column('x') != None)
          x IS NOT NULL

   * ColumnOperators.is_distinct_from():

     Produces SQL IS DISTINCT FROM:

          >>> print(column('x').is_distinct_from('some value'))
          x IS DISTINCT FROM :x_1

   * ColumnOperators.isnot_distinct_from():

     Produces SQL IS NOT DISTINCT FROM:

          >>> print(column('x').isnot_distinct_from('some value'))
          x IS NOT DISTINCT FROM :x_1

4.2.2.9 String Comparisons
..........................

   * ColumnOperators.like():

          >>> print(column('x').like('word'))
          x LIKE :x_1

   * ColumnOperators.ilike():

     Case insensitive LIKE makes use of the SQL ‘lower()’ function on a
     generic backend.  On the PostgreSQL backend it will use ‘ILIKE’:

          >>> print(column('x').ilike('word'))
          lower(x) LIKE lower(:x_1)

   * ColumnOperators.notlike():

          >>> print(column('x').notlike('word'))
          x NOT LIKE :x_1

   * ColumnOperators.notilike():

          >>> print(column('x').notilike('word'))
          lower(x) NOT LIKE lower(:x_1)

4.2.2.10 String Containment
...........................

String containment operators are basically built as a combination of
LIKE and the string concatenation operator, which is ‘||’ on most
backends or sometimes a function like ‘concat()’:

   * ColumnOperators.startswith():

          The string containment operators
          >>> print(column('x').startswith('word'))
          x LIKE :x_1 || '%'

   * ColumnOperators.endswith():

          >>> print(column('x').endswith('word'))
          x LIKE '%' || :x_1

   * ColumnOperators.contains():

          >>> print(column('x').contains('word'))
          x LIKE '%' || :x_1 || '%'

4.2.2.11 String matching
........................

Matching operators are always backend-specific and may provide different
behaviors and results on different databases:

   * ColumnOperators.match():

     This is a dialect-specific operator that makes use of the MATCH
     feature of the underlying database, if available:

          >>> print(column('x').match('word'))
          x MATCH :x_1

   * ColumnOperators.regexp_match():

     This operator is dialect specific.  We can illustrate it in terms
     of for example the PostgreSQL dialect:

          >>> from sqlalchemy.dialects import postgresql
          >>> print(column('x').regexp_match('word').compile(dialect=postgresql.dialect()))
          x ~ %(x_1)s

     Or MySQL:

          >>> from sqlalchemy.dialects import mysql
          >>> print(column('x').regexp_match('word').compile(dialect=mysql.dialect()))
          x REGEXP %s

4.2.2.12 String Alteration
..........................

   * ColumnOperators.concat():

     String concatenation:

          >>> print(column('x').concat("some string"))
          x || :x_1

     This operator is available via ColumnOperators.__add__(),
     that is, the Python ‘+’ operator, when working with a column
     expression that derives from String:

          >>> print(column('x', String) + "some string")
          x || :x_1

     The operator will produce the appropriate database-specific
     construct, such as on MySQL it’s historically been the ‘concat()’
     SQL function:

          >>> print((column('x', String) + "some string").compile(dialect=mysql.dialect()))
          concat(x, %s)

   * ColumnOperators.regexp_replace():

     Complementary to ‘ColumnOperators.regexp()’ this produces REGEXP
     REPLACE equivalent for the backends which support it:

          >>> print(column('x').regexp_replace('foo', 'bar').compile(dialect=postgresql.dialect()))
          REGEXP_REPLACE(x, %(x_1)s, %(x_2)s)

   * ColumnOperators.collate():

     Produces the COLLATE SQL operator which provides for specific
     collations at expression time:

          >>> print((column('x').collate('latin1_german2_ci') == 'Müller').compile(dialect=mysql.dialect()))
          (x COLLATE latin1_german2_ci) = %s

     To use COLLATE against a literal value, use the literal()
     construct:

          >>> from sqlalchemy import literal
          >>> print((literal('Müller').collate('latin1_german2_ci') == column('x')).compile(dialect=mysql.dialect()))
          (%s COLLATE latin1_german2_ci) = x

4.2.2.13 Arithmetic Operators
.............................

   * ColumnOperators.__add__(),
     ColumnOperators.__radd__(). (Python “‘+’” operator):

          >>> print(column('x') + 5)
          x + :x_1

          >>> print(5 + column('x'))
          :x_1 + x

     Note that when the datatype of the expression is String
     or similar, the ColumnOperators.__add__() operator
     instead produces string concatenation.

   * ColumnOperators.__sub__(),
     ColumnOperators.__rsub__(). (Python “‘-’” operator):

          >>> print(column('x') - 5)
          x - :x_1

          >>> print(5 - column('x'))
          :x_1 - x

   * ColumnOperators.__mul__(),
     ColumnOperators.__rmul__(). (Python “‘*’” operator):

          >>> print(column('x') * 5)
          x * :x_1

          >>> print(5 * column('x'))
          :x_1 * x

   * ColumnOperators.__div__(),
     ColumnOperators.__rdiv__(). (Python “‘/’” operator):

          >>> print(column('x') / 5)
          x / :x_1
          >>> print(5 / column('x'))
          :x_1 / x

   * ColumnOperators.__mod__(),
     ColumnOperators.__rmod__(). (Python “‘%’” operator):

          >>> print(column('x') % 5)
          x % :x_1
          >>> print(5 % column('x'))
          :x_1 % x

4.2.2.14 Using Conjunctions and Negations
.........................................

The most common conjunction, “AND”, is automatically applied if we make
repeated use of the Select.where() method, as well as similar
methods such as Update.where() and Delete.where():

     >>> print(
     ...        select(address_table.c.email_address).
     ...        where(user_table.c.name == 'squidward').
     ...        where(address_table.c.user_id == user_table.c.id)
     ...    )
     SELECT address.email_address
     FROM address, user_account
     WHERE user_account.name = :name_1 AND address.user_id = user_account.id

See Select.where(), Update.where() and
Delete.where() also accept multiple expressions with the same
effect:

     >>> print(
     ...        select(address_table.c.email_address).
     ...        where(
     ...            user_table.c.name == 'squidward',
     ...            address_table.c.user_id == user_table.c.id
     ...        )
     ...    )
     SELECT address.email_address
     FROM address, user_account
     WHERE user_account.name = :name_1 AND address.user_id = user_account.id

The “AND” conjunction, as well as its partner “OR”, are both available
directly using the and_() and or_() functions:

     >>> from sqlalchemy import and_, or_
     >>> print(
     ...     select(address_table.c.email_address).
     ...     where(
     ...         and_(
     ...             or_(user_table.c.name == 'squidward', user_table.c.name == 'sandy'),
     ...             address_table.c.user_id == user_table.c.id
     ...         )
     ...     )
     ... )
     SELECT address.email_address
     FROM address, user_account
     WHERE (user_account.name = :name_1 OR user_account.name = :name_2)
     AND address.user_id = user_account.id

A negation is available using the not_() function.  This
will typically invert the operator in a boolean expression:

     >>> from sqlalchemy import not_
     >>> print(not_(column('x') == 5))
     x != :x_1

It also may apply a keyword such as ‘NOT’ when appropriate:

     >>> from sqlalchemy import Boolean
     >>> print(not_(column('x', Boolean)))
     NOT x

4.2.2.15 Conjunction Operators
..............................

The above conjunction functions and_(), or_(),
not_() are also available as overloaded Python operators:

     Note: The Python ‘&’, ‘|’ and ‘~’ operators take high precedence in
     the language; as a result, parenthesis must usually be applied for
     operands that themselves contain expressions, as indicated in the
     examples below.

   * Operators.__and__(). (Python “‘&’” operator):

     The Python binary ‘&’ operator is overloaded to behave the same as
     and_(). (note parenthesis around the two operands):

          >>> print((column('x') == 5) & (column('y') == 10))
          x = :x_1 AND y = :y_1

   * Operators.__or__(). (Python “‘|’” operator):

     The Python binary ‘|’ operator is overloaded to behave the same as
     or_(). (note parenthesis around the two operands):

          >>> print((column('x') == 5) | (column('y') == 10))
          x = :x_1 OR y = :y_1

   * Operators.__invert__(). (Python “‘~’” operator):

     The Python binary ‘~’ operator is overloaded to behave the same as
     not_(), either inverting the existing operator, or
     applying the ‘NOT’ keyword to the expression as a whole:

          >>> print(~(column('x') == 5))
          x != :x_1

          >>> from sqlalchemy import Boolean
          >>> print(~column('x', Boolean))
          NOT x

4.2.2.16 Operator Customization
...............................

TODO

4.2.3 Selectables, Tables, FROM objects
---------------------------------------

The term “selectable” refers to any object that rows can be selected
from; in SQLAlchemy, these objects descend from FromClause
and their distinguishing feature is their FromClause.c
attribute, which is a namespace of all the columns contained within the
FROM clause (these elements are themselves ColumnElement
subclasses).

4.2.3.1 Selectable Foundational Constructors
............................................

Top level “FROM clause” and “SELECT” constructors.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See except_.(*selects,Return an ‘EXCEPT’ of multiple selectables.
**kwargs)

See except_all.(*selects,Return an ‘EXCEPT ALL’ of multiple selectables.
**kwargs)

See exists.(*args,Construct a new Exists construct.
**kwargs)

See intersect.(*selects,Return an ‘INTERSECT’ of multiple selectables.
**kwargs)

See intersect_all.(*selects,Return an ‘INTERSECT ALL’ of multiple selectables.
**kwargs)

See select.(*args,Create a Select using either the 1.x or 2.0 constructor style.
**kw)

See table.(name,Produce a new TableClause.
*columns,
**kw)

See union.(*selects,Return a ‘UNION’ of multiple selectables.
**kwargs)

See union_all.(*selects,Return a ‘UNION ALL’ of multiple selectables.
**kwargs)

See values.(*columns,Construct a Values construct.
**kw)

 -- Function: sqlalchemy.sql.expression.except_ (*selects, **kwargs)

     Return an ‘EXCEPT’ of multiple selectables.

     The returned object is an instance of CompoundSelect.

     Parameters:

        * ‘*selects’ – a list of Select instances.

        * ‘**kwargs’ – available keyword arguments are the same as those
          of select().

 -- Function: sqlalchemy.sql.expression.except_all (*selects, **kwargs)

     Return an ‘EXCEPT ALL’ of multiple selectables.

     The returned object is an instance of CompoundSelect.

     Parameters:

        * ‘*selects’ – a list of Select instances.

        * ‘**kwargs’ – available keyword arguments are the same as those
          of select().

 -- Function: sqlalchemy.sql.expression.exists (*args, **kwargs)

     Construct a new Exists construct.

     The exists() can be invoked by itself to produce an
     Exists construct, which will accept simple WHERE
     criteria:

          exists_criteria = exists().where(table1.c.col1 == table2.c.col2)

     However, for greater flexibility in constructing the SELECT, an
     existing Select construct may be converted to an
     Exists, most conveniently by making use of the
     SelectBase.exists() method:

          exists_criteria = (
              select(table2.c.col2).
              where(table1.c.col1 == table2.c.col2).
              exists()
          )

     The EXISTS criteria is then used inside of an enclosing SELECT:

          stmt = select(table1.c.col1).where(exists_criteria)

     The above statement will then be of the form:

          SELECT col1 FROM table1 WHERE EXISTS
          (SELECT table2.col2 FROM table2 WHERE table2.col2 = table1.col1)

     See also
     ........

     See EXISTS subqueries. - in the 2.0 style tutorial.

 -- Function: sqlalchemy.sql.expression.intersect (*selects, **kwargs)

     Return an ‘INTERSECT’ of multiple selectables.

     The returned object is an instance of CompoundSelect.

     Parameters:

        * ‘*selects’ – a list of Select instances.

        * ‘**kwargs’ – available keyword arguments are the same as those
          of select().

 -- Function: sqlalchemy.sql.expression.intersect_all (*selects,
          **kwargs)

     Return an ‘INTERSECT ALL’ of multiple selectables.

     The returned object is an instance of CompoundSelect.

     Parameters:

        * ‘*selects’ – a list of Select instances.

        * ‘**kwargs’ – available keyword arguments are the same as those
          of select().

 -- Function: sqlalchemy.sql.expression.select (*args, **kw)

     Create a Select using either the 1.x or 2.0 constructor
     style.

     For the legacy calling style, see
     Select.create_legacy_select().  If the first argument passed
     is a Python sequence or if keyword arguments are present, this
     style is used.

     New in version 2.0: - the select() construct is the
     same construct as the one returned by select(), except
     that the function only accepts the “columns clause” entities up
     front; the rest of the state of the SELECT should be built up using
     generative methods.

     Similar functionality is also available via the
     FromClause.select() method on any FromClause.

     See also
     ........

     See Selecting. - Core Tutorial description of
     select().

     Parameters: ‘*entities’ – Entities to SELECT from.  For Core usage,
     this is typically a series of ColumnElement and / or
     FromClause objects which will form the columns clause of
     the resulting statement.  For those objects that are instances of
     FromClause. (typically Table or Alias
     objects), the FromClause.c collection is extracted
     to form a collection of ColumnElement objects.

     This parameter will also accept TextClause constructs
     as given, as well as ORM-mapped classes.

 -- Function: sqlalchemy.sql.expression.table (name, *columns, **kw)

     Produce a new TableClause.

     The object returned is an instance of TableClause, which
     represents the “syntactical” portion of the schema-level
     Table object.  It may be used to construct lightweight table
     constructs.

     Changed in version 1.0.0: table() can now be imported
     from the plain ‘sqlalchemy’ namespace like any other SQL element.

     Parameters:

        * ‘name’ – Name of the table.

        * ‘columns’ – A collection of column() constructs.

        * ‘schema’ – The schema name for this table.

          New in version 1.3.18: table() can now accept a
          ‘schema’ argument.

 -- Function: sqlalchemy.sql.expression.union (*selects, **kwargs)

     Return a ‘UNION’ of multiple selectables.

     The returned object is an instance of CompoundSelect.

     A similar union() method is available on all
     FromClause subclasses.

     Parameters:

        * ‘*selects’ – a list of Select instances.

        * ‘**kwargs’ – available keyword arguments are the same as those
          of select().

 -- Function: sqlalchemy.sql.expression.union_all (*selects, **kwargs)

     Return a ‘UNION ALL’ of multiple selectables.

     The returned object is an instance of CompoundSelect.

     A similar union_all() method is available on all
     FromClause subclasses.

     Parameters:

        * ‘*selects’ – a list of Select instances.

        * ‘**kwargs’ – available keyword arguments are the same as those
          of select().

 -- Function: sqlalchemy.sql.expression.values (*columns, **kw)

     Construct a Values construct.

     The column expressions and the actual data for Values
     are given in two separate steps.  The constructor receives the
     column expressions typically as column() constructs,
     and the data is then passed via the Values.data()
     method as a list, which can be called multiple times to add more
     data, e.g.:

          from sqlalchemy import column
          from sqlalchemy import values

          value_expr = values(
              column('id', Integer),
              column('name', String),
              name="my_values"
          ).data(
              [(1, 'name1'), (2, 'name2'), (3, 'name3')]
          )

     Parameters:

        * ‘*columns’ – column expressions, typically composed using
          column() objects.

        * ‘name’ – the name for this VALUES construct.  If omitted, the
          VALUES construct will be unnamed in a SQL expression.
          Different backends may have different requirements here.

        * ‘literal_binds’ – Defaults to False.  Whether or not to render
          the data values inline in the SQL output, rather than using
          bound parameters.

4.2.3.2 Selectable Modifier Constructors
........................................

Functions listed here are more commonly available as methods from
FromClause and Selectable elements, for example, the
alias() function is usually invoked via the
FromClause.alias() method.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See alias.(selectable[,Return an Alias object.
name, flat])

See cte.(selectable[,Return a new CTE, or Common Table Expression instance.
name,
recursive])

See join.(left,Produce a Join object, given two FromClause expressions.
right[,
onclause,
isouter,
...])

See lateral.(selectable[,Return a Lateral object.
name])

See outerjoin.(left,Return an ‘OUTER JOIN’ clause element.
right[,
onclause,
full])

See tablesample.(selectable,Return a TableSample object.
sampling[,
name, seed])

 -- Function: sqlalchemy.sql.expression.alias (selectable, name=None,
          flat=False)

     Return an Alias object.

     An Alias represents any FromClause with an
     alternate name assigned within SQL, typically using the ‘AS’ clause
     when generated, e.g.  ‘SELECT * FROM table AS aliasname’.

     Similar functionality is available via the
     FromClause.alias() method available on all FromClause
     subclasses.  In terms of a SELECT object as generated from the
     select() function, the SelectBase.alias()
     method returns an Alias or similar object which
     represents a named, parenthesized subquery.

     When an Alias is created from a Table
     object, this has the effect of the table being rendered as
     ‘tablename AS aliasname’ in a SELECT statement.

     For select() objects, the effect is that of creating a
     named subquery, i.e.  ‘(select ...) AS aliasname’.

     The ‘name’ parameter is optional, and provides the name to use in
     the rendered SQL. If blank, an “anonymous” name will be
     deterministically generated at compile time.  Deterministic means
     the name is guaranteed to be unique against other constructs used
     in the same statement, and will also be the same name for each
     successive compilation of the same statement object.

     Parameters:

        * ‘selectable’ – any FromClause subclass, such as a
          table, select statement, etc.

        * ‘name’ – string name to be assigned as the alias.  If ‘None’,
          a name will be deterministically generated at compile time.

        * ‘flat’ – Will be passed through to if the given selectable is
          an instance of Join. - see Join.alias()
          for details.

 -- Function: sqlalchemy.sql.expression.cte (selectable, name=None,
          recursive=False)

     Return a new CTE, or Common Table Expression instance.

     Please see HasCTE.cte() for detail on CTE usage.

 -- Function: sqlalchemy.sql.expression.join (left, right,
          onclause=None, isouter=False, full=False)

     Produce a Join object, given two FromClause
     expressions.

     E.g.:

          j = join(user_table, address_table,
                   user_table.c.id == address_table.c.user_id)
          stmt = select(user_table).select_from(j)

     would emit SQL along the lines of:

          SELECT user.id, user.name FROM user
          JOIN address ON user.id = address.user_id

     Similar functionality is available given any FromClause
     object (e.g.  such as a Table) using the
     FromClause.join() method.

     Parameters:

        * ‘left’ – The left side of the join.

        * ‘right’ – the right side of the join; this is any
          FromClause object such as a Table object, and
          may also be a selectable-compatible object such as an
          ORM-mapped class.

        * ‘onclause’ – a SQL expression representing the ON clause of
          the join.  If left at ‘None’, see FromClause.join()
          will attempt to join the two tables based on a foreign key
          relationship.

        * ‘isouter’ – if True, render a LEFT OUTER JOIN, instead of
          JOIN.

        * ‘full’ – if True, render a FULL OUTER JOIN, instead of JOIN.

          New in version 1.1.

     See also
     ........

     See FromClause.join(). - method form, based on a given left
     side.

     See Join. - the type of object produced.

 -- Function: sqlalchemy.sql.expression.lateral (selectable, name=None)

     Return a Lateral object.

     Lateral is an Alias subclass that
     represents a subquery with the LATERAL keyword applied to it.

     The special behavior of a LATERAL subquery is that it appears in
     the FROM clause of an enclosing SELECT, but may correlate to other
     FROM clauses of that SELECT. It is a special case of subquery only
     supported by a small number of backends, currently more recent
     PostgreSQL versions.

     New in version 1.1.

     See also
     ........

     See LATERAL correlation. - overview of usage.

 -- Function: sqlalchemy.sql.expression.outerjoin (left, right,
          onclause=None, full=False)

     Return an ‘OUTER JOIN’ clause element.

     The returned object is an instance of Join.

     Similar functionality is also available via the
     FromClause.outerjoin() method on any FromClause.

     Parameters:

        * ‘left’ – The left side of the join.

        * ‘right’ – The right side of the join.

        * ‘onclause’ – Optional criterion for the ‘ON’ clause, is
          derived from foreign key relationships established between
          left and right otherwise.

     To chain joins together, use the FromClause.join() or
     FromClause.outerjoin() methods on the resulting
     Join object.

 -- Function: sqlalchemy.sql.expression.tablesample (selectable,
          sampling, name=None, seed=None)

     Return a TableSample object.

     TableSample is an Alias subclass that
     represents a table with the TABLESAMPLE clause applied to it.
     tablesample() is also available from the
     FromClause class via the FromClause.tablesample()
     method.

     The TABLESAMPLE clause allows selecting a randomly selected
     approximate percentage of rows from a table.  It supports multiple
     sampling methods, most commonly BERNOULLI and SYSTEM.

     e.g.:

          from sqlalchemy import func

          selectable = people.tablesample(
                      func.bernoulli(1),
                      name='alias',
                      seed=func.random())
          stmt = select(selectable.c.people_id)

     Assuming ‘people’ with a column ‘people_id’, the above statement
     would render as:

          SELECT alias.people_id FROM
          people AS alias TABLESAMPLE bernoulli(:bernoulli_1)
          REPEATABLE (random())

     New in version 1.1.

     Parameters:

        * ‘sampling’ – a ‘float’ percentage between 0 and 100 or
          Function.

        * ‘name’ – optional alias name

        * ‘seed’ – any real-valued SQL expression.  When specified, the
          REPEATABLE sub-clause is also rendered.

4.2.3.3 Selectable Class Documentation
......................................

The classes here are generated using the constructors listed at
Selectable Foundational Constructors and Selectable Modifier Constructors.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See Alias.Represents an table or selectable alias (AS).

See AliasedReturnsRows.Base class of aliases against tables, subqueries, and other selectables.

See CompoundSelect.Forms the basis of ‘UNION’, ‘UNION ALL’, and other SELECT-based set operations.

See CTE.Represent a Common Table Expression.

See Executable.Mark a ClauseElement as supporting execution.

See Exists.Represent an ‘EXISTS’ clause.

See FromClause.Represent an element that can be used within the ‘FROM’ clause of a ‘SELECT’ statement.

See GenerativeSelect.Base class for SELECT statements where additional elements can be added.

See HasCTE.Mixin that declares a class to include CTE support.

See HasPrefixes.

See HasSuffixes.

See Join.Represent a ‘JOIN’ construct between two FromClause elements.

See Lateral.Represent a LATERAL subquery.

See ReturnsRows.The base-most class for Core constructs that have some concept of columns that can represent
               rows.

See ScalarSelect.Represent a scalar subquery.

See Select.Represents a ‘SELECT’ statement.

See Selectable.Mark a class as being selectable.

See SelectBase.Base class for SELECT statements.

See Subquery.Represent a subquery of a SELECT.

See TableClause.Represents a minimal “table” construct.

See TableSample.Represent a TABLESAMPLE clause.

See TableValuedAlias.An alias against a “table valued” SQL function.

See TextualSelect.Wrap a TextClause construct within a SelectBase interface.

See Values.Represent a ‘VALUES’ construct that can be used as a FROM element in a statement.

 -- Class: sqlalchemy.sql.expression.Alias (*arg, **kw)

     Represents an table or selectable alias (AS).

     Represents an alias, as typically applied to any table or
     sub-select within a SQL statement using the ‘AS’ keyword (or
     without the keyword on certain databases such as Oracle).

     This object is constructed from the alias() module
     level function as well as the FromClause.alias() method
     available on all FromClause subclasses.

     See also
     ........

     See FromClause.alias().

     `Class signature'

     class sqlalchemy.sql.expression.Alias.
     (‘sqlalchemy.sql.roles.DMLTableRole’, see
     sqlalchemy.sql.expression.AliasedReturnsRows)

 -- Class: sqlalchemy.sql.expression.AliasedReturnsRows (*arg, **kw)

     Base class of aliases against tables, subqueries, and other
     selectables.

     `Class signature'

     class sqlalchemy.sql.expression.AliasedReturnsRows.
     (‘sqlalchemy.sql.expression.NoInit’, see
     sqlalchemy.sql.expression.FromClause)

      -- Attribute: sqlalchemy.sql.expression.AliasedReturnsRows..
               description

      -- Method: sqlalchemy.sql.expression.AliasedReturnsRows..
               is_derived_from (fromclause)

          Return ‘True’ if this FromClause is ‘derived’ from
          the given ‘FromClause’.

          An example would be an Alias of a Table is derived from that
          Table.

      -- Attribute: sqlalchemy.sql.expression.AliasedReturnsRows..
               original

          Legacy for dialects that are referring to Alias.original.

 -- Class: sqlalchemy.sql.expression.CompoundSelect (keyword, *selects,
          **kwargs)

     Forms the basis of ‘UNION’, ‘UNION ALL’, and other SELECT-based set
     operations.

     See also
     ........

     See union().

     See union_all().

     See intersect().

     See intersect_all().

     ‘except()’

     See except_all().

     `Class signature'

     class sqlalchemy.sql.expression.CompoundSelect.
     (‘sqlalchemy.sql.expression.HasCompileState’, see
     sqlalchemy.sql.expression.GenerativeSelect)

      -- Attribute: sqlalchemy.sql.expression.CompoundSelect..
               bind

          Returns the Engine or Connection to
          which this Executable is bound, or None if none
          found.

          Deprecated since version 1.4: The Executable.bind
          attribute is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  Bound metadata is
          being removed as of SQLAlchemy 2.0.  (Background on SQLAlchemy
          2.0 at: Migrating to SQLAlchemy 2.0)

      -- Attribute: sqlalchemy.sql.expression.CompoundSelect..
               selected_columns

          A ColumnCollection representing the columns that
          this SELECT statement or similar construct returns in its
          result set.

          For a CompoundSelect, the
          CompoundSelect.selected_columns attribute returns the
          selected columns of the first SELECT statement contained
          within the series of statements within the set operation.

          New in version 1.4.

      -- Method: sqlalchemy.sql.expression.CompoundSelect..
               self_group (against: Optional[Any] = None) ->
               FromClause

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

 -- Class: sqlalchemy.sql.expression.CTE (*arg, **kw)

     Represent a Common Table Expression.

     The CTE object is obtained using the
     SelectBase.cte() method from any SELECT statement.  A less
     often available syntax also allows use of the HasCTE.cte()
     method present on DML constructs such as Insert,
     Update and Delete.  See the
     HasCTE.cte() method for usage details on CTEs.

     See also
     ........

     See Subqueries and CTEs. - in the 2.0 tutorial

     See HasCTE.cte(). - examples of calling styles

     `Class signature'

     class sqlalchemy.sql.expression.CTE.
     (‘sqlalchemy.sql.expression.Generative’, see
     sqlalchemy.sql.expression.HasPrefixes,
     sqlalchemy.sql.expression.HasSuffixes,
     sqlalchemy.sql.expression.AliasedReturnsRows)

      -- Method: sqlalchemy.sql.expression.CTE..alias
               (name=None, flat=False)

          Return an Alias of this CTE.

          This method is a CTE-specific specialization of the
          FromClause.alias() method.

          See also
          ........

          See Using Aliases and Subqueries.

          See alias().

 -- Class: sqlalchemy.sql.expression.Executable

     Mark a ClauseElement as supporting execution.

     Executable is a superclass for all “statement” types of
     objects, including select(), delete(),
     update(), insert(), text().

     `Class signature'

     class sqlalchemy.sql.expression.Executable.
     (‘sqlalchemy.sql.roles.CoerceTextStatementRole’,
     ‘sqlalchemy.sql.expression.Generative’)

      -- Attribute: sqlalchemy.sql.expression.Executable..
               bind

          Returns the Engine or Connection to
          which this Executable is bound, or None if none
          found.

          Deprecated since version 1.4: The Executable.bind
          attribute is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  Bound metadata is
          being removed as of SQLAlchemy 2.0.  (Background on SQLAlchemy
          2.0 at: Migrating to SQLAlchemy 2.0)

          This is a traversal which checks locally, then checks among
          the “from” clauses of associated objects until a bound engine
          or connection is found.

      -- Method: sqlalchemy.sql.expression.Executable..
               execute (*multiparams, **params)

          Compile and execute this Executable.

          Deprecated since version 1.4: The Executable.execute()
          method is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  All statement
          execution in SQLAlchemy 2.0 is performed by the
          Connection.execute() method of Connection, or
          in the ORM by the Session.execute() method of
          Session.  (Background on SQLAlchemy 2.0 at:
          Migrating to SQLAlchemy 2.0)

      -- Method: sqlalchemy.sql.expression.Executable..
               execution_options (**kw)

          Set non-SQL options for the statement which take effect during
          execution.

          Execution options can be set on a per-statement or per
          Connection basis.  Additionally, the Engine
          and ORM ‘Query’ objects provide access to execution options
          which they in turn configure upon connections.

          The execution_options() method is generative.  A
          new instance of this statement is returned that contains the
          options:

               statement = select(table.c.x, table.c.y)
               statement = statement.execution_options(autocommit=True)

          Note that only a subset of possible execution options can be
          applied to a statement - these include “autocommit” and
          “stream_results”, but not “isolation_level” or
          “compiled_cache”.  See Connection.execution_options()
          for a full list of possible options.

          See also
          ........

          See Connection.execution_options().

          See Query.execution_options().

          See Executable.get_execution_options().

      -- Method: sqlalchemy.sql.expression.Executable..
               get_execution_options ()

          Get the non-SQL options which will take effect during
          execution.

          New in version 1.3.

          See also
          ........

          See Executable.execution_options().

      -- Method: sqlalchemy.sql.expression.Executable..
               options (*options)

          Apply options to this statement.

          In the general sense, options are any kind of Python object
          that can be interpreted by the SQL compiler for the statement.
          These options can be consumed by specific dialects or specific
          kinds of compilers.

          The most commonly known kind of option are the ORM level
          options that apply “eager load” and other loading behaviors to
          an ORM query.  However, options can theoretically be used for
          many other purposes.

          For background on specific kinds of options for specific kinds
          of statements, refer to the documentation for those option
          objects.

          Changed in version 1.4: - added ‘Generative.options()’ to Core
          statement objects towards the goal of allowing unified Core /
          ORM querying capabilities.

          See also
          ........

          See Deferred Column Loader Query Options. - refers to
          options specific to the usage of ORM queries

          See Relationship Loading with Loader Options. - refers
          to options specific to the usage of ORM queries

      -- Method: sqlalchemy.sql.expression.Executable..scalar
               (*multiparams, **params)

          Compile and execute this Executable, returning the
          result’s scalar representation.

          Deprecated since version 1.4: The Executable.scalar()
          method is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  Scalar execution in
          SQLAlchemy 2.0 is performed by the Connection.scalar()
          method of Connection, or in the ORM by the
          Session.scalar() method of Session.
          (Background on SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

 -- Class: sqlalchemy.sql.expression.Exists (*args, **kwargs)

     Represent an ‘EXISTS’ clause.

     See exists() for a description of usage.

     `Class signature'

     class sqlalchemy.sql.expression.Exists. (see
     sqlalchemy.sql.expression.UnaryExpression)

      -- Method: sqlalchemy.sql.expression.Exists..__init__
               (*args, **kwargs)

          Construct a new Exists object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.sql.expression.exists() for a full
          usage and argument description.

      -- Method: sqlalchemy.sql.expression.Exists..correlate
               (*fromclause)

          Apply correlation to the subquery noted by this Exists.

          See also
          ........

          See ScalarSelect.correlate().

      -- Method: sqlalchemy.sql.expression.Exists..
               correlate_except (*fromclause)

          Apply correlation to the subquery noted by this Exists.

          See also
          ........

          See ScalarSelect.correlate_except().

      -- Method: sqlalchemy.sql.expression.Exists..select
               (whereclause=None, **kwargs)

          Return a SELECT of this Exists.

          e.g.:

               stmt = exists(some_table.c.id).where(some_table.c.id == 5).select()

          This will produce a statement resembling:

               SELECT EXISTS (SELECT id FROM some_table WHERE some_table = :param) AS anon_1

          Parameters:

             * ‘whereclause’ – a WHERE clause, equivalent to calling the
               Select.where() method.

               Deprecated since version 1.4: The
               Exists.select().whereclause parameter is deprecated
               and will be removed in version 2.0.  Please make use of
               the Select.where() method to add WHERE
               criteria to the SELECT statement.

             * ‘**kwargs’ – additional keyword arguments are passed to
               the legacy constructor for Select described at
               Select.create_legacy_select().

               Deprecated since version 1.4: The Exists.select()
               method will no longer accept keyword arguments in
               version 2.0.  Please use generative methods from the
               Select construct in order to apply additional
               modifications.

          See also
          ........

          See select(). - general purpose method which allows for
          arbitrary column lists.

      -- Method: sqlalchemy.sql.expression.Exists..
               select_from (*froms)

          Return a new Exists construct, applying the given
          expression to the Select.select_from() method of
          the select statement contained.

               Note: it is typically preferable to build a Select
               statement first, including the desired WHERE clause,
               then use the SelectBase.exists() method to
               produce an Exists object at once.

      -- Method: sqlalchemy.sql.expression.Exists..where
               (clause)

          Return a new exists() construct with the given
          expression added to its WHERE clause, joined to the existing
          clause via AND, if any.

               Note: it is typically preferable to build a Select
               statement first, including the desired WHERE clause,
               then use the SelectBase.exists() method to
               produce an Exists object at once.

 -- Class: sqlalchemy.sql.expression.FromClause

     Represent an element that can be used within the ‘FROM’ clause of a
     ‘SELECT’ statement.

     The most common forms of FromClause are the Table
     and the select() constructs.  Key features common to
     all FromClause objects include:

        * a c collection, which provides per-name access to
          a collection of ColumnElement objects.

        * a primary_key attribute, which is a collection of
          all those ColumnElement objects that indicate the
          ‘primary_key’ flag.

        * Methods to generate various derivations of a “from” clause,
          including FromClause.alias(),
          FromClause.join(), FromClause.select().

     `Class signature'

     class sqlalchemy.sql.expression.FromClause.
     (‘sqlalchemy.sql.roles.AnonymizedFromClauseRole’, see
     sqlalchemy.sql.expression.Selectable)

      -- Method: sqlalchemy.sql.expression.FromClause..alias
               (name=None, flat=False)

          Return an alias of this FromClause.

          E.g.:

               a2 = some_table.alias('a2')

          The above code creates an Alias object which can
          be used as a FROM clause in any SELECT statement.

          See also
          ........

          See Using Aliases and Subqueries.

          See alias().

      -- Attribute: sqlalchemy.sql.expression.FromClause..c

          A named-based collection of ColumnElement objects
          maintained by this FromClause.

          The FromClause.c attribute is an alias for the
          FromClause.columns atttribute.

          Returns: a ColumnCollection.

      -- Attribute: sqlalchemy.sql.expression.FromClause..
               columns

          A named-based collection of ColumnElement objects
          maintained by this FromClause.

          The columns, or c collection, is the
          gateway to the construction of SQL expressions using
          table-bound or other selectable-bound columns:

               select(mytable).where(mytable.c.somecolumn == 5)

          Returns: a ColumnCollection object.

      -- Attribute: sqlalchemy.sql.expression.FromClause..
               description

          A brief description of this FromClause.

          Used primarily for error message formatting.

      -- Attribute: sqlalchemy.sql.expression.FromClause..
               entity_namespace

          Return a namespace used for name-based access in SQL
          expressions.

          This is the namespace that is used to resolve “filter_by()”
          type expressions, such as:

               stmt.filter_by(address='some address')

          It defaults to the ‘.c’ collection, however internally it can
          be overridden using the “entity_namespace” annotation to
          deliver alternative results.

      -- Attribute: sqlalchemy.sql.expression.FromClause..
               exported_columns

          A ColumnCollection that represents the “exported”
          columns of this Selectable.

          The “exported” columns for a FromClause object are
          synonymous with the FromClause.columns collection.

          New in version 1.4.

          See also
          ........

          See Selectable.exported_columns.

          See SelectBase.exported_columns.

      -- Attribute: sqlalchemy.sql.expression.FromClause..
               foreign_keys

          Return the collection of ForeignKey marker objects
          which this FromClause references.

          Each ForeignKey is a member of a Table.
          -wide ForeignKeyConstraint.

          See also
          ........

          See Table.foreign_key_constraints.

      -- Method: sqlalchemy.sql.expression.FromClause..
               is_derived_from (fromclause)

          Return ‘True’ if this FromClause is ‘derived’ from
          the given ‘FromClause’.

          An example would be an Alias of a Table is derived from that
          Table.

      -- Method: sqlalchemy.sql.expression.FromClause..join
               (right, onclause=None, isouter=False, full=False)

          Return a Join from this FromClause to
          another FromClause.

          E.g.:

               from sqlalchemy import join

               j = user_table.join(address_table,
                               user_table.c.id == address_table.c.user_id)
               stmt = select(user_table).select_from(j)

          would emit SQL along the lines of:

               SELECT user.id, user.name FROM user
               JOIN address ON user.id = address.user_id

          Parameters:

             * ‘right’ – the right side of the join; this is any
               FromClause object such as a Table object,
               and may also be a selectable-compatible object such as an
               ORM-mapped class.

             * ‘onclause’ – a SQL expression representing the ON clause
               of the join.  If left at ‘None’, see FromClause.join()
               will attempt to join the two tables based on a
               foreign key relationship.

             * ‘isouter’ – if True, render a LEFT OUTER JOIN, instead of
               JOIN.

             * ‘full’ – if True, render a FULL OUTER JOIN, instead of
               LEFT OUTER JOIN. Implies FromClause.join.isouter.

               New in version 1.1.

          See also
          ........

          See join(). - standalone function

          See Join. - the type of object produced

      -- Method: sqlalchemy.sql.expression.FromClause..
               outerjoin (right, onclause=None, full=False)

          Return a Join from this FromClause to
          another FromClause, with the “isouter” flag set to
          True.

          E.g.:

               from sqlalchemy import outerjoin

               j = user_table.outerjoin(address_table,
                               user_table.c.id == address_table.c.user_id)

          The above is equivalent to:

               j = user_table.join(
                   address_table,
                   user_table.c.id == address_table.c.user_id,
                   isouter=True)

          Parameters:

             * ‘right’ – the right side of the join; this is any
               FromClause object such as a Table object,
               and may also be a selectable-compatible object such as an
               ORM-mapped class.

             * ‘onclause’ – a SQL expression representing the ON clause
               of the join.  If left at ‘None’, see FromClause.join()
               will attempt to join the two tables based on a
               foreign key relationship.

             * ‘full’ – if True, render a FULL OUTER JOIN, instead of
               LEFT OUTER JOIN.

               New in version 1.1.

          See also
          ........

          See FromClause.join().

          See Join.

      -- Attribute: sqlalchemy.sql.expression.FromClause..
               primary_key

          Return the iterable collection of Column objects
          which comprise the primary key of this
          ‘_selectable.FromClause’.

          For a Table object, this collection is represented
          by the PrimaryKeyConstraint which itself is an
          iterable collection of Column objects.

      -- Attribute: sqlalchemy.sql.expression.FromClause..
               schema = None

          Define the ‘schema’ attribute for this FromClause.

          This is typically ‘None’ for most objects except that of
          Table, where it is taken as the value of the
          Table.schema argument.

      -- Method: sqlalchemy.sql.expression.FromClause..select
               (whereclause=None, **kwargs)

          Return a SELECT of this FromClause.

          e.g.:

               stmt = some_table.select().where(some_table.c.id == 5)

          Parameters:

             * ‘whereclause’ – a WHERE clause, equivalent to calling the
               Select.where() method.

               Deprecated since version 1.4: The
               FromClause.select().whereclause parameter is
               deprecated and will be removed in version 2.0.  Please
               make use of the Select.where() method to add
               WHERE criteria to the SELECT statement.

             * ‘**kwargs’ – additional keyword arguments are passed to
               the legacy constructor for Select described at
               Select.create_legacy_select().

          See also
          ........

          See select(). - general purpose method which allows for
          arbitrary column lists.

      -- Method: sqlalchemy.sql.expression.FromClause..
               table_valued ()

          Return a ‘TableValuedColumn’ object for this FromClause.

          A ‘TableValuedColumn’ is a ColumnElement that
          represents a complete row in a table.  Support for this
          construct is backend dependent, and is supported in various
          forms by backends such as PostgreSQL, Oracle and SQL Server.

          E.g.:

               >>> from sqlalchemy import select, column, func, table
               >>> a = table("a", column("id"), column("x"), column("y"))
               >>> stmt = select(func.row_to_json(a.table_valued()))
               >>> print(stmt)
               SELECT row_to_json(a) AS row_to_json_1
               FROM a

          New in version 1.4.0b2.

          See also
          ........

          See Working with SQL Functions. - in the
          SQLAlchemy 1.4 / 2.0 Tutorial.

      -- Method: sqlalchemy.sql.expression.FromClause..
               tablesample (sampling, name=None, seed=None)

          Return a TABLESAMPLE alias of this FromClause.

          The return value is the TableSample construct also
          provided by the top-level tablesample() function.

          New in version 1.1.

          See also
          ........

          See tablesample(). - usage guidelines and parameters

 -- Class: sqlalchemy.sql.expression.GenerativeSelect
          (_label_style=symbol('LABEL_STYLE_DISAMBIGUATE_ONLY'),
          use_labels=False, limit=None, offset=None, order_by=None,
          group_by=None, bind=None)

     Base class for SELECT statements where additional elements can be
     added.

     This serves as the base for Select and
     CompoundSelect where elements such as ORDER BY, GROUP BY can
     be added and column rendering can be controlled.  Compare to
     TextualSelect, which, while it subclasses SelectBase
     and is also a SELECT construct, represents a fixed textual
     string which cannot be altered at this level, only wrapped as a
     subquery.

     `Class signature'

     class sqlalchemy.sql.expression.GenerativeSelect.
     (‘sqlalchemy.sql.expression.DeprecatedSelectBaseGenerations’, see
     sqlalchemy.sql.expression.SelectBase)

      -- Method: sqlalchemy.sql.expression.GenerativeSelect..
               apply_labels ()

          Deprecated since version 1.4: The
          GenerativeSelect.apply_labels() method is considered
          legacy as of the 1.x series of SQLAlchemy and will be removed
          in 2.0.  Use set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
          instead.  (Background on SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

      -- Method: sqlalchemy.sql.expression.GenerativeSelect..
               fetch (count, with_ties=False, percent=False)

          Return a new selectable with the given FETCH FIRST criterion
          applied.

          This is a numeric value which usually renders as ‘FETCH {FIRST
          | NEXT} [ count ] {ROW | ROWS} {ONLY | WITH TIES}’ expression
          in the resulting select.  This functionality is is currently
          implemented for Oracle, PostgreSQL, MSSQL.

          Use GenerativeSelect.offset() to specify the
          offset.

               Note: The GenerativeSelect.fetch() method
               will replace any clause applied with
               GenerativeSelect.limit().

          New in version 1.4.

          Parameters:

             * ‘count’ – an integer COUNT parameter, or a SQL expression
               that provides an integer result.  When ‘percent=True’
               this will represent the percentage of rows to return, not
               the absolute value.  Pass ‘None’ to reset it.

             * ‘with_ties’ – When ‘True’, the WITH TIES option is used
               to return any additional rows that tie for the last place
               in the result set according to the ‘ORDER BY’ clause.
               The ‘ORDER BY’ may be mandatory in this case.  Defaults
               to ‘False’

             * ‘percent’ – When ‘True’, ‘count’ represents the
               percentage of the total number of selected rows to
               return.  Defaults to ‘False’

          See also
          ........

          See GenerativeSelect.limit().

          See GenerativeSelect.offset().

      -- Method: sqlalchemy.sql.expression.GenerativeSelect..
               get_label_style ()

          Retrieve the current label style.

          New in version 1.4.

      -- Method: sqlalchemy.sql.expression.GenerativeSelect..
               group_by (*clauses)

          Return a new selectable with the given list of GROUP BY
          criterion applied.

          e.g.:

               stmt = select(table.c.name, func.max(table.c.stat)).\
               group_by(table.c.name)

          Parameters: ‘*clauses’ – a series of ColumnElement
          constructs which will be used to generate an GROUP BY clause.

          See also
          ........

          See Ordering, Grouping, Limiting, Offset…ing….

      -- Method: sqlalchemy.sql.expression.GenerativeSelect..
               limit (limit)

          Return a new selectable with the given LIMIT criterion
          applied.

          This is a numerical value which usually renders as a ‘LIMIT’
          expression in the resulting select.  Backends that don’t
          support ‘LIMIT’ will attempt to provide similar functionality.

               Note: The GenerativeSelect.limit() method
               will replace any clause applied with
               GenerativeSelect.fetch().

          Changed in version 1.0.0: - see Select.limit() can now
          accept arbitrary SQL expressions as well as integer values.

          Parameters: ‘limit’ – an integer LIMIT parameter, or a SQL
          expression that provides an integer result.  Pass ‘None’ to
          reset it.

          See also
          ........

          See GenerativeSelect.fetch().

          See GenerativeSelect.offset().

      -- Method: sqlalchemy.sql.expression.GenerativeSelect..
               offset (offset)

          Return a new selectable with the given OFFSET criterion
          applied.

          This is a numeric value which usually renders as an ‘OFFSET’
          expression in the resulting select.  Backends that don’t
          support ‘OFFSET’ will attempt to provide similar
          functionality.

          Changed in version 1.0.0: - see Select.offset() can
          now accept arbitrary SQL expressions as well as integer
          values.

          Parameters: ‘offset’ – an integer OFFSET parameter, or a SQL
          expression that provides an integer result.  Pass ‘None’ to
          reset it.

          See also
          ........

          See GenerativeSelect.limit().

          See GenerativeSelect.fetch().

      -- Method: sqlalchemy.sql.expression.GenerativeSelect..
               order_by (*clauses)

          Return a new selectable with the given list of ORDER BY
          criterion applied.

          e.g.:

               stmt = select(table).order_by(table.c.id, table.c.name)

          Parameters: ‘*clauses’ – a series of ColumnElement
          constructs which will be used to generate an ORDER BY clause.

          See also
          ........

          See Ordering, Grouping, Limiting, Offset…ing….

      -- Method: sqlalchemy.sql.expression.GenerativeSelect..
               set_label_style (style)

          Return a new selectable with the specified label style.

          There are three “label styles” available, see
          LABEL_STYLE_DISAMBIGUATE_ONLY,
          LABEL_STYLE_TABLENAME_PLUS_COL, and
          LABEL_STYLE_NONE.  The default style is
          LABEL_STYLE_TABLENAME_PLUS_COL.

          In modern SQLAlchemy, there is not generally a need to change
          the labeling style, as per-expression labels are more
          effectively used by making use of the
          ColumnElement.label() method.  In past versions, see
          LABEL_STYLE_TABLENAME_PLUS_COL was used to disambiguate
          same-named columns from different tables, aliases, or
          subqueries; the newer LABEL_STYLE_DISAMBIGUATE_ONLY
          now applies labels only to names that conflict with an
          existing name so that the impact of this labeling is minimal.

          The rationale for disambiguation is mostly so that all column
          expressions are available from a given FromClause.c
          collection when a subquery is created.

          New in version 1.4: - the
          GenerativeSelect.set_label_style() method replaces the
          previous combination of ‘.apply_labels()’, ‘.with_labels()’
          and ‘use_labels=True’ methods and/or parameters.

          See also
          ........

          See LABEL_STYLE_DISAMBIGUATE_ONLY.

          See LABEL_STYLE_TABLENAME_PLUS_COL.

          See LABEL_STYLE_NONE.

          See LABEL_STYLE_DEFAULT.

      -- Method: sqlalchemy.sql.expression.GenerativeSelect..
               slice (start, stop)

          Apply LIMIT / OFFSET to this statement based on a slice.

          The start and stop indices behave like the argument to
          Python’s built-in ‘range()’ function.  This method provides an
          alternative to using ‘LIMIT’/‘OFFSET’ to get a slice of the
          query.

          For example,

               stmt = select(User).order_by(User).id.slice(1, 3)

          renders as

               SELECT users.id AS users_id,
                      users.name AS users_name
               FROM users ORDER BY users.id
               LIMIT ? OFFSET ?
               (2, 1)

               Note: The GenerativeSelect.slice() method
               will replace any clause applied with
               GenerativeSelect.fetch().

          New in version 1.4: Added the GenerativeSelect.slice()
          method generalized from the ORM.

          See also
          ........

          See GenerativeSelect.limit().

          See GenerativeSelect.offset().

          See GenerativeSelect.fetch().

      -- Method: sqlalchemy.sql.expression.GenerativeSelect..
               with_for_update (nowait=False, read=False, of=None,
               skip_locked=False, key_share=False)

          Specify a ‘FOR UPDATE’ clause for this GenerativeSelect.

          E.g.:

               stmt = select(table).with_for_update(nowait=True)

          On a database like PostgreSQL or Oracle, the above would
          render a statement like:

               SELECT table.a, table.b FROM table FOR UPDATE NOWAIT

          on other backends, the ‘nowait’ option is ignored and instead
          would produce:

               SELECT table.a, table.b FROM table FOR UPDATE

          When called with no arguments, the statement will render with
          the suffix ‘FOR UPDATE’.  Additional arguments can then be
          provided which allow for common database-specific variants.

          Parameters:

             * ‘nowait’ – boolean; will render ‘FOR UPDATE NOWAIT’ on
               Oracle and PostgreSQL dialects.

             * ‘read’ – boolean; will render ‘LOCK IN SHARE MODE’ on
               MySQL, ‘FOR SHARE’ on PostgreSQL. On PostgreSQL, when
               combined with ‘nowait’, will render ‘FOR SHARE NOWAIT’.

             * ‘of’ – SQL expression or list of SQL expression elements
               (typically Column objects or a compatible
               expression) which will render into a ‘FOR UPDATE OF’
               clause; supported by PostgreSQL and Oracle.  May render
               as a table or as a column depending on backend.

             * ‘skip_locked’ – boolean, will render ‘FOR UPDATE SKIP
               LOCKED’ on Oracle and PostgreSQL dialects or ‘FOR SHARE
               SKIP LOCKED’ if ‘read=True’ is also specified.

             * ‘key_share’ – boolean, will render ‘FOR NO KEY UPDATE’,
               or if combined with ‘read=True’ will render ‘FOR KEY
               SHARE’, on the PostgreSQL dialect.

 -- Class: sqlalchemy.sql.expression.HasCTE

     Mixin that declares a class to include CTE support.

     New in version 1.1.

     `Class signature'

     class sqlalchemy.sql.expression.HasCTE.
     (‘sqlalchemy.sql.roles.HasCTERole’)

      -- Method: sqlalchemy.sql.expression.HasCTE..cte
               (name=None, recursive=False)

          Return a new CTE, or Common Table Expression
          instance.

          Common table expressions are a SQL standard whereby SELECT
          statements can draw upon secondary statements specified along
          with the primary statement, using a clause called “WITH”.
          Special semantics regarding UNION can also be employed to
          allow “recursive” queries, where a SELECT statement can draw
          upon the set of rows that have previously been selected.

          CTEs can also be applied to DML constructs UPDATE, INSERT and
          DELETE on some databases, both as a source of CTE rows when
          combined with RETURNING, as well as a consumer of CTE rows.

          Changed in version 1.1: Added support for UPDATE/INSERT/DELETE
          as CTE, CTEs added to UPDATE/INSERT/DELETE.

          SQLAlchemy detects CTE objects, which are treated
          similarly to Alias objects, as special elements to
          be delivered to the FROM clause of the statement as well as to
          a WITH clause at the top of the statement.

          For special prefixes such as PostgreSQL “MATERIALIZED” and
          “NOT MATERIALIZED”, the ‘CTE.prefix_with()’ method may be used
          to establish these.

          Changed in version 1.3.13: Added support for prefixes.  In
          particular - MATERIALIZED and NOT MATERIALIZED.

          Parameters:

             * ‘name’ – name given to the common table expression.  Like
               FromClause.alias(), the name can be left as
               ‘None’ in which case an anonymous symbol will be used at
               query compile time.

             * ‘recursive’ – if ‘True’, will render ‘WITH RECURSIVE’.  A
               recursive common table expression is intended to be used
               in conjunction with UNION ALL in order to derive rows
               from those already selected.

          The following examples include two from PostgreSQL’s
          documentation at
          ‘http://www.postgresql.org/docs/current/static/queries-with.html’,
          as well as additional examples.

          Example 1, non recursive:

               from sqlalchemy import (Table, Column, String, Integer,
                                       MetaData, select, func)

               metadata = MetaData()

               orders = Table('orders', metadata,
                   Column('region', String),
                   Column('amount', Integer),
                   Column('product', String),
                   Column('quantity', Integer)
               )

               regional_sales = select(
                                   orders.c.region,
                                   func.sum(orders.c.amount).label('total_sales')
                               ).group_by(orders.c.region).cte("regional_sales")

               top_regions = select(regional_sales.c.region).\
                       where(
                           regional_sales.c.total_sales >
                           select(
                               func.sum(regional_sales.c.total_sales) / 10
                           )
                       ).cte("top_regions")

               statement = select(
                           orders.c.region,
                           orders.c.product,
                           func.sum(orders.c.quantity).label("product_units"),
                           func.sum(orders.c.amount).label("product_sales")
                   ).where(orders.c.region.in_(
                       select(top_regions.c.region)
                   )).group_by(orders.c.region, orders.c.product)

               result = conn.execute(statement).fetchall()

          Example 2, WITH RECURSIVE:

               from sqlalchemy import (Table, Column, String, Integer,
                                       MetaData, select, func)

               metadata = MetaData()

               parts = Table('parts', metadata,
                   Column('part', String),
                   Column('sub_part', String),
                   Column('quantity', Integer),
               )

               included_parts = select(\
                   parts.c.sub_part, parts.c.part, parts.c.quantity\
                   ).\
                   where(parts.c.part=='our part').\
                   cte(recursive=True)

               incl_alias = included_parts.alias()
               parts_alias = parts.alias()
               included_parts = included_parts.union_all(
                   select(
                       parts_alias.c.sub_part,
                       parts_alias.c.part,
                       parts_alias.c.quantity
                   ).\
                   where(parts_alias.c.part==incl_alias.c.sub_part)
               )

               statement = select(
                           included_parts.c.sub_part,
                           func.sum(included_parts.c.quantity).
                             label('total_quantity')
                       ).\
                       group_by(included_parts.c.sub_part)

               result = conn.execute(statement).fetchall()

          Example 3, an upsert using UPDATE and INSERT with CTEs:

               from datetime import date
               from sqlalchemy import (MetaData, Table, Column, Integer,
                                       Date, select, literal, and_, exists)

               metadata = MetaData()

               visitors = Table('visitors', metadata,
                   Column('product_id', Integer, primary_key=True),
                   Column('date', Date, primary_key=True),
                   Column('count', Integer),
               )

               # add 5 visitors for the product_id == 1
               product_id = 1
               day = date.today()
               count = 5

               update_cte = (
                   visitors.update()
                   .where(and_(visitors.c.product_id == product_id,
                               visitors.c.date == day))
                   .values(count=visitors.c.count + count)
                   .returning(literal(1))
                   .cte('update_cte')
               )

               upsert = visitors.insert().from_select(
                   [visitors.c.product_id, visitors.c.date, visitors.c.count],
                   select(literal(product_id), literal(day), literal(count))
                       .where(~exists(update_cte.select()))
               )

               connection.execute(upsert)

          See also
          ........

          See Query.cte(). - ORM version of HasCTE.cte().

 -- Class: sqlalchemy.sql.expression.HasPrefixes

      -- Method: sqlalchemy.sql.expression.HasPrefixes..
               prefix_with (*expr, **kw)

          Add one or more expressions following the statement keyword,
          i.e.  SELECT, INSERT, UPDATE, or DELETE. Generative.

          This is used to support backend-specific prefix keywords such
          as those provided by MySQL.

          E.g.:

               stmt = table.insert().prefix_with("LOW_PRIORITY", dialect="mysql")

               # MySQL 5.7 optimizer hints
               stmt = select(table).prefix_with(
                   "/*+ BKA(t1) */", dialect="mysql")

          Multiple prefixes can be specified by multiple calls to
          HasPrefixes.prefix_with().

          Parameters:

             * ‘*expr’ – textual or ClauseElement construct
               which will be rendered following the INSERT, UPDATE, or
               DELETE keyword.

             * ‘**kw’ – A single keyword ‘dialect’ is accepted.  This is
               an optional string dialect name which will limit
               rendering of this prefix to only that dialect.

 -- Class: sqlalchemy.sql.expression.HasSuffixes

      -- Method: sqlalchemy.sql.expression.HasSuffixes..
               suffix_with (*expr, **kw)

          Add one or more expressions following the statement as a
          whole.

          This is used to support backend-specific suffix keywords on
          certain constructs.

          E.g.:

               stmt = select(col1, col2).cte().suffix_with(
                   "cycle empno set y_cycle to 1 default 0", dialect="oracle")

          Multiple suffixes can be specified by multiple calls to
          HasSuffixes.suffix_with().

          Parameters:

             * ‘*expr’ – textual or ClauseElement construct
               which will be rendered following the target clause.

             * ‘**kw’ – A single keyword ‘dialect’ is accepted.  This is
               an optional string dialect name which will limit
               rendering of this suffix to only that dialect.

 -- Class: sqlalchemy.sql.expression.Join (left, right, onclause=None,
          isouter=False, full=False)

     Represent a ‘JOIN’ construct between two FromClause
     elements.

     The public constructor function for Join is the
     module-level join() function, as well as the
     FromClause.join() method of any FromClause. (e.g.
     such as Table).

     See also
     ........

     See join().

     See FromClause.join().

     `Class signature'

     class sqlalchemy.sql.expression.Join.
     (‘sqlalchemy.sql.roles.DMLTableRole’, see
     sqlalchemy.sql.expression.FromClause)

      -- Method: sqlalchemy.sql.expression.Join..__init__
               (left, right, onclause=None, isouter=False, full=False)

          Construct a new Join.

          The usual entrypoint here is the join() function
          or the FromClause.join() method of any
          FromClause object.

      -- Method: sqlalchemy.sql.expression.Join..alias
               (name=None, flat=False)

          Return an alias of this Join.

          Deprecated since version 1.4: The Join.alias()
          method is considered legacy as of the 1.x series of SQLAlchemy
          and will be removed in 2.0.  Create a select + subquery, or
          alias the individual tables inside the join, instead.
          (Background on SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

          The default behavior here is to first produce a SELECT
          construct from this Join, then to produce an
          Alias from that.  So given a join of the form:

               j = table_a.join(table_b, table_a.c.id == table_b.c.a_id)

          The JOIN by itself would look like:

               table_a JOIN table_b ON table_a.id = table_b.a_id

          Whereas the alias of the above, ‘j.alias()’, would in a SELECT
          context look like:

               (SELECT table_a.id AS table_a_id, table_b.id AS table_b_id,
                   table_b.a_id AS table_b_a_id
                   FROM table_a
                   JOIN table_b ON table_a.id = table_b.a_id) AS anon_1

          The equivalent long-hand form, given a Join object
          ‘j’, is:

               from sqlalchemy import select, alias
               j = alias(
                   select(j.left, j.right).\
                       select_from(j).\
                       set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL).\
                       correlate(False),
                   name=name
               )

          The selectable produced by Join.alias() features
          the same columns as that of the two individual selectables
          presented under a single name - the individual columns are
          “auto-labeled”, meaning the ‘.c.’ collection of the resulting
          Alias represents the names of the individual
          columns using a ‘<tablename>_<columname>’ scheme:

               j.c.table_a_id
               j.c.table_b_a_id

          Join.alias() also features an alternate option for
          aliasing joins which produces no enclosing SELECT and does not
          normally apply labels to the column names.  The ‘flat=True’
          option will call FromClause.alias() against the
          left and right sides individually.  Using this option, no new
          ‘SELECT’ is produced; we instead, from a construct as below:

               j = table_a.join(table_b, table_a.c.id == table_b.c.a_id)
               j = j.alias(flat=True)

          we get a result like this:

               table_a AS table_a_1 JOIN table_b AS table_b_1 ON
               table_a_1.id = table_b_1.a_id

          The ‘flat=True’ argument is also propagated to the contained
          selectables, so that a composite join such as:

               j = table_a.join(
                       table_b.join(table_c,
                               table_b.c.id == table_c.c.b_id),
                       table_b.c.a_id == table_a.c.id
                   ).alias(flat=True)

          Will produce an expression like:

               table_a AS table_a_1 JOIN (
                       table_b AS table_b_1 JOIN table_c AS table_c_1
                       ON table_b_1.id = table_c_1.b_id
               ) ON table_a_1.id = table_b_1.a_id

          The standalone alias() function as well as the
          base FromClause.alias() method also support the
          ‘flat=True’ argument as a no-op, so that the argument can be
          passed to the ‘alias()’ method of any selectable.

          Parameters:

             * ‘name’ – name given to the alias.

             * ‘flat’ – if True, produce an alias of the left and right
               sides of this Join and return the join of
               those two selectables.  This produces join expression
               that does not include an enclosing SELECT.

          See also
          ........

          See Using Aliases and Subqueries.

          See alias().

      -- Attribute: sqlalchemy.sql.expression.Join..bind

          Return the bound engine associated with either the left or
          right side of this Join.

          Deprecated since version 1.4: The Executable.bind
          attribute is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  Bound metadata is
          being removed as of SQLAlchemy 2.0.  (Background on SQLAlchemy
          2.0 at: Migrating to SQLAlchemy 2.0)

      -- Attribute: sqlalchemy.sql.expression.Join..
               description

      -- Method: sqlalchemy.sql.expression.Join..
               is_derived_from (fromclause)

          Return ‘True’ if this FromClause is ‘derived’ from
          the given ‘FromClause’.

          An example would be an Alias of a Table is derived from that
          Table.

      -- Method: sqlalchemy.sql.expression.Join..select
               (whereclause=None, **kwargs)

          Create a Select from this Join.

          E.g.:

               stmt = table_a.join(table_b, table_a.c.id == table_b.c.a_id)

               stmt = stmt.select()

          The above will produce a SQL string resembling:

               SELECT table_a.id, table_a.col, table_b.id, table_b.a_id
               FROM table_a JOIN table_b ON table_a.id = table_b.a_id

          Parameters:

             * ‘whereclause’ – WHERE criteria, same as calling
               Select.where() on the resulting statement

               Deprecated since version 1.4: The
               Join.select().whereclause parameter is deprecated
               and will be removed in version 2.0.  Please make use of
               the Select.where() method to add WHERE
               criteria to the SELECT statement.

             * ‘**kwargs’ – additional keyword arguments are passed to
               the legacy constructor for Select described at
               Select.create_legacy_select().

      -- Method: sqlalchemy.sql.expression.Join..self_group
               (against=None)

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

 -- Class: sqlalchemy.sql.expression.Lateral (*arg, **kw)

     Represent a LATERAL subquery.

     This object is constructed from the lateral() module
     level function as well as the ‘FromClause.lateral()’ method
     available on all FromClause subclasses.

     While LATERAL is part of the SQL standard, currently only more
     recent PostgreSQL versions provide support for this keyword.

     New in version 1.1.

     See also
     ........

     See LATERAL correlation. - overview of usage.

     `Class signature'

     class sqlalchemy.sql.expression.Lateral. (see
     sqlalchemy.sql.expression.AliasedReturnsRows)

 -- Class: sqlalchemy.sql.expression.ReturnsRows

     The base-most class for Core constructs that have some concept of
     columns that can represent rows.

     While the SELECT statement and TABLE are the primary things we
     think of in this category, DML like INSERT, UPDATE and DELETE can
     also specify RETURNING which means they can be used in CTEs and
     other forms, and PostgreSQL has functions that return rows also.

     New in version 1.4.

     `Class signature'

     class sqlalchemy.sql.expression.ReturnsRows.
     (‘sqlalchemy.sql.roles.ReturnsRowsRole’, see
     sqlalchemy.sql.expression.ClauseElement)

      -- Attribute: sqlalchemy.sql.expression.ReturnsRows..
               exported_columns

          A ColumnCollection that represents the “exported”
          columns of this ReturnsRows.

          The “exported” columns represent the collection of
          ColumnElement expressions that are rendered by this SQL
          construct.  There are primary varieties which are the “FROM
          clause columns” of a FROM clause, such as a table, join, or
          subquery, the “SELECTed columns”, which are the columns in the
          “columns clause” of a SELECT statement, and the RETURNING
          columns in a DML statement..

          New in version 1.4.

          See also
          ........

          See FromClause.exported_columns.

          See SelectBase.exported_columns.

 -- Class: sqlalchemy.sql.expression.ScalarSelect (element)

     Represent a scalar subquery.

     A ‘ScalarSubquery’ is created by invoking the
     SelectBase.scalar_subquery() method.  The object then
     participates in other SQL expressions as a SQL column expression
     within the ColumnElement hierarchy.

     See also
     ........

     See SelectBase.scalar_subquery().

     See Scalar and Correlated Subqueries. - in the 2.0 tutorial

     See Scalar Selects. - in the 1.x tutorial

     `Class signature'

     class sqlalchemy.sql.expression.ScalarSelect.
     (‘sqlalchemy.sql.roles.InElementRole’,
     ‘sqlalchemy.sql.expression.Generative’,
     ‘sqlalchemy.sql.expression.Grouping’)

      -- Method: sqlalchemy.sql.expression.ScalarSelect..
               correlate (*fromclauses)

          Return a new ScalarSelect which will correlate the
          given FROM clauses to that of an enclosing Select.

          This method is mirrored from the Select.correlate()
          method of the underlying Select.  The method
          applies the :meth:_sql.Select.correlate‘ method, then returns
          a new ScalarSelect against that statement.

          New in version 1.4: Previously, the
          ScalarSelect.correlate() method was only available from
          Select.

          Parameters: ‘*fromclauses’ – a list of one or more
          FromClause constructs, or other compatible constructs
          (i.e.  ORM-mapped classes) to become part of the correlate
          collection.

          See also
          ........

          See ScalarSelect.correlate_except().

          See Scalar and Correlated Subqueries. - in the 2.0
          tutorial

          See Correlated Subqueries. - in the 1.x tutorial

      -- Method: sqlalchemy.sql.expression.ScalarSelect..
               correlate_except (*fromclauses)

          Return a new ScalarSelect which will omit the
          given FROM clauses from the auto-correlation process.

          This method is mirrored from the
          Select.correlate_except() method of the underlying
          Select.  The method applies the
          :meth:_sql.Select.correlate_except‘ method, then returns a new
          ScalarSelect against that statement.

          New in version 1.4: Previously, the
          ScalarSelect.correlate_except() method was only
          available from Select.

          Parameters: ‘*fromclauses’ – a list of one or more
          FromClause constructs, or other compatible constructs
          (i.e.  ORM-mapped classes) to become part of the
          correlate-exception collection.

          See also
          ........

          See ScalarSelect.correlate().

          See Scalar and Correlated Subqueries. - in the 2.0
          tutorial

          See Correlated Subqueries. - in the 1.x tutorial

      -- Method: sqlalchemy.sql.expression.ScalarSelect..
               self_group (**kwargs)

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

      -- Method: sqlalchemy.sql.expression.ScalarSelect..
               where (crit)

          Apply a WHERE clause to the SELECT statement referred to by
          this ScalarSelect.

 -- Class: sqlalchemy.sql.expression.Select

     Represents a ‘SELECT’ statement.

     The Select object is normally constructed using the
     select() function.  See that function for details.

     See also
     ........

     See select().

     See Selecting. - in the 1.x tutorial

     See Selecting Data. - in the 2.0 tutorial

     `Class signature'

     class sqlalchemy.sql.expression.Select. (see
     sqlalchemy.sql.expression.HasPrefixes,
     sqlalchemy.sql.expression.HasSuffixes,
     ‘sqlalchemy.sql.expression.HasHints’,
     ‘sqlalchemy.sql.expression.HasCompileState’,
     ‘sqlalchemy.sql.expression.DeprecatedSelectGenerations’,
     ‘sqlalchemy.sql.expression._SelectFromElements’, see
     sqlalchemy.sql.expression.GenerativeSelect)

      -- Method: sqlalchemy.sql.expression.Select..add_columns
               (*columns)

          Return a new select() construct with the given
          column expressions added to its columns clause.

          E.g.:

               my_select = my_select.add_columns(table.c.new_column)

          See the documentation for Select.with_only_columns()
          for guidelines on adding /replacing the columns of a
          Select object.

      -- Method: sqlalchemy.sql.expression.Select..alias
               (name=None, flat=False)

          `inherited from the' SelectBase.alias(). `method
          of' SelectBase.

          Return a named subquery against this SelectBase.

          For a SelectBase. (as opposed to a
          FromClause), this returns a Subquery object
          which behaves mostly the same as the Alias object
          that is used with a FromClause.

          Changed in version 1.4: The SelectBase.alias()
          method is now a synonym for the SelectBase.subquery()
          method.

      -- Method: sqlalchemy.sql.expression.Select..
               apply_labels ()

          `inherited from the' GenerativeSelect.apply_labels().
          `method of' GenerativeSelect.

          Deprecated since version 1.4: The
          GenerativeSelect.apply_labels() method is considered
          legacy as of the 1.x series of SQLAlchemy and will be removed
          in 2.0.  Use set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
          instead.  (Background on SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

      -- Method: sqlalchemy.sql.expression.Select..as_scalar
               ()

          `inherited from the' SelectBase.as_scalar().
          `method of' SelectBase.

          Deprecated since version 1.4: The
          SelectBase.as_scalar() method is deprecated and will be
          removed in a future release.  Please refer to
          SelectBase.scalar_subquery().

      -- Attribute: sqlalchemy.sql.expression.Select..bind

          Returns the Engine or Connection to
          which this Executable is bound, or None if none
          found.

          Deprecated since version 1.4: The Executable.bind
          attribute is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  Bound metadata is
          being removed as of SQLAlchemy 2.0.  (Background on SQLAlchemy
          2.0 at: Migrating to SQLAlchemy 2.0)

      -- Attribute: sqlalchemy.sql.expression.Select..c

          `inherited from the' SelectBase.c. `attribute of'
          SelectBase.

          Deprecated since version 1.4: The SelectBase.c and
          ‘SelectBase.columns’ attributes are deprecated and will be
          removed in a future release; these attributes implicitly
          create a subquery that should be explicit.  Please call
          SelectBase.subquery() first in order to create a
          subquery, which then contains this attribute.  To access the
          columns that this SELECT object SELECTs from, use the
          SelectBase.selected_columns attribute.

      -- Method: sqlalchemy.sql.expression.Select..column
               (column)

          Return a new select() construct with the given
          column expression added to its columns clause.

          Deprecated since version 1.4: The Select.column()
          method is deprecated and will be removed in a future release.
          Please use Select.add_columns().

          E.g.:

               my_select = my_select.column(table.c.new_column)

          See the documentation for Select.with_only_columns()
          for guidelines on adding /replacing the columns of a
          Select object.

      -- Attribute: sqlalchemy.sql.expression.Select..
               column_descriptions

          Return a ‘column descriptions’ structure which may be
          plugin-specific.

      -- Method: sqlalchemy.sql.expression.Select..correlate
               (*fromclauses)

          Return a new Select which will correlate the given
          FROM clauses to that of an enclosing Select.

          Calling this method turns off the Select object’s
          default behavior of “auto-correlation”.  Normally, FROM
          elements which appear in a Select that encloses
          this one via its WHERE clause, ORDER BY, HAVING or columns
          clause will be omitted from this Select object’s
          FROM clause.  Setting an explicit correlation collection using
          the Select.correlate() method provides a fixed
          list of FROM objects that can potentially take place in this
          process.

          When Select.correlate() is used to apply specific
          FROM clauses for correlation, the FROM elements become
          candidates for correlation regardless of how deeply nested
          this Select object is, relative to an enclosing
          Select which refers to the same FROM object.  This
          is in contrast to the behavior of “auto-correlation” which
          only correlates to an immediate enclosing Select.
          Multi-level correlation ensures that the link between enclosed
          and enclosing Select is always via at least one
          WHERE/ORDER BY/HAVING/columns clause in order for correlation
          to take place.

          If ‘None’ is passed, the Select object will
          correlate none of its FROM entries, and all will render
          unconditionally in the local FROM clause.

          Parameters: ‘*fromclauses’ – a list of one or more
          FromClause constructs, or other compatible constructs
          (i.e.  ORM-mapped classes) to become part of the correlate
          collection.

          See also
          ........

          See Select.correlate_except().

          See Correlated Subqueries.

      -- Method: sqlalchemy.sql.expression.Select..
               correlate_except (*fromclauses)

          Return a new Select which will omit the given FROM
          clauses from the auto-correlation process.

          Calling Select.correlate_except() turns off the
          Select object’s default behavior of
          “auto-correlation” for the given FROM elements.  An element
          specified here will unconditionally appear in the FROM list,
          while all other FROM elements remain subject to normal
          auto-correlation behaviors.

          If ‘None’ is passed, the Select object will
          correlate all of its FROM entries.

          Parameters: ‘*fromclauses’ – a list of one or more
          FromClause constructs, or other compatible constructs
          (i.e.  ORM-mapped classes) to become part of the
          correlate-exception collection.

          See also
          ........

          See Select.correlate().

          See Correlated Subqueries.

      -- Method: sqlalchemy.sql.expression.Select..
               corresponding_column (column, require_embedded=False)

          `inherited from the' Selectable.corresponding_column().
          `method of' Selectable.

          Given a ColumnElement, return the exported
          ColumnElement object from the
          Selectable.exported_columns collection of this
          Selectable which corresponds to that original
          ColumnElement via a common ancestor column.

          Parameters:

             * ‘column’ – the target ColumnElement to be
               matched.

             * ‘require_embedded’ – only return corresponding columns
               for the given ColumnElement, if the given
               ColumnElement is actually present within a
               sub-element of this Selectable.  Normally the
               column will match if it merely shares a common ancestor
               with one of the exported columns of this
               Selectable.

          See also
          ........

          See Selectable.exported_columns. - the
          ColumnCollection that is used for the operation.

          See ColumnCollection.corresponding_column(). -
          implementation method.

      -- Method: sqlalchemy.sql.expression.Select..classmethod
               create_legacy_select (columns=None, whereclause=None,
               from_obj=None, distinct=False, having=None,
               correlate=True, prefixes=None, suffixes=None, **kwargs)

          Construct a new Select using the 1.x style API.

          Deprecated since version 1.4: The legacy calling style of
          select() is deprecated and will be removed in
          SQLAlchemy 2.0.  Please use the new calling style described at
          select().  (Background on SQLAlchemy 2.0 at:
          Migrating to SQLAlchemy 2.0)

          This method is called implicitly when the select()
          construct is used and the first argument is a Python list or
          other plain sequence object, which is taken to refer to the
          columns collection.

          Changed in version 1.4: Added the
          Select.create_legacy_select() constructor which
          documents the calling style in use when the select()
          construct is invoked using 1.x-style arguments.

          Similar functionality is also available via the
          FromClause.select() method on any FromClause.

          All arguments which accept ClauseElement arguments
          also accept string arguments, which will be converted as
          appropriate into either text() or
          literal_column() constructs.

          See also
          ........

          See Selecting. - Core Tutorial description of
          select().

          Parameters:

             * ‘columns’ – A list of ColumnElement or
               FromClause objects which will form the columns
               clause of the resulting statement.  For those objects
               that are instances of FromClause. (typically
               Table or Alias objects), the
               FromClause.c collection is extracted to form a
               collection of ColumnElement objects.

               This parameter will also accept TextClause
               constructs as given, as well as ORM-mapped classes.

                    Note: The select.columns parameter is
                    not available in the method form of select(),
                    e.g.  see FromClause.select().

               See also
               ........

               See Select.column().

               See Select.with_only_columns().

             * ‘whereclause’ – A ClauseElement expression
               which will be used to form the ‘WHERE’ clause.  It is
               typically preferable to add WHERE criterion to an
               existing Select using method chaining with
               Select.where().

               See also
               ........

               See Select.where().

             * ‘from_obj’ – A list of ClauseElement objects
               which will be added to the ‘FROM’ clause of the resulting
               statement.  This is equivalent to calling
               Select.select_from() using method chaining on an
               existing Select object.

               See also
               ........

               See Select.select_from(). - full description of
               explicit FROM clause specification.

             * ‘bind=None’ – an Engine or Connection
               instance to which the resulting Select
               object will be bound.  The Select object will
               otherwise automatically bind to whatever ‘Connectable’
               instances can be located within its contained
               ClauseElement members.

             * ‘correlate=True’ – indicates that this Select.
               object should have its contained FromClause
               elements “correlated” to an enclosing Select
               object.  It is typically preferable to specify
               correlations on an existing Select construct
               using Select.correlate().

               See also
               ........

               See Select.correlate(). - full description of
               correlation.

             * ‘distinct=False’ – when ‘True’, applies a ‘DISTINCT’
               qualifier to the columns clause of the resulting
               statement.

               The boolean argument may also be a column expression or
               list of column expressions - this is a special calling
               form which is understood by the PostgreSQL dialect to
               render the ‘DISTINCT ON (<columns>)’ syntax.

               ‘distinct’ is also available on an existing Select
               object via the Select.distinct() method.

               See also
               ........

               See Select.distinct().

             * ‘group_by’ – a list of ClauseElement objects
               which will comprise the ‘GROUP BY’ clause of the
               resulting select.  This parameter is typically specified
               more naturally using the Select.group_by()
               method on an existing Select.

               See also
               ........

               See Select.group_by().

             * ‘having’ – a ClauseElement that will comprise
               the ‘HAVING’ clause of the resulting select when ‘GROUP
               BY’ is used.  This parameter is typically specified more
               naturally using the Select.having() method on
               an existing Select.

               See also
               ........

               See Select.having().

             * ‘limit=None’ – a numerical value which usually renders as
               a ‘LIMIT’ expression in the resulting select.  Backends
               that don’t support ‘LIMIT’ will attempt to provide
               similar functionality.  This parameter is typically
               specified more naturally using the Select.limit()
               method on an existing Select.

               See also
               ........

               See Select.limit().

             * ‘offset=None’ – a numeric value which usually renders as
               an ‘OFFSET’ expression in the resulting select.  Backends
               that don’t support ‘OFFSET’ will attempt to provide
               similar functionality.  This parameter is typically
               specified more naturally using the Select.offset()
               method on an existing Select.

               See also
               ........

               See Select.offset().

             * ‘order_by’ – a scalar or list of ClauseElement
               objects which will comprise the ‘ORDER BY’ clause of
               the resulting select.  This parameter is typically
               specified more naturally using the
               Select.order_by() method on an existing
               Select.

               See also
               ........

               See Select.order_by().

             * ‘use_labels=False’ – when ‘True’, the statement will be
               generated using labels for each column in the columns
               clause, which qualify each column with its parent table’s
               (or aliases) name so that name conflicts between columns
               in different tables don’t occur.  The format of the label
               is ‘<tablename>_<column>’.  The “c” collection of a
               Subquery created against this Select
               object, as well as the Select.selected_columns
               collection of the Select itself, will use
               these names for targeting column members.

               This parameter can also be specified on an existing
               Select object using the
               Select.set_label_style() method.

               See also
               ........

               See Select.set_label_style().

      -- Method: sqlalchemy.sql.expression.Select..cte
               (name=None, recursive=False)

          `inherited from the' HasCTE.cte(). `method of'
          HasCTE.

          Return a new CTE, or Common Table Expression
          instance.

          Common table expressions are a SQL standard whereby SELECT
          statements can draw upon secondary statements specified along
          with the primary statement, using a clause called “WITH”.
          Special semantics regarding UNION can also be employed to
          allow “recursive” queries, where a SELECT statement can draw
          upon the set of rows that have previously been selected.

          CTEs can also be applied to DML constructs UPDATE, INSERT and
          DELETE on some databases, both as a source of CTE rows when
          combined with RETURNING, as well as a consumer of CTE rows.

          Changed in version 1.1: Added support for UPDATE/INSERT/DELETE
          as CTE, CTEs added to UPDATE/INSERT/DELETE.

          SQLAlchemy detects CTE objects, which are treated
          similarly to Alias objects, as special elements to
          be delivered to the FROM clause of the statement as well as to
          a WITH clause at the top of the statement.

          For special prefixes such as PostgreSQL “MATERIALIZED” and
          “NOT MATERIALIZED”, the ‘CTE.prefix_with()’ method may be used
          to establish these.

          Changed in version 1.3.13: Added support for prefixes.  In
          particular - MATERIALIZED and NOT MATERIALIZED.

          Parameters:

             * ‘name’ – name given to the common table expression.  Like
               FromClause.alias(), the name can be left as
               ‘None’ in which case an anonymous symbol will be used at
               query compile time.

             * ‘recursive’ – if ‘True’, will render ‘WITH RECURSIVE’.  A
               recursive common table expression is intended to be used
               in conjunction with UNION ALL in order to derive rows
               from those already selected.

          The following examples include two from PostgreSQL’s
          documentation at
          ‘http://www.postgresql.org/docs/current/static/queries-with.html’,
          as well as additional examples.

          Example 1, non recursive:

               from sqlalchemy import (Table, Column, String, Integer,
                                       MetaData, select, func)

               metadata = MetaData()

               orders = Table('orders', metadata,
                   Column('region', String),
                   Column('amount', Integer),
                   Column('product', String),
                   Column('quantity', Integer)
               )

               regional_sales = select(
                                   orders.c.region,
                                   func.sum(orders.c.amount).label('total_sales')
                               ).group_by(orders.c.region).cte("regional_sales")

               top_regions = select(regional_sales.c.region).\
                       where(
                           regional_sales.c.total_sales >
                           select(
                               func.sum(regional_sales.c.total_sales) / 10
                           )
                       ).cte("top_regions")

               statement = select(
                           orders.c.region,
                           orders.c.product,
                           func.sum(orders.c.quantity).label("product_units"),
                           func.sum(orders.c.amount).label("product_sales")
                   ).where(orders.c.region.in_(
                       select(top_regions.c.region)
                   )).group_by(orders.c.region, orders.c.product)

               result = conn.execute(statement).fetchall()

          Example 2, WITH RECURSIVE:

               from sqlalchemy import (Table, Column, String, Integer,
                                       MetaData, select, func)

               metadata = MetaData()

               parts = Table('parts', metadata,
                   Column('part', String),
                   Column('sub_part', String),
                   Column('quantity', Integer),
               )

               included_parts = select(\
                   parts.c.sub_part, parts.c.part, parts.c.quantity\
                   ).\
                   where(parts.c.part=='our part').\
                   cte(recursive=True)

               incl_alias = included_parts.alias()
               parts_alias = parts.alias()
               included_parts = included_parts.union_all(
                   select(
                       parts_alias.c.sub_part,
                       parts_alias.c.part,
                       parts_alias.c.quantity
                   ).\
                   where(parts_alias.c.part==incl_alias.c.sub_part)
               )

               statement = select(
                           included_parts.c.sub_part,
                           func.sum(included_parts.c.quantity).
                             label('total_quantity')
                       ).\
                       group_by(included_parts.c.sub_part)

               result = conn.execute(statement).fetchall()

          Example 3, an upsert using UPDATE and INSERT with CTEs:

               from datetime import date
               from sqlalchemy import (MetaData, Table, Column, Integer,
                                       Date, select, literal, and_, exists)

               metadata = MetaData()

               visitors = Table('visitors', metadata,
                   Column('product_id', Integer, primary_key=True),
                   Column('date', Date, primary_key=True),
                   Column('count', Integer),
               )

               # add 5 visitors for the product_id == 1
               product_id = 1
               day = date.today()
               count = 5

               update_cte = (
                   visitors.update()
                   .where(and_(visitors.c.product_id == product_id,
                               visitors.c.date == day))
                   .values(count=visitors.c.count + count)
                   .returning(literal(1))
                   .cte('update_cte')
               )

               upsert = visitors.insert().from_select(
                   [visitors.c.product_id, visitors.c.date, visitors.c.count],
                   select(literal(product_id), literal(day), literal(count))
                       .where(~exists(update_cte.select()))
               )

               connection.execute(upsert)

          See also
          ........

          See Query.cte(). - ORM version of HasCTE.cte().

      -- Method: sqlalchemy.sql.expression.Select..distinct
               (*expr)

          Return a new select() construct which will apply
          DISTINCT to its columns clause.

          Parameters: ‘*expr’ – optional column expressions.  When
          present, the PostgreSQL dialect will render a ‘DISTINCT ON
          (<expressions>>)’ construct.

          Deprecated since version 1.4: Using *expr in other dialects is
          deprecated and will raise CompileError in a future
          version.

      -- Method: sqlalchemy.sql.expression.Select..except_
               (other, **kwargs)

          Return a SQL ‘EXCEPT’ of this select() construct against the
          given selectable.

      -- Method: sqlalchemy.sql.expression.Select..except_all
               (other, **kwargs)

          Return a SQL ‘EXCEPT ALL’ of this select() construct against
          the given selectable.

      -- Method: sqlalchemy.sql.expression.Select..execute
               (*multiparams, **params)

          `inherited from the' Executable.execute(). `method
          of' Executable.

          Compile and execute this Executable.

          Deprecated since version 1.4: The Executable.execute()
          method is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  All statement
          execution in SQLAlchemy 2.0 is performed by the
          Connection.execute() method of Connection, or
          in the ORM by the Session.execute() method of
          Session.  (Background on SQLAlchemy 2.0 at:
          Migrating to SQLAlchemy 2.0)

      -- Method: sqlalchemy.sql.expression.Select..
               execution_options (**kw)

          `inherited from the' Executable.execution_options().
          `method of' Executable.

          Set non-SQL options for the statement which take effect during
          execution.

          Execution options can be set on a per-statement or per
          Connection basis.  Additionally, the Engine
          and ORM ‘Query’ objects provide access to execution options
          which they in turn configure upon connections.

          The execution_options() method is generative.  A
          new instance of this statement is returned that contains the
          options:

               statement = select(table.c.x, table.c.y)
               statement = statement.execution_options(autocommit=True)

          Note that only a subset of possible execution options can be
          applied to a statement - these include “autocommit” and
          “stream_results”, but not “isolation_level” or
          “compiled_cache”.  See Connection.execution_options()
          for a full list of possible options.

          See also
          ........

          See Connection.execution_options().

          See Query.execution_options().

          See Executable.get_execution_options().

      -- Method: sqlalchemy.sql.expression.Select..exists ()

          `inherited from the' SelectBase.exists(). `method
          of' SelectBase.

          Return an Exists representation of this
          selectable, which can be used as a column expression.

          The returned object is an instance of Exists.

          See also
          ........

          See exists().

          See EXISTS subqueries. - in the 2.0 style tutorial.

          New in version 1.4.

      -- Attribute: sqlalchemy.sql.expression.Select..
               exported_columns

          `inherited from the' SelectBase.exported_columns.
          `attribute of' SelectBase.

          A ColumnCollection that represents the “exported”
          columns of this Selectable.

          The “exported” columns for a SelectBase object are
          synonymous with the SelectBase.selected_columns
          collection.

          New in version 1.4.

          See also
          ........

          See Selectable.exported_columns.

          See FromClause.exported_columns.

      -- Method: sqlalchemy.sql.expression.Select..fetch
               (count, with_ties=False, percent=False)

          `inherited from the' GenerativeSelect.fetch().
          `method of' GenerativeSelect.

          Return a new selectable with the given FETCH FIRST criterion
          applied.

          This is a numeric value which usually renders as ‘FETCH {FIRST
          | NEXT} [ count ] {ROW | ROWS} {ONLY | WITH TIES}’ expression
          in the resulting select.  This functionality is is currently
          implemented for Oracle, PostgreSQL, MSSQL.

          Use GenerativeSelect.offset() to specify the
          offset.

               Note: The GenerativeSelect.fetch() method
               will replace any clause applied with
               GenerativeSelect.limit().

          New in version 1.4.

          Parameters:

             * ‘count’ – an integer COUNT parameter, or a SQL expression
               that provides an integer result.  When ‘percent=True’
               this will represent the percentage of rows to return, not
               the absolute value.  Pass ‘None’ to reset it.

             * ‘with_ties’ – When ‘True’, the WITH TIES option is used
               to return any additional rows that tie for the last place
               in the result set according to the ‘ORDER BY’ clause.
               The ‘ORDER BY’ may be mandatory in this case.  Defaults
               to ‘False’

             * ‘percent’ – When ‘True’, ‘count’ represents the
               percentage of the total number of selected rows to
               return.  Defaults to ‘False’

          See also
          ........

          See GenerativeSelect.limit().

          See GenerativeSelect.offset().

      -- Method: sqlalchemy.sql.expression.Select..filter
               (*criteria)

          A synonym for the ‘Select.where()’ method.

      -- Method: sqlalchemy.sql.expression.Select..filter_by
               (**kwargs)

          apply the given filtering criterion as a WHERE clause to this
          select.

      -- Method: sqlalchemy.sql.expression.Select..
               from_statement (statement)

          Apply the columns which this Select would select
          onto another statement.

          This operation is plugin-specific and will raise a not
          supported exception if this Select does not select
          from plugin-enabled entities.

          The statement is typically either a text() or
          select() construct, and should return the set of columns
          appropriate to the entities represented by this Select.

          See also
          ........

          See Getting ORM Results from Textual and Core Statements.
          - usage examples in the ORM Querying Guide

      -- Attribute: sqlalchemy.sql.expression.Select..froms

          Return the displayed list of FromClause elements.

      -- Method: sqlalchemy.sql.expression.Select..
               get_children (**kwargs)

          Return immediate child Traversible elements of
          this Traversible.

          This is used for visit traversal.

          **kw may contain flags that change the collection that is
          returned, for example to return a subset of items in order to
          cut down on larger traversals, or to return child items from a
          different context (such as schema-level collections instead of
          clause-level).

      -- Method: sqlalchemy.sql.expression.Select..
               get_execution_options ()

          `inherited from the' Executable.get_execution_options().
          `method of' Executable.

          Get the non-SQL options which will take effect during
          execution.

          New in version 1.3.

          See also
          ........

          See Executable.execution_options().

      -- Method: sqlalchemy.sql.expression.Select..
               get_label_style ()

          `inherited from the' GenerativeSelect.get_label_style().
          `method of' GenerativeSelect.

          Retrieve the current label style.

          New in version 1.4.

      -- Method: sqlalchemy.sql.expression.Select..group_by
               (*clauses)

          `inherited from the' GenerativeSelect.group_by().
          `method of' GenerativeSelect.

          Return a new selectable with the given list of GROUP BY
          criterion applied.

          e.g.:

               stmt = select(table.c.name, func.max(table.c.stat)).\
               group_by(table.c.name)

          Parameters: ‘*clauses’ – a series of ColumnElement
          constructs which will be used to generate an GROUP BY clause.

          See also
          ........

          See Ordering, Grouping, Limiting, Offset…ing….

      -- Method: sqlalchemy.sql.expression.Select..having
               (having)

          Return a new select() construct with the given
          expression added to its HAVING clause, joined to the existing
          clause via AND, if any.

      -- Attribute: sqlalchemy.sql.expression.Select..
               inner_columns

          An iterator of all ColumnElement expressions which
          would be rendered into the columns clause of the resulting
          SELECT statement.

          This method is legacy as of 1.4 and is superseded by the
          Select.exported_columns collection.

      -- Method: sqlalchemy.sql.expression.Select..intersect
               (other, **kwargs)

          Return a SQL ‘INTERSECT’ of this select() construct against
          the given selectable.

      -- Method: sqlalchemy.sql.expression.Select..
               intersect_all (other, **kwargs)

          Return a SQL ‘INTERSECT ALL’ of this select() construct
          against the given selectable.

      -- Method: sqlalchemy.sql.expression.Select..join
               (target, onclause=None, isouter=False, full=False)

          Create a SQL JOIN against this Select object’s
          criterion and apply generatively, returning the newly
          resulting Select.

          E.g.:

               stmt = select(user_table).join(address_table, user_table.c.id == address_table.c.user_id)

          The above statement generates SQL similar to:

               SELECT user.id, user.name FROM user JOIN address ON user.id = address.user_id

          Changed in version 1.4: Select.join() now creates
          a Join object between a FromClause
          source that is within the FROM clause of the existing SELECT,
          and a given target FromClause, and then adds this
          Join to the FROM clause of the newly generated
          SELECT statement.  This is completely reworked from the
          behavior in 1.3, which would instead create a subquery of the
          entire Select and then join that subquery to the
          target.

          This is a `backwards incompatible change' as the previous
          behavior was mostly useless, producing an unnamed subquery
          rejected by most databases in any case.  The new behavior is
          modeled after that of the very successful Query.join()
          method in the ORM, in order to support the functionality
          of Query being available by using a Select
          object with an Session.

          See the notes for this change at *note select().join() and
          outerjoin() add JOIN criteria to the current query, rather
          than creating a subquery: f04.

          Parameters:

             * ‘target’ – target table to join towards

             * ‘onclause’ – ON clause of the join.  If omitted, an ON
               clause is generated automatically based on the
               ForeignKey linkages between the two tables, if one
               can be unambiguously determined, otherwise an error is
               raised.

             * ‘isouter’ – if True, generate LEFT OUTER join.  Same as
               Select.outerjoin().

             * ‘full’ – if True, generate FULL OUTER join.

          See also
          ........

          See Explicit FROM clauses and JOINs. - in the
          SQLAlchemy 1.4 / 2.0 Tutorial.

          See Joins. - in the ORM Querying Guide.

          See Select.join_from().

          See Select.outerjoin().

      -- Method: sqlalchemy.sql.expression.Select..join_from
               (from_, target, onclause=None, isouter=False, full=False)

          Create a SQL JOIN against this Select object’s
          criterion and apply generatively, returning the newly
          resulting Select.

          E.g.:

               stmt = select(user_table, address_table).join_from(
                   user_table, address_table, user_table.c.id == address_table.c.user_id
               )

          The above statement generates SQL similar to:

               SELECT user.id, user.name, address.id, address.email, address.user_id
               FROM user JOIN address ON user.id = address.user_id

          New in version 1.4.

          Parameters:

             * ‘from_’ – the left side of the join, will be rendered in
               the FROM clause and is roughly equivalent to using the
               Select.select_from() method.

             * ‘target’ – target table to join towards

             * ‘onclause’ – ON clause of the join.

             * ‘isouter’ – if True, generate LEFT OUTER join.  Same as
               Select.outerjoin().

             * ‘full’ – if True, generate FULL OUTER join.

          See also
          ........

          See Explicit FROM clauses and JOINs. - in the
          SQLAlchemy 1.4 / 2.0 Tutorial.

          See Joins. - in the ORM Querying Guide.

          See Select.join().

      -- Method: sqlalchemy.sql.expression.Select..label
               (name)

          `inherited from the' SelectBase.label(). `method
          of' SelectBase.

          Return a ‘scalar’ representation of this selectable, embedded
          as a subquery with a label.

          See also
          ........

          See SelectBase.as_scalar().

      -- Method: sqlalchemy.sql.expression.Select..lateral
               (name=None)

          `inherited from the' SelectBase.lateral(). `method
          of' SelectBase.

          Return a LATERAL alias of this Selectable.

          The return value is the Lateral construct also
          provided by the top-level lateral() function.

          New in version 1.1.

          See also
          ........

          See LATERAL correlation. - overview of usage.

      -- Method: sqlalchemy.sql.expression.Select..limit
               (limit)

          `inherited from the' GenerativeSelect.limit().
          `method of' GenerativeSelect.

          Return a new selectable with the given LIMIT criterion
          applied.

          This is a numerical value which usually renders as a ‘LIMIT’
          expression in the resulting select.  Backends that don’t
          support ‘LIMIT’ will attempt to provide similar functionality.

               Note: The GenerativeSelect.limit() method
               will replace any clause applied with
               GenerativeSelect.fetch().

          Changed in version 1.0.0: - see Select.limit() can now
          accept arbitrary SQL expressions as well as integer values.

          Parameters: ‘limit’ – an integer LIMIT parameter, or a SQL
          expression that provides an integer result.  Pass ‘None’ to
          reset it.

          See also
          ........

          See GenerativeSelect.fetch().

          See GenerativeSelect.offset().

      -- Method: sqlalchemy.sql.expression.Select..offset
               (offset)

          `inherited from the' GenerativeSelect.offset().
          `method of' GenerativeSelect.

          Return a new selectable with the given OFFSET criterion
          applied.

          This is a numeric value which usually renders as an ‘OFFSET’
          expression in the resulting select.  Backends that don’t
          support ‘OFFSET’ will attempt to provide similar
          functionality.

          Changed in version 1.0.0: - see Select.offset() can
          now accept arbitrary SQL expressions as well as integer
          values.

          Parameters: ‘offset’ – an integer OFFSET parameter, or a SQL
          expression that provides an integer result.  Pass ‘None’ to
          reset it.

          See also
          ........

          See GenerativeSelect.limit().

          See GenerativeSelect.fetch().

      -- Method: sqlalchemy.sql.expression.Select..options
               (*options)

          `inherited from the' Executable.options(). `method
          of' Executable.

          Apply options to this statement.

          In the general sense, options are any kind of Python object
          that can be interpreted by the SQL compiler for the statement.
          These options can be consumed by specific dialects or specific
          kinds of compilers.

          The most commonly known kind of option are the ORM level
          options that apply “eager load” and other loading behaviors to
          an ORM query.  However, options can theoretically be used for
          many other purposes.

          For background on specific kinds of options for specific kinds
          of statements, refer to the documentation for those option
          objects.

          Changed in version 1.4: - added ‘Generative.options()’ to Core
          statement objects towards the goal of allowing unified Core /
          ORM querying capabilities.

          See also
          ........

          See Deferred Column Loader Query Options. - refers to
          options specific to the usage of ORM queries

          See Relationship Loading with Loader Options. - refers
          to options specific to the usage of ORM queries

      -- Method: sqlalchemy.sql.expression.Select..order_by
               (*clauses)

          `inherited from the' GenerativeSelect.order_by().
          `method of' GenerativeSelect.

          Return a new selectable with the given list of ORDER BY
          criterion applied.

          e.g.:

               stmt = select(table).order_by(table.c.id, table.c.name)

          Parameters: ‘*clauses’ – a series of ColumnElement
          constructs which will be used to generate an ORDER BY clause.

          See also
          ........

          See Ordering, Grouping, Limiting, Offset…ing….

      -- Method: sqlalchemy.sql.expression.Select..outerjoin
               (target, onclause=None, full=False)

          Create a left outer join.

          Parameters are the same as that of Select.join().

          Changed in version 1.4: Select.outerjoin() now
          creates a Join object between a FromClause
          source that is within the FROM clause of the existing
          SELECT, and a given target FromClause, and then adds
          this Join to the FROM clause of the newly
          generated SELECT statement.  This is completely reworked from
          the behavior in 1.3, which would instead create a subquery of
          the entire Select and then join that subquery to
          the target.

          This is a `backwards incompatible change' as the previous
          behavior was mostly useless, producing an unnamed subquery
          rejected by most databases in any case.  The new behavior is
          modeled after that of the very successful Query.join()
          method in the ORM, in order to support the functionality
          of Query being available by using a Select
          object with an Session.

          See the notes for this change at *note select().join() and
          outerjoin() add JOIN criteria to the current query, rather
          than creating a subquery: f04.

          See also
          ........

          See Explicit FROM clauses and JOINs. - in the
          SQLAlchemy 1.4 / 2.0 Tutorial.

          See Joins. - in the ORM Querying Guide.

          See Select.join().

      -- Method: sqlalchemy.sql.expression.Select..
               outerjoin_from (from_, target, onclause=None,
               full=False)

          Create a SQL LEFT OUTER JOIN against this Select
          object’s criterion and apply generatively, returning the newly
          resulting Select.

          Usage is the same as that of ‘Select.join_from()’.

      -- Method: sqlalchemy.sql.expression.Select..prefix_with
               (*expr, **kw)

          `inherited from the' HasPrefixes.prefix_with().
          `method of' HasPrefixes.

          Add one or more expressions following the statement keyword,
          i.e.  SELECT, INSERT, UPDATE, or DELETE. Generative.

          This is used to support backend-specific prefix keywords such
          as those provided by MySQL.

          E.g.:

               stmt = table.insert().prefix_with("LOW_PRIORITY", dialect="mysql")

               # MySQL 5.7 optimizer hints
               stmt = select(table).prefix_with(
                   "/*+ BKA(t1) */", dialect="mysql")

          Multiple prefixes can be specified by multiple calls to
          HasPrefixes.prefix_with().

          Parameters:

             * ‘*expr’ – textual or ClauseElement construct
               which will be rendered following the INSERT, UPDATE, or
               DELETE keyword.

             * ‘**kw’ – A single keyword ‘dialect’ is accepted.  This is
               an optional string dialect name which will limit
               rendering of this prefix to only that dialect.

      -- Method: sqlalchemy.sql.expression.Select..
               reduce_columns (only_synonyms=True)

          Return a new select() construct with redundantly
          named, equivalently-valued columns removed from the columns
          clause.

          “Redundant” here means two columns where one refers to the
          other either based on foreign key, or via a simple equality
          comparison in the WHERE clause of the statement.  The primary
          purpose of this method is to automatically construct a select
          statement with all uniquely-named columns, without the need to
          use table-qualified labels as Select.set_label_style()
          does.

          When columns are omitted based on foreign key, the referred-to
          column is the one that’s kept.  When columns are omitted based
          on WHERE equivalence, the first column in the columns clause
          is the one that’s kept.

          Parameters: ‘only_synonyms’ – when True, limit the removal of
          columns to those which have the same name as the equivalent.
          Otherwise, all columns that are equivalent to another are
          removed.

      -- Method: sqlalchemy.sql.expression.Select..
               replace_selectable (old, alias)

          `inherited from the' Selectable.replace_selectable().
          `method of' Selectable.

          Replace all occurrences of FromClause. ‘old’ with
          the given Alias object, returning a copy of this
          FromClause.

          Deprecated since version 1.4: The
          Selectable.replace_selectable() method is deprecated,
          and will be removed in a future release.  Similar
          functionality is available via the sqlalchemy.sql.visitors
          module.

      -- Method: sqlalchemy.sql.expression.Select..scalar
               (*multiparams, **params)

          `inherited from the' Executable.scalar(). `method
          of' Executable.

          Compile and execute this Executable, returning the
          result’s scalar representation.

          Deprecated since version 1.4: The Executable.scalar()
          method is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  Scalar execution in
          SQLAlchemy 2.0 is performed by the Connection.scalar()
          method of Connection, or in the ORM by the
          Session.scalar() method of Session.
          (Background on SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

      -- Method: sqlalchemy.sql.expression.Select..
               scalar_subquery ()

          `inherited from the' SelectBase.scalar_subquery().
          `method of' SelectBase.

          Return a ‘scalar’ representation of this selectable, which can
          be used as a column expression.

          The returned object is an instance of ScalarSelect.

          Typically, a select statement which has only one column in its
          columns clause is eligible to be used as a scalar expression.
          The scalar subquery can then be used in the WHERE clause or
          columns clause of an enclosing SELECT.

          Note that the scalar subquery differentiates from the
          FROM-level subquery that can be produced using the
          SelectBase.subquery() method.

          See also
          ........

          See Scalar and Correlated Subqueries. - in the 2.0
          tutorial

          See Scalar Selects. - in the 1.x tutorial

      -- Method: sqlalchemy.sql.expression.Select..select
               (*arg, **kw)

          `inherited from the' SelectBase.select(). `method
          of' SelectBase.

          Deprecated since version 1.4: The SelectBase.select()
          method is deprecated and will be removed in a future
          release; this method implicitly creates a subquery that should
          be explicit.  Please call SelectBase.subquery()
          first in order to create a subquery, which then can be
          selected.

      -- Method: sqlalchemy.sql.expression.Select..select_from
               (*froms)

          Return a new select() construct with the given FROM
          expression(s) merged into its list of FROM objects.

          E.g.:

               table1 = table('t1', column('a'))
               table2 = table('t2', column('b'))
               s = select(table1.c.a).\
                   select_from(
                       table1.join(table2, table1.c.a==table2.c.b)
                   )

          The “from” list is a unique set on the identity of each
          element, so adding an already present Table or
          other selectable will have no effect.  Passing a Join
          that refers to an already present Table or
          other selectable will have the effect of concealing the
          presence of that selectable as an individual element in the
          rendered FROM list, instead rendering it into a JOIN clause.

          While the typical purpose of Select.select_from()
          is to replace the default, derived FROM clause with a join, it
          can also be called with individual table elements, multiple
          times if desired, in the case that the FROM clause cannot be
          fully derived from the columns clause:

               select(func.count('*')).select_from(table1)

      -- Attribute: sqlalchemy.sql.expression.Select..
               selected_columns

          A ColumnCollection representing the columns that
          this SELECT statement or similar construct returns in its
          result set.

          This collection differs from the FromClause.columns
          collection of a FromClause in that the columns
          within this collection cannot be directly nested inside
          another SELECT statement; a subquery must be applied first
          which provides for the necessary parenthesization required by
          SQL.

          For a select() construct, the collection here is
          exactly what would be rendered inside the “SELECT” statement,
          and the ColumnElement objects are directly present
          as they were given, e.g.:

               col1 = column('q', Integer)
               col2 = column('p', Integer)
               stmt = select(col1, col2)

          Above, ‘stmt.selected_columns’ would be a collection that
          contains the ‘col1’ and ‘col2’ objects directly.  For a
          statement that is against a Table or other
          FromClause, the collection will use the
          ColumnElement objects that are in the
          FromClause.c collection of the from element.

          New in version 1.4.

      -- Method: sqlalchemy.sql.expression.Select..self_group
               (against=None)

          Return a ‘grouping’ construct as per the ClauseElement
          specification.

          This produces an element that can be embedded in an
          expression.  Note that this method is called automatically as
          needed when constructing expressions and should not require
          explicit use.

      -- Method: sqlalchemy.sql.expression.Select..
               set_label_style (style)

          `inherited from the' GenerativeSelect.set_label_style().
          `method of' GenerativeSelect.

          Return a new selectable with the specified label style.

          There are three “label styles” available, see
          LABEL_STYLE_DISAMBIGUATE_ONLY,
          LABEL_STYLE_TABLENAME_PLUS_COL, and
          LABEL_STYLE_NONE.  The default style is
          LABEL_STYLE_TABLENAME_PLUS_COL.

          In modern SQLAlchemy, there is not generally a need to change
          the labeling style, as per-expression labels are more
          effectively used by making use of the
          ColumnElement.label() method.  In past versions, see
          LABEL_STYLE_TABLENAME_PLUS_COL was used to disambiguate
          same-named columns from different tables, aliases, or
          subqueries; the newer LABEL_STYLE_DISAMBIGUATE_ONLY
          now applies labels only to names that conflict with an
          existing name so that the impact of this labeling is minimal.

          The rationale for disambiguation is mostly so that all column
          expressions are available from a given FromClause.c
          collection when a subquery is created.

          New in version 1.4: - the
          GenerativeSelect.set_label_style() method replaces the
          previous combination of ‘.apply_labels()’, ‘.with_labels()’
          and ‘use_labels=True’ methods and/or parameters.

          See also
          ........

          See LABEL_STYLE_DISAMBIGUATE_ONLY.

          See LABEL_STYLE_TABLENAME_PLUS_COL.

          See LABEL_STYLE_NONE.

          See LABEL_STYLE_DEFAULT.

      -- Method: sqlalchemy.sql.expression.Select..slice
               (start, stop)

          `inherited from the' GenerativeSelect.slice().
          `method of' GenerativeSelect.

          Apply LIMIT / OFFSET to this statement based on a slice.

          The start and stop indices behave like the argument to
          Python’s built-in ‘range()’ function.  This method provides an
          alternative to using ‘LIMIT’/‘OFFSET’ to get a slice of the
          query.

          For example,

               stmt = select(User).order_by(User).id.slice(1, 3)

          renders as

               SELECT users.id AS users_id,
                      users.name AS users_name
               FROM users ORDER BY users.id
               LIMIT ? OFFSET ?
               (2, 1)

               Note: The GenerativeSelect.slice() method
               will replace any clause applied with
               GenerativeSelect.fetch().

          New in version 1.4: Added the GenerativeSelect.slice()
          method generalized from the ORM.

          See also
          ........

          See GenerativeSelect.limit().

          See GenerativeSelect.offset().

          See GenerativeSelect.fetch().

      -- Method: sqlalchemy.sql.expression.Select..subquery
               (name=None)

          `inherited from the' SelectBase.subquery(). `method
          of' SelectBase.

          Return a subquery of this SelectBase.

          A subquery is from a SQL perspective a parenthesized, named
          construct that can be placed in the FROM clause of another
          SELECT statement.

          Given a SELECT statement such as:

               stmt = select(table.c.id, table.c.name)

          The above statement might look like:

               SELECT table.id, table.name FROM table

          The subquery form by itself renders the same way, however when
          embedded into the FROM clause of another SELECT statement, it
          becomes a named sub-element:

               subq = stmt.subquery()
               new_stmt = select(subq)

          The above renders as:

               SELECT anon_1.id, anon_1.name
               FROM (SELECT table.id, table.name FROM table) AS anon_1

          Historically, see SelectBase.subquery() is equivalent
          to calling the FromClause.alias() method on a FROM
          object; however, as a SelectBase object is not
          directly FROM object, the SelectBase.subquery()
          method provides clearer semantics.

          New in version 1.4.

      -- Method: sqlalchemy.sql.expression.Select..suffix_with
               (*expr, **kw)

          `inherited from the' HasSuffixes.suffix_with().
          `method of' HasSuffixes.

          Add one or more expressions following the statement as a
          whole.

          This is used to support backend-specific suffix keywords on
          certain constructs.

          E.g.:

               stmt = select(col1, col2).cte().suffix_with(
                   "cycle empno set y_cycle to 1 default 0", dialect="oracle")

          Multiple suffixes can be specified by multiple calls to
          HasSuffixes.suffix_with().

          Parameters:

             * ‘*expr’ – textual or ClauseElement construct
               which will be rendered following the target clause.

             * ‘**kw’ – A single keyword ‘dialect’ is accepted.  This is
               an optional string dialect name which will limit
               rendering of this suffix to only that dialect.

      -- Method: sqlalchemy.sql.expression.Select..union
               (other, **kwargs)

          Return a SQL ‘UNION’ of this select() construct against the
          given selectable.

      -- Method: sqlalchemy.sql.expression.Select..union_all
               (other, **kwargs)

          Return a SQL ‘UNION ALL’ of this select() construct against
          the given selectable.

      -- Method: sqlalchemy.sql.expression.Select..where
               (*whereclause)

          Return a new select() construct with the given
          expression added to its WHERE clause, joined to the existing
          clause via AND, if any.

      -- Attribute: sqlalchemy.sql.expression.Select..
               whereclause

          Return the completed WHERE clause for this Select
          statement.

          This assembles the current collection of WHERE criteria into a
          single ‘BooleanClauseList’ construct.

          New in version 1.4.

      -- Method: sqlalchemy.sql.expression.Select..
               with_for_update (nowait=False, read=False, of=None,
               skip_locked=False, key_share=False)

          `inherited from the' GenerativeSelect.with_for_update().
          `method of' GenerativeSelect.

          Specify a ‘FOR UPDATE’ clause for this GenerativeSelect.

          E.g.:

               stmt = select(table).with_for_update(nowait=True)

          On a database like PostgreSQL or Oracle, the above would
          render a statement like:

               SELECT table.a, table.b FROM table FOR UPDATE NOWAIT

          on other backends, the ‘nowait’ option is ignored and instead
          would produce:

               SELECT table.a, table.b FROM table FOR UPDATE

          When called with no arguments, the statement will render with
          the suffix ‘FOR UPDATE’.  Additional arguments can then be
          provided which allow for common database-specific variants.

          Parameters:

             * ‘nowait’ – boolean; will render ‘FOR UPDATE NOWAIT’ on
               Oracle and PostgreSQL dialects.

             * ‘read’ – boolean; will render ‘LOCK IN SHARE MODE’ on
               MySQL, ‘FOR SHARE’ on PostgreSQL. On PostgreSQL, when
               combined with ‘nowait’, will render ‘FOR SHARE NOWAIT’.

             * ‘of’ – SQL expression or list of SQL expression elements
               (typically Column objects or a compatible
               expression) which will render into a ‘FOR UPDATE OF’
               clause; supported by PostgreSQL and Oracle.  May render
               as a table or as a column depending on backend.

             * ‘skip_locked’ – boolean, will render ‘FOR UPDATE SKIP
               LOCKED’ on Oracle and PostgreSQL dialects or ‘FOR SHARE
               SKIP LOCKED’ if ‘read=True’ is also specified.

             * ‘key_share’ – boolean, will render ‘FOR NO KEY UPDATE’,
               or if combined with ‘read=True’ will render ‘FOR KEY
               SHARE’, on the PostgreSQL dialect.

      -- Method: sqlalchemy.sql.expression.Select..with_hint
               (selectable, text, dialect_name='*')

          `inherited from the' ‘HasHints.with_hint()’ `method of'
          ‘HasHints’

          Add an indexing or other executional context hint for the
          given selectable to this Select or other selectable
          object.

          The text of the hint is rendered in the appropriate location
          for the database backend in use, relative to the given
          Table or Alias passed as the ‘selectable’
          argument.  The dialect implementation typically uses Python
          string substitution syntax with the token ‘%(name)s’ to render
          the name of the table or alias.  E.g.  when using Oracle, the
          following:

               select(mytable).\
                   with_hint(mytable, "index(%(name)s ix_mytable)")

          Would render SQL as:

               select /*+ index(mytable ix_mytable) */ ... from mytable

          The ‘dialect_name’ option will limit the rendering of a
          particular hint to a particular backend.  Such as, to add
          hints for both Oracle and Sybase simultaneously:

               select(mytable).\
                   with_hint(mytable, "index(%(name)s ix_mytable)", 'oracle').\
                   with_hint(mytable, "WITH INDEX ix_mytable", 'sybase')

          See also
          ........

          See Select.with_statement_hint().

      -- Method: sqlalchemy.sql.expression.Select..
               with_only_columns (*columns)

          Return a new select() construct with its columns
          clause replaced with the given columns.

          This method is exactly equivalent to as if the original
          select() had been called with the given columns clause.
          I.e.  a statement:

               s = select(table1.c.a, table1.c.b)
               s = s.with_only_columns(table1.c.b)

          should be exactly equivalent to:

               s = select(table1.c.b)

          Note that this will also dynamically alter the FROM clause of
          the statement if it is not explicitly stated.  To maintain the
          FROM clause, ensure the Select.select_from()
          method is used appropriately:

               s = select(table1.c.a, table2.c.b)
               s = s.select_from(table2.c.b).with_only_columns(table1.c.a)

          Parameters: ‘*columns’ – column expressions to be used.

          Changed in version 1.4: the Select.with_only_columns()
          method accepts the list of column expressions
          positionally; passing the expressions as a list is deprecated.

      -- Method: sqlalchemy.sql.expression.Select..
               with_statement_hint (text, dialect_name='*')

          `inherited from the' ‘HasHints.with_statement_hint()’ `method
          of' ‘HasHints’

          Add a statement hint to this Select or other
          selectable object.

          This method is similar to Select.with_hint()
          except that it does not require an individual table, and
          instead applies to the statement as a whole.

          Hints here are specific to the backend database and may
          include directives such as isolation levels, file directives,
          fetch directives, etc.

          New in version 1.0.0.

          See also
          ........

          See Select.with_hint().

          See Select.prefix_with(). - generic SELECT prefixing
          which also can suit some database-specific HINT syntaxes such
          as MySQL optimizer hints

 -- Class: sqlalchemy.sql.expression.Selectable

     Mark a class as being selectable.

     `Class signature'

     class sqlalchemy.sql.expression.Selectable. (see
     sqlalchemy.sql.expression.ReturnsRows)

      -- Method: sqlalchemy.sql.expression.Selectable..
               corresponding_column (column, require_embedded=False)

          Given a ColumnElement, return the exported
          ColumnElement object from the
          Selectable.exported_columns collection of this
          Selectable which corresponds to that original
          ColumnElement via a common ancestor column.

          Parameters:

             * ‘column’ – the target ColumnElement to be
               matched.

             * ‘require_embedded’ – only return corresponding columns
               for the given ColumnElement, if the given
               ColumnElement is actually present within a
               sub-element of this Selectable.  Normally the
               column will match if it merely shares a common ancestor
               with one of the exported columns of this
               Selectable.

          See also
          ........

          See Selectable.exported_columns. - the
          ColumnCollection that is used for the operation.

          See ColumnCollection.corresponding_column(). -
          implementation method.

      -- Attribute: sqlalchemy.sql.expression.Selectable..
               exported_columns

          `inherited from the' ReturnsRows.exported_columns.
          `attribute of' ReturnsRows.

          A ColumnCollection that represents the “exported”
          columns of this ReturnsRows.

          The “exported” columns represent the collection of
          ColumnElement expressions that are rendered by this SQL
          construct.  There are primary varieties which are the “FROM
          clause columns” of a FROM clause, such as a table, join, or
          subquery, the “SELECTed columns”, which are the columns in the
          “columns clause” of a SELECT statement, and the RETURNING
          columns in a DML statement..

          New in version 1.4.

          See also
          ........

          See FromClause.exported_columns.

          See SelectBase.exported_columns.

      -- Method: sqlalchemy.sql.expression.Selectable..
               lateral (name=None)

          Return a LATERAL alias of this Selectable.

          The return value is the Lateral construct also
          provided by the top-level lateral() function.

          New in version 1.1.

          See also
          ........

          See LATERAL correlation. - overview of usage.

      -- Method: sqlalchemy.sql.expression.Selectable..
               replace_selectable (old, alias)

          Replace all occurrences of FromClause. ‘old’ with
          the given Alias object, returning a copy of this
          FromClause.

          Deprecated since version 1.4: The
          Selectable.replace_selectable() method is deprecated,
          and will be removed in a future release.  Similar
          functionality is available via the sqlalchemy.sql.visitors
          module.

 -- Class: sqlalchemy.sql.expression.SelectBase

     Base class for SELECT statements.

     This includes Select, CompoundSelect and
     TextualSelect.

     `Class signature'

     class sqlalchemy.sql.expression.SelectBase.
     (‘sqlalchemy.sql.roles.SelectStatementRole’,
     ‘sqlalchemy.sql.roles.DMLSelectRole’,
     ‘sqlalchemy.sql.roles.CompoundElementRole’,
     ‘sqlalchemy.sql.roles.InElementRole’, see
     sqlalchemy.sql.expression.HasCTE,
     sqlalchemy.sql.expression.Executable,
     ‘sqlalchemy.sql.annotation.SupportsCloneAnnotations’, see
     sqlalchemy.sql.expression.Selectable)

      -- Method: sqlalchemy.sql.expression.SelectBase..alias
               (name=None, flat=False)

          Return a named subquery against this SelectBase.

          For a SelectBase. (as opposed to a
          FromClause), this returns a Subquery object
          which behaves mostly the same as the Alias object
          that is used with a FromClause.

          Changed in version 1.4: The SelectBase.alias()
          method is now a synonym for the SelectBase.subquery()
          method.

      -- Method: sqlalchemy.sql.expression.SelectBase..
               as_scalar ()

          Deprecated since version 1.4: The
          SelectBase.as_scalar() method is deprecated and will be
          removed in a future release.  Please refer to
          SelectBase.scalar_subquery().

      -- Attribute: sqlalchemy.sql.expression.SelectBase..
               bind

          `inherited from the' Executable.bind. `attribute
          of' Executable.

          Returns the Engine or Connection to
          which this Executable is bound, or None if none
          found.

          Deprecated since version 1.4: The Executable.bind
          attribute is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  Bound metadata is
          being removed as of SQLAlchemy 2.0.  (Background on SQLAlchemy
          2.0 at: Migrating to SQLAlchemy 2.0)

          This is a traversal which checks locally, then checks among
          the “from” clauses of associated objects until a bound engine
          or connection is found.

      -- Attribute: sqlalchemy.sql.expression.SelectBase..c

          Deprecated since version 1.4: The SelectBase.c and
          ‘SelectBase.columns’ attributes are deprecated and will be
          removed in a future release; these attributes implicitly
          create a subquery that should be explicit.  Please call
          SelectBase.subquery() first in order to create a
          subquery, which then contains this attribute.  To access the
          columns that this SELECT object SELECTs from, use the
          SelectBase.selected_columns attribute.

      -- Method: sqlalchemy.sql.expression.SelectBase..
               corresponding_column (column, require_embedded=False)

          `inherited from the' Selectable.corresponding_column().
          `method of' Selectable.

          Given a ColumnElement, return the exported
          ColumnElement object from the
          Selectable.exported_columns collection of this
          Selectable which corresponds to that original
          ColumnElement via a common ancestor column.

          Parameters:

             * ‘column’ – the target ColumnElement to be
               matched.

             * ‘require_embedded’ – only return corresponding columns
               for the given ColumnElement, if the given
               ColumnElement is actually present within a
               sub-element of this Selectable.  Normally the
               column will match if it merely shares a common ancestor
               with one of the exported columns of this
               Selectable.

          See also
          ........

          See Selectable.exported_columns. - the
          ColumnCollection that is used for the operation.

          See ColumnCollection.corresponding_column(). -
          implementation method.

      -- Method: sqlalchemy.sql.expression.SelectBase..cte
               (name=None, recursive=False)

          `inherited from the' HasCTE.cte(). `method of'
          HasCTE.

          Return a new CTE, or Common Table Expression
          instance.

          Common table expressions are a SQL standard whereby SELECT
          statements can draw upon secondary statements specified along
          with the primary statement, using a clause called “WITH”.
          Special semantics regarding UNION can also be employed to
          allow “recursive” queries, where a SELECT statement can draw
          upon the set of rows that have previously been selected.

          CTEs can also be applied to DML constructs UPDATE, INSERT and
          DELETE on some databases, both as a source of CTE rows when
          combined with RETURNING, as well as a consumer of CTE rows.

          Changed in version 1.1: Added support for UPDATE/INSERT/DELETE
          as CTE, CTEs added to UPDATE/INSERT/DELETE.

          SQLAlchemy detects CTE objects, which are treated
          similarly to Alias objects, as special elements to
          be delivered to the FROM clause of the statement as well as to
          a WITH clause at the top of the statement.

          For special prefixes such as PostgreSQL “MATERIALIZED” and
          “NOT MATERIALIZED”, the ‘CTE.prefix_with()’ method may be used
          to establish these.

          Changed in version 1.3.13: Added support for prefixes.  In
          particular - MATERIALIZED and NOT MATERIALIZED.

          Parameters:

             * ‘name’ – name given to the common table expression.  Like
               FromClause.alias(), the name can be left as
               ‘None’ in which case an anonymous symbol will be used at
               query compile time.

             * ‘recursive’ – if ‘True’, will render ‘WITH RECURSIVE’.  A
               recursive common table expression is intended to be used
               in conjunction with UNION ALL in order to derive rows
               from those already selected.

          The following examples include two from PostgreSQL’s
          documentation at
          ‘http://www.postgresql.org/docs/current/static/queries-with.html’,
          as well as additional examples.

          Example 1, non recursive:

               from sqlalchemy import (Table, Column, String, Integer,
                                       MetaData, select, func)

               metadata = MetaData()

               orders = Table('orders', metadata,
                   Column('region', String),
                   Column('amount', Integer),
                   Column('product', String),
                   Column('quantity', Integer)
               )

               regional_sales = select(
                                   orders.c.region,
                                   func.sum(orders.c.amount).label('total_sales')
                               ).group_by(orders.c.region).cte("regional_sales")

               top_regions = select(regional_sales.c.region).\
                       where(
                           regional_sales.c.total_sales >
                           select(
                               func.sum(regional_sales.c.total_sales) / 10
                           )
                       ).cte("top_regions")

               statement = select(
                           orders.c.region,
                           orders.c.product,
                           func.sum(orders.c.quantity).label("product_units"),
                           func.sum(orders.c.amount).label("product_sales")
                   ).where(orders.c.region.in_(
                       select(top_regions.c.region)
                   )).group_by(orders.c.region, orders.c.product)

               result = conn.execute(statement).fetchall()

          Example 2, WITH RECURSIVE:

               from sqlalchemy import (Table, Column, String, Integer,
                                       MetaData, select, func)

               metadata = MetaData()

               parts = Table('parts', metadata,
                   Column('part', String),
                   Column('sub_part', String),
                   Column('quantity', Integer),
               )

               included_parts = select(\
                   parts.c.sub_part, parts.c.part, parts.c.quantity\
                   ).\
                   where(parts.c.part=='our part').\
                   cte(recursive=True)

               incl_alias = included_parts.alias()
               parts_alias = parts.alias()
               included_parts = included_parts.union_all(
                   select(
                       parts_alias.c.sub_part,
                       parts_alias.c.part,
                       parts_alias.c.quantity
                   ).\
                   where(parts_alias.c.part==incl_alias.c.sub_part)
               )

               statement = select(
                           included_parts.c.sub_part,
                           func.sum(included_parts.c.quantity).
                             label('total_quantity')
                       ).\
                       group_by(included_parts.c.sub_part)

               result = conn.execute(statement).fetchall()

          Example 3, an upsert using UPDATE and INSERT with CTEs:

               from datetime import date
               from sqlalchemy import (MetaData, Table, Column, Integer,
                                       Date, select, literal, and_, exists)

               metadata = MetaData()

               visitors = Table('visitors', metadata,
                   Column('product_id', Integer, primary_key=True),
                   Column('date', Date, primary_key=True),
                   Column('count', Integer),
               )

               # add 5 visitors for the product_id == 1
               product_id = 1
               day = date.today()
               count = 5

               update_cte = (
                   visitors.update()
                   .where(and_(visitors.c.product_id == product_id,
                               visitors.c.date == day))
                   .values(count=visitors.c.count + count)
                   .returning(literal(1))
                   .cte('update_cte')
               )

               upsert = visitors.insert().from_select(
                   [visitors.c.product_id, visitors.c.date, visitors.c.count],
                   select(literal(product_id), literal(day), literal(count))
                       .where(~exists(update_cte.select()))
               )

               connection.execute(upsert)

          See also
          ........

          See Query.cte(). - ORM version of HasCTE.cte().

      -- Method: sqlalchemy.sql.expression.SelectBase..
               execute (*multiparams, **params)

          `inherited from the' Executable.execute(). `method
          of' Executable.

          Compile and execute this Executable.

          Deprecated since version 1.4: The Executable.execute()
          method is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  All statement
          execution in SQLAlchemy 2.0 is performed by the
          Connection.execute() method of Connection, or
          in the ORM by the Session.execute() method of
          Session.  (Background on SQLAlchemy 2.0 at:
          Migrating to SQLAlchemy 2.0)

      -- Method: sqlalchemy.sql.expression.SelectBase..
               execution_options (**kw)

          `inherited from the' Executable.execution_options().
          `method of' Executable.

          Set non-SQL options for the statement which take effect during
          execution.

          Execution options can be set on a per-statement or per
          Connection basis.  Additionally, the Engine
          and ORM ‘Query’ objects provide access to execution options
          which they in turn configure upon connections.

          The execution_options() method is generative.  A
          new instance of this statement is returned that contains the
          options:

               statement = select(table.c.x, table.c.y)
               statement = statement.execution_options(autocommit=True)

          Note that only a subset of possible execution options can be
          applied to a statement - these include “autocommit” and
          “stream_results”, but not “isolation_level” or
          “compiled_cache”.  See Connection.execution_options()
          for a full list of possible options.

          See also
          ........

          See Connection.execution_options().

          See Query.execution_options().

          See Executable.get_execution_options().

      -- Method: sqlalchemy.sql.expression.SelectBase..exists
               ()

          Return an Exists representation of this
          selectable, which can be used as a column expression.

          The returned object is an instance of Exists.

          See also
          ........

          See exists().

          See EXISTS subqueries. - in the 2.0 style tutorial.

          New in version 1.4.

      -- Attribute: sqlalchemy.sql.expression.SelectBase..
               exported_columns

          A ColumnCollection that represents the “exported”
          columns of this Selectable.

          The “exported” columns for a SelectBase object are
          synonymous with the SelectBase.selected_columns
          collection.

          New in version 1.4.

          See also
          ........

          See Selectable.exported_columns.

          See FromClause.exported_columns.

      -- Method: sqlalchemy.sql.expression.SelectBase..
               get_execution_options ()

          `inherited from the' Executable.get_execution_options().
          `method of' Executable.

          Get the non-SQL options which will take effect during
          execution.

          New in version 1.3.

          See also
          ........

          See Executable.execution_options().

      -- Method: sqlalchemy.sql.expression.SelectBase..label
               (name)

          Return a ‘scalar’ representation of this selectable, embedded
          as a subquery with a label.

          See also
          ........

          See SelectBase.as_scalar().

      -- Method: sqlalchemy.sql.expression.SelectBase..
               lateral (name=None)

          Return a LATERAL alias of this Selectable.

          The return value is the Lateral construct also
          provided by the top-level lateral() function.

          New in version 1.1.

          See also
          ........

          See LATERAL correlation. - overview of usage.

      -- Method: sqlalchemy.sql.expression.SelectBase..
               options (*options)

          `inherited from the' Executable.options(). `method
          of' Executable.

          Apply options to this statement.

          In the general sense, options are any kind of Python object
          that can be interpreted by the SQL compiler for the statement.
          These options can be consumed by specific dialects or specific
          kinds of compilers.

          The most commonly known kind of option are the ORM level
          options that apply “eager load” and other loading behaviors to
          an ORM query.  However, options can theoretically be used for
          many other purposes.

          For background on specific kinds of options for specific kinds
          of statements, refer to the documentation for those option
          objects.

          Changed in version 1.4: - added ‘Generative.options()’ to Core
          statement objects towards the goal of allowing unified Core /
          ORM querying capabilities.

          See also
          ........

          See Deferred Column Loader Query Options. - refers to
          options specific to the usage of ORM queries

          See Relationship Loading with Loader Options. - refers
          to options specific to the usage of ORM queries

      -- Method: sqlalchemy.sql.expression.SelectBase..
               replace_selectable (old, alias)

          `inherited from the' Selectable.replace_selectable().
          `method of' Selectable.

          Replace all occurrences of FromClause. ‘old’ with
          the given Alias object, returning a copy of this
          FromClause.

          Deprecated since version 1.4: The
          Selectable.replace_selectable() method is deprecated,
          and will be removed in a future release.  Similar
          functionality is available via the sqlalchemy.sql.visitors
          module.

      -- Method: sqlalchemy.sql.expression.SelectBase..scalar
               (*multiparams, **params)

          `inherited from the' Executable.scalar(). `method
          of' Executable.

          Compile and execute this Executable, returning the
          result’s scalar representation.

          Deprecated since version 1.4: The Executable.scalar()
          method is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  Scalar execution in
          SQLAlchemy 2.0 is performed by the Connection.scalar()
          method of Connection, or in the ORM by the
          Session.scalar() method of Session.
          (Background on SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

      -- Method: sqlalchemy.sql.expression.SelectBase..
               scalar_subquery ()

          Return a ‘scalar’ representation of this selectable, which can
          be used as a column expression.

          The returned object is an instance of ScalarSelect.

          Typically, a select statement which has only one column in its
          columns clause is eligible to be used as a scalar expression.
          The scalar subquery can then be used in the WHERE clause or
          columns clause of an enclosing SELECT.

          Note that the scalar subquery differentiates from the
          FROM-level subquery that can be produced using the
          SelectBase.subquery() method.

          See also
          ........

          See Scalar and Correlated Subqueries. - in the 2.0
          tutorial

          See Scalar Selects. - in the 1.x tutorial

      -- Method: sqlalchemy.sql.expression.SelectBase..select
               (*arg, **kw)

          Deprecated since version 1.4: The SelectBase.select()
          method is deprecated and will be removed in a future
          release; this method implicitly creates a subquery that should
          be explicit.  Please call SelectBase.subquery()
          first in order to create a subquery, which then can be
          selected.

      -- Attribute: sqlalchemy.sql.expression.SelectBase..
               selected_columns

          A ColumnCollection representing the columns that
          this SELECT statement or similar construct returns in its
          result set.

          This collection differs from the FromClause.columns
          collection of a FromClause in that the columns
          within this collection cannot be directly nested inside
          another SELECT statement; a subquery must be applied first
          which provides for the necessary parenthesization required by
          SQL.

          New in version 1.4.

      -- Method: sqlalchemy.sql.expression.SelectBase..
               subquery (name=None)

          Return a subquery of this SelectBase.

          A subquery is from a SQL perspective a parenthesized, named
          construct that can be placed in the FROM clause of another
          SELECT statement.

          Given a SELECT statement such as:

               stmt = select(table.c.id, table.c.name)

          The above statement might look like:

               SELECT table.id, table.name FROM table

          The subquery form by itself renders the same way, however when
          embedded into the FROM clause of another SELECT statement, it
          becomes a named sub-element:

               subq = stmt.subquery()
               new_stmt = select(subq)

          The above renders as:

               SELECT anon_1.id, anon_1.name
               FROM (SELECT table.id, table.name FROM table) AS anon_1

          Historically, see SelectBase.subquery() is equivalent
          to calling the FromClause.alias() method on a FROM
          object; however, as a SelectBase object is not
          directly FROM object, the SelectBase.subquery()
          method provides clearer semantics.

          New in version 1.4.

 -- Class: sqlalchemy.sql.expression.Subquery (*arg, **kw)

     Represent a subquery of a SELECT.

     A Subquery is created by invoking the
     SelectBase.subquery() method, or for convenience the
     SelectBase.alias() method, on any SelectBase
     subclass which includes Select, CompoundSelect,
     and TextualSelect.  As rendered in a FROM clause,
     it represents the body of the SELECT statement inside of
     parenthesis, followed by the usual “AS <somename>” that defines all
     “alias” objects.

     The Subquery object is very similar to the Alias
     object and can be used in an equivalent way.  The difference
     between Alias and Subquery is that
     Alias always contains a FromClause object whereas
     Subquery always contains a SelectBase
     object.

     New in version 1.4: The Subquery class was added which
     now serves the purpose of providing an aliased version of a SELECT
     statement.

     `Class signature'

     class sqlalchemy.sql.expression.Subquery. (see
     sqlalchemy.sql.expression.AliasedReturnsRows)

      -- Method: sqlalchemy.sql.expression.Subquery..
               as_scalar ()

          Deprecated since version 1.4: The Subquery.as_scalar()
          method, which was previously ‘Alias.as_scalar()’ prior to
          version 1.4, is deprecated and will be removed in a future
          release; Please use the Select.scalar_subquery()
          method of the select() construct before
          constructing a subquery object, or with the ORM use the
          Query.scalar_subquery() method.

 -- Class: sqlalchemy.sql.expression.TableClause (name, *columns, **kw)

     Represents a minimal “table” construct.

     This is a lightweight table object that has only a name, a
     collection of columns, which are typically produced by the
     column() function, and a schema:

          from sqlalchemy import table, column

          user = table("user",
                  column("id"),
                  column("name"),
                  column("description"),
          )

     The TableClause construct serves as the base for the
     more commonly used Table object, providing the usual set
     of FromClause services including the ‘.c.’ collection
     and statement generation methods.

     It does `not' provide all the additional schema-level services of
     Table, including constraints, references to other tables,
     or support for MetaData.-level services.  It’s useful on
     its own as an ad-hoc construct used to generate quick SQL
     statements when a more fully fledged Table is not on
     hand.

     `Class signature'

     class sqlalchemy.sql.expression.TableClause.
     (‘sqlalchemy.sql.roles.DMLTableRole’,
     ‘sqlalchemy.sql.expression.Immutable’, see
     sqlalchemy.sql.expression.FromClause)

      -- Method: sqlalchemy.sql.expression.TableClause..
               __init__ (name, *columns, **kw)

          Construct a new TableClause object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.sql.expression.table() for a full usage
          and argument description.

      -- Method: sqlalchemy.sql.expression.TableClause..alias
               (name=None, flat=False)

          `inherited from the' FromClause.alias(). `method
          of' FromClause.

          Return an alias of this FromClause.

          E.g.:

               a2 = some_table.alias('a2')

          The above code creates an Alias object which can
          be used as a FROM clause in any SELECT statement.

          See also
          ........

          See Using Aliases and Subqueries.

          See alias().

      -- Attribute: sqlalchemy.sql.expression.TableClause..c

          `inherited from the' FromClause.c. `attribute of'
          FromClause.

          A named-based collection of ColumnElement objects
          maintained by this FromClause.

          The FromClause.c attribute is an alias for the
          FromClause.columns atttribute.

          Returns: a ColumnCollection.

      -- Attribute: sqlalchemy.sql.expression.TableClause..
               columns

          `inherited from the' FromClause.columns. `attribute
          of' FromClause.

          A named-based collection of ColumnElement objects
          maintained by this FromClause.

          The columns, or c collection, is the
          gateway to the construction of SQL expressions using
          table-bound or other selectable-bound columns:

               select(mytable).where(mytable.c.somecolumn == 5)

          Returns: a ColumnCollection object.

      -- Method: sqlalchemy.sql.expression.TableClause..
               compare (other, **kw)

          `inherited from the' ClauseElement.compare().
          `method of' ClauseElement.

          Compare this ClauseElement to the given
          ClauseElement.

          Subclasses should override the default behavior, which is a
          straight identity comparison.

          **kw are arguments consumed by subclass ‘compare()’ methods
          and may be used to modify the criteria for comparison (see
          ColumnElement).

      -- Method: sqlalchemy.sql.expression.TableClause..
               compile (bind=None, dialect=None, **kw)

          `inherited from the' ClauseElement.compile().
          `method of' ClauseElement.

          Compile this SQL expression.

          The return value is a Compiled object.  Calling
          ‘str()’ or ‘unicode()’ on the returned value will yield a
          string representation of the result.  The Compiled
          object also can return a dictionary of bind parameter names
          and values using the ‘params’ accessor.

          Parameters:

             * ‘bind’ – An ‘Engine’ or ‘Connection’ from which a
               ‘Compiled’ will be acquired.  This argument takes
               precedence over this ClauseElement.’s bound
               engine, if any.

             * ‘column_keys’ – Used for INSERT and UPDATE statements, a
               list of column names which should be present in the
               VALUES clause of the compiled statement.  If ‘None’, all
               columns from the target table object are rendered.

             * ‘dialect’ – A ‘Dialect’ instance from which a ‘Compiled’
               will be acquired.  This argument takes precedence over
               the ‘bind’ argument as well as this ClauseElement.
               ‘s bound engine, if any.

             * ‘compile_kwargs’ – optional dictionary of additional
               parameters that will be passed through to the compiler
               within all “visit” methods.  This allows any custom flag
               to be passed through to a custom compilation construct,
               for example.  It is also used for the case of passing the
               ‘literal_binds’ flag through:

                    from sqlalchemy.sql import table, column, select

                    t = table('t', column('x'))

                    s = select(t).where(t.c.x == 5)

                    print(s.compile(compile_kwargs={"literal_binds": True}))

               New in version 0.9.0.

          See also
          ........

          See How do I render SQL expressions as strings, possibly with bound parameters inlined?.

      -- Method: sqlalchemy.sql.expression.TableClause..
               corresponding_column (column, require_embedded=False)

          `inherited from the' Selectable.corresponding_column().
          `method of' Selectable.

          Given a ColumnElement, return the exported
          ColumnElement object from the
          Selectable.exported_columns collection of this
          Selectable which corresponds to that original
          ColumnElement via a common ancestor column.

          Parameters:

             * ‘column’ – the target ColumnElement to be
               matched.

             * ‘require_embedded’ – only return corresponding columns
               for the given ColumnElement, if the given
               ColumnElement is actually present within a
               sub-element of this Selectable.  Normally the
               column will match if it merely shares a common ancestor
               with one of the exported columns of this
               Selectable.

          See also
          ........

          See Selectable.exported_columns. - the
          ColumnCollection that is used for the operation.

          See ColumnCollection.corresponding_column(). -
          implementation method.

      -- Method: sqlalchemy.sql.expression.TableClause..
               delete (whereclause=None, **kwargs)

          Generate a delete() construct against this
          TableClause.

          E.g.:

               table.delete().where(table.c.id==7)

          See delete() for argument and usage information.

      -- Attribute: sqlalchemy.sql.expression.TableClause..
               entity_namespace

          `inherited from the' FromClause.entity_namespace.
          `attribute of' FromClause.

          Return a namespace used for name-based access in SQL
          expressions.

          This is the namespace that is used to resolve “filter_by()”
          type expressions, such as:

               stmt.filter_by(address='some address')

          It defaults to the ‘.c’ collection, however internally it can
          be overridden using the “entity_namespace” annotation to
          deliver alternative results.

      -- Attribute: sqlalchemy.sql.expression.TableClause..
               exported_columns

          `inherited from the' FromClause.exported_columns.
          `attribute of' FromClause.

          A ColumnCollection that represents the “exported”
          columns of this Selectable.

          The “exported” columns for a FromClause object are
          synonymous with the FromClause.columns collection.

          New in version 1.4.

          See also
          ........

          See Selectable.exported_columns.

          See SelectBase.exported_columns.

      -- Attribute: sqlalchemy.sql.expression.TableClause..
               foreign_keys

          `inherited from the' FromClause.foreign_keys.
          `attribute of' FromClause.

          Return the collection of ForeignKey marker objects
          which this FromClause references.

          Each ForeignKey is a member of a Table.
          -wide ForeignKeyConstraint.

          See also
          ........

          See Table.foreign_key_constraints.

      -- Method: sqlalchemy.sql.expression.TableClause..
               get_children (omit_attrs=(), **kw)

          `inherited from the' ClauseElement.get_children().
          `method of' ClauseElement.

          Return immediate child Traversible elements of
          this Traversible.

          This is used for visit traversal.

          **kw may contain flags that change the collection that is
          returned, for example to return a subset of items in order to
          cut down on larger traversals, or to return child items from a
          different context (such as schema-level collections instead of
          clause-level).

      -- Attribute: sqlalchemy.sql.expression.TableClause..
               implicit_returning = False

          TableClause doesn’t support having a primary key
          or column -level defaults, so implicit returning doesn’t
          apply.

      -- Method: sqlalchemy.sql.expression.TableClause..
               insert (values=None, inline=False, **kwargs)

          Generate an insert() construct against this
          TableClause.

          E.g.:

               table.insert().values(name='foo')

          See insert() for argument and usage information.

      -- Method: sqlalchemy.sql.expression.TableClause..
               is_derived_from (fromclause)

          `inherited from the' FromClause.is_derived_from().
          `method of' FromClause.

          Return ‘True’ if this FromClause is ‘derived’ from
          the given ‘FromClause’.

          An example would be an Alias of a Table is derived from that
          Table.

      -- Method: sqlalchemy.sql.expression.TableClause..join
               (right, onclause=None, isouter=False, full=False)

          `inherited from the' FromClause.join(). `method of'
          FromClause.

          Return a Join from this FromClause to
          another FromClause.

          E.g.:

               from sqlalchemy import join

               j = user_table.join(address_table,
                               user_table.c.id == address_table.c.user_id)
               stmt = select(user_table).select_from(j)

          would emit SQL along the lines of:

               SELECT user.id, user.name FROM user
               JOIN address ON user.id = address.user_id

          Parameters:

             * ‘right’ – the right side of the join; this is any
               FromClause object such as a Table object,
               and may also be a selectable-compatible object such as an
               ORM-mapped class.

             * ‘onclause’ – a SQL expression representing the ON clause
               of the join.  If left at ‘None’, see FromClause.join()
               will attempt to join the two tables based on a
               foreign key relationship.

             * ‘isouter’ – if True, render a LEFT OUTER JOIN, instead of
               JOIN.

             * ‘full’ – if True, render a FULL OUTER JOIN, instead of
               LEFT OUTER JOIN. Implies FromClause.join.isouter.

               New in version 1.1.

          See also
          ........

          See join(). - standalone function

          See Join. - the type of object produced

      -- Method: sqlalchemy.sql.expression.TableClause..
               lateral (name=None)

          `inherited from the' Selectable.lateral(). `method
          of' Selectable.

          Return a LATERAL alias of this Selectable.

          The return value is the Lateral construct also
          provided by the top-level lateral() function.

          New in version 1.1.

          See also
          ........

          See LATERAL correlation. - overview of usage.

      -- Class: memoized_attribute (fget, doc=None)

          A read-only @property that is only evaluated once.

      -- Method: sqlalchemy.sql.expression.TableClause..
               classmethod memoized_instancemethod (fn)

          `inherited from the' ‘HasMemoized.memoized_instancemethod()’
          `method of' ‘HasMemoized’

          Decorate a method memoize its return value.

      -- Method: sqlalchemy.sql.expression.TableClause..
               outerjoin (right, onclause=None, full=False)

          `inherited from the' FromClause.outerjoin().
          `method of' FromClause.

          Return a Join from this FromClause to
          another FromClause, with the “isouter” flag set to
          True.

          E.g.:

               from sqlalchemy import outerjoin

               j = user_table.outerjoin(address_table,
                               user_table.c.id == address_table.c.user_id)

          The above is equivalent to:

               j = user_table.join(
                   address_table,
                   user_table.c.id == address_table.c.user_id,
                   isouter=True)

          Parameters:

             * ‘right’ – the right side of the join; this is any
               FromClause object such as a Table object,
               and may also be a selectable-compatible object such as an
               ORM-mapped class.

             * ‘onclause’ – a SQL expression representing the ON clause
               of the join.  If left at ‘None’, see FromClause.join()
               will attempt to join the two tables based on a
               foreign key relationship.

             * ‘full’ – if True, render a FULL OUTER JOIN, instead of
               LEFT OUTER JOIN.

               New in version 1.1.

          See also
          ........

          See FromClause.join().

          See Join.

      -- Attribute: sqlalchemy.sql.expression.TableClause..
               primary_key

          `inherited from the' FromClause.primary_key.
          `attribute of' FromClause.

          Return the iterable collection of Column objects
          which comprise the primary key of this
          ‘_selectable.FromClause’.

          For a Table object, this collection is represented
          by the PrimaryKeyConstraint which itself is an
          iterable collection of Column objects.

      -- Method: sqlalchemy.sql.expression.TableClause..
               replace_selectable (old, alias)

          `inherited from the' Selectable.replace_selectable().
          `method of' Selectable.

          Replace all occurrences of FromClause. ‘old’ with
          the given Alias object, returning a copy of this
          FromClause.

          Deprecated since version 1.4: The
          Selectable.replace_selectable() method is deprecated,
          and will be removed in a future release.  Similar
          functionality is available via the sqlalchemy.sql.visitors
          module.

      -- Method: sqlalchemy.sql.expression.TableClause..
               select (whereclause=None, **kwargs)

          `inherited from the' FromClause.select(). `method
          of' FromClause.

          Return a SELECT of this FromClause.

          e.g.:

               stmt = some_table.select().where(some_table.c.id == 5)

          Parameters:

             * ‘whereclause’ – a WHERE clause, equivalent to calling the
               Select.where() method.

               Deprecated since version 1.4: The
               FromClause.select().whereclause parameter is
               deprecated and will be removed in version 2.0.  Please
               make use of the Select.where() method to add
               WHERE criteria to the SELECT statement.

             * ‘**kwargs’ – additional keyword arguments are passed to
               the legacy constructor for Select described at
               Select.create_legacy_select().

          See also
          ........

          See select(). - general purpose method which allows for
          arbitrary column lists.

      -- Method: sqlalchemy.sql.expression.TableClause..
               self_group (against: Optional[Any] = None) ->
               ClauseElement

          `inherited from the' ClauseElement.self_group().
          `method of' ClauseElement.

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

      -- Method: sqlalchemy.sql.expression.TableClause..
               table_valued ()

          `inherited from the' FromClause.table_valued().
          `method of' FromClause.

          Return a ‘TableValuedColumn’ object for this FromClause.

          A ‘TableValuedColumn’ is a ColumnElement that
          represents a complete row in a table.  Support for this
          construct is backend dependent, and is supported in various
          forms by backends such as PostgreSQL, Oracle and SQL Server.

          E.g.:

               >>> from sqlalchemy import select, column, func, table
               >>> a = table("a", column("id"), column("x"), column("y"))
               >>> stmt = select(func.row_to_json(a.table_valued()))
               >>> print(stmt)
               SELECT row_to_json(a) AS row_to_json_1
               FROM a

          New in version 1.4.0b2.

          See also
          ........

          See Working with SQL Functions. - in the
          SQLAlchemy 1.4 / 2.0 Tutorial.

      -- Method: sqlalchemy.sql.expression.TableClause..
               tablesample (sampling, name=None, seed=None)

          `inherited from the' FromClause.tablesample().
          `method of' FromClause.

          Return a TABLESAMPLE alias of this FromClause.

          The return value is the TableSample construct also
          provided by the top-level tablesample() function.

          New in version 1.1.

          See also
          ........

          See tablesample(). - usage guidelines and parameters

      -- Method: sqlalchemy.sql.expression.TableClause..
               update (whereclause=None, values=None, inline=False,
               **kwargs)

          Generate an update() construct against this
          TableClause.

          E.g.:

               table.update().where(table.c.id==7).values(name='foo')

          See update() for argument and usage information.

 -- Class: sqlalchemy.sql.expression.TableSample (*arg, **kw)

     Represent a TABLESAMPLE clause.

     This object is constructed from the tablesample()
     module level function as well as the
     FromClause.tablesample() method available on all
     FromClause subclasses.

     New in version 1.1.

     See also
     ........

     See tablesample().

     `Class signature'

     class sqlalchemy.sql.expression.TableSample. (see
     sqlalchemy.sql.expression.AliasedReturnsRows)

 -- Class: sqlalchemy.sql.expression.TableValuedAlias (*arg, **kw)

     An alias against a “table valued” SQL function.

     This construct provides for a SQL function that returns columns to
     be used in the FROM clause of a SELECT statement.  The object is
     generated using the FunctionElement.table_valued()
     method, e.g.:

          >>> from sqlalchemy import select, func
          >>> fn = func.json_array_elements_text('["one", "two", "three"]').table_valued("value")
          >>> print(select(fn.c.value))
          SELECT anon_1.value
          FROM json_array_elements_text(:json_array_elements_text_1) AS anon_1

     New in version 1.4.0b2.

     See also
     ........

     See Table-Valued Functions. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

     `Class signature'

     class sqlalchemy.sql.expression.TableValuedAlias. (see
     sqlalchemy.sql.expression.Alias)

      -- Method: sqlalchemy.sql.expression.TableValuedAlias..
               alias (name=None)

          Return a new alias of this TableValuedAlias.

          This creates a distinct FROM object that will be distinguished
          from the original one when used in a SQL statement.

      -- Attribute: sqlalchemy.sql.expression.TableValuedAlias..
               column

          Return a column expression representing this
          TableValuedAlias.

          This accessor is used to implement the
          FunctionElement.column_valued() method.  See that method
          for further details.

          E.g.:

               >>> print(select(func.some_func().table_valued("value").column))
               SELECT anon_1 FROM some_func() AS anon_1

          See also
          ........

          See FunctionElement.column_valued().

      -- Method: sqlalchemy.sql.expression.TableValuedAlias..
               lateral (name=None)

          Return a new TableValuedAlias with the lateral
          flag set, so that it renders as LATERAL.

          See also
          ........

          See lateral().

      -- Method: sqlalchemy.sql.expression.TableValuedAlias..
               render_derived (name=None, with_types=False)

          Apply “render derived” to this TableValuedAlias.

          This has the effect of the individual column names listed out
          after the alias name in the “AS” sequence, e.g.:

               >>> print(
               ...     select(
               ...         func.unnest(array(["one", "two", "three"])).
                           table_valued("x", with_ordinality="o").render_derived()
               ...     )
               ... )
               SELECT anon_1.x, anon_1.o
               FROM unnest(ARRAY[%(param_1)s, %(param_2)s, %(param_3)s]) WITH ORDINALITY AS anon_1(x, o)

          The ‘with_types’ keyword will render column types inline
          within the alias expression (this syntax currently applies to
          the PostgreSQL database):

               >>> print(
               ...     select(
               ...         func.json_to_recordset(
               ...             '[{"a":1,"b":"foo"},{"a":"2","c":"bar"}]'
               ...         )
               ...         .table_valued(column("a", Integer), column("b", String))
               ...         .render_derived(with_types=True)
               ...     )
               ... )
               SELECT anon_1.a, anon_1.b FROM json_to_recordset(:json_to_recordset_1)
               AS anon_1(a INTEGER, b VARCHAR)

          Parameters:

             * ‘name’ – optional string name that will be applied to the
               alias generated.  If left as None, a unique anonymizing
               name will be used.

             * ‘with_types’ – if True, the derived columns will include
               the datatype specification with each column.  This is a
               special syntax currently known to be required by
               PostgreSQL for some SQL functions.

 -- Class: sqlalchemy.sql.expression.TextualSelect (text, columns,
          positional=False)

     Wrap a TextClause construct within a SelectBase
     interface.

     This allows the TextClause object to gain a ‘.c’
     collection and other FROM-like capabilities such as
     FromClause.alias(), SelectBase.cte(), etc.

     The TextualSelect construct is produced via the
     TextClause.columns() method - see that method for details.

     Changed in version 1.4: the TextualSelect class was
     renamed from ‘TextAsFrom’, to more correctly suit its role as a
     SELECT-oriented object and not a FROM clause.

     See also
     ........

     See text().

     See TextClause.columns(). - primary creation interface.

     `Class signature'

     class sqlalchemy.sql.expression.TextualSelect. (see
     sqlalchemy.sql.expression.SelectBase)

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               alias (name=None, flat=False)

          `inherited from the' SelectBase.alias(). `method
          of' SelectBase.

          Return a named subquery against this SelectBase.

          For a SelectBase. (as opposed to a
          FromClause), this returns a Subquery object
          which behaves mostly the same as the Alias object
          that is used with a FromClause.

          Changed in version 1.4: The SelectBase.alias()
          method is now a synonym for the SelectBase.subquery()
          method.

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               as_scalar ()

          `inherited from the' SelectBase.as_scalar().
          `method of' SelectBase.

          Deprecated since version 1.4: The
          SelectBase.as_scalar() method is deprecated and will be
          removed in a future release.  Please refer to
          SelectBase.scalar_subquery().

      -- Attribute: sqlalchemy.sql.expression.TextualSelect..
               bind

          `inherited from the' Executable.bind. `attribute
          of' Executable.

          Returns the Engine or Connection to
          which this Executable is bound, or None if none
          found.

          Deprecated since version 1.4: The Executable.bind
          attribute is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  Bound metadata is
          being removed as of SQLAlchemy 2.0.  (Background on SQLAlchemy
          2.0 at: Migrating to SQLAlchemy 2.0)

          This is a traversal which checks locally, then checks among
          the “from” clauses of associated objects until a bound engine
          or connection is found.

      -- Attribute: sqlalchemy.sql.expression.TextualSelect..
               c

          `inherited from the' SelectBase.c. `attribute of'
          SelectBase.

          Deprecated since version 1.4: The SelectBase.c and
          ‘SelectBase.columns’ attributes are deprecated and will be
          removed in a future release; these attributes implicitly
          create a subquery that should be explicit.  Please call
          SelectBase.subquery() first in order to create a
          subquery, which then contains this attribute.  To access the
          columns that this SELECT object SELECTs from, use the
          SelectBase.selected_columns attribute.

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               compare (other, **kw)

          `inherited from the' ClauseElement.compare().
          `method of' ClauseElement.

          Compare this ClauseElement to the given
          ClauseElement.

          Subclasses should override the default behavior, which is a
          straight identity comparison.

          **kw are arguments consumed by subclass ‘compare()’ methods
          and may be used to modify the criteria for comparison (see
          ColumnElement).

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               compile (bind=None, dialect=None, **kw)

          `inherited from the' ClauseElement.compile().
          `method of' ClauseElement.

          Compile this SQL expression.

          The return value is a Compiled object.  Calling
          ‘str()’ or ‘unicode()’ on the returned value will yield a
          string representation of the result.  The Compiled
          object also can return a dictionary of bind parameter names
          and values using the ‘params’ accessor.

          Parameters:

             * ‘bind’ – An ‘Engine’ or ‘Connection’ from which a
               ‘Compiled’ will be acquired.  This argument takes
               precedence over this ClauseElement.’s bound
               engine, if any.

             * ‘column_keys’ – Used for INSERT and UPDATE statements, a
               list of column names which should be present in the
               VALUES clause of the compiled statement.  If ‘None’, all
               columns from the target table object are rendered.

             * ‘dialect’ – A ‘Dialect’ instance from which a ‘Compiled’
               will be acquired.  This argument takes precedence over
               the ‘bind’ argument as well as this ClauseElement.
               ‘s bound engine, if any.

             * ‘compile_kwargs’ – optional dictionary of additional
               parameters that will be passed through to the compiler
               within all “visit” methods.  This allows any custom flag
               to be passed through to a custom compilation construct,
               for example.  It is also used for the case of passing the
               ‘literal_binds’ flag through:

                    from sqlalchemy.sql import table, column, select

                    t = table('t', column('x'))

                    s = select(t).where(t.c.x == 5)

                    print(s.compile(compile_kwargs={"literal_binds": True}))

               New in version 0.9.0.

          See also
          ........

          See How do I render SQL expressions as strings, possibly with bound parameters inlined?.

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               corresponding_column (column, require_embedded=False)

          `inherited from the' Selectable.corresponding_column().
          `method of' Selectable.

          Given a ColumnElement, return the exported
          ColumnElement object from the
          Selectable.exported_columns collection of this
          Selectable which corresponds to that original
          ColumnElement via a common ancestor column.

          Parameters:

             * ‘column’ – the target ColumnElement to be
               matched.

             * ‘require_embedded’ – only return corresponding columns
               for the given ColumnElement, if the given
               ColumnElement is actually present within a
               sub-element of this Selectable.  Normally the
               column will match if it merely shares a common ancestor
               with one of the exported columns of this
               Selectable.

          See also
          ........

          See Selectable.exported_columns. - the
          ColumnCollection that is used for the operation.

          See ColumnCollection.corresponding_column(). -
          implementation method.

      -- Method: sqlalchemy.sql.expression.TextualSelect..cte
               (name=None, recursive=False)

          `inherited from the' HasCTE.cte(). `method of'
          HasCTE.

          Return a new CTE, or Common Table Expression
          instance.

          Common table expressions are a SQL standard whereby SELECT
          statements can draw upon secondary statements specified along
          with the primary statement, using a clause called “WITH”.
          Special semantics regarding UNION can also be employed to
          allow “recursive” queries, where a SELECT statement can draw
          upon the set of rows that have previously been selected.

          CTEs can also be applied to DML constructs UPDATE, INSERT and
          DELETE on some databases, both as a source of CTE rows when
          combined with RETURNING, as well as a consumer of CTE rows.

          Changed in version 1.1: Added support for UPDATE/INSERT/DELETE
          as CTE, CTEs added to UPDATE/INSERT/DELETE.

          SQLAlchemy detects CTE objects, which are treated
          similarly to Alias objects, as special elements to
          be delivered to the FROM clause of the statement as well as to
          a WITH clause at the top of the statement.

          For special prefixes such as PostgreSQL “MATERIALIZED” and
          “NOT MATERIALIZED”, the ‘CTE.prefix_with()’ method may be used
          to establish these.

          Changed in version 1.3.13: Added support for prefixes.  In
          particular - MATERIALIZED and NOT MATERIALIZED.

          Parameters:

             * ‘name’ – name given to the common table expression.  Like
               FromClause.alias(), the name can be left as
               ‘None’ in which case an anonymous symbol will be used at
               query compile time.

             * ‘recursive’ – if ‘True’, will render ‘WITH RECURSIVE’.  A
               recursive common table expression is intended to be used
               in conjunction with UNION ALL in order to derive rows
               from those already selected.

          The following examples include two from PostgreSQL’s
          documentation at
          ‘http://www.postgresql.org/docs/current/static/queries-with.html’,
          as well as additional examples.

          Example 1, non recursive:

               from sqlalchemy import (Table, Column, String, Integer,
                                       MetaData, select, func)

               metadata = MetaData()

               orders = Table('orders', metadata,
                   Column('region', String),
                   Column('amount', Integer),
                   Column('product', String),
                   Column('quantity', Integer)
               )

               regional_sales = select(
                                   orders.c.region,
                                   func.sum(orders.c.amount).label('total_sales')
                               ).group_by(orders.c.region).cte("regional_sales")

               top_regions = select(regional_sales.c.region).\
                       where(
                           regional_sales.c.total_sales >
                           select(
                               func.sum(regional_sales.c.total_sales) / 10
                           )
                       ).cte("top_regions")

               statement = select(
                           orders.c.region,
                           orders.c.product,
                           func.sum(orders.c.quantity).label("product_units"),
                           func.sum(orders.c.amount).label("product_sales")
                   ).where(orders.c.region.in_(
                       select(top_regions.c.region)
                   )).group_by(orders.c.region, orders.c.product)

               result = conn.execute(statement).fetchall()

          Example 2, WITH RECURSIVE:

               from sqlalchemy import (Table, Column, String, Integer,
                                       MetaData, select, func)

               metadata = MetaData()

               parts = Table('parts', metadata,
                   Column('part', String),
                   Column('sub_part', String),
                   Column('quantity', Integer),
               )

               included_parts = select(\
                   parts.c.sub_part, parts.c.part, parts.c.quantity\
                   ).\
                   where(parts.c.part=='our part').\
                   cte(recursive=True)

               incl_alias = included_parts.alias()
               parts_alias = parts.alias()
               included_parts = included_parts.union_all(
                   select(
                       parts_alias.c.sub_part,
                       parts_alias.c.part,
                       parts_alias.c.quantity
                   ).\
                   where(parts_alias.c.part==incl_alias.c.sub_part)
               )

               statement = select(
                           included_parts.c.sub_part,
                           func.sum(included_parts.c.quantity).
                             label('total_quantity')
                       ).\
                       group_by(included_parts.c.sub_part)

               result = conn.execute(statement).fetchall()

          Example 3, an upsert using UPDATE and INSERT with CTEs:

               from datetime import date
               from sqlalchemy import (MetaData, Table, Column, Integer,
                                       Date, select, literal, and_, exists)

               metadata = MetaData()

               visitors = Table('visitors', metadata,
                   Column('product_id', Integer, primary_key=True),
                   Column('date', Date, primary_key=True),
                   Column('count', Integer),
               )

               # add 5 visitors for the product_id == 1
               product_id = 1
               day = date.today()
               count = 5

               update_cte = (
                   visitors.update()
                   .where(and_(visitors.c.product_id == product_id,
                               visitors.c.date == day))
                   .values(count=visitors.c.count + count)
                   .returning(literal(1))
                   .cte('update_cte')
               )

               upsert = visitors.insert().from_select(
                   [visitors.c.product_id, visitors.c.date, visitors.c.count],
                   select(literal(product_id), literal(day), literal(count))
                       .where(~exists(update_cte.select()))
               )

               connection.execute(upsert)

          See also
          ........

          See Query.cte(). - ORM version of HasCTE.cte().

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               execute (*multiparams, **params)

          `inherited from the' Executable.execute(). `method
          of' Executable.

          Compile and execute this Executable.

          Deprecated since version 1.4: The Executable.execute()
          method is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  All statement
          execution in SQLAlchemy 2.0 is performed by the
          Connection.execute() method of Connection, or
          in the ORM by the Session.execute() method of
          Session.  (Background on SQLAlchemy 2.0 at:
          Migrating to SQLAlchemy 2.0)

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               execution_options (**kw)

          `inherited from the' Executable.execution_options().
          `method of' Executable.

          Set non-SQL options for the statement which take effect during
          execution.

          Execution options can be set on a per-statement or per
          Connection basis.  Additionally, the Engine
          and ORM ‘Query’ objects provide access to execution options
          which they in turn configure upon connections.

          The execution_options() method is generative.  A
          new instance of this statement is returned that contains the
          options:

               statement = select(table.c.x, table.c.y)
               statement = statement.execution_options(autocommit=True)

          Note that only a subset of possible execution options can be
          applied to a statement - these include “autocommit” and
          “stream_results”, but not “isolation_level” or
          “compiled_cache”.  See Connection.execution_options()
          for a full list of possible options.

          See also
          ........

          See Connection.execution_options().

          See Query.execution_options().

          See Executable.get_execution_options().

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               exists ()

          `inherited from the' SelectBase.exists(). `method
          of' SelectBase.

          Return an Exists representation of this
          selectable, which can be used as a column expression.

          The returned object is an instance of Exists.

          See also
          ........

          See exists().

          See EXISTS subqueries. - in the 2.0 style tutorial.

          New in version 1.4.

      -- Attribute: sqlalchemy.sql.expression.TextualSelect..
               exported_columns

          `inherited from the' SelectBase.exported_columns.
          `attribute of' SelectBase.

          A ColumnCollection that represents the “exported”
          columns of this Selectable.

          The “exported” columns for a SelectBase object are
          synonymous with the SelectBase.selected_columns
          collection.

          New in version 1.4.

          See also
          ........

          See Selectable.exported_columns.

          See FromClause.exported_columns.

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               get_children (omit_attrs=(), **kw)

          `inherited from the' ClauseElement.get_children().
          `method of' ClauseElement.

          Return immediate child Traversible elements of
          this Traversible.

          This is used for visit traversal.

          **kw may contain flags that change the collection that is
          returned, for example to return a subset of items in order to
          cut down on larger traversals, or to return child items from a
          different context (such as schema-level collections instead of
          clause-level).

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               get_execution_options ()

          `inherited from the' Executable.get_execution_options().
          `method of' Executable.

          Get the non-SQL options which will take effect during
          execution.

          New in version 1.3.

          See also
          ........

          See Executable.execution_options().

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               label (name)

          `inherited from the' SelectBase.label(). `method
          of' SelectBase.

          Return a ‘scalar’ representation of this selectable, embedded
          as a subquery with a label.

          See also
          ........

          See SelectBase.as_scalar().

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               lateral (name=None)

          `inherited from the' SelectBase.lateral(). `method
          of' SelectBase.

          Return a LATERAL alias of this Selectable.

          The return value is the Lateral construct also
          provided by the top-level lateral() function.

          New in version 1.1.

          See also
          ........

          See LATERAL correlation. - overview of usage.

      -- Class: memoized_attribute (fget, doc=None)

          A read-only @property that is only evaluated once.

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               classmethod memoized_instancemethod (fn)

          `inherited from the' ‘HasMemoized.memoized_instancemethod()’
          `method of' ‘HasMemoized’

          Decorate a method memoize its return value.

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               options (*options)

          `inherited from the' Executable.options(). `method
          of' Executable.

          Apply options to this statement.

          In the general sense, options are any kind of Python object
          that can be interpreted by the SQL compiler for the statement.
          These options can be consumed by specific dialects or specific
          kinds of compilers.

          The most commonly known kind of option are the ORM level
          options that apply “eager load” and other loading behaviors to
          an ORM query.  However, options can theoretically be used for
          many other purposes.

          For background on specific kinds of options for specific kinds
          of statements, refer to the documentation for those option
          objects.

          Changed in version 1.4: - added ‘Generative.options()’ to Core
          statement objects towards the goal of allowing unified Core /
          ORM querying capabilities.

          See also
          ........

          See Deferred Column Loader Query Options. - refers to
          options specific to the usage of ORM queries

          See Relationship Loading with Loader Options. - refers
          to options specific to the usage of ORM queries

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               params (*optionaldict, **kwargs)

          `inherited from the' ClauseElement.params().
          `method of' ClauseElement.

          Return a copy with bindparam() elements replaced.

          Returns a copy of this ClauseElement with bindparam()
          elements replaced with values taken from the given
          dictionary:

               >>> clause = column('x') + bindparam('foo')
               >>> print(clause.compile().params)
               {'foo':None}
               >>> print(clause.params({'foo':7}).compile().params)
               {'foo':7}

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               replace_selectable (old, alias)

          `inherited from the' Selectable.replace_selectable().
          `method of' Selectable.

          Replace all occurrences of FromClause. ‘old’ with
          the given Alias object, returning a copy of this
          FromClause.

          Deprecated since version 1.4: The
          Selectable.replace_selectable() method is deprecated,
          and will be removed in a future release.  Similar
          functionality is available via the sqlalchemy.sql.visitors
          module.

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               scalar (*multiparams, **params)

          `inherited from the' Executable.scalar(). `method
          of' Executable.

          Compile and execute this Executable, returning the
          result’s scalar representation.

          Deprecated since version 1.4: The Executable.scalar()
          method is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  Scalar execution in
          SQLAlchemy 2.0 is performed by the Connection.scalar()
          method of Connection, or in the ORM by the
          Session.scalar() method of Session.
          (Background on SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               scalar_subquery ()

          `inherited from the' SelectBase.scalar_subquery().
          `method of' SelectBase.

          Return a ‘scalar’ representation of this selectable, which can
          be used as a column expression.

          The returned object is an instance of ScalarSelect.

          Typically, a select statement which has only one column in its
          columns clause is eligible to be used as a scalar expression.
          The scalar subquery can then be used in the WHERE clause or
          columns clause of an enclosing SELECT.

          Note that the scalar subquery differentiates from the
          FROM-level subquery that can be produced using the
          SelectBase.subquery() method.

          See also
          ........

          See Scalar and Correlated Subqueries. - in the 2.0
          tutorial

          See Scalar Selects. - in the 1.x tutorial

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               select (*arg, **kw)

          `inherited from the' SelectBase.select(). `method
          of' SelectBase.

          Deprecated since version 1.4: The SelectBase.select()
          method is deprecated and will be removed in a future
          release; this method implicitly creates a subquery that should
          be explicit.  Please call SelectBase.subquery()
          first in order to create a subquery, which then can be
          selected.

      -- Attribute: sqlalchemy.sql.expression.TextualSelect..
               selected_columns

          A ColumnCollection representing the columns that
          this SELECT statement or similar construct returns in its
          result set.

          This collection differs from the FromClause.columns
          collection of a FromClause in that the columns
          within this collection cannot be directly nested inside
          another SELECT statement; a subquery must be applied first
          which provides for the necessary parenthesization required by
          SQL.

          For a TextualSelect construct, the collection
          contains the ColumnElement objects that were
          passed to the constructor, typically via the
          TextClause.columns() method.

          New in version 1.4.

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               self_group (against: Optional[Any] = None) ->
               ClauseElement

          `inherited from the' ClauseElement.self_group().
          `method of' ClauseElement.

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               subquery (name=None)

          `inherited from the' SelectBase.subquery(). `method
          of' SelectBase.

          Return a subquery of this SelectBase.

          A subquery is from a SQL perspective a parenthesized, named
          construct that can be placed in the FROM clause of another
          SELECT statement.

          Given a SELECT statement such as:

               stmt = select(table.c.id, table.c.name)

          The above statement might look like:

               SELECT table.id, table.name FROM table

          The subquery form by itself renders the same way, however when
          embedded into the FROM clause of another SELECT statement, it
          becomes a named sub-element:

               subq = stmt.subquery()
               new_stmt = select(subq)

          The above renders as:

               SELECT anon_1.id, anon_1.name
               FROM (SELECT table.id, table.name FROM table) AS anon_1

          Historically, see SelectBase.subquery() is equivalent
          to calling the FromClause.alias() method on a FROM
          object; however, as a SelectBase object is not
          directly FROM object, the SelectBase.subquery()
          method provides clearer semantics.

          New in version 1.4.

      -- Method: sqlalchemy.sql.expression.TextualSelect..
               unique_params (*optionaldict, **kwargs)

          `inherited from the' ClauseElement.unique_params().
          `method of' ClauseElement.

          Return a copy with bindparam() elements replaced.

          Same functionality as ClauseElement.params(),
          except adds ‘unique=True’ to affected bind parameters so that
          multiple statements can be used.

 -- Class: sqlalchemy.sql.expression.Values (*columns, **kw)

     Represent a ‘VALUES’ construct that can be used as a FROM element
     in a statement.

     The Values object is created from the values()
     function.

     New in version 1.4.

     `Class signature'

     class sqlalchemy.sql.expression.Values.
     (‘sqlalchemy.sql.expression.Generative’, see
     sqlalchemy.sql.expression.FromClause)

      -- Method: sqlalchemy.sql.expression.Values..__init__
               (*columns, **kw)

          Construct a new Values object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.sql.expression.values() for a full
          usage and argument description.

      -- Method: sqlalchemy.sql.expression.Values..alias
               (name, **kw)

          Return a new Values construct that is a copy of
          this one with the given name.

          This method is a VALUES-specific specialization of the
          FromClause.alias() method.

          See also
          ........

          See Using Aliases and Subqueries.

          See alias().

      -- Method: sqlalchemy.sql.expression.Values..data
               (values)

          Return a new Values construct, adding the given
          data to the data list.

          E.g.:

               my_values = my_values.data([(1, 'value 1'), (2, 'value2')])

          Parameters: ‘values’ – a sequence (i.e.  list) of tuples that
          map to the column expressions given in the Values
          constructor.

      -- Method: sqlalchemy.sql.expression.Values..lateral
               (name=None)

          Return a new Values with the lateral flag set, so
          that it renders as LATERAL.

          See also
          ........

          See lateral().

4.2.3.4 Label Style Constants
.............................

Constants used with the GenerativeSelect.set_label_style()
method.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See LABEL_STYLE_DEFAULT.The default label style, refers to LABEL_STYLE_DISAMBIGUATE_ONLY.

See LABEL_STYLE_DISAMBIGUATE_ONLY.Label style indicating that columns with a name that conflicts with an existing name should
               be labeled with a semi-anonymizing label when generating the columns clause of a SELECT
               statement.

See LABEL_STYLE_NONE.Label style indicating no automatic labeling should be applied to the columns clause of a
               SELECT statement.

See LABEL_STYLE_TABLENAME_PLUS_COL.Label style indicating all columns should be labeled as ‘<tablename>_<columnname>’ when
               generating the columns clause of a SELECT statement, to disambiguate same-named columns
               referenced from different tables, aliases, or subqueries.

 -- Data: sqlalchemy.sql.expression.LABEL_STYLE_DISAMBIGUATE_ONLY =
          symbol('LABEL_STYLE_DISAMBIGUATE_ONLY')

     Label style indicating that columns with a name that conflicts with
     an existing name should be labeled with a semi-anonymizing label
     when generating the columns clause of a SELECT statement.

     Below, most column names are left unaffected, except for the second
     occurrence of the name ‘columna’, which is labeled using the label
     ‘columna_1’ to disambiguate it from that of ‘tablea.columna’:

          >>> from sqlalchemy import table, column, select, true, LABEL_STYLE_DISAMBIGUATE_ONLY
          >>> table1 = table("table1", column("columna"), column("columnb"))
          >>> table2 = table("table2", column("columna"), column("columnc"))
          >>> print(select(table1, table2).join(table2, true()).set_label_style(LABEL_STYLE_DISAMBIGUATE_ONLY))
          SELECT table1.columna, table1.columnb, table2.columna AS columna_1, table2.columnc
          FROM table1 JOIN table2 ON true

     Used with the GenerativeSelect.set_label_style()
     method, see LABEL_STYLE_DISAMBIGUATE_ONLY is the default
     labeling style for all SELECT statements outside of 1.x style ORM
     queries.

     New in version 1.4.

 -- Data: sqlalchemy.sql.expression.LABEL_STYLE_NONE =
          symbol('LABEL_STYLE_NONE')

     Label style indicating no automatic labeling should be applied to
     the columns clause of a SELECT statement.

     Below, the columns named ‘columna’ are both rendered as is, meaning
     that the name ‘columna’ can only refer to the first occurrence of
     this name within a result set, as well as if the statement were
     used as a subquery:

          >>> from sqlalchemy import table, column, select, true, LABEL_STYLE_NONE
          >>> table1 = table("table1", column("columna"), column("columnb"))
          >>> table2 = table("table2", column("columna"), column("columnc"))
          >>> print(select(table1, table2).join(table2, true()).set_label_style(LABEL_STYLE_NONE))
          SELECT table1.columna, table1.columnb, table2.columna, table2.columnc
          FROM table1 JOIN table2 ON true

     Used with the Select.set_label_style() method.

     New in version 1.4.

 -- Data: sqlalchemy.sql.expression.LABEL_STYLE_TABLENAME_PLUS_COL =
          symbol('LABEL_STYLE_TABLENAME_PLUS_COL')

     Label style indicating all columns should be labeled as
     ‘<tablename>_<columnname>’ when generating the columns clause of a
     SELECT statement, to disambiguate same-named columns referenced
     from different tables, aliases, or subqueries.

     Below, all column names are given a label so that the two
     same-named columns ‘columna’ are disambiguated as ‘table1_columna’
     and >>‘‘<<table2_columna‘:

          >>> from sqlalchemy import table, column, select, true, LABEL_STYLE_TABLENAME_PLUS_COL
          >>> table1 = table("table1", column("columna"), column("columnb"))
          >>> table2 = table("table2", column("columna"), column("columnc"))
          >>> print(select(table1, table2).join(table2, true()).set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL))
          SELECT table1.columna AS table1_columna, table1.columnb AS table1_columnb, table2.columna AS table2_columna, table2.columnc AS table2_columnc
          FROM table1 JOIN table2 ON true

     Used with the GenerativeSelect.set_label_style()
     method.  Equivalent to the legacy method ‘Select.apply_labels()’;
     see LABEL_STYLE_TABLENAME_PLUS_COL is SQLAlchemy’s legacy
     auto-labeling style.  LABEL_STYLE_DISAMBIGUATE_ONLY
     provides a less intrusive approach to disambiguation of same-named
     column expressions.

     New in version 1.4.

 -- Data: sqlalchemy.sql.expression.LABEL_STYLE_DEFAULT

     The default label style, refers to
     LABEL_STYLE_DISAMBIGUATE_ONLY.

     New in version 1.4.

     See also
     ........

     See Select.set_label_style().

     See Select.get_label_style().

4.2.4 Insert, Updates, Deletes
------------------------------

INSERT, UPDATE and DELETE statements build on a hierarchy starting with
UpdateBase.  The Insert and Update
constructs build on the intermediary ValuesBase.

4.2.4.1 DML Foundational Constructors
.....................................

Top level “INSERT”, “UPDATE”, “DELETE” constructors.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See delete.(table[,Construct Delete object.
whereclause,
bind,
returning,
...],
**dialect_kw)

See insert.(table[,Construct an Insert object.
values,
inline,
bind, ...],
**dialect_kw)

See update.(table[,Construct an Update object.
whereclause,
values,
inline,
...],
**dialect_kw)

 -- Function: sqlalchemy.sql.expression.delete (table, whereclause=None,
          bind=None, returning=None, prefixes=None, **dialect_kw)

     Construct Delete object.

     E.g.:

          from sqlalchemy import delete

          stmt = (
              delete(user_table).
              where(user_table.c.id == 5)
          )

     Similar functionality is available via the
     TableClause.delete() method on Table.

     See also
     ........

     See Inserts, Updates and Deletes. - in the 1.x tutorial.

     See Core UPDATE and DELETE. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

     Parameters:

        * ‘table’ – The table to delete rows from.

        * ‘whereclause’ – Optional SQL expression describing the ‘WHERE’
          condition of the ‘DELETE’ statement; is equivalent to using
          the more modern Delete.where() method to specify
          the ‘WHERE’ clause.

          Deprecated since version 1.4: The delete.whereclause
          parameter will be removed in SQLAlchemy 2.0.  Please
          refer to the Delete.where() method.

     See also
     ........

     See Deletes. - SQL Expression Tutorial

 -- Function: sqlalchemy.sql.expression.insert (table, values=None,
          inline=False, bind=None, prefixes=None, returning=None,
          return_defaults=False, **dialect_kw)

     Construct an Insert object.

     E.g.:

          from sqlalchemy import insert

          stmt = (
              insert(user_table).
              values(name='username', fullname='Full Username')
          )

     Similar functionality is available via the
     TableClause.insert() method on Table.

     See also
     ........

     See Insert Expressions. - in the 1.x tutorial.

     See Core Insert. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

     Parameters:

        * ‘table’ – see TableClause which is the subject of the
          insert.

        * ‘values’ – collection of values to be inserted; see
          Insert.values() for a description of allowed formats
          here.  Can be omitted entirely; a Insert construct
          will also dynamically render the VALUES clause at execution
          time based on the parameters passed to
          Connection.execute().

          Deprecated since version 1.4: The insert.values
          parameter will be removed in SQLAlchemy 2.0.  Please refer to
          the Insert.values() method.

        * ‘inline’ – if True, no attempt will be made to retrieve the
          SQL-generated default values to be provided within the
          statement; in particular, this allows SQL expressions to be
          rendered ‘inline’ within the statement without the need to
          pre-execute them beforehand; for backends that support
          “returning”, this turns off the “implicit returning” feature
          for the statement.

          Deprecated since version 1.4: The insert.inline
          parameter will be removed in SQLAlchemy 2.0.  Please use the
          Insert.inline() method.

     If both Insert.values and compile-time bind parameters
     are present, the compile-time bind parameters override the
     information specified within Insert.values on a per-key
     basis.

     The keys within Insert.values can be either
     Column objects or their string identifiers.  Each key may
     reference one of:

        * a literal data value (i.e.  string, number, etc.);

        * a Column object;

        * a SELECT statement.

     If a ‘SELECT’ statement is specified which references this ‘INSERT’
     statement’s table, the statement will be correlated against the
     ‘INSERT’ statement.

     See also
     ........

     See Insert Expressions. - SQL Expression Tutorial

     See Inserts, Updates and Deletes. - SQL Expression Tutorial

 -- Function: sqlalchemy.sql.expression.update (table, whereclause=None,
          values=None, inline=False, bind=None, prefixes=None,
          returning=None, return_defaults=False,
          preserve_parameter_order=False, **dialect_kw)

     Construct an Update object.

     E.g.:

          from sqlalchemy import update

          stmt = (
              update(user_table).
              where(user_table.c.id == 5).
              values(name='user #5')
          )

     Similar functionality is available via the
     TableClause.update() method on Table.

     See also
     ........

     See Inserts, Updates and Deletes. - in the 1.x tutorial.

     See Core UPDATE and DELETE. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

     Parameters:

        * ‘table’ – A Table object representing the database
          table to be updated.

        * ‘whereclause’ – Optional SQL expression describing the ‘WHERE’
          condition of the ‘UPDATE’ statement; is equivalent to using
          the more modern Update.where() method to specify
          the ‘WHERE’ clause.

          Deprecated since version 1.4: The update.whereclause
          parameter will be removed in SQLAlchemy 2.0.  Please
          refer to the Update.where() method.

        * ‘values’ – Optional dictionary which specifies the ‘SET’
          conditions of the ‘UPDATE’.  If left as ‘None’, the ‘SET’
          conditions are determined from those parameters passed to the
          statement during the execution and/or compilation of the
          statement.  When compiled standalone without any parameters,
          the ‘SET’ clause generates for all columns.

          Deprecated since version 1.4: The update.values
          parameter will be removed in SQLAlchemy 2.0.  Please refer to
          the Update.values() method.

          Modern applications may prefer to use the generative
          Update.values() method to set the values of the UPDATE
          statement.

        * ‘inline’ – if True, SQL defaults present on Column.
          objects via the ‘default’ keyword will be compiled ‘inline’
          into the statement and not pre-executed.  This means that
          their values will not be available in the dictionary returned
          from CursorResult.last_updated_params().

          Deprecated since version 1.4: The update.inline
          parameter will be removed in SQLAlchemy 2.0.  Please use the
          Update.inline() method.

        * ‘preserve_parameter_order’ – if True, the update statement is
          expected to receive parameters `only' via the
          Update.values() method, and they must be passed as a
          Python ‘list’ of 2-tuples.  The rendered UPDATE statement will
          emit the SET clause for each referenced column maintaining
          this order.

          Deprecated since version 1.4: The
          update.preserve_parameter_order parameter will be
          removed in SQLAlchemy 2.0.  Use the
          Update.ordered_values() method with a list of tuples.

          New in version 1.0.10.

          See also
          ........

          See Parameter-Ordered Updates. - illustrates the
          Update.ordered_values() method.

     If both ‘values’ and compile-time bind parameters are present, the
     compile-time bind parameters override the information specified
     within ‘values’ on a per-key basis.

     The keys within ‘values’ can be either Column objects or
     their string identifiers (specifically the “key” of the
     Column, normally but not necessarily equivalent to its “name”).
     Normally, the Column objects used here are expected to
     be part of the target Table that is the table to be
     updated.  However when using MySQL, a multiple-table UPDATE
     statement can refer to columns from any of the tables referred to
     in the WHERE clause.

     The values referred to in ‘values’ are typically:

        * a literal data value (i.e.  string, number, etc.)

        * a SQL expression, such as a related Column, a
          scalar-returning select() construct, etc.

     When combining select() constructs within the values
     clause of an update() construct, the subquery
     represented by the select() should be `correlated' to
     the parent table, that is, providing criterion which links the
     table inside the subquery to the outer table being updated:

          users.update().values(
                  name=select(addresses.c.email_address).\
                          where(addresses.c.user_id==users.c.id).\
                          scalar_subquery()
              )

     See also
     ........

     See Inserts, Updates and Deletes. - SQL Expression Language
     Tutorial

4.2.4.2 DML Class Documentation Constructors
............................................

Class documentation for the constructors listed at DML Foundational Constructors.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See Delete.Represent a DELETE construct.

See Insert.Represent an INSERT construct.

See Update.Represent an Update construct.

See UpdateBase.Form the base for ‘INSERT’, ‘UPDATE’, and ‘DELETE’ statements.

See ValuesBase.Supplies support for ValuesBase.values() to INSERT and UPDATE constructs.

 -- Class: sqlalchemy.sql.expression.Delete (table, whereclause=None,
          bind=None, returning=None, prefixes=None, **dialect_kw)

     Represent a DELETE construct.

     The Delete object is created using the delete()
     function.

     `Class signature'

     class sqlalchemy.sql.expression.Delete.
     (‘sqlalchemy.sql.expression.DMLWhereBase’, see
     sqlalchemy.sql.expression.UpdateBase)

      -- Method: sqlalchemy.sql.expression.Delete..where
               (*whereclause)

          `inherited from the' ‘DMLWhereBase.where()’ `method of'
          ‘DMLWhereBase’

          Return a new construct with the given expression(s) added to
          its WHERE clause, joined to the existing clause via AND, if
          any.

          Both Update.where() and Delete.where()
          support multiple-table forms, including database-specific
          ‘UPDATE...FROM’ as well as ‘DELETE..USING’.  For backends that
          don’t have multiple-table support, a backend agnostic approach
          to using multiple tables is to make use of correlated
          subqueries.  See the linked tutorial sections below for
          examples.

          See also
          ........

          `1.x Tutorial Examples'

          See Correlated Updates.

          See Multiple Table Updates.

          See Multiple Table Deletes.

          `2.0 Tutorial Examples'

          See Correlated Updates.

          See UPDATE..FROM.

          See Multiple Table Deletes.

      -- Method: sqlalchemy.sql.expression.Delete..returning
               (*cols)

          `inherited from the' UpdateBase.returning().
          `method of' UpdateBase.

          Add a RETURNING or equivalent clause to this statement.

          e.g.:

               >>> stmt = (
               ...     table.update()
               ...     .where(table.c.data == "value")
               ...     .values(status="X")
               ...     .returning(table.c.server_flag, table.c.updated_timestamp)
               ... )
               >>> print(stmt)
               UPDATE some_table SET status=:status
               WHERE some_table.data = :data_1
               RETURNING some_table.server_flag, some_table.updated_timestamp

          The method may be invoked multiple times to add new entries to
          the list of expressions to be returned.

          New in version 1.4.0b2: The method may be invoked multiple
          times to add new entries to the list of expressions to be
          returned.

          The given collection of column expressions should be derived
          from the table that is the target of the INSERT, UPDATE, or
          DELETE. While Column objects are typical, the
          elements can also be expressions:

               >>> stmt = table.insert().returning(
               ...     (table.c.first_name + " " + table.c.last_name).label("fullname")
               ... )
               >>> print(stmt)
               INSERT INTO some_table (first_name, last_name)
               VALUES (:first_name, :last_name)
               RETURNING some_table.first_name || :first_name_1 || some_table.last_name AS fullname

          Upon compilation, a RETURNING clause, or database equivalent,
          will be rendered within the statement.  For INSERT and UPDATE,
          the values are the newly inserted/updated values.  For DELETE,
          the values are those of the rows which were deleted.

          Upon execution, the values of the columns to be returned are
          made available via the result set and can be iterated using
          CursorResult.fetchone() and similar.  For DBAPIs
          which do not natively support returning values (i.e.
          cx_oracle), SQLAlchemy will approximate this behavior at the
          result level so that a reasonable amount of behavioral
          neutrality is provided.

          Note that not all databases/DBAPIs support RETURNING. For
          those backends with no support, an exception is raised upon
          compilation and/or execution.  For those who do support it,
          the functionality across backends varies greatly, including
          restrictions on executemany() and other statements which
          return multiple rows.  Please read the documentation notes for
          the database in use in order to determine the availability of
          RETURNING.

          See also
          ........

          See ValuesBase.return_defaults(). - an alternative
          method tailored towards efficient fetching of server-side
          defaults and triggers for single-row INSERTs or UPDATEs.

          See INSERT…RETURNING. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

      -- Method: sqlalchemy.sql.expression.Delete..__init__
               (table, whereclause=None, bind=None, returning=None,
               prefixes=None, **dialect_kw)

          Construct a new Delete object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.sql.expression.delete() for a full
          usage and argument description.

 -- Class: sqlalchemy.sql.expression.Insert (table, values=None,
          inline=False, bind=None, prefixes=None, returning=None,
          return_defaults=False, **dialect_kw)

     Represent an INSERT construct.

     The Insert object is created using the insert()
     function.

     `Class signature'

     class sqlalchemy.sql.expression.Insert. (see
     sqlalchemy.sql.expression.ValuesBase)

      -- Method: sqlalchemy.sql.expression.Insert..values
               (*args, **kwargs)

          `inherited from the' ValuesBase.values(). `method
          of' ValuesBase.

          Specify a fixed VALUES clause for an INSERT statement, or the
          SET clause for an UPDATE.

          Note that the Insert and Update
          constructs support per-execution time formatting of the VALUES
          and/or SET clauses, based on the arguments passed to
          Connection.execute().  However, the
          ValuesBase.values() method can be used to “fix” a
          particular set of parameters into the statement.

          Multiple calls to ValuesBase.values() will produce
          a new construct, each one with the parameter list modified to
          include the new parameters sent.  In the typical case of a
          single dictionary of parameters, the newly passed keys will
          replace the same keys in the previous construct.  In the case
          of a list-based “multiple values” construct, each new list of
          values is extended onto the existing list of values.

          Parameters:

             * ‘**kwargs’ – key value pairs representing the string key
               of a Column mapped to the value to be rendered
               into the VALUES or SET clause:

                    users.insert().values(name="some name")

                    users.update().where(users.c.id==5).values(name="some name")

             * ‘*args’ – As an alternative to passing key/value
               parameters, a dictionary, tuple, or list of dictionaries
               or tuples can be passed as a single positional argument
               in order to form the VALUES or SET clause of the
               statement.  The forms that are accepted vary based on
               whether this is an Insert or an Update
               construct.

               For either an Insert or Update
               construct, a single dictionary can be passed, which works
               the same as that of the kwargs form:

                    users.insert().values({"name": "some name"})

                    users.update().values({"name": "some new name"})

               Also for either form but more typically for the
               Insert construct, a tuple that contains an entry for
               every column in the table is also accepted:

                    users.insert().values((5, "some name"))

               The Insert construct also supports being
               passed a list of dictionaries or full-table-tuples, which
               on the server will render the less common SQL syntax of
               “multiple values” - this syntax is supported on backends
               such as SQLite, PostgreSQL, MySQL, but not necessarily
               others:

                    users.insert().values([
                                        {"name": "some name"},
                                        {"name": "some other name"},
                                        {"name": "yet another name"},
                                    ])

               The above form would render a multiple VALUES statement
               similar to:

                    INSERT INTO users (name) VALUES
                                    (:name_1),
                                    (:name_2),
                                    (:name_3)

               It is essential to note that `passing multiple values is
               NOT the same as using traditional executemany() form'.
               The above syntax is a `special' syntax not typically
               used.  To emit an INSERT statement against multiple rows,
               the normal method is to pass a multiple values list to
               the Connection.execute() method, which is
               supported by all database backends and is generally more
               efficient for a very large number of parameters.

                         See also
                         ........

                         See Executing Multiple Statements. - an
                         introduction to the traditional Core method of
                         multiple parameter set invocation for INSERTs
                         and other statements.

                         Changed in version 1.0.0: an INSERT that uses a
                         multiple-VALUES clause, even a list of length
                         one, implies that the Insert.inline
                         flag is set to True, indicating that the
                         statement will not attempt to fetch the “last
                         inserted primary key” or other defaults.  The
                         statement deals with an arbitrary number of
                         rows, so the
                         CursorResult.inserted_primary_key accessor
                         does not apply.

                         Changed in version 1.0.0: A multiple-VALUES
                         INSERT now supports columns with Python side
                         default values and callables in the same way as
                         that of an “executemany” style of invocation;
                         the callable is invoked for each row.  See
                         Python-side defaults invoked for each row individually when using a multivalued insert
                         for other details.

                    The UPDATE construct also supports rendering the SET
                    parameters in a specific order.  For this feature
                    refer to the Update.ordered_values()
                    method.

                         See also
                         ........

                         See Update.ordered_values().

      -- Method: sqlalchemy.sql.expression.Insert..returning
               (*cols)

          `inherited from the' UpdateBase.returning().
          `method of' UpdateBase.

          Add a RETURNING or equivalent clause to this statement.

          e.g.:

               >>> stmt = (
               ...     table.update()
               ...     .where(table.c.data == "value")
               ...     .values(status="X")
               ...     .returning(table.c.server_flag, table.c.updated_timestamp)
               ... )
               >>> print(stmt)
               UPDATE some_table SET status=:status
               WHERE some_table.data = :data_1
               RETURNING some_table.server_flag, some_table.updated_timestamp

          The method may be invoked multiple times to add new entries to
          the list of expressions to be returned.

          New in version 1.4.0b2: The method may be invoked multiple
          times to add new entries to the list of expressions to be
          returned.

          The given collection of column expressions should be derived
          from the table that is the target of the INSERT, UPDATE, or
          DELETE. While Column objects are typical, the
          elements can also be expressions:

               >>> stmt = table.insert().returning(
               ...     (table.c.first_name + " " + table.c.last_name).label("fullname")
               ... )
               >>> print(stmt)
               INSERT INTO some_table (first_name, last_name)
               VALUES (:first_name, :last_name)
               RETURNING some_table.first_name || :first_name_1 || some_table.last_name AS fullname

          Upon compilation, a RETURNING clause, or database equivalent,
          will be rendered within the statement.  For INSERT and UPDATE,
          the values are the newly inserted/updated values.  For DELETE,
          the values are those of the rows which were deleted.

          Upon execution, the values of the columns to be returned are
          made available via the result set and can be iterated using
          CursorResult.fetchone() and similar.  For DBAPIs
          which do not natively support returning values (i.e.
          cx_oracle), SQLAlchemy will approximate this behavior at the
          result level so that a reasonable amount of behavioral
          neutrality is provided.

          Note that not all databases/DBAPIs support RETURNING. For
          those backends with no support, an exception is raised upon
          compilation and/or execution.  For those who do support it,
          the functionality across backends varies greatly, including
          restrictions on executemany() and other statements which
          return multiple rows.  Please read the documentation notes for
          the database in use in order to determine the availability of
          RETURNING.

          See also
          ........

          See ValuesBase.return_defaults(). - an alternative
          method tailored towards efficient fetching of server-side
          defaults and triggers for single-row INSERTs or UPDATEs.

          See INSERT…RETURNING. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

      -- Method: sqlalchemy.sql.expression.Insert..__init__
               (table, values=None, inline=False, bind=None,
               prefixes=None, returning=None, return_defaults=False,
               **dialect_kw)

          Construct a new Insert object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.sql.expression.insert() for a full usage
          and argument description.

      -- Method: sqlalchemy.sql.expression.Insert..from_select
               (names, select, include_defaults=True)

          Return a new Insert construct which represents an
          ‘INSERT...FROM SELECT’ statement.

          e.g.:

               sel = select(table1.c.a, table1.c.b).where(table1.c.c > 5)
               ins = table2.insert().from_select(['a', 'b'], sel)

          Parameters:

             * ‘names’ – a sequence of string column names or
               Column objects representing the target columns.

             * ‘select’ – a select() construct, see
               FromClause or other construct which resolves into a
               FromClause, such as an ORM Query
               object, etc.  The order of columns returned from this
               FROM clause should correspond to the order of columns
               sent as the ‘names’ parameter; while this is not checked
               before passing along to the database, the database would
               normally raise an exception if these column lists don’t
               correspond.

             * ‘include_defaults’ – if True, non-server default values
               and SQL expressions as specified on Column
               objects (as documented in Column INSERT/UPDATE Defaults)
               not otherwise specified in the list of
               names will be rendered into the INSERT and SELECT
               statements, so that these values are also included in the
               data to be inserted.

                    Note: A Python-side default that uses a Python
                    callable function will only be invoked `once' for
                    the whole statement, and `not per row'.

               New in version 1.0.0: - see Insert.from_select()
               now renders Python-side and SQL expression column
               defaults into the SELECT statement for columns otherwise
               not included in the list of column names.

          Changed in version 1.0.0: an INSERT that uses FROM SELECT
          implies that the insert.inline flag is set to
          True, indicating that the statement will not attempt to fetch
          the “last inserted primary key” or other defaults.  The
          statement deals with an arbitrary number of rows, so the
          CursorResult.inserted_primary_key accessor does not
          apply.

      -- Method: sqlalchemy.sql.expression.Insert..inline ()

          Make this Insert construct “inline” .

          When set, no attempt will be made to retrieve the
          SQL-generated default values to be provided within the
          statement; in particular, this allows SQL expressions to be
          rendered ‘inline’ within the statement without the need to
          pre-execute them beforehand; for backends that support
          “returning”, this turns off the “implicit returning” feature
          for the statement.

          Changed in version 1.4: the Insert.inline
          parameter is now superseded by the Insert.inline()
          method.

 -- Class: sqlalchemy.sql.expression.Update (table, whereclause=None,
          values=None, inline=False, bind=None, prefixes=None,
          returning=None, return_defaults=False,
          preserve_parameter_order=False, **dialect_kw)

     Represent an Update construct.

     The Update object is created using the update()
     function.

     `Class signature'

     class sqlalchemy.sql.expression.Update.
     (‘sqlalchemy.sql.expression.DMLWhereBase’, see
     sqlalchemy.sql.expression.ValuesBase)

      -- Method: sqlalchemy.sql.expression.Update..returning
               (*cols)

          `inherited from the' UpdateBase.returning().
          `method of' UpdateBase.

          Add a RETURNING or equivalent clause to this statement.

          e.g.:

               >>> stmt = (
               ...     table.update()
               ...     .where(table.c.data == "value")
               ...     .values(status="X")
               ...     .returning(table.c.server_flag, table.c.updated_timestamp)
               ... )
               >>> print(stmt)
               UPDATE some_table SET status=:status
               WHERE some_table.data = :data_1
               RETURNING some_table.server_flag, some_table.updated_timestamp

          The method may be invoked multiple times to add new entries to
          the list of expressions to be returned.

          New in version 1.4.0b2: The method may be invoked multiple
          times to add new entries to the list of expressions to be
          returned.

          The given collection of column expressions should be derived
          from the table that is the target of the INSERT, UPDATE, or
          DELETE. While Column objects are typical, the
          elements can also be expressions:

               >>> stmt = table.insert().returning(
               ...     (table.c.first_name + " " + table.c.last_name).label("fullname")
               ... )
               >>> print(stmt)
               INSERT INTO some_table (first_name, last_name)
               VALUES (:first_name, :last_name)
               RETURNING some_table.first_name || :first_name_1 || some_table.last_name AS fullname

          Upon compilation, a RETURNING clause, or database equivalent,
          will be rendered within the statement.  For INSERT and UPDATE,
          the values are the newly inserted/updated values.  For DELETE,
          the values are those of the rows which were deleted.

          Upon execution, the values of the columns to be returned are
          made available via the result set and can be iterated using
          CursorResult.fetchone() and similar.  For DBAPIs
          which do not natively support returning values (i.e.
          cx_oracle), SQLAlchemy will approximate this behavior at the
          result level so that a reasonable amount of behavioral
          neutrality is provided.

          Note that not all databases/DBAPIs support RETURNING. For
          those backends with no support, an exception is raised upon
          compilation and/or execution.  For those who do support it,
          the functionality across backends varies greatly, including
          restrictions on executemany() and other statements which
          return multiple rows.  Please read the documentation notes for
          the database in use in order to determine the availability of
          RETURNING.

          See also
          ........

          See ValuesBase.return_defaults(). - an alternative
          method tailored towards efficient fetching of server-side
          defaults and triggers for single-row INSERTs or UPDATEs.

          See INSERT…RETURNING. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

      -- Method: sqlalchemy.sql.expression.Update..where
               (*whereclause)

          `inherited from the' ‘DMLWhereBase.where()’ `method of'
          ‘DMLWhereBase’

          Return a new construct with the given expression(s) added to
          its WHERE clause, joined to the existing clause via AND, if
          any.

          Both Update.where() and Delete.where()
          support multiple-table forms, including database-specific
          ‘UPDATE...FROM’ as well as ‘DELETE..USING’.  For backends that
          don’t have multiple-table support, a backend agnostic approach
          to using multiple tables is to make use of correlated
          subqueries.  See the linked tutorial sections below for
          examples.

          See also
          ........

          `1.x Tutorial Examples'

          See Correlated Updates.

          See Multiple Table Updates.

          See Multiple Table Deletes.

          `2.0 Tutorial Examples'

          See Correlated Updates.

          See UPDATE..FROM.

          See Multiple Table Deletes.

      -- Method: sqlalchemy.sql.expression.Update..values
               (*args, **kwargs)

          `inherited from the' ValuesBase.values(). `method
          of' ValuesBase.

          Specify a fixed VALUES clause for an INSERT statement, or the
          SET clause for an UPDATE.

          Note that the Insert and Update
          constructs support per-execution time formatting of the VALUES
          and/or SET clauses, based on the arguments passed to
          Connection.execute().  However, the
          ValuesBase.values() method can be used to “fix” a
          particular set of parameters into the statement.

          Multiple calls to ValuesBase.values() will produce
          a new construct, each one with the parameter list modified to
          include the new parameters sent.  In the typical case of a
          single dictionary of parameters, the newly passed keys will
          replace the same keys in the previous construct.  In the case
          of a list-based “multiple values” construct, each new list of
          values is extended onto the existing list of values.

          Parameters:

             * ‘**kwargs’ – key value pairs representing the string key
               of a Column mapped to the value to be rendered
               into the VALUES or SET clause:

                    users.insert().values(name="some name")

                    users.update().where(users.c.id==5).values(name="some name")

             * ‘*args’ – As an alternative to passing key/value
               parameters, a dictionary, tuple, or list of dictionaries
               or tuples can be passed as a single positional argument
               in order to form the VALUES or SET clause of the
               statement.  The forms that are accepted vary based on
               whether this is an Insert or an Update
               construct.

               For either an Insert or Update
               construct, a single dictionary can be passed, which works
               the same as that of the kwargs form:

                    users.insert().values({"name": "some name"})

                    users.update().values({"name": "some new name"})

               Also for either form but more typically for the
               Insert construct, a tuple that contains an entry for
               every column in the table is also accepted:

                    users.insert().values((5, "some name"))

               The Insert construct also supports being
               passed a list of dictionaries or full-table-tuples, which
               on the server will render the less common SQL syntax of
               “multiple values” - this syntax is supported on backends
               such as SQLite, PostgreSQL, MySQL, but not necessarily
               others:

                    users.insert().values([
                                        {"name": "some name"},
                                        {"name": "some other name"},
                                        {"name": "yet another name"},
                                    ])

               The above form would render a multiple VALUES statement
               similar to:

                    INSERT INTO users (name) VALUES
                                    (:name_1),
                                    (:name_2),
                                    (:name_3)

               It is essential to note that `passing multiple values is
               NOT the same as using traditional executemany() form'.
               The above syntax is a `special' syntax not typically
               used.  To emit an INSERT statement against multiple rows,
               the normal method is to pass a multiple values list to
               the Connection.execute() method, which is
               supported by all database backends and is generally more
               efficient for a very large number of parameters.

                         See also
                         ........

                         See Executing Multiple Statements. - an
                         introduction to the traditional Core method of
                         multiple parameter set invocation for INSERTs
                         and other statements.

                         Changed in version 1.0.0: an INSERT that uses a
                         multiple-VALUES clause, even a list of length
                         one, implies that the Insert.inline
                         flag is set to True, indicating that the
                         statement will not attempt to fetch the “last
                         inserted primary key” or other defaults.  The
                         statement deals with an arbitrary number of
                         rows, so the
                         CursorResult.inserted_primary_key accessor
                         does not apply.

                         Changed in version 1.0.0: A multiple-VALUES
                         INSERT now supports columns with Python side
                         default values and callables in the same way as
                         that of an “executemany” style of invocation;
                         the callable is invoked for each row.  See
                         Python-side defaults invoked for each row individually when using a multivalued insert
                         for other details.

                    The UPDATE construct also supports rendering the SET
                    parameters in a specific order.  For this feature
                    refer to the Update.ordered_values()
                    method.

                         See also
                         ........

                         See Update.ordered_values().

      -- Method: sqlalchemy.sql.expression.Update..__init__
               (table, whereclause=None, values=None, inline=False,
               bind=None, prefixes=None, returning=None,
               return_defaults=False, preserve_parameter_order=False,
               **dialect_kw)

          Construct a new Update object.

          This constructor is mirrored as a public API function; see
          sqlalchemy.sql.expression.update() for a full
          usage and argument description.

      -- Method: sqlalchemy.sql.expression.Update..inline ()

          Make this Update construct “inline” .

          When set, SQL defaults present on Column objects
          via the ‘default’ keyword will be compiled ‘inline’ into the
          statement and not pre-executed.  This means that their values
          will not be available in the dictionary returned from
          CursorResult.last_updated_params().

          Changed in version 1.4: the update.inline
          parameter is now superseded by the Update.inline()
          method.

      -- Method: sqlalchemy.sql.expression.Update..
               ordered_values (*args)

          Specify the VALUES clause of this UPDATE statement with an
          explicit parameter ordering that will be maintained in the SET
          clause of the resulting UPDATE statement.

          E.g.:

               stmt = table.update().ordered_values(
                   ("name", "ed"), ("ident": "foo")
               )

          See also
          ........

          See Parameter-Ordered Updates. - full example of the
          Update.ordered_values() method.

          Changed in version 1.4: The Update.ordered_values()
          method supersedes the
          update.preserve_parameter_order parameter, which will be
          removed in SQLAlchemy 2.0.

 -- Class: sqlalchemy.sql.expression.UpdateBase

     Form the base for ‘INSERT’, ‘UPDATE’, and ‘DELETE’ statements.

     `Class signature'

     class sqlalchemy.sql.expression.UpdateBase.
     (‘sqlalchemy.sql.roles.DMLRole’, see
     sqlalchemy.sql.expression.HasCTE,
     ‘sqlalchemy.sql.expression.HasCompileState’, see
     sqlalchemy.sql.base.DialectKWArgs,
     sqlalchemy.sql.expression.HasPrefixes,
     sqlalchemy.sql.expression.Executable,
     sqlalchemy.sql.expression.ClauseElement)

      -- Attribute: sqlalchemy.sql.expression.UpdateBase..
               bind

          Return a ‘bind’ linked to this UpdateBase or a
          Table associated with it.

      -- Attribute: sqlalchemy.sql.expression.UpdateBase..
               exported_columns

          Return the RETURNING columns as a column collection for this
          statement.

          New in version 1.4.

      -- Method: sqlalchemy.sql.expression.UpdateBase..params
               (*arg, **kw)

          Set the parameters for the statement.

          This method raises ‘NotImplementedError’ on the base class,
          and is overridden by ValuesBase to provide the
          SET/VALUES clause of UPDATE and INSERT.

      -- Method: sqlalchemy.sql.expression.UpdateBase..
               returning (*cols)

          Add a RETURNING or equivalent clause to this statement.

          e.g.:

               >>> stmt = (
               ...     table.update()
               ...     .where(table.c.data == "value")
               ...     .values(status="X")
               ...     .returning(table.c.server_flag, table.c.updated_timestamp)
               ... )
               >>> print(stmt)
               UPDATE some_table SET status=:status
               WHERE some_table.data = :data_1
               RETURNING some_table.server_flag, some_table.updated_timestamp

          The method may be invoked multiple times to add new entries to
          the list of expressions to be returned.

          New in version 1.4.0b2: The method may be invoked multiple
          times to add new entries to the list of expressions to be
          returned.

          The given collection of column expressions should be derived
          from the table that is the target of the INSERT, UPDATE, or
          DELETE. While Column objects are typical, the
          elements can also be expressions:

               >>> stmt = table.insert().returning(
               ...     (table.c.first_name + " " + table.c.last_name).label("fullname")
               ... )
               >>> print(stmt)
               INSERT INTO some_table (first_name, last_name)
               VALUES (:first_name, :last_name)
               RETURNING some_table.first_name || :first_name_1 || some_table.last_name AS fullname

          Upon compilation, a RETURNING clause, or database equivalent,
          will be rendered within the statement.  For INSERT and UPDATE,
          the values are the newly inserted/updated values.  For DELETE,
          the values are those of the rows which were deleted.

          Upon execution, the values of the columns to be returned are
          made available via the result set and can be iterated using
          CursorResult.fetchone() and similar.  For DBAPIs
          which do not natively support returning values (i.e.
          cx_oracle), SQLAlchemy will approximate this behavior at the
          result level so that a reasonable amount of behavioral
          neutrality is provided.

          Note that not all databases/DBAPIs support RETURNING. For
          those backends with no support, an exception is raised upon
          compilation and/or execution.  For those who do support it,
          the functionality across backends varies greatly, including
          restrictions on executemany() and other statements which
          return multiple rows.  Please read the documentation notes for
          the database in use in order to determine the availability of
          RETURNING.

          See also
          ........

          See ValuesBase.return_defaults(). - an alternative
          method tailored towards efficient fetching of server-side
          defaults and triggers for single-row INSERTs or UPDATEs.

          See INSERT…RETURNING. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

      -- Method: sqlalchemy.sql.expression.UpdateBase..
               with_dialect_options (**opt)

          Add dialect options to this INSERT/UPDATE/DELETE object.

          e.g.:

               upd = table.update().dialect_options(mysql_limit=10)

      -- Method: sqlalchemy.sql.expression.UpdateBase..
               with_hint (text, selectable=None, dialect_name='*')

          Add a table hint for a single table to this
          INSERT/UPDATE/DELETE statement.

               Note: UpdateBase.with_hint() currently
               applies only to Microsoft SQL Server.  For MySQL
               INSERT/UPDATE/DELETE hints, use
               ‘UpdateBase.prefix_with()’.

          The text of the hint is rendered in the appropriate location
          for the database backend in use, relative to the Table
          that is the subject of this statement, or optionally to
          that of the given Table passed as the ‘selectable’
          argument.

          The ‘dialect_name’ option will limit the rendering of a
          particular hint to a particular backend.  Such as, to add a
          hint that only takes effect for SQL Server:

               mytable.insert().with_hint("WITH (PAGLOCK)", dialect_name="mssql")

          Parameters:

             * ‘text’ – Text of the hint.

             * ‘selectable’ – optional Table that specifies
               an element of the FROM clause within an UPDATE or DELETE
               to be the subject of the hint - applies only to certain
               backends.

             * ‘dialect_name’ – defaults to ‘*’, if specified as the
               name of a particular dialect, will apply these hints only
               when that dialect is in use.

 -- Class: sqlalchemy.sql.expression.ValuesBase (table, values,
          prefixes)

     Supplies support for ValuesBase.values() to INSERT and
     UPDATE constructs.

     `Class signature'

     class sqlalchemy.sql.expression.ValuesBase. (see
     sqlalchemy.sql.expression.UpdateBase)

      -- Method: sqlalchemy.sql.expression.ValuesBase..
               return_defaults (*cols)

          Make use of a RETURNING clause for the purpose of fetching
          server-side expressions and defaults.

          E.g.:

               stmt = table.insert().values(data='newdata').return_defaults()

               result = connection.execute(stmt)

               server_created_at = result.returned_defaults['created_at']

          When used against a backend that supports RETURNING, all
          column values generated by SQL expression or
          server-side-default will be added to any existing RETURNING
          clause, provided that UpdateBase.returning() is
          not used simultaneously.  The column values will then be
          available on the result using the
          CursorResult.returned_defaults accessor as a dictionary,
          referring to values keyed to the Column object as
          well as its ‘.key’.

          This method differs from UpdateBase.returning() in
          these ways:

            1. ValuesBase.return_defaults() is only intended
               for use with an INSERT or an UPDATE statement that
               matches exactly one row per parameter set.  While the
               RETURNING construct in the general sense supports
               multiple rows for a multi-row UPDATE or DELETE statement,
               or for special cases of INSERT that return multiple rows
               (e.g.  INSERT from SELECT, multi-valued VALUES clause),
               see ValuesBase.return_defaults() is intended only
               for an “ORM-style” single-row INSERT/UPDATE statement.
               The row returned by the statement is also consumed
               implicitly when ValuesBase.return_defaults()
               is used.  By contrast, see UpdateBase.returning()
               leaves the RETURNING result-set intact with a collection
               of any number of rows.

            2. It is compatible with the existing logic to fetch
               auto-generated primary key values, also known as
               “implicit returning”.  Backends that support RETURNING
               will automatically make use of RETURNING in order to
               fetch the value of newly generated primary keys; while
               the UpdateBase.returning() method circumvents
               this behavior, see ValuesBase.return_defaults()
               leaves it intact.

            3. It can be called against any backend.  Backends that
               don’t support RETURNING will skip the usage of the
               feature, rather than raising an exception.  The return
               value of CursorResult.returned_defaults will
               be ‘None’

            4. An INSERT statement invoked with executemany() is
               supported if the backend database driver supports the
               ‘insert_executemany_returning’ feature, currently this
               includes PostgreSQL with psycopg2.  When executemany is
               used, the CursorResult.returned_defaults_rows
               and CursorResult.inserted_primary_key_rows
               accessors will return the inserted defaults and primary
               keys.

               New in version 1.4.

          ValuesBase.return_defaults() is used by the ORM to
          provide an efficient implementation for the ‘eager_defaults’
          feature of mapper().

          Parameters: ‘cols’ – optional list of column key names or
          Column objects.  If omitted, all column expressions
          evaluated on the server are added to the returning list.

          New in version 0.9.0.

          See also
          ........

          See UpdateBase.returning().

          See CursorResult.returned_defaults.

          See CursorResult.returned_defaults_rows.

          See CursorResult.inserted_primary_key.

          See CursorResult.inserted_primary_key_rows.

      -- Method: sqlalchemy.sql.expression.ValuesBase..values
               (*args, **kwargs)

          Specify a fixed VALUES clause for an INSERT statement, or the
          SET clause for an UPDATE.

          Note that the Insert and Update
          constructs support per-execution time formatting of the VALUES
          and/or SET clauses, based on the arguments passed to
          Connection.execute().  However, the
          ValuesBase.values() method can be used to “fix” a
          particular set of parameters into the statement.

          Multiple calls to ValuesBase.values() will produce
          a new construct, each one with the parameter list modified to
          include the new parameters sent.  In the typical case of a
          single dictionary of parameters, the newly passed keys will
          replace the same keys in the previous construct.  In the case
          of a list-based “multiple values” construct, each new list of
          values is extended onto the existing list of values.

          Parameters:

             * ‘**kwargs’ – key value pairs representing the string key
               of a Column mapped to the value to be rendered
               into the VALUES or SET clause:

                    users.insert().values(name="some name")

                    users.update().where(users.c.id==5).values(name="some name")

             * ‘*args’ – As an alternative to passing key/value
               parameters, a dictionary, tuple, or list of dictionaries
               or tuples can be passed as a single positional argument
               in order to form the VALUES or SET clause of the
               statement.  The forms that are accepted vary based on
               whether this is an Insert or an Update
               construct.

               For either an Insert or Update
               construct, a single dictionary can be passed, which works
               the same as that of the kwargs form:

                    users.insert().values({"name": "some name"})

                    users.update().values({"name": "some new name"})

               Also for either form but more typically for the
               Insert construct, a tuple that contains an entry for
               every column in the table is also accepted:

                    users.insert().values((5, "some name"))

               The Insert construct also supports being
               passed a list of dictionaries or full-table-tuples, which
               on the server will render the less common SQL syntax of
               “multiple values” - this syntax is supported on backends
               such as SQLite, PostgreSQL, MySQL, but not necessarily
               others:

                    users.insert().values([
                                        {"name": "some name"},
                                        {"name": "some other name"},
                                        {"name": "yet another name"},
                                    ])

               The above form would render a multiple VALUES statement
               similar to:

                    INSERT INTO users (name) VALUES
                                    (:name_1),
                                    (:name_2),
                                    (:name_3)

               It is essential to note that `passing multiple values is
               NOT the same as using traditional executemany() form'.
               The above syntax is a `special' syntax not typically
               used.  To emit an INSERT statement against multiple rows,
               the normal method is to pass a multiple values list to
               the Connection.execute() method, which is
               supported by all database backends and is generally more
               efficient for a very large number of parameters.

                         See also
                         ........

                         See Executing Multiple Statements. - an
                         introduction to the traditional Core method of
                         multiple parameter set invocation for INSERTs
                         and other statements.

                         Changed in version 1.0.0: an INSERT that uses a
                         multiple-VALUES clause, even a list of length
                         one, implies that the Insert.inline
                         flag is set to True, indicating that the
                         statement will not attempt to fetch the “last
                         inserted primary key” or other defaults.  The
                         statement deals with an arbitrary number of
                         rows, so the
                         CursorResult.inserted_primary_key accessor
                         does not apply.

                         Changed in version 1.0.0: A multiple-VALUES
                         INSERT now supports columns with Python side
                         default values and callables in the same way as
                         that of an “executemany” style of invocation;
                         the callable is invoked for each row.  See
                         Python-side defaults invoked for each row individually when using a multivalued insert
                         for other details.

                    The UPDATE construct also supports rendering the SET
                    parameters in a specific order.  For this feature
                    refer to the Update.ordered_values()
                    method.

                         See also
                         ........

                         See Update.ordered_values().

4.2.5 SQL and Generic Functions
-------------------------------

SQL functions which are known to SQLAlchemy with regards to
database-specific rendering, return types and argument behavior.
Generic functions are invoked like all SQL functions, using the ‘func’
attribute:

     select(func.count()).select_from(sometable)

Note that any name not known to ‘func’ generates the function name as is
- there is no restriction on what SQL functions can be called, known or
unknown to SQLAlchemy, built-in or user defined.  The section here only
describes those functions where SQLAlchemy already knows what argument
and return types are in use.

See also
........

See Working with SQL Functions. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

SQL function API, factories, and built-in functions.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See AnsiFunction.Define a function in “ansi” format, which doesn’t render parenthesis.

See array_agg.Support for the ARRAY_AGG function.

See char_length.The CHAR_LENGTH() SQL function.

See coalesce.

See concat.The SQL CONCAT() function, which concatenates strings.

See count.The ANSI COUNT aggregate function.  With no arguments, emits COUNT *.

See cube.Implement the ‘CUBE’ grouping operation.

See cume_dist.Implement the ‘cume_dist’ hypothetical-set aggregate function.

See current_date.The CURRENT_DATE() SQL function.

See current_time.The CURRENT_TIME() SQL function.

See current_timestamp.The CURRENT_TIMESTAMP() SQL function.

See current_user.The CURRENT_USER() SQL function.

See dense_rank.Implement the ‘dense_rank’ hypothetical-set aggregate function.

See Function.Describe a named SQL function.

See FunctionAsBinary.

See FunctionElement.Base for SQL function-oriented constructs.

See GenericFunction.Define a ‘generic’ function.

See grouping_sets.Implement the ‘GROUPING SETS’ grouping operation.

See localtime.The localtime() SQL function.

See localtimestamp.The localtimestamp() SQL function.

See max.The SQL MAX() aggregate function.

See min.The SQL MIN() aggregate function.

See mode.Implement the ‘mode’ ordered-set aggregate function.

See next_value.Represent the ‘next value’, given a Sequence as its single argument.

See now.The SQL now() datetime function.

See OrderedSetAgg.Define a function where the return type is based on the sort expression type as defined by
               the expression passed to the FunctionElement.within_group() method.

See percent_rank.Implement the ‘percent_rank’ hypothetical-set aggregate function.

See percentile_cont.Implement the ‘percentile_cont’ ordered-set aggregate function.

See percentile_disc.Implement the ‘percentile_disc’ ordered-set aggregate function.

See random.The RANDOM() SQL function.

See rank.Implement the ‘rank’ hypothetical-set aggregate function.

See register_function.(identifier,Associate a callable with a particular func.  name.
fn[,
package])

See ReturnTypeFromArgs.Define a function whose return type is the same as its arguments.

See rollup.Implement the ‘ROLLUP’ grouping operation.

See ScalarFunctionColumn.

See session_user.The SESSION_USER() SQL function.

See sum.The SQL SUM() aggregate function.

See sysdate.The SYSDATE() SQL function.

See user.The USER() SQL function.

 -- Class: sqlalchemy.sql.functions.AnsiFunction (*args, **kwargs)

     Define a function in “ansi” format, which doesn’t render
     parenthesis.

     `Class signature'

     class sqlalchemy.sql.functions.AnsiFunction. (see
     sqlalchemy.sql.functions.GenericFunction)

 -- Class: sqlalchemy.sql.functions.Function (name, *clauses, **kw)

     Describe a named SQL function.

     The Function object is typically generated from the
     func generation object.

     Parameters:

        * ‘*clauses’ – list of column expressions that form the
          arguments of the SQL function call.

        * ‘type_’ – optional TypeEngine datatype object that
          will be used as the return value of the column expression
          generated by this function call.

        * ‘packagenames’ – a string which indicates package prefix names
          to be prepended to the function name when the SQL is
          generated.  The func generator creates these when
          it is called using dotted format, e.g.:

               func.mypackage.some_function(col1, col2)

     See also
     ........

     See Working with SQL Functions. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

     See func. - namespace which produces registered or ad-hoc
     Function instances.

     See GenericFunction. - allows creation of registered
     function types.

     `Class signature'

     class sqlalchemy.sql.functions.Function. (see
     sqlalchemy.sql.functions.FunctionElement)

      -- Method: sqlalchemy.sql.functions.Function..__init__
               (name, *clauses, **kw)

          Construct a Function.

          The func construct is normally used to construct
          new Function instances.

      -- Attribute: sqlalchemy.sql.functions.Function..type =
               NullType()

          A TypeEngine object which refers to the SQL return
          type represented by this SQL function.

          This datatype may be configured when generating a
          Function object by passing the Function.type_
          parameter, e.g.:

               >>> select(func.lower("some VALUE", type_=String))

          The small number of built-in classes of Function
          come with a built-in datatype that’s appropriate to the class
          of function and its arguments.  For functions that aren’t
          known, the type defaults to the “null type”.

 -- Class: sqlalchemy.sql.functions.FunctionAsBinary (fn, left_index,
          right_index)

     `Class signature'

     class sqlalchemy.sql.functions.FunctionAsBinary. (see
     sqlalchemy.sql.expression.BinaryExpression)

 -- Class: sqlalchemy.sql.functions.FunctionElement (*clauses, **kwargs)

     Base for SQL function-oriented constructs.

     See also
     ........

     See Functions. - in the Core tutorial

     See Function. - named SQL function.

     See func. - namespace which produces registered or ad-hoc
     Function instances.

     See GenericFunction. - allows creation of registered
     function types.

     `Class signature'

     class sqlalchemy.sql.functions.FunctionElement. (see
     sqlalchemy.sql.expression.Executable,
     sqlalchemy.sql.expression.ColumnElement,
     sqlalchemy.sql.expression.FromClause,
     ‘sqlalchemy.sql.expression.Generative’)

      -- Method: sqlalchemy.sql.functions.FunctionElement..
               __init__ (*clauses, **kwargs)

          Construct a FunctionElement.

          Parameters:

             * ‘*clauses’ – list of column expressions that form the
               arguments of the SQL function call.

             * ‘**kwargs’ – additional kwargs are typically consumed by
               subclasses.

          See also
          ........

          See func.

          See Function.

      -- Method: sqlalchemy.sql.functions.FunctionElement..
               alias (name=None)

          Produce a Alias construct against this
          FunctionElement.

               Tip: The FunctionElement.alias() method is
               part of the mechanism by which “table valued” SQL
               functions are created.  However, most use cases are
               covered by higher level methods on FunctionElement
               including FunctionElement.table_valued(),
               and FunctionElement.column_valued().

          This construct wraps the function in a named alias which is
          suitable for the FROM clause, in the style accepted for
          example by PostgreSQL. A column expression is also provided
          using the special ‘.column’ attribute, which may be used to
          refer to the output of the function as a scalar value in the
          columns or where clause, for a backend such as PostgreSQL.

          For a full table-valued expression, use the
          ‘FunctionElement.table_valued()’ method first to establish
          named columns.

          e.g.:

               >>> from sqlalchemy import func, select, column
               >>> data_view = func.unnest([1, 2, 3]).alias("data_view")
               >>> print(select(data_view.column))
               SELECT data_view
               FROM unnest(:unnest_1) AS data_view

          The FunctionElement.column_valued() method
          provides a shortcut for the above pattern:

               >>> data_view = func.unnest([1, 2, 3]).column_valued("data_view")
               >>> print(select(data_view))
               SELECT data_view
               FROM unnest(:unnest_1) AS data_view

          New in version 1.4.0b2: Added the ‘.column’ accessor

          See also
          ........

          See Table-Valued Functions. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

          See FunctionElement.table_valued().

          See FunctionElement.scalar_table_valued().

          See FunctionElement.column_valued().

      -- Method: sqlalchemy.sql.functions.FunctionElement..
               as_comparison (left_index, right_index)

          Interpret this expression as a boolean comparison between two
          values.

          This method is used for an ORM use case described at
          Custom operators based on SQL functions.

          A hypothetical SQL function “is_equal()” which compares to
          values for equality would be written in the Core expression
          language as:

               expr = func.is_equal("a", "b")

          If “is_equal()” above is comparing “a” and “b” for equality,
          the FunctionElement.as_comparison() method would
          be invoked as:

               expr = func.is_equal("a", "b").as_comparison(1, 2)

          Where above, the integer value “1” refers to the first
          argument of the “is_equal()” function and the integer value
          “2” refers to the second.

          This would create a BinaryExpression that is
          equivalent to:

               BinaryExpression("a", "b", operator=op.eq)

          However, at the SQL level it would still render as
          “is_equal(‘a’, ‘b’)”.

          The ORM, when it loads a related object or collection, needs
          to be able to manipulate the “left” and “right” sides of the
          ON clause of a JOIN expression.  The purpose of this method is
          to provide a SQL function construct that can also supply this
          information to the ORM, when used with the
          relationship.primaryjoin parameter.  The return value is
          a containment object called FunctionAsBinary.

          An ORM example is as follows:

               class Venue(Base):
                   __tablename__ = 'venue'
                   id = Column(Integer, primary_key=True)
                   name = Column(String)

                   descendants = relationship(
                       "Venue",
                       primaryjoin=func.instr(
                           remote(foreign(name)), name + "/"
                       ).as_comparison(1, 2) == 1,
                       viewonly=True,
                       order_by=name
                   )

          Above, the “Venue” class can load descendant “Venue” objects
          by determining if the name of the parent Venue is contained
          within the start of the hypothetical descendant value’s name,
          e.g.  “parent1” would match up to “parent1/child1”, but not to
          “parent2/child1”.

          Possible use cases include the “materialized path” example
          given above, as well as making use of special SQL functions
          such as geometric functions to create join conditions.

          Parameters:

             * ‘left_index’ – the integer 1-based index of the function
               argument that serves as the “left” side of the
               expression.

             * ‘right_index’ – the integer 1-based index of the function
               argument that serves as the “right” side of the
               expression.

          New in version 1.3.

          See also
          ........

          See Custom operators based on SQL functions. - example
          use within the ORM

      -- Attribute: sqlalchemy.sql.functions.FunctionElement..
               clauses

          Return the underlying ClauseList which contains
          the arguments for this FunctionElement.

      -- Method: sqlalchemy.sql.functions.FunctionElement..
               column_valued (name=None)

          Return this FunctionElement as a column expression
          that selects from itself as a FROM clause.

          E.g.:

               >>> from sqlalchemy import select, func
               >>> gs = func.generate_series(1, 5, -1).column_valued()
               >>> print(select(gs))
               SELECT anon_1
               FROM generate_series(:generate_series_1, :generate_series_2, :generate_series_3) AS anon_1

          This is shorthand for:

               gs = func.generate_series(1, 5, -1).alias().column

          See also
          ........

          See Column Valued Functions - Table Valued Function as a Scalar Column.
          - in the SQLAlchemy 1.4 / 2.0 Tutorial.

          See Column Valued Functions. - in the PostgreSQL
          documentation

          See FunctionElement.table_valued().

      -- Attribute: sqlalchemy.sql.functions.FunctionElement..
               columns

          The set of columns exported by this FunctionElement.

          This is a placeholder collection that allows the function to
          be placed in the FROM clause of a statement:

               >>> from sqlalchemy import column, select, func
               >>> stmt = select(column('x'), column('y')).select_from(func.myfunction())
               >>> print(stmt)
               SELECT x, y FROM myfunction()

          The above form is a legacy feature that is now superseded by
          the fully capable FunctionElement.table_valued()
          method; see that method for details.

          See also
          ........

          See FunctionElement.table_valued(). - generates
          table-valued SQL function expressions.

      -- Method: sqlalchemy.sql.functions.FunctionElement..
               execute ()

          Execute this FunctionElement against an embedded
          ‘bind’.

          Deprecated since version 1.4: The
          FunctionElement.execute() method is considered legacy as
          of the 1.x series of SQLAlchemy and will be removed in 2.0.
          All statement execution in SQLAlchemy 2.0 is performed by the
          Connection.execute() method of Connection,
          or in the ORM by the Session.execute() method
          of Session.  (Background on SQLAlchemy 2.0 at:
          Migrating to SQLAlchemy 2.0)

          This first calls FunctionElement.select() to
          produce a SELECT construct.

          Note that FunctionElement can be passed to the
          ‘Connectable.execute()’ method of Connection or
          Engine.

      -- Method: sqlalchemy.sql.functions.FunctionElement..
               filter (*criterion)

          Produce a FILTER clause against this function.

          Used against aggregate and window functions, for database
          backends that support the “FILTER” clause.

          The expression:

               func.count(1).filter(True)

          is shorthand for:

               from sqlalchemy import funcfilter
               funcfilter(func.count(1), True)

          New in version 1.0.0.

          See also
          ........

          See Special Modifiers WITHIN GROUP, FILTER. - in the
          SQLAlchemy 1.4 / 2.0 Tutorial.

          See FunctionFilter.

          See funcfilter().

      -- Method: sqlalchemy.sql.functions.FunctionElement..
               over (partition_by=None, order_by=None, rows=None,
               range_=None)

          Produce an OVER clause against this function.

          Used against aggregate or so-called “window” functions, for
          database backends that support window functions.

          The expression:

               func.row_number().over(order_by='x')

          is shorthand for:

               from sqlalchemy import over
               over(func.row_number(), order_by='x')

          See over() for a full description.

          See also
          ........

          See over().

          See Using Window Functions. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

      -- Method: sqlalchemy.sql.functions.FunctionElement..
               scalar ()

          Execute this FunctionElement against an embedded
          ‘bind’ and return a scalar value.

          Deprecated since version 1.4: The
          FunctionElement.scalar() method is considered legacy as
          of the 1.x series of SQLAlchemy and will be removed in 2.0.
          Scalar execution in SQLAlchemy 2.0 is performed by the
          Connection.scalar() method of Connection, or
          in the ORM by the Session.scalar() method of
          Session.  (Background on SQLAlchemy 2.0 at:
          Migrating to SQLAlchemy 2.0)

          This first calls FunctionElement.select() to
          produce a SELECT construct.

          Note that FunctionElement can be passed to the
          ‘Connectable.scalar()’ method of Connection or
          Engine.

      -- Method: sqlalchemy.sql.functions.FunctionElement..
               scalar_table_valued (name, type_=None)

          Return a column expression that’s against this
          FunctionElement as a scalar table-valued expression.

          The returned expression is similar to that returned by a
          single column accessed off of a
          FunctionElement.table_valued() construct, except no FROM
          clause is generated; the function is rendered in the similar
          way as a scalar subquery.

          E.g.:

               >>> from sqlalchemy import func, select
               >>> fn = func.jsonb_each("{'k', 'v'}").scalar_table_valued("key")
               >>> print(select(fn))
               SELECT (jsonb_each(:jsonb_each_1)).key

          New in version 1.4.0b2.

          See also
          ........

          See FunctionElement.table_valued().

          See FunctionElement.alias().

          See FunctionElement.column_valued().

      -- Method: sqlalchemy.sql.functions.FunctionElement..
               select ()

          Produce a select() construct against this
          FunctionElement.

          This is shorthand for:

               s = select(function_element)

      -- Method: sqlalchemy.sql.functions.FunctionElement..
               self_group (against=None)

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

      -- Method: sqlalchemy.sql.functions.FunctionElement..
               table_valued (*expr, **kw)

          Return a TableValuedAlias representation of this
          FunctionElement with table-valued expressions
          added.

          e.g.:

               >>> fn = (
               ...     func.generate_series(1, 5).
               ...     table_valued("value", "start", "stop", "step")
               ... )

               >>> print(select(fn))
               SELECT anon_1.value, anon_1.start, anon_1.stop, anon_1.step
               FROM generate_series(:generate_series_1, :generate_series_2) AS anon_1

               >>> print(select(fn.c.value, fn.c.stop).where(fn.c.value > 2))
               SELECT anon_1.value, anon_1.stop
               FROM generate_series(:generate_series_1, :generate_series_2) AS anon_1
               WHERE anon_1.value > :value_1

          A WITH ORDINALITY expression may be generated by passing the
          keyword argument “with_ordinality”:

               >>> fn = func.generate_series(4, 1, -1).table_valued("gen", with_ordinality="ordinality")
               >>> print(select(fn))
               SELECT anon_1.gen, anon_1.ordinality
               FROM generate_series(:generate_series_1, :generate_series_2, :generate_series_3) WITH ORDINALITY AS anon_1

          Parameters:

             * ‘*expr’ – A series of string column names that will be
               added to the ‘.c’ collection of the resulting
               TableValuedAlias construct as columns.
               column() objects with or without datatypes may also
               be used.

             * ‘name’ – optional name to assign to the alias name that’s
               generated.  If omitted, a unique anonymizing name is
               used.

             * ‘with_ordinality’ – string name that when present results
               in the ‘WITH ORDINALITY’ clause being added to the alias,
               and the given string name will be added as a column to
               the .c collection of the resulting
               TableValuedAlias.

          New in version 1.4.0b2.

          See also
          ........

          See Table-Valued Functions. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

          See Table-Valued Functions. - in the PostgreSQL
          documentation

          See FunctionElement.scalar_table_valued(). - variant of
          FunctionElement.table_valued() which delivers the
          complete table valued expression as a scalar column expression

          See FunctionElement.column_valued().

          See TableValuedAlias.render_derived(). - renders the
          alias using a derived column clause, e.g.  ‘AS name(col1,
          col2, ...)’

      -- Method: sqlalchemy.sql.functions.FunctionElement..
               within_group (*order_by)

          Produce a WITHIN GROUP (ORDER BY expr) clause against this
          function.

          Used against so-called “ordered set aggregate” and
          “hypothetical set aggregate” functions, including
          percentile_cont, rank, dense_rank,
          etc.

          See within_group() for a full description.

          New in version 1.1.

          See also
          ........

          See Special Modifiers WITHIN GROUP, FILTER. - in the
          SQLAlchemy 1.4 / 2.0 Tutorial.

      -- Method: sqlalchemy.sql.functions.FunctionElement..
               within_group_type (within_group)

          For types that define their return type as based on the
          criteria within a WITHIN GROUP (ORDER BY) expression, called
          by the WithinGroup construct.

          Returns None by default, in which case the function’s normal
          ‘.type’ is used.

 -- Class: sqlalchemy.sql.functions.GenericFunction (*args, **kwargs)

     Define a ‘generic’ function.

     A generic function is a pre-established Function class
     that is instantiated automatically when called by name from the
     func attribute.  Note that calling any name from
     func has the effect that a new Function instance
     is created automatically, given that name.  The primary use case
     for defining a GenericFunction class is so that a
     function of a particular name may be given a fixed return type.  It
     can also include custom argument parsing schemes as well as
     additional methods.

     Subclasses of GenericFunction are automatically
     registered under the name of the class.  For example, a
     user-defined function ‘as_utc()’ would be available immediately:

          from sqlalchemy.sql.functions import GenericFunction
          from sqlalchemy.types import DateTime

          class as_utc(GenericFunction):
              type = DateTime

          print(select(func.as_utc()))

     User-defined generic functions can be organized into packages by
     specifying the “package” attribute when defining
     GenericFunction.  Third party libraries containing many
     functions may want to use this in order to avoid name conflicts
     with other systems.  For example, if our ‘as_utc()’ function were
     part of a package “time”:

          class as_utc(GenericFunction):
              type = DateTime
              package = "time"

     The above function would be available from func using
     the package name ‘time’:

          print(select(func.time.as_utc()))

     A final option is to allow the function to be accessed from one
     name in func but to render as a different name.  The
     ‘identifier’ attribute will override the name used to access the
     function as loaded from func, but will retain the usage
     of ‘name’ as the rendered name:

          class GeoBuffer(GenericFunction):
              type = Geometry
              package = "geo"
              name = "ST_Buffer"
              identifier = "buffer"

     The above function will render as follows:

          >>> print(func.geo.buffer())
          ST_Buffer()

     The name will be rendered as is, however without quoting unless the
     name contains special characters that require quoting.  To force
     quoting on or off for the name, use the ‘quoted_name’ construct:

          from sqlalchemy.sql import quoted_name

          class GeoBuffer(GenericFunction):
              type = Geometry
              package = "geo"
              name = quoted_name("ST_Buffer", True)
              identifier = "buffer"

     The above function will render as:

          >>> print(func.geo.buffer())
          "ST_Buffer"()

     New in version 1.3.13: The quoted_name construct is now
     recognized for quoting when used with the “name” attribute of the
     object, so that quoting can be forced on or off for the function
     name.

     `Class signature'

     class sqlalchemy.sql.functions.GenericFunction. (see
     sqlalchemy.sql.functions.Function)

 -- Class: sqlalchemy.sql.functions.OrderedSetAgg (*args, **kwargs)

     Define a function where the return type is based on the sort
     expression type as defined by the expression passed to the
     FunctionElement.within_group() method.

     `Class signature'

     class sqlalchemy.sql.functions.OrderedSetAgg. (see
     sqlalchemy.sql.functions.GenericFunction)

      -- Method: sqlalchemy.sql.functions.OrderedSetAgg..
               within_group_type (within_group)

          For types that define their return type as based on the
          criteria within a WITHIN GROUP (ORDER BY) expression, called
          by the WithinGroup construct.

          Returns None by default, in which case the function’s normal
          ‘.type’ is used.

 -- Class: sqlalchemy.sql.functions.ReturnTypeFromArgs (*args, **kwargs)

     Define a function whose return type is the same as its arguments.

     `Class signature'

     class sqlalchemy.sql.functions.ReturnTypeFromArgs.
     (see sqlalchemy.sql.functions.GenericFunction)

 -- Class: sqlalchemy.sql.functions.ScalarFunctionColumn (fn, name,
          type_=None)

     `Class signature'

     class sqlalchemy.sql.functions.ScalarFunctionColumn.
     (‘sqlalchemy.sql.expression.NamedColumn’)

 -- Class: sqlalchemy.sql.functions.array_agg (*args, **kwargs)

     Support for the ARRAY_AGG function.

     The ‘func.array_agg(expr)’ construct returns an expression of type
     ARRAY.

     e.g.:

          stmt = select(func.array_agg(table.c.values)[2:5])

     New in version 1.1.

     See also
     ........

     See array_agg(). - PostgreSQL-specific version that returns
     ARRAY, which has PG-specific operators added.

     `Class signature'

     class sqlalchemy.sql.functions.array_agg. (see
     sqlalchemy.sql.functions.GenericFunction)

      -- Attribute: sqlalchemy.sql.functions.array_agg..type

          alias of ‘sqlalchemy.sql.sqltypes.ARRAY’

 -- Class: sqlalchemy.sql.functions.char_length (arg, **kwargs)

     The CHAR_LENGTH() SQL function.

     `Class signature'

     class sqlalchemy.sql.functions.char_length. (see
     sqlalchemy.sql.functions.GenericFunction)

      -- Attribute: sqlalchemy.sql.functions.char_length..
               type

          alias of ‘sqlalchemy.sql.sqltypes.Integer’

 -- Class: sqlalchemy.sql.functions.coalesce (*args, **kwargs)

     `Class signature'

     class sqlalchemy.sql.functions.coalesce. (see
     sqlalchemy.sql.functions.ReturnTypeFromArgs)

 -- Class: sqlalchemy.sql.functions.concat (*args, **kwargs)

     The SQL CONCAT() function, which concatenates strings.

     E.g.:

          >>> print(select(func.concat('a', 'b')))
          SELECT concat(:concat_2, :concat_3) AS concat_1

     String concatenation in SQLAlchemy is more commonly available using
     the Python ‘+’ operator with string datatypes, which will render a
     backend-specific concatenation operator, such as

          >>> print(select(literal("a") + "b"))
          SELECT :param_1 || :param_2 AS anon_1

     `Class signature'

     class sqlalchemy.sql.functions.concat. (see
     sqlalchemy.sql.functions.GenericFunction)

      -- Attribute: sqlalchemy.sql.functions.concat..type

          alias of ‘sqlalchemy.sql.sqltypes.String’

 -- Class: sqlalchemy.sql.functions.count (expression=None, **kwargs)

     The ANSI COUNT aggregate function.  With no arguments, emits COUNT
     *.

     E.g.:

          from sqlalchemy import func
          from sqlalchemy import select
          from sqlalchemy import table, column

          my_table = table('some_table', column('id'))

          stmt = select(func.count()).select_from(my_table)

     Executing ‘stmt’ would emit:

          SELECT count(*) AS count_1
          FROM some_table

     `Class signature'

     class sqlalchemy.sql.functions.count. (see
     sqlalchemy.sql.functions.GenericFunction)

      -- Attribute: sqlalchemy.sql.functions.count..type

          alias of ‘sqlalchemy.sql.sqltypes.Integer’

 -- Class: sqlalchemy.sql.functions.cube (*args, **kwargs)

     Implement the ‘CUBE’ grouping operation.

     This function is used as part of the GROUP BY of a statement, e.g.
     see Select.group_by():

          stmt = select(
              func.sum(table.c.value), table.c.col_1, table.c.col_2
          ).group_by(func.cube(table.c.col_1, table.c.col_2))

     New in version 1.2.

     `Class signature'

     class sqlalchemy.sql.functions.cube. (see
     sqlalchemy.sql.functions.GenericFunction)

 -- Class: sqlalchemy.sql.functions.cume_dist (*args, **kwargs)

     Implement the ‘cume_dist’ hypothetical-set aggregate function.

     This function must be used with the
     FunctionElement.within_group() modifier to supply a sort
     expression to operate upon.

     The return type of this function is Numeric.

     New in version 1.1.

     `Class signature'

     class sqlalchemy.sql.functions.cume_dist. (see
     sqlalchemy.sql.functions.GenericFunction)

 -- Class: sqlalchemy.sql.functions.current_date (*args, **kwargs)

     The CURRENT_DATE() SQL function.

     `Class signature'

     class sqlalchemy.sql.functions.current_date. (see
     sqlalchemy.sql.functions.AnsiFunction)

      -- Attribute: sqlalchemy.sql.functions.current_date..
               type

          alias of ‘sqlalchemy.sql.sqltypes.Date’

 -- Class: sqlalchemy.sql.functions.current_time (*args, **kwargs)

     The CURRENT_TIME() SQL function.

     `Class signature'

     class sqlalchemy.sql.functions.current_time. (see
     sqlalchemy.sql.functions.AnsiFunction)

      -- Attribute: sqlalchemy.sql.functions.current_time..
               type

          alias of ‘sqlalchemy.sql.sqltypes.Time’

 -- Class: sqlalchemy.sql.functions.current_timestamp (*args, **kwargs)

     The CURRENT_TIMESTAMP() SQL function.

     `Class signature'

     class sqlalchemy.sql.functions.current_timestamp. (see
     sqlalchemy.sql.functions.AnsiFunction)

      -- Attribute: sqlalchemy.sql.functions.current_timestamp..
               type

          alias of ‘sqlalchemy.sql.sqltypes.DateTime’

 -- Class: sqlalchemy.sql.functions.current_user (*args, **kwargs)

     The CURRENT_USER() SQL function.

     `Class signature'

     class sqlalchemy.sql.functions.current_user. (see
     sqlalchemy.sql.functions.AnsiFunction)

      -- Attribute: sqlalchemy.sql.functions.current_user..
               type

          alias of ‘sqlalchemy.sql.sqltypes.String’

 -- Class: sqlalchemy.sql.functions.dense_rank (*args, **kwargs)

     Implement the ‘dense_rank’ hypothetical-set aggregate function.

     This function must be used with the
     FunctionElement.within_group() modifier to supply a sort
     expression to operate upon.

     The return type of this function is Integer.

     New in version 1.1.

     `Class signature'

     class sqlalchemy.sql.functions.dense_rank. (see
     sqlalchemy.sql.functions.GenericFunction)

 -- Class: sqlalchemy.sql.functions.grouping_sets (*args, **kwargs)

     Implement the ‘GROUPING SETS’ grouping operation.

     This function is used as part of the GROUP BY of a statement, e.g.
     see Select.group_by():

          stmt = select(
              func.sum(table.c.value), table.c.col_1, table.c.col_2
          ).group_by(func.grouping_sets(table.c.col_1, table.c.col_2))

     In order to group by multiple sets, use the tuple_()
     construct:

          from sqlalchemy import tuple_

          stmt = select(
              func.sum(table.c.value),
              table.c.col_1, table.c.col_2,
              table.c.col_3
          ).group_by(
              func.grouping_sets(
                  tuple_(table.c.col_1, table.c.col_2),
                  tuple_(table.c.value, table.c.col_3),
              )
          )

     New in version 1.2.

     `Class signature'

     class sqlalchemy.sql.functions.grouping_sets. (see
     sqlalchemy.sql.functions.GenericFunction)

 -- Class: sqlalchemy.sql.functions.localtime (*args, **kwargs)

     The localtime() SQL function.

     `Class signature'

     class sqlalchemy.sql.functions.localtime. (see
     sqlalchemy.sql.functions.AnsiFunction)

      -- Attribute: sqlalchemy.sql.functions.localtime..type

          alias of ‘sqlalchemy.sql.sqltypes.DateTime’

 -- Class: sqlalchemy.sql.functions.localtimestamp (*args, **kwargs)

     The localtimestamp() SQL function.

     `Class signature'

     class sqlalchemy.sql.functions.localtimestamp. (see
     sqlalchemy.sql.functions.AnsiFunction)

      -- Attribute: sqlalchemy.sql.functions.localtimestamp..
               type

          alias of ‘sqlalchemy.sql.sqltypes.DateTime’

 -- Class: sqlalchemy.sql.functions.max (*args, **kwargs)

     The SQL MAX() aggregate function.

     `Class signature'

     class sqlalchemy.sql.functions.max. (see
     sqlalchemy.sql.functions.ReturnTypeFromArgs)

 -- Class: sqlalchemy.sql.functions.min (*args, **kwargs)

     The SQL MIN() aggregate function.

     `Class signature'

     class sqlalchemy.sql.functions.min. (see
     sqlalchemy.sql.functions.ReturnTypeFromArgs)

 -- Class: sqlalchemy.sql.functions.mode (*args, **kwargs)

     Implement the ‘mode’ ordered-set aggregate function.

     This function must be used with the
     FunctionElement.within_group() modifier to supply a sort
     expression to operate upon.

     The return type of this function is the same as the sort
     expression.

     New in version 1.1.

     `Class signature'

     class sqlalchemy.sql.functions.mode. (see
     sqlalchemy.sql.functions.OrderedSetAgg)

 -- Class: sqlalchemy.sql.functions.next_value (seq, **kw)

     Represent the ‘next value’, given a Sequence as its
     single argument.

     Compiles into the appropriate function on each backend, or will
     raise NotImplementedError if used on a backend that does not
     provide support for sequences.

     `Class signature'

     class sqlalchemy.sql.functions.next_value. (see
     sqlalchemy.sql.functions.GenericFunction)

      -- Method: sqlalchemy.sql.functions.next_value..compare
               (other, **kw)

          Compare this ClauseElement to the given
          ClauseElement.

          Subclasses should override the default behavior, which is a
          straight identity comparison.

          **kw are arguments consumed by subclass ‘compare()’ methods
          and may be used to modify the criteria for comparison (see
          ColumnElement).

 -- Class: sqlalchemy.sql.functions.now (*args, **kwargs)

     The SQL now() datetime function.

     SQLAlchemy dialects will usually render this particular function in
     a backend-specific way, such as rendering it as
     ‘CURRENT_TIMESTAMP’.

     `Class signature'

     class sqlalchemy.sql.functions.now. (see
     sqlalchemy.sql.functions.GenericFunction)

      -- Attribute: sqlalchemy.sql.functions.now..type

          alias of ‘sqlalchemy.sql.sqltypes.DateTime’

 -- Class: sqlalchemy.sql.functions.percent_rank (*args, **kwargs)

     Implement the ‘percent_rank’ hypothetical-set aggregate function.

     This function must be used with the
     FunctionElement.within_group() modifier to supply a sort
     expression to operate upon.

     The return type of this function is Numeric.

     New in version 1.1.

     `Class signature'

     class sqlalchemy.sql.functions.percent_rank. (see
     sqlalchemy.sql.functions.GenericFunction)

 -- Class: sqlalchemy.sql.functions.percentile_cont (*args, **kwargs)

     Implement the ‘percentile_cont’ ordered-set aggregate function.

     This function must be used with the
     FunctionElement.within_group() modifier to supply a sort
     expression to operate upon.

     The return type of this function is the same as the sort
     expression, or if the arguments are an array, an ARRAY
     of the sort expression’s type.

     New in version 1.1.

     `Class signature'

     class sqlalchemy.sql.functions.percentile_cont. (see
     sqlalchemy.sql.functions.OrderedSetAgg)

 -- Class: sqlalchemy.sql.functions.percentile_disc (*args, **kwargs)

     Implement the ‘percentile_disc’ ordered-set aggregate function.

     This function must be used with the
     FunctionElement.within_group() modifier to supply a sort
     expression to operate upon.

     The return type of this function is the same as the sort
     expression, or if the arguments are an array, an ARRAY
     of the sort expression’s type.

     New in version 1.1.

     `Class signature'

     class sqlalchemy.sql.functions.percentile_disc. (see
     sqlalchemy.sql.functions.OrderedSetAgg)

 -- Class: sqlalchemy.sql.functions.random (*args, **kwargs)

     The RANDOM() SQL function.

     `Class signature'

     class sqlalchemy.sql.functions.random. (see
     sqlalchemy.sql.functions.GenericFunction)

 -- Class: sqlalchemy.sql.functions.rank (*args, **kwargs)

     Implement the ‘rank’ hypothetical-set aggregate function.

     This function must be used with the
     FunctionElement.within_group() modifier to supply a sort
     expression to operate upon.

     The return type of this function is Integer.

     New in version 1.1.

     `Class signature'

     class sqlalchemy.sql.functions.rank. (see
     sqlalchemy.sql.functions.GenericFunction)

 -- Function: sqlalchemy.sql.functions.register_function (identifier,
          fn, package='_default')

     Associate a callable with a particular func.  name.

     This is normally called by _GenericMeta, but is also available by
     itself so that a non-Function construct can be associated with the
     func accessor (i.e.  CAST, EXTRACT).

 -- Class: sqlalchemy.sql.functions.rollup (*args, **kwargs)

     Implement the ‘ROLLUP’ grouping operation.

     This function is used as part of the GROUP BY of a statement, e.g.
     see Select.group_by():

          stmt = select(
              func.sum(table.c.value), table.c.col_1, table.c.col_2
          ).group_by(func.rollup(table.c.col_1, table.c.col_2))

     New in version 1.2.

     `Class signature'

     class sqlalchemy.sql.functions.rollup. (see
     sqlalchemy.sql.functions.GenericFunction)

 -- Class: sqlalchemy.sql.functions.session_user (*args, **kwargs)

     The SESSION_USER() SQL function.

     `Class signature'

     class sqlalchemy.sql.functions.session_user. (see
     sqlalchemy.sql.functions.AnsiFunction)

      -- Attribute: sqlalchemy.sql.functions.session_user..
               type

          alias of ‘sqlalchemy.sql.sqltypes.String’

 -- Class: sqlalchemy.sql.functions.sum (*args, **kwargs)

     The SQL SUM() aggregate function.

     `Class signature'

     class sqlalchemy.sql.functions.sum. (see
     sqlalchemy.sql.functions.ReturnTypeFromArgs)

 -- Class: sqlalchemy.sql.functions.sysdate (*args, **kwargs)

     The SYSDATE() SQL function.

     `Class signature'

     class sqlalchemy.sql.functions.sysdate. (see
     sqlalchemy.sql.functions.AnsiFunction)

      -- Attribute: sqlalchemy.sql.functions.sysdate..type

          alias of ‘sqlalchemy.sql.sqltypes.DateTime’

 -- Class: sqlalchemy.sql.functions.user (*args, **kwargs)

     The USER() SQL function.

     `Class signature'

     class sqlalchemy.sql.functions.user. (see
     sqlalchemy.sql.functions.AnsiFunction)

      -- Attribute: sqlalchemy.sql.functions.user..type

          alias of ‘sqlalchemy.sql.sqltypes.String’

4.2.6 Custom SQL Constructs and Compilation Extension
-----------------------------------------------------

Provides an API for creation of custom ClauseElements and compilers.

4.2.6.1 Synopsis
................

Usage involves the creation of one or more ClauseElement
subclasses and one or more callables defining its compilation:

     from sqlalchemy.ext.compiler import compiles
     from sqlalchemy.sql.expression import ColumnClause

     class MyColumn(ColumnClause):
         pass

     @compiles(MyColumn)
     def compile_mycolumn(element, compiler, **kw):
         return "[%s]" % element.name

Above, ‘MyColumn’ extends ColumnClause, the base expression
element for named column objects.  The ‘compiles’ decorator registers
itself with the ‘MyColumn’ class so that it is invoked when the object
is compiled to a string:

     from sqlalchemy import select

     s = select(MyColumn('x'), MyColumn('y'))
     print(str(s))

Produces:

     SELECT [x], [y]

4.2.6.2 Dialect-specific compilation rules
..........................................

Compilers can also be made dialect-specific.  The appropriate compiler
will be invoked for the dialect in use:

     from sqlalchemy.schema import DDLElement

     class AlterColumn(DDLElement):

         def __init__(self, column, cmd):
             self.column = column
             self.cmd = cmd

     @compiles(AlterColumn)
     def visit_alter_column(element, compiler, **kw):
         return "ALTER COLUMN %s ..." % element.column.name

     @compiles(AlterColumn, 'postgresql')
     def visit_alter_column(element, compiler, **kw):
         return "ALTER TABLE %s ALTER COLUMN %s ..." % (element.table.name,
                                                        element.column.name)

The second ‘visit_alter_table’ will be invoked when any ‘postgresql’
dialect is used.

4.2.6.3 Compiling sub-elements of a custom expression construct
...............................................................

The ‘compiler’ argument is the ‘Compiled’ object in use.  This object
can be inspected for any information about the in-progress compilation,
including ‘compiler.dialect’, ‘compiler.statement’ etc.  The
SQLCompiler and DDLCompiler both include a
‘process()’ method which can be used for compilation of embedded
attributes:

     from sqlalchemy.sql.expression import Executable, ClauseElement

     class InsertFromSelect(Executable, ClauseElement):
         def __init__(self, table, select):
             self.table = table
             self.select = select

     @compiles(InsertFromSelect)
     def visit_insert_from_select(element, compiler, **kw):
         return "INSERT INTO %s (%s)" % (
             compiler.process(element.table, asfrom=True, **kw),
             compiler.process(element.select, **kw)
         )

     insert = InsertFromSelect(t1, select(t1).where(t1.c.x>5))
     print(insert)

Produces:

     "INSERT INTO mytable (SELECT mytable.x, mytable.y, mytable.z
                           FROM mytable WHERE mytable.x > :x_1)"

     Note: The above ‘InsertFromSelect’ construct is only an example,
     this actual functionality is already available using the
     Insert.from_select() method.

     Note: The above ‘InsertFromSelect’ construct probably wants to have
     “autocommit” enabled.  See Enabling Autocommit on a Construct
     for this step.

4.2.6.4 Cross Compiling between SQL and DDL compilers
.....................................................

SQL and DDL constructs are each compiled using different base compilers
- ‘SQLCompiler’ and ‘DDLCompiler’.  A common need is to access the
compilation rules of SQL expressions from within a DDL expression.  The
‘DDLCompiler’ includes an accessor ‘sql_compiler’ for this reason, such
as below where we generate a CHECK constraint that embeds a SQL
expression:

     @compiles(MyConstraint)
     def compile_my_constraint(constraint, ddlcompiler, **kw):
         kw['literal_binds'] = True
         return "CONSTRAINT %s CHECK (%s)" % (
             constraint.name,
             ddlcompiler.sql_compiler.process(
                 constraint.expression, **kw)
         )

Above, we add an additional flag to the process step as called by
‘SQLCompiler.process()’, which is the ‘literal_binds’ flag.  This
indicates that any SQL expression which refers to a BindParameter
object or other “literal” object such as those which refer to
strings or integers should be rendered `in-place', rather than being
referred to as a bound parameter; when emitting DDL, bound parameters
are typically not supported.

4.2.6.5 Enabling Autocommit on a Construct
..........................................

Recall from the section Library Level (e.g. emulated) Autocommit
that the Engine, when asked to execute a construct in
the absence of a user-defined transaction, detects if the given
construct represents DML or DDL, that is, a data modification or data
definition statement, which requires (or may require, in the case of
DDL) that the transaction generated by the DBAPI be committed (recall
that DBAPI always has a transaction going on regardless of what
SQLAlchemy does).  Checking for this is actually accomplished by
checking for the “autocommit” execution option on the construct.  When
building a construct like an INSERT derivation, a new DDL type, or
perhaps a stored procedure that alters data, the “autocommit” option
needs to be set in order for the statement to function with
“connectionless” execution (as described in Connectionless Execution, Implicit Execution).

Currently a quick way to do this is to subclass Executable,
then add the “autocommit” flag to the ‘_execution_options’ dictionary
(note this is a “frozen” dictionary which supplies a generative
‘union()’ method):

     from sqlalchemy.sql.expression import Executable, ClauseElement

     class MyInsertThing(Executable, ClauseElement):
         _execution_options = \
             Executable._execution_options.union({'autocommit': True})

More succinctly, if the construct is truly similar to an INSERT, UPDATE,
or DELETE, see UpdateBase can be used, which already is a
subclass of Executable, ClauseElement and
includes the ‘autocommit’ flag:

     from sqlalchemy.sql.expression import UpdateBase

     class MyInsertThing(UpdateBase):
         def __init__(self, ...):
             ...

DDL elements that subclass DDLElement already have the
“autocommit” flag turned on.

4.2.6.6 Changing the default compilation of existing constructs
...............................................................

The compiler extension applies just as well to the existing constructs.
When overriding the compilation of a built in SQL construct, the
@compiles decorator is invoked upon the appropriate class (be sure to
use the class, i.e.  ‘Insert’ or ‘Select’, instead of the creation
function such as ‘insert()’ or ‘select()’).

Within the new compilation function, to get at the “original”
compilation routine, use the appropriate visit_XXX method - this because
compiler.process() will call upon the overriding routine and cause an
endless loop.  Such as, to add “prefix” to all insert statements:

     from sqlalchemy.sql.expression import Insert

     @compiles(Insert)
     def prefix_inserts(insert, compiler, **kw):
         return compiler.visit_insert(insert.prefix_with("some prefix"), **kw)

The above compiler will prefix all INSERT statements with “some prefix”
when compiled.

4.2.6.7 Changing Compilation of Types
.....................................

‘compiler’ works for types, too, such as below where we implement the
MS-SQL specific ‘max’ keyword for ‘String’/‘VARCHAR’:

     @compiles(String, 'mssql')
     @compiles(VARCHAR, 'mssql')
     def compile_varchar(element, compiler, **kw):
         if element.length == 'max':
             return "VARCHAR('max')"
         else:
             return compiler.visit_VARCHAR(element, **kw)

     foo = Table('foo', metadata,
         Column('data', VARCHAR('max'))
     )

4.2.6.8 Subclassing Guidelines
..............................

A big part of using the compiler extension is subclassing SQLAlchemy
expression constructs.  To make this easier, the expression and schema
packages feature a set of “bases” intended for common tasks.  A synopsis
is as follows:

   * ClauseElement. - This is the root expression class.  Any
     SQL expression can be derived from this base, and is probably the
     best choice for longer constructs such as specialized INSERT
     statements.

   * ColumnElement. - The root of all “column-like” elements.
     Anything that you’d place in the “columns” clause of a SELECT
     statement (as well as order by and group by) can derive from this -
     the object will automatically have Python “comparison” behavior.

     ColumnElement classes want to have a ‘type’ member
     which is expression’s return type.  This can be established at the
     instance level in the constructor, or at the class level if its
     generally constant:

          class timestamp(ColumnElement):
              type = TIMESTAMP()

   * FunctionElement. - This is a hybrid of a ‘ColumnElement’
     and a “from clause” like object, and represents a SQL function or
     stored procedure type of call.  Since most databases support
     statements along the line of “SELECT FROM <some function>”
     ‘FunctionElement’ adds in the ability to be used in the FROM clause
     of a ‘select()’ construct:

          from sqlalchemy.sql.expression import FunctionElement

          class coalesce(FunctionElement):
              name = 'coalesce'

          @compiles(coalesce)
          def compile(element, compiler, **kw):
              return "coalesce(%s)" % compiler.process(element.clauses, **kw)

          @compiles(coalesce, 'oracle')
          def compile(element, compiler, **kw):
              if len(element.clauses) > 2:
                  raise TypeError("coalesce only supports two arguments on Oracle")
              return "nvl(%s)" % compiler.process(element.clauses, **kw)

   * DDLElement. - The root of all DDL expressions, like
     CREATE TABLE, ALTER TABLE, etc.  Compilation of ‘DDLElement’
     subclasses is issued by a ‘DDLCompiler’ instead of a ‘SQLCompiler’.
     ‘DDLElement’ also features ‘Table’ and ‘MetaData’ event hooks via
     the ‘execute_at()’ method, allowing the construct to be invoked
     during CREATE TABLE and DROP TABLE sequences.

   * Executable. - This is a mixin which should be used with
     any expression class that represents a “standalone” SQL statement
     that can be passed directly to an ‘execute()’ method.  It is
     already implicit within ‘DDLElement’ and ‘FunctionElement’.

4.2.6.9 Further Examples
........................

4.2.6.10 “UTC timestamp” function
.................................

A function that works like “CURRENT_TIMESTAMP” except applies the
appropriate conversions so that the time is in UTC time.  Timestamps are
best stored in relational databases as UTC, without time zones.  UTC so
that your database doesn’t think time has gone backwards in the hour
when daylight savings ends, without timezones because timezones are like
character encodings - they’re best applied only at the endpoints of an
application (i.e.  convert to UTC upon user input, re-apply desired
timezone upon display).

For PostgreSQL and Microsoft SQL Server:

     from sqlalchemy.sql import expression
     from sqlalchemy.ext.compiler import compiles
     from sqlalchemy.types import DateTime

     class utcnow(expression.FunctionElement):
         type = DateTime()

     @compiles(utcnow, 'postgresql')
     def pg_utcnow(element, compiler, **kw):
         return "TIMEZONE('utc', CURRENT_TIMESTAMP)"

     @compiles(utcnow, 'mssql')
     def ms_utcnow(element, compiler, **kw):
         return "GETUTCDATE()"

Example usage:

     from sqlalchemy import (
                 Table, Column, Integer, String, DateTime, MetaData
             )
     metadata = MetaData()
     event = Table("event", metadata,
         Column("id", Integer, primary_key=True),
         Column("description", String(50), nullable=False),
         Column("timestamp", DateTime, server_default=utcnow())
     )

4.2.6.11 “GREATEST” function
............................

The “GREATEST” function is given any number of arguments and returns the
one that is of the highest value - its equivalent to Python’s ‘max’
function.  A SQL standard version versus a CASE based version which only
accommodates two arguments:

     from sqlalchemy.sql import expression, case
     from sqlalchemy.ext.compiler import compiles
     from sqlalchemy.types import Numeric

     class greatest(expression.FunctionElement):
         type = Numeric()
         name = 'greatest'

     @compiles(greatest)
     def default_greatest(element, compiler, **kw):
         return compiler.visit_function(element)

     @compiles(greatest, 'sqlite')
     @compiles(greatest, 'mssql')
     @compiles(greatest, 'oracle')
     def case_greatest(element, compiler, **kw):
         arg1, arg2 = list(element.clauses)
         return compiler.process(case([(arg1 > arg2, arg1)], else_=arg2), **kw)

Example usage:

     Session.query(Account).\
             filter(
                 greatest(
                     Account.checking_balance,
                     Account.savings_balance) > 10000
             )

4.2.6.12 “false” expression
...........................

Render a “false” constant expression, rendering as “0” on platforms that
don’t have a “false” constant:

     from sqlalchemy.sql import expression
     from sqlalchemy.ext.compiler import compiles

     class sql_false(expression.ColumnElement):
         pass

     @compiles(sql_false)
     def default_false(element, compiler, **kw):
         return "false"

     @compiles(sql_false, 'mssql')
     @compiles(sql_false, 'mysql')
     @compiles(sql_false, 'oracle')
     def int_false(element, compiler, **kw):
         return "0"

Example usage:

     from sqlalchemy import select, union_all

     exp = union_all(
         select(users.c.name, sql_false().label("enrolled")),
         select(customers.c.name, customers.c.enrolled)
     )

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See compiles.(class_,Register a function as a compiler for a given ClauseElement type.
*specs)

See deregister.(class_)Remove all custom compilers associated with a given ClauseElement type.

 -- Function: sqlalchemy.ext.compiler.compiles (class_, *specs)

     Register a function as a compiler for a given ClauseElement
     type.

 -- Function: sqlalchemy.ext.compiler.deregister (class_)

     Remove all custom compilers associated with a given
     ClauseElement type.

4.2.7 Expression Serializer Extension
-------------------------------------

Serializer/Deserializer objects for usage with SQLAlchemy query
structures, allowing “contextual” deserialization.

Any SQLAlchemy query structure, either based on sqlalchemy.sql.* or
sqlalchemy.orm.* can be used.  The mappers, Tables, Columns, Session
etc.  which are referenced by the structure are not persisted in
serialized form, but are instead re-associated with the query structure
when it is deserialized.

Usage is nearly the same as that of the standard Python pickle module:

     from sqlalchemy.ext.serializer import loads, dumps
     metadata = MetaData(bind=some_engine)
     Session = scoped_session(sessionmaker())

     # ... define mappers

     query = Session.query(MyClass).
         filter(MyClass.somedata=='foo').order_by(MyClass.sortkey)

     # pickle the query
     serialized = dumps(query)

     # unpickle.  Pass in metadata + scoped_session
     query2 = loads(serialized, metadata, Session)

     print query2.all()

Similar restrictions as when using raw pickle apply; mapped classes must
be themselves be pickleable, meaning they are importable from a
module-level namespace.

The serializer module is only appropriate for query structures.  It is
not needed for:

   * instances of user-defined classes.  These contain no references to
     engines, sessions or expression constructs in the typical case and
     can be serialized directly.

   * Table metadata that is to be loaded entirely from the serialized
     structure (i.e.  is not already declared in the application).
     Regular pickle.loads()/dumps() can be used to fully dump any
     ‘MetaData’ object, typically one which was reflected from an
     existing database at some previous point in time.  The serializer
     module is specifically for the opposite case, where the Table
     metadata is already present in memory.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See Deserializer.(file[,
metadata,
scoped_session,
engine])

See dumps.(obj[,
protocol])

See loads.(data[,
metadata,
scoped_session,
engine])

See Serializer.(*args,
**kw)

 -- Function: sqlalchemy.ext.serializer.Deserializer (file,
          metadata=None, scoped_session=None, engine=None)

 -- Function: sqlalchemy.ext.serializer.Serializer (*args, **kw)

 -- Function: sqlalchemy.ext.serializer.dumps (obj, protocol=5)

 -- Function: sqlalchemy.ext.serializer.loads (data, metadata=None,
          scoped_session=None, engine=None)

4.2.8 Visitor and Traversal Utilities
-------------------------------------

The sqlalchemy.sql.visitors module consists of classes and
functions that serve the purpose of generically `traversing' a Core SQL
expression structure.  This is not unlike the Python ‘ast’ module in
that is presents a system by which a program can operate upon each
component of a SQL expression.  Common purposes this serves are locating
various kinds of elements such as Table or
BindParameter objects, as well as altering the state of the
structure such as replacing certain FROM clauses with others.

     Note: the sqlalchemy.sql.visitors module is an internal
     API and is not fully public.  It is subject to change and may
     additionally not function as expected for use patterns that aren’t
     considered within SQLAlchemy’s own internals.

The sqlalchemy.sql.visitors module is part of the `internals'
of SQLAlchemy and it is not usually used by calling application code.
It is however used in certain edge cases such as when constructing
caching routines as well as when building out custom SQL expressions
using the Custom SQL Constructs and Compilation Extension.

Visitor/traversal interface and library functions.

SQLAlchemy schema and expression constructs rely on a Python-centric
version of the classic “visitor” pattern as the primary way in which
they apply functionality.  The most common use of this pattern is
statement compilation, where individual expression classes match up to
rendering methods that produce a string result.  Beyond this, the
visitor system is also used to inspect expressions for various
information and patterns, as well as for the purposes of applying
transformations to expressions.

Examples of how the visit system is used can be seen in the source code
of for example the ‘sqlalchemy.sql.util’ and the
‘sqlalchemy.sql.compiler’ modules.  Some background on clause adaption
is also at
‘http://techspot.zzzeek.org/2008/01/23/expression-transformations/’ .

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See cloned_traverse.(obj,Clone the given expression structure, allowing modifications by visitors.
opts,
visitors)

See ExternalTraversal.Base class for visitor objects which can traverse externally using the
               traverse() function.

See InternalTraversal.Defines visitor symbols used for internal traversal.

See iterate.(obj[,Traverse the given expression structure, returning an iterator.
opts])

See replacement_traverse.(obj,Clone the given expression structure, allowing element replacement by a given replacement
opts,          function.
replace)

See traverse.(obj,Traverse and visit the given expression structure using the default iterator.
opts,
visitors)

See traverse_using.(iterator,Visit the given expression structure using the given iterator of objects.
obj,
visitors)

See Traversible.Base class for visitable objects, applies the TraversibleType metaclass.

See TraversibleType.Metaclass which assigns dispatch attributes to various kinds of “visitable” classes.

 -- Class: sqlalchemy.sql.visitors.ExternalTraversal

     Base class for visitor objects which can traverse externally using
     the traverse() function.

     Direct usage of the traverse() function is usually
     preferred.

      -- Method: sqlalchemy.sql.visitors.ExternalTraversal..
               chain (visitor)

          ‘Chain’ an additional ClauseVisitor onto this ClauseVisitor.

          The chained visitor will receive all visit events after this
          one.

      -- Method: sqlalchemy.sql.visitors.ExternalTraversal..
               iterate (obj)

          Traverse the given expression structure, returning an iterator
          of all elements.

      -- Method: sqlalchemy.sql.visitors.ExternalTraversal..
               traverse (obj)

          Traverse and visit the given expression structure.

      -- Attribute: sqlalchemy.sql.visitors.ExternalTraversal..
               visitor_iterator

          Iterate through this visitor and each ‘chained’ visitor.

 -- Class: sqlalchemy.sql.visitors.InternalTraversal

     Defines visitor symbols used for internal traversal.

     The InternalTraversal class is used in two ways.  One
     is that it can serve as the superclass for an object that
     implements the various visit methods of the class.  The other is
     that the symbols themselves of InternalTraversal are
     used within the ‘_traverse_internals’ collection.  Such as, the
     Case object defines ‘_travserse_internals’ as

          _traverse_internals = [
              ("value", InternalTraversal.dp_clauseelement),
              ("whens", InternalTraversal.dp_clauseelement_tuples),
              ("else_", InternalTraversal.dp_clauseelement),
          ]

     Above, the Case class indicates its internal state as
     the attributes named ‘value’, ‘whens’, and ‘else_’.  They each link
     to an InternalTraversal method which indicates the
     type of datastructure referred towards.

     Using the ‘_traverse_internals’ structure, objects of type
     ‘InternalTraversible’ will have the following methods automatically
     implemented:

        * ‘Traversible.get_children()’

        * ‘Traversible._copy_internals()’

        * ‘Traversible._gen_cache_key()’

     Subclasses can also implement these methods directly, particularly
     for the ‘Traversible._copy_internals()’ method, when special steps
     are needed.

     New in version 1.4.

      -- Method: sqlalchemy.sql.visitors.InternalTraversal..
               dispatch (visit_symbol)

          Given a method from InternalTraversal, return the
          corresponding method on a subclass.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_annotations_key = symbol('AK')

          Visit the _annotations_cache_key element.

          This is a dictionary of additional information about a
          ClauseElement that modifies its role.  It should be included
          when comparing or caching objects, however generating this key
          is relatively expensive.  Visitors should check the
          “_annotations” dict for non-None first before creating this
          key.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_anon_name = symbol('AN')

          Visit a potentially “anonymized” string value.

          The string value is considered to be significant for cache key
          generation.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_boolean = symbol('B')

          Visit a boolean value.

          The boolean value is considered to be significant for cache
          key generation.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_clauseelement = symbol('CE')

          Visit a ClauseElement object.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_clauseelement_list = symbol('CL')

          Visit a list of ClauseElement objects.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_clauseelement_tuple = symbol('CT')

          Visit a tuple of ClauseElement objects.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_clauseelement_tuples = symbol('CTS')

          Visit a list of tuples which contain ClauseElement
          objects.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_dialect_options = symbol('DO')

          Visit a dialect options structure.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_dml_multi_values = symbol('DML_MV')

          Visit the values() multi-valued list of dictionaries of an
          Insert object.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_dml_ordered_values = symbol('DML_OV')

          Visit the values() ordered tuple list of an Update
          object.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_dml_values = symbol('DML_V')

          Visit the values() dictionary of a ValuesBase.
          (e.g.  Insert or Update) object.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_fromclause_canonical_column_collection =
               symbol('FC')

          Visit a FromClause object in the context of the
          ‘columns’ attribute.

          The column collection is “canonical”, meaning it is the
          originally defined location of the ColumnClause
          objects.  Right now this means that the object being visited
          is a TableClause or Table object only.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_fromclause_ordered_set = symbol('CO')

          Visit an ordered set of FromClause objects.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_has_cache_key = symbol('HC')

          Visit a ‘HasCacheKey’ object.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_has_cache_key_list = symbol('HL')

          Visit a list of ‘HasCacheKey’ objects.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_named_ddl_element = symbol('DD')

          Visit a simple named DDL element.

          The current object used by this method is the Sequence.

          The object is only considered to be important for cache key
          generation as far as its name, but not any other aspects of
          it.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_operator = symbol('O')

          Visit an operator.

          The operator is a function from the ‘sqlalchemy.sql.operators’
          module.

          The operator value is considered to be significant for cache
          key generation.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_plain_dict = symbol('PD')

          Visit a dictionary with string keys.

          The keys of the dictionary should be strings, the values
          should be immutable and hashable.  The dictionary is
          considered to be significant for cache key generation.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_plain_obj = symbol('PO')

          Visit a plain python object.

          The value should be immutable and hashable, such as an
          integer.  The value is considered to be significant for cache
          key generation.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_prefix_sequence = symbol('PS')

          Visit the sequence represented by HasPrefixes or
          HasSuffixes.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_propagate_attrs = symbol('PA')

          Visit the propagate attrs dict.  this hardcodes to the
          particular elements we care about right now.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_statement_hint_list = symbol('SH')

          Visit the ‘_statement_hints’ collection of a Select
          object.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_string = symbol('S')

          Visit a plain string value.

          Examples include table and column names, bound parameter keys,
          special keywords such as “UNION”, “UNION ALL”.

          The string value is considered to be significant for cache key
          generation.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_string_clauseelement_dict = symbol('CD')

          Visit a dictionary of string keys to ClauseElement
          objects.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_string_list = symbol('SL')

          Visit a list of strings.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_string_multi_dict = symbol('MD')

          Visit a dictionary of string keys to values which may either
          be plain immutable/hashable or ‘HasCacheKey’ objects.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_table_hint_list = symbol('TH')

          Visit the ‘_hints’ collection of a Select object.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_type = symbol('T')

          Visit a TypeEngine object

          The type object is considered to be significant for cache key
          generation.

      -- Attribute: sqlalchemy.sql.visitors.InternalTraversal..
               dp_unknown_structure = symbol('UK')

          Visit an unknown structure.

 -- Class: sqlalchemy.sql.visitors.Traversible

     Base class for visitable objects, applies the
     TraversibleType metaclass.

 -- Class: sqlalchemy.sql.visitors.TraversibleType (clsname, bases,
          clsdict)

     Metaclass which assigns dispatch attributes to various kinds of
     “visitable” classes.

     Attributes include:

        * The ‘_compiler_dispatch’ method, corresponding to
          ‘__visit_name__’.  This is called “external traversal” because
          the caller of each visit() method is responsible for
          sub-traversing the inner elements of each object.  This is
          appropriate for string compilers and other traversals that
          need to call upon the inner elements in a specific pattern.

        * internal traversal collections ‘_children_traversal’,
          ‘_cache_key_traversal’, ‘_copy_internals_traversal’, generated
          from an optional ‘_traverse_internals’ collection of symbols
          which comes from the InternalTraversal list of
          symbols.  This is called “internal traversal” MARKMARK

     `Class signature'

     class sqlalchemy.sql.visitors.TraversibleType.
     (‘builtins.type’)

 -- Function: sqlalchemy.sql.visitors.cloned_traverse (obj, opts,
          visitors)

     Clone the given expression structure, allowing modifications by
     visitors.

     Traversal usage is the same as that of traverse().  The
     visitor functions present in the ‘visitors’ dictionary may also
     modify the internals of the given structure as the traversal
     proceeds.

     The central API feature used by the cloned_traverse()
     and replacement_traverse() functions, in addition to
     the ClauseElement.get_children() function that is used
     to achieve the iteration, is the ‘ClauseElement._copy_internals()’
     method.  For a ClauseElement structure to support
     cloning and replacement traversals correctly, it needs to be able
     to pass a cloning function into its internal members in order to
     make copies of them.

     See also
     ........

     See traverse().

     See replacement_traverse().

 -- Function: sqlalchemy.sql.visitors.iterate (obj, opts={})

     Traverse the given expression structure, returning an iterator.

     Traversal is configured to be breadth-first.

     The central API feature used by the iterate() function
     is the ClauseElement.get_children() method of
     ClauseElement objects.  This method should return all the
     ClauseElement objects which are associated with a
     particular ClauseElement object.  For example, a
     Case structure will refer to a series of ColumnElement
     objects within its “whens” and “else_” member variables.

     Parameters:

        * ‘obj’ – see ClauseElement structure to be traversed

        * ‘opts’ – dictionary of iteration options.  This dictionary is
          usually empty in modern usage.

 -- Function: sqlalchemy.sql.visitors.replacement_traverse (obj, opts,
          replace)

     Clone the given expression structure, allowing element replacement
     by a given replacement function.

     This function is very similar to the cloned_traverse()
     function, except instead of being passed a dictionary of visitors,
     all elements are unconditionally passed into the given replace
     function.  The replace function then has the option to return an
     entirely new object which will replace the one given.  If it
     returns ‘None’, then the object is kept in place.

     The difference in usage between cloned_traverse() and
     replacement_traverse() is that in the former case, an
     already-cloned object is passed to the visitor function, and the
     visitor function can then manipulate the internal state of the
     object.  In the case of the latter, the visitor function should
     only return an entirely different object, or do nothing.

     The use case for replacement_traverse() is that of
     replacing a FROM clause inside of a SQL structure with a different
     one, as is a common use case within the ORM.

 -- Function: sqlalchemy.sql.visitors.traverse (obj, opts, visitors)

     Traverse and visit the given expression structure using the default
     iterator.

          e.g.:

               from sqlalchemy.sql import visitors

               stmt = select(some_table).where(some_table.c.foo == 'bar')

               def visit_bindparam(bind_param):
                   print("found bound value: %s" % bind_param.value)

               visitors.traverse(stmt, {}, {"bindparam": visit_bindparam})

     The iteration of objects uses the iterate() function,
     which does a breadth-first traversal using a stack.

     Parameters:

        * ‘obj’ – see ClauseElement structure to be traversed

        * ‘opts’ – dictionary of iteration options.  This dictionary is
          usually empty in modern usage.

        * ‘visitors’ – dictionary of visit functions.  The dictionary
          should have strings as keys, each of which would correspond to
          the ‘__visit_name__’ of a particular kind of SQL expression
          object, and callable functions as values, each of which
          represents a visitor function for that kind of object.

 -- Function: sqlalchemy.sql.visitors.traverse_using (iterator, obj,
          visitors)

     Visit the given expression structure using the given iterator of
     objects.

     traverse_using() is usually called internally as the
     result of the traverse() function.

     Parameters:

        * ‘iterator’ – an iterable or sequence which will yield
          ClauseElement structures; the iterator is assumed to be
          the product of the iterate() function.

        * ‘obj’ – the ClauseElement that was used as the
          target of the iterate() function.

        * ‘visitors’ – dictionary of visit functions.  See
          traverse() for details on this dictionary.

     See also
     ........

     See traverse().

4.3 Schema Definition Language
==============================

This section references SQLAlchemy `schema metadata', a comprehensive
system of describing and inspecting database schemas.

The core of SQLAlchemy’s query and object mapping operations are
supported by `database metadata', which is comprised of Python objects
that describe tables and other schema-level objects.  These objects are
at the core of three major types of operations - issuing CREATE and DROP
statements (known as `DDL'), constructing SQL queries, and expressing
information about structures that already exist within the database.

Database metadata can be expressed by explicitly naming the various
components and their properties, using constructs such as Table,
see Column, ForeignKey and Sequence, all
of which are imported from the ‘sqlalchemy.schema’ package.  It can also
be generated by SQLAlchemy using a process called `reflection', which
means you start with a single object such as Table, assign it
a name, and then instruct SQLAlchemy to load all the additional
information related to that name from a particular engine source.

A key feature of SQLAlchemy’s database metadata constructs is that they
are designed to be used in a `declarative' style which closely resembles
that of real DDL. They are therefore most intuitive to those who have
some background in creating real schema generation scripts.

4.3.1 Describing Databases with MetaData
----------------------------------------

This section discusses the fundamental Table, Column
and MetaData objects.

A collection of metadata entities is stored in an object aptly named
MetaData:

     from sqlalchemy import *

     metadata = MetaData()

MetaData is a container object that keeps together many
different features of a database (or multiple databases) being
described.

To represent a table, use the Table class.  Its two primary
arguments are the table name, then the MetaData object which
it will be associated with.  The remaining positional arguments are
mostly Column objects describing each column:

     user = Table('user', metadata,
         Column('user_id', Integer, primary_key=True),
         Column('user_name', String(16), nullable=False),
         Column('email_address', String(60)),
         Column('nickname', String(50), nullable=False)
     )

Above, a table called ‘user’ is described, which contains four columns.
The primary key of the table consists of the ‘user_id’ column.  Multiple
columns may be assigned the ‘primary_key=True’ flag which denotes a
multi-column primary key, known as a `composite' primary key.

Note also that each column describes its datatype using objects
corresponding to genericized types, such as Integer and
String.  SQLAlchemy features dozens of types of varying levels of
specificity as well as the ability to create custom types.
Documentation on the type system can be found at Column and Data Types.

4.3.1.1 Accessing Tables and Columns
....................................

The MetaData object contains all of the schema constructs
we’ve associated with it.  It supports a few methods of accessing these
table objects, such as the ‘sorted_tables’ accessor which returns a list
of each Table object in order of foreign key dependency (that
is, each table is preceded by all tables which it references):

     >>> for t in metadata.sorted_tables:
     ...    print(t.name)
     user
     user_preference
     invoice
     invoice_item

In most cases, individual Table objects have been explicitly
declared, and these objects are typically accessed directly as
module-level variables in an application.  Once a Table has
been defined, it has a full set of accessors which allow inspection of
its properties.  Given the following Table definition:

     employees = Table('employees', metadata,
         Column('employee_id', Integer, primary_key=True),
         Column('employee_name', String(60), nullable=False),
         Column('employee_dept', Integer, ForeignKey("departments.department_id"))
     )

Note the ForeignKey object used in this table - this
construct defines a reference to a remote table, and is fully described
in Defining Foreign Keys.  Methods of accessing information
about this table include:

     # access the column "EMPLOYEE_ID":
     employees.columns.employee_id

     # or just
     employees.c.employee_id

     # via string
     employees.c['employee_id']

     # iterate through all columns
     for c in employees.c:
         print(c)

     # get the table's primary key columns
     for primary_key in employees.primary_key:
         print(primary_key)

     # get the table's foreign key objects:
     for fkey in employees.foreign_keys:
         print(fkey)

     # access the table's MetaData:
     employees.metadata

     # access the table's bound Engine or Connection, if its MetaData is bound:
     employees.bind

     # access a column's name, type, nullable, primary key, foreign key
     employees.c.employee_id.name
     employees.c.employee_id.type
     employees.c.employee_id.nullable
     employees.c.employee_id.primary_key
     employees.c.employee_dept.foreign_keys

     # get the "key" of a column, which defaults to its name, but can
     # be any user-defined string:
     employees.c.employee_name.key

     # access a column's table:
     employees.c.employee_id.table is employees

     # get the table related by a foreign key
     list(employees.c.employee_dept.foreign_keys)[0].column.table

4.3.1.2 Creating and Dropping Database Tables
.............................................

Once you’ve defined some Table objects, assuming you’re
working with a brand new database one thing you might want to do is
issue CREATE statements for those tables and their related constructs
(as an aside, it’s also quite possible that you `don’t' want to do this,
if you already have some preferred methodology such as tools included
with your database or an existing scripting system - if that’s the case,
feel free to skip this section - SQLAlchemy has no requirement that it
be used to create your tables).

The usual way to issue CREATE is to use create_all() on the
MetaData object.  This method will issue queries that first
check for the existence of each individual table, and if not found will
issue the CREATE statements:

          engine = create_engine('sqlite:///:memory:')

          metadata = MetaData()

          user = Table('user', metadata,
              Column('user_id', Integer, primary_key=True),
              Column('user_name', String(16), nullable=False),
              Column('email_address', String(60), key='email'),
              Column('nickname', String(50), nullable=False)
          )

          user_prefs = Table('user_prefs', metadata,
              Column('pref_id', Integer, primary_key=True),
              Column('user_id', Integer, ForeignKey("user.user_id"), nullable=False),
              Column('pref_name', String(40), nullable=False),
              Column('pref_value', String(100))
          )

          {sql}metadata.create_all(engine)
          PRAGMA table_info(user){}
          CREATE TABLE user(
                  user_id INTEGER NOT NULL PRIMARY KEY,
                  user_name VARCHAR(16) NOT NULL,
                  email_address VARCHAR(60),
                  nickname VARCHAR(50) NOT NULL
          )
          PRAGMA table_info(user_prefs){}
          CREATE TABLE user_prefs(
                  pref_id INTEGER NOT NULL PRIMARY KEY,
                  user_id INTEGER NOT NULL REFERENCES user(user_id),
                  pref_name VARCHAR(40) NOT NULL,
                  pref_value VARCHAR(100)
          )

create_all() creates foreign key constraints between tables
usually inline with the table definition itself, and for this reason it
also generates the tables in order of their dependency.  There are
options to change this behavior such that ‘ALTER TABLE’ is used instead.

Dropping all tables is similarly achieved using the drop_all()
method.  This method does the exact opposite of create_all().
- the presence of each table is checked first, and tables are
dropped in reverse order of dependency.

Creating and dropping individual tables can be done via the ‘create()’
and ‘drop()’ methods of Table.  These methods by default issue
the CREATE or DROP regardless of the table being present:

     engine = create_engine('sqlite:///:memory:')

     meta = MetaData()

     employees = Table('employees', meta,
         Column('employee_id', Integer, primary_key=True),
         Column('employee_name', String(60), nullable=False, key='name'),
         Column('employee_dept', Integer, ForeignKey("departments.department_id"))
     )
     {sql}employees.create(engine)
     CREATE TABLE employees(
     employee_id SERIAL NOT NULL PRIMARY KEY,
     employee_name VARCHAR(60) NOT NULL,
     employee_dept INTEGER REFERENCES departments(department_id)
     )
     {}

‘drop()’ method:

     {sql}employees.drop(engine)
     DROP TABLE employees
     {}

To enable the “check first for the table existing” logic, add the
‘checkfirst=True’ argument to ‘create()’ or ‘drop()’:

     employees.create(engine, checkfirst=True)
     employees.drop(engine, checkfirst=False)

4.3.1.3 Altering Database Objects through Migrations
....................................................

While SQLAlchemy directly supports emitting CREATE and DROP statements
for schema constructs, the ability to alter those constructs, usually
via the ALTER statement as well as other database-specific constructs,
is outside of the scope of SQLAlchemy itself.  While it’s easy enough to
emit ALTER statements and similar by hand, such as by passing a
text() construct to Connection.execute() or by using
the DDL construct, it’s a common practice to automate the
maintenance of database schemas in relation to application code using
schema migration tools.

The SQLAlchemy project offers the Alembic(1) migration tool for this
purpose.  Alembic features a highly customizable environment and a
minimalistic usage pattern, supporting such features as transactional
DDL, automatic generation of “candidate” migrations, an “offline” mode
which generates SQL scripts, and support for branch resolution.

Alembic supersedes the SQLAlchemy-Migrate(2) project, which is the
original migration tool for SQLAlchemy and is now considered legacy.

   ---------- Footnotes ----------

   (1) https://alembic.sqlalchemy.org

   (2) https://github.com/openstack/sqlalchemy-migrate

4.3.1.4 Specifying the Schema Name
..................................

Most databases support the concept of multiple “schemas” - namespaces
that refer to alternate sets of tables and other constructs.  The
server-side geometry of a “schema” takes many forms, including names of
“schemas” under the scope of a particular database (e.g.  PostgreSQL
schemas), named sibling databases (e.g.  MySQL / MariaDB access to other
databases on the same server), as well as other concepts like tables
owned by other usernames (Oracle, SQL Server) or even names that refer
to alternate database files (SQLite ATTACH) or remote servers (Oracle
DBLINK with synonyms).

What all of the above approaches have (mostly) in common is that there’s
a way of referring to this alternate set of tables using a string name.
SQLAlchemy refers to this name as the `schema name'.  Within SQLAlchemy,
this is nothing more than a string name which is associated with a
Table object, and is then rendered into SQL statements in a manner
appropriate to the target database such that the table is referred
towards in its remote “schema”, whatever mechanism that is on the target
database.

The “schema” name may be associated directly with a Table
using the Table.schema argument; when using the ORM with
declarative table configuration, the parameter is passed
using the ‘__table_args__’ parameter dictionary.

The “schema” name may also be associated with the MetaData
object where it will take effect automatically for all Table
objects associated with that MetaData that don’t otherwise
specify their own name.  Finally, SQLAlchemy also supports a “dynamic”
schema name system that is often used for multi-tenant applications such
that a single set of Table metadata may refer to a
dynamically configured set of schema names on a per-connection or
per-statement basis.

See also
........

See Explicit Schema Name with Declarative Table. - schema name
specification when using the ORM declarative table
configuration

The most basic example is that of the Table.schema argument
using a Core Table object as follows:

     metadata = MetaData()

     financial_info = Table(
         'financial_info',
         metadata,
         Column('id', Integer, primary_key=True),
         Column('value', String(100), nullable=False),
         schema='remote_banks'
     )

SQL that is rendered using this Table, such as the SELECT
statement below, will explicitly qualify the table name ‘financial_info’
with the ‘remote_banks’ schema name:

     >>> print(select(financial_info))
     SELECT remote_banks.financial_info.id, remote_banks.financial_info.value
     FROM remote_banks.financial_info

When a Table object is declared with an explicit schema name,
it is stored in the internal MetaData namespace using the
combination of the schema and table name.  We can view this in the
MetaData.tables collection by searching for the key
‘'remote_banks.financial_info'’:

     >>> metadata.tables['remote_banks.financial_info']
     Table('financial_info', MetaData(),
     Column('id', Integer(), table=<financial_info>, primary_key=True, nullable=False),
     Column('value', String(length=100), table=<financial_info>, nullable=False),
     schema='remote_banks')

This dotted name is also what must be used when referring to the table
for use with the ForeignKey or ForeignKeyConstraint
objects, even if the referring table is also in that same schema:

     customer = Table(
         "customer",
         metadata,
         Column('id', Integer, primary_key=True),
         Column('financial_info_id', ForeignKey("remote_banks.financial_info.id")),
         schema='remote_banks'
     )

The Table.schema argument may also be used with certain
dialects to indicate a multiple-token (e.g.  dotted) path to a
particular table.  This is particularly important on a database such as
Microsoft SQL Server where there are often dotted “database/owner”
tokens.  The tokens may be placed directly in the name at once, such as:

     schema="dbo.scott"

See also
........

See Multipart Schema Names. - describes use of dotted schema
names with the SQL Server dialect.

4.3.1.5 Specifying a Default Schema Name with MetaData
......................................................

The MetaData object may also set up an explicit default
option for all Table.schema parameters by passing the
MetaData.schema argument to the top level MetaData
construct:

     metadata = MetaData(schema="remote_banks")

     financial_info = Table(
         'financial_info',
         metadata,
         Column('id', Integer, primary_key=True),
         Column('value', String(100), nullable=False),
     )

Above, for any Table object (or Sequence object
directly associated with the MetaData) which leaves the
Table.schema parameter at its default of ‘None’ will instead act
as though the parameter were set to the value ‘"remote_banks"’.  This
includes that the Table is cataloged in the MetaData
using the schema-qualified name, that is:

     metadata.tables['remote_banks.financial_info']

When using the ForeignKey or ForeignKeyConstraint
objects to refer to this table, either the schema-qualified name or the
non-schema-qualified name may be used to refer to the
‘remote_banks.financial_info’ table:

     # either will work:

     refers_to_financial_info = Table(
         'refers_to_financial_info',
         metadata,
         Column('id', Integer, primary_key=True),
         Column('fiid', ForeignKey('financial_info.id')),
     )

     # or

     refers_to_financial_info = Table(
         'refers_to_financial_info',
         metadata,
         Column('id', Integer, primary_key=True),
         Column('fiid', ForeignKey('remote_banks.financial_info.id')),
     )

When using a MetaData object that sets MetaData.schema,
a Table that wishes to specify that it should not be
schema qualified may use the special symbol BLANK_SCHEMA:

     from sqlalchemy import BLANK_SCHEMA

     metadata = MetaData(schema="remote_banks")

     financial_info = Table(
         'financial_info',
         metadata,
         Column('id', Integer, primary_key=True),
         Column('value', String(100), nullable=False),
         schema=BLANK_SCHEMA  # will not use "remote_banks"
     )

See also
........

See MetaData.schema.

4.3.1.6 Applying Dynamic Schema Naming Conventions
..................................................

The names used by the Table.schema parameter may also be
applied against a lookup that is dynamic on a per-connection or
per-execution basis, so that for example in multi-tenant situations,
each transaction or statement may be targeted at a specific set of
schema names that change.  The section Translation of Schema Names
describes how this feature is used.

See also
........

See Translation of Schema Names.

4.3.1.7 Setting a Default Schema for New Connections
....................................................

The above approaches all refer to methods of including an explicit
schema-name within SQL statements.  Database connections in fact feature
the concept of a “default” schema, which is the name of the “schema” (or
database, owner, etc.)  that takes place if a table name is not
explicitly schema-qualified.  These names are usually configured at the
login level, such as when connecting to a PostgreSQL database, the
default “schema” is called “public”.

There are often cases where the default “schema” cannot be set via the
login itself and instead would usefully be configured each time a
connection is made, using a statement such as “SET SEARCH_PATH” on
PostgreSQL or “ALTER SESSION” on Oracle.  These approaches may be
achieved by using the ‘PoolEvents.connect()’ event, which allows access
to the DBAPI connection when it is first created.  For example, to set
the Oracle CURRENT_SCHEMA variable to an alternate name:

     from sqlalchemy import event
     from sqlalchemy import create_engine

     engine = create_engine("oracle+cx_oracle://scott:tiger@tsn_name")

     @event.listens_for(engine, "connect", insert=True)
     def set_current_schema(dbapi_connection, connection_record):
         cursor = dbapi_connection.cursor()
         cursor.execute("ALTER SESSION SET CURRENT_SCHEMA=%s" % schema_name)
         cursor.close()

Above, the ‘set_current_schema()’ event handler will take place
immediately when the above Engine first connects; as the
event is “inserted” into the beginning of the handler list, it will also
take place before the dialect’s own event handlers are run, in
particular including the one that will determine the “default schema”
for the connection.

For other databases, consult the database and/or dialect documentation
for specific information regarding how default schemas are configured.

Changed in version 1.4.0b2: The above recipe now works without the need
to establish additional event handlers.

See also
........

See Setting Alternate Search Paths on Connect. - in the
PostgreSQL dialect documentation.

4.3.1.8 Backend-Specific Options
................................

Table supports database-specific options.  For example, MySQL
has different table backend types, including “MyISAM” and “InnoDB”.
This can be expressed with Table using ‘mysql_engine’:

     addresses = Table('engine_email_addresses', meta,
         Column('address_id', Integer, primary_key=True),
         Column('remote_user_id', Integer, ForeignKey(users.c.user_id)),
         Column('email_address', String(20)),
         mysql_engine='InnoDB'
     )

Other backends may support table-level options as well - these would be
described in the individual documentation sections for each dialect.

4.3.1.9 Column, Table, MetaData API
...................................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See Column.Represents a column in a database table.

See MetaData.A collection of Table objects and their associated schema constructs.

See SchemaItem.Base class for items that define a database schema.

See BLANK_SCHEMA.Symbol indicating that a Table or Sequence should have ‘None’ for its
               schema, even if the parent MetaData has specified a schema.

See Table.Represent a table in a database.

See ThreadLocalMetaData.A MetaData variant that presents a different ‘bind’ in every thread.

 -- Attribute: sqlalchemy.schema.sqlalchemy.schema..
          sqlalchemy.schema.BLANK_SCHEMA

     Symbol indicating that a Table or Sequence
     should have ‘None’ for its schema, even if the parent
     MetaData has specified a schema.

     See also
     ........

     See MetaData.schema.

     See Table.schema.

     See Sequence.schema.

     New in version 1.0.14.

 -- Class: sqlalchemy.schema.Column (*args, **kwargs)

     Represents a column in a database table.

     `Class signature'

     class sqlalchemy.schema.Column. (see
     sqlalchemy.sql.base.DialectKWArgs,
     sqlalchemy.schema.SchemaItem,
     sqlalchemy.sql.expression.ColumnClause)

      -- Method: sqlalchemy.schema.Column..__eq__ (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__eq__’ `method of'
          ColumnOperators.

          Implement the ‘==’ operator.

          In a column context, produces the clause ‘a = b’.  If the
          target is ‘None’, produces ‘a IS NULL’.

      -- Method: sqlalchemy.schema.Column..__init__ (*args,
               **kwargs)

          Construct a new ‘Column’ object.

          Parameters:

             * ‘name’ – The name of this column as represented in the
               database.  This argument may be the first positional
               argument, or specified via keyword.

               Names which contain no upper case characters will be
               treated as case insensitive names, and will not be quoted
               unless they are a reserved word.  Names with any number
               of upper case characters will be quoted and sent exactly.
               Note that this behavior applies even for databases which
               standardize upper case names as case insensitive such as
               Oracle.

               The name field may be omitted at construction time and
               applied later, at any time before the Column is
               associated with a Table.  This is to support
               convenient usage within the declarative
               extension.

             * ‘type_’ – The column’s type, indicated using an instance
               which subclasses TypeEngine.  If no arguments
               are required for the type, the class of the type can be
               sent as well, e.g.:

                    # use a type with arguments
                    Column('data', String(50))

                    # use no arguments
                    Column('level', Integer)

               The ‘type’ argument may be the second positional argument
               or specified by keyword.

               If the ‘type’ is ‘None’ or is omitted, it will first
               default to the special type NullType.  If and
               when this Column is made to refer to another
               column using ForeignKey and/or
               ForeignKeyConstraint, the type of the
               remote-referenced column will be copied to this column as
               well, at the moment that the foreign key is resolved
               against that remote Column object.

               Changed in version 0.9.0: Support for propagation of type
               to a Column from its ForeignKey
               object has been improved and should be more reliable and
               timely.

             * ‘*args’ – Additional positional arguments include various
               SchemaItem derived constructs which will be
               applied as options to the column.  These include
               instances of Constraint, ForeignKey,
               ColumnDefault, Sequence,
               Computed. See Identity.  In some cases an
               equivalent keyword argument is available such as
               ‘server_default’, ‘default’ and ‘unique’.

             * ‘autoincrement’ – Set up “auto increment” semantics for
               an integer primary key column.  The default value is the
               string ‘"auto"’ which indicates that a single-column
               primary key that is of an INTEGER type with no stated
               client-side or python-side defaults should receive auto
               increment semantics automatically; all other varieties of
               primary key columns will not.  This includes that DDL
               such as PostgreSQL SERIAL or MySQL AUTO_INCREMENT will be
               emitted for this column during a table create, as well as
               that the column is assumed to generate new integer
               primary key values when an INSERT statement invokes which
               will be retrieved by the dialect.  When used in
               conjunction with Identity on a dialect that
               supports it, this parameter has no effect.

               The flag may be set to ‘True’ to indicate that a column
               which is part of a composite (e.g.  multi-column) primary
               key should have autoincrement semantics, though note that
               only one column within a primary key may have this
               setting.  It can also be set to ‘True’ to indicate
               autoincrement semantics on a column that has a
               client-side or server-side default configured, however
               note that not all dialects can accommodate all styles of
               default as an “autoincrement”.  It can also be set to
               ‘False’ on a single-column primary key that has a
               datatype of INTEGER in order to disable auto increment
               semantics for that column.

               Changed in version 1.1: The autoincrement flag now
               defaults to ‘"auto"’ which indicates autoincrement
               semantics by default for single-column integer primary
               keys only; for composite (multi-column) primary keys,
               autoincrement is never implicitly enabled; as always,
               ‘autoincrement=True’ will allow for at most one of those
               columns to be an “autoincrement” column.
               ‘autoincrement=True’ may also be set on a Column
               that has an explicit client-side or server-side
               default, subject to limitations of the backend database
               and dialect.

               The setting `only' has an effect for columns which are:

                  * Integer derived (i.e.  INT, SMALLINT, BIGINT).

                  * Part of the primary key

                  * Not referring to another column via
                    ForeignKey, unless the value is specified as
                    ‘'ignore_fk'’:

                         # turn on autoincrement for this column despite
                         # the ForeignKey()
                         Column('id', ForeignKey('other.id'),
                                     primary_key=True, autoincrement='ignore_fk')

                    It is typically not desirable to have
                    “autoincrement” enabled on a column that refers to
                    another via foreign key, as such a column is
                    required to refer to a value that originates from
                    elsewhere.

               The setting has these two effects on columns that meet
               the above criteria:

                  * DDL issued for the column will include
                    database-specific keywords intended to signify this
                    column as an “autoincrement” column, such as AUTO
                    INCREMENT on MySQL, SERIAL on PostgreSQL, and
                    IDENTITY on MS-SQL. It does `not' issue
                    AUTOINCREMENT for SQLite since this is a special
                    SQLite flag that is not required for
                    autoincrementing behavior.

                    See also
                    ........

                    See SQLite Auto Incrementing Behavior.

                  * The column will be considered to be available using
                    an “autoincrement” method specific to the backend
                    database, such as calling upon ‘cursor.lastrowid’,
                    using RETURNING in an INSERT statement to get at a
                    sequence-generated value, or using special functions
                    such as “SELECT scope_identity()”.  These methods
                    are highly specific to the DBAPIs and databases in
                    use and vary greatly, so care should be taken when
                    associating ‘autoincrement=True’ with a custom
                    default generation function.

             * ‘default’ – A scalar, Python callable, or
               ColumnElement expression representing the `default
               value' for this column, which will be invoked upon insert
               if this column is otherwise not specified in the VALUES
               clause of the insert.  This is a shortcut to using
               ColumnDefault as a positional argument; see that
               class for full detail on the structure of the argument.

               Contrast this argument to Column.server_default
               which creates a default generator on the database
               side.

               See also
               ........

               See Column INSERT/UPDATE Defaults.

             * ‘doc’ – optional String that can be used by the ORM or
               similar to document attributes on the Python side.  This
               attribute does `not' render SQL comments; use the
               Column.comment parameter for this purpose.

             * ‘key’ – An optional string identifier which will identify
               this ‘Column’ object on the Table.  When a key
               is provided, this is the only identifier referencing the
               ‘Column’ within the application, including ORM attribute
               mapping; the ‘name’ field is used only when rendering
               SQL.

             * ‘index’ – When ‘True’, indicates that a Index.
               construct will be automatically generated for this
               Column, which will result in a “CREATE INDEX”
               statement being emitted for the Table when the
               DDL create operation is invoked.

               Using this flag is equivalent to making use of the
               Index construct explicitly at the level of the
               Table construct itself:

                    Table(
                        "some_table",
                        metadata,
                        Column("x", Integer),
                        Index("ix_some_table_x", "x")
                    )

               To add the Index.unique flag to the
               Index, set both the Column.unique and
               Column.index flags to True simultaneously,
               which will have the effect of rendering the “CREATE
               UNIQUE INDEX” DDL instruction instead of “CREATE INDEX”.

               The name of the index is generated using the
               default naming convention which for the
               Index construct is of the form
               ‘ix_<tablename>_<columnname>’.

               As this flag is intended only as a convenience for the
               common case of adding a single-column, default configured
               index to a table definition, explicit use of the
               Index construct should be preferred for most use
               cases, including composite indexes that encompass more
               than one column, indexes with SQL expressions or
               ordering, backend-specific index configuration options,
               and indexes that use a specific name.

                    Note: the Column.index attribute on
                    Column. `does not indicate' if this column
                    is indexed or not, only if this flag was explicitly
                    set here.  To view indexes on a column, view the
                    Table.indexes collection or use
                    Inspector.get_indexes().

               See also
               ........

               See Indexes.

               See Configuring Constraint Naming Conventions.

               See Column.unique.

             * ‘info’ – Optional data dictionary which will be populated
               into the SchemaItem.info attribute of this
               object.

             * ‘nullable’ – When set to ‘False’, will cause the “NOT
               NULL” phrase to be added when generating DDL for the
               column.  When ‘True’, will normally generate nothing (in
               SQL this defaults to “NULL”), except in some very
               specific backend-specific edge cases where “NULL” may
               render explicitly.  Defaults to ‘True’ unless
               Column.primary_key is also ‘True’ or the column
               specifies a ‘Identity’, in which case it defaults to
               ‘False’.  This parameter is only used when issuing CREATE
               TABLE statements.

                    Note: When the column specifies a ‘Identity’ this
                    parameter is in general ignored by the DDL compiler.
                    The PostgreSQL database allows nullable identity
                    column by setting this parameter to ‘True’
                    explicitly.

             * ‘onupdate’ – A scalar, Python callable, or
               ClauseElement representing a default value to be
               applied to the column within UPDATE statements, which
               will be invoked upon update if this column is not present
               in the SET clause of the update.  This is a shortcut to
               using ColumnDefault as a positional argument
               with ‘for_update=True’.

               See also
               ........

               See Column INSERT/UPDATE Defaults. - complete
               discussion of onupdate

             * ‘primary_key’ – If ‘True’, marks this column as a primary
               key column.  Multiple columns can have this flag set to
               specify composite primary keys.  As an alternative, the
               primary key of a Table can be specified via an
               explicit PrimaryKeyConstraint object.

             * ‘server_default’ – A FetchedValue instance,
               str, Unicode or text() construct representing
               the DDL DEFAULT value for the column.

               String types will be emitted as-is, surrounded by single
               quotes:

                    Column('x', Text, server_default="val")

                    x TEXT DEFAULT 'val'

               A text() expression will be rendered as-is,
               without quotes:

                    Column('y', DateTime, server_default=text('NOW()'))

                    y DATETIME DEFAULT NOW()

               Strings and text() will be converted into a
               DefaultClause object upon initialization.

               Use FetchedValue to indicate that an
               already-existing column will generate a default value on
               the database side which will be available to SQLAlchemy
               for post-fetch after inserts.  This construct does not
               specify any DDL and the implementation is left to the
               database, such as via a trigger.

               See also
               ........

               See Server-invoked DDL-Explicit Default Expressions.
               - complete discussion of server side defaults

             * ‘server_onupdate’ – A FetchedValue instance
               representing a database-side default generation function,
               such as a trigger.  This indicates to SQLAlchemy that a
               newly generated value will be available after updates.
               This construct does not actually implement any kind of
               generation function within the database, which instead
               must be specified separately.

                    Warning: This directive `does not' currently produce
                    MySQL’s “ON UPDATE CURRENT_TIMESTAMP()” clause.  See
                    Rendering ON UPDATE CURRENT TIMESTAMP for MySQL / MariaDB’s explicit_defaults_for_timestamp
                    for background on how to produce this clause.

               See also
               ........

               See Marking Implicitly Generated Values, timestamps, and Triggered Columns.

             * ‘quote’ – Force quoting of this column’s name on or off,
               corresponding to ‘True’ or ‘False’.  When left at its
               default of ‘None’, the column identifier will be quoted
               according to whether the name is case sensitive
               (identifiers with at least one upper case character are
               treated as case sensitive), or if it’s a reserved word.
               This flag is only needed to force quoting of a reserved
               word which is not known by the SQLAlchemy dialect.

             * ‘unique’ – When ‘True’, and the Column.index.
               parameter is left at its default value of ‘False’,
               indicates that a UniqueConstraint construct
               will be automatically generated for this Column,
               which will result in a “UNIQUE CONSTRAINT” clause
               referring to this column being included in the ‘CREATE
               TABLE’ statement emitted, when the DDL create operation
               for the Table object is invoked.

               When this flag is ‘True’ while the Column.index
               parameter is simultaneously set to ‘True’, the
               effect instead is that a Index construct
               which includes the Index.unique parameter
               set to ‘True’ is generated.  See the documentation for
               Column.index for additional detail.

               Using this flag is equivalent to making use of the
               UniqueConstraint construct explicitly at the level
               of the Table construct itself:

                    Table(
                        "some_table",
                        metadata,
                        Column("x", Integer),
                        UniqueConstraint("x")
                    )

               The UniqueConstraint.name parameter of the
               unique constraint object is left at its default value of
               ‘None’; in the absence of a naming convention
               for the enclosing MetaData, the UNIQUE
               CONSTRAINT construct will be emitted as unnamed, which
               typically invokes a database-specific naming convention
               to take place.

               As this flag is intended only as a convenience for the
               common case of adding a single-column, default configured
               unique constraint to a table definition, explicit use of
               the UniqueConstraint construct should be
               preferred for most use cases, including composite
               constraints that encompass more than one column,
               backend-specific index configuration options, and
               constraints that use a specific name.

                    Note: the Column.unique attribute on
                    Column. `does not indicate' if this column
                    has a unique constraint or not, only if this flag
                    was explicitly set here.  To view indexes and unique
                    constraints that may involve this column, view the
                    Table.indexes and/or
                    Table.constraints collections or use
                    Inspector.get_indexes() and/or
                    Inspector.get_unique_constraints().

               See also
               ........

               See UNIQUE Constraint.

               See Configuring Constraint Naming Conventions.

               See Column.index.

             * ‘system’ – When ‘True’, indicates this is a “system”
               column, that is a column which is automatically made
               available by the database, and should not be included in
               the columns list for a ‘CREATE TABLE’ statement.

               For more elaborate scenarios where columns should be
               conditionally rendered differently on different backends,
               consider custom compilation rules for CreateColumn.

             * ‘comment’ – Optional string that will render an SQL
               comment on table creation.

               New in version 1.2: Added the Column.comment
               parameter to Column.

      -- Method: sqlalchemy.schema.Column..__le__ (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__le__’ `method of'
          ColumnOperators.

          Implement the ‘<=’ operator.

          In a column context, produces the clause ‘a <= b’.

      -- Method: sqlalchemy.schema.Column..__lt__ (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__lt__’ `method of'
          ColumnOperators.

          Implement the ‘<’ operator.

          In a column context, produces the clause ‘a < b’.

      -- Method: sqlalchemy.schema.Column..__ne__ (other)

          `inherited from the'
          ‘sqlalchemy.sql.expression.ColumnOperators.__ne__’ `method of'
          ColumnOperators.

          Implement the ‘!=’ operator.

          In a column context, produces the clause ‘a != b’.  If the
          target is ‘None’, produces ‘a IS NOT NULL’.

      -- Method: sqlalchemy.schema.Column..all_ ()

          `inherited from the' ColumnOperators.all_().
          `method of' ColumnOperators.

          Produce a all_() clause against the parent object.

          This operator is only appropriate against a scalar subquery
          object, or for some backends an column expression that is
          against the ARRAY type, e.g.:

               # postgresql '5 = ALL (somearray)'
               expr = 5 == mytable.c.somearray.all_()

               # mysql '5 = ALL (SELECT value FROM table)'
               expr = 5 == select(table.c.value).scalar_subquery().all_()

          See also
          ........

          See all_(). - standalone version

          See any_(). - ANY operator

          New in version 1.1.

      -- Attribute: sqlalchemy.schema.Column..anon_key_label

          `inherited from the' ColumnElement.anon_key_label.
          `attribute of' ColumnElement.

          Provides a constant ‘anonymous key label’ for this
          ColumnElement.

          Compare to ‘anon_label’, except that the “key” of the column,
          if available, is used to generate the label.

          This is used when a deduplicating key is placed into the
          columns collection of a selectable.

      -- Attribute: sqlalchemy.schema.Column..anon_label

          `inherited from the' ColumnElement.anon_label.
          `attribute of' ColumnElement.

          Provides a constant ‘anonymous label’ for this ColumnElement.

          This is a label() expression which will be named at compile
          time.  The same label() is returned each time ‘anon_label’ is
          called so that expressions can reference ‘anon_label’ multiple
          times, producing the same label name at compile time.

          The compiler uses this function automatically at compile time
          for expressions that are known to be ‘unnamed’ like binary
          expressions and function calls.

      -- Method: sqlalchemy.schema.Column..any_ ()

          `inherited from the' ColumnOperators.any_().
          `method of' ColumnOperators.

          Produce a any_() clause against the parent object.

          This operator is only appropriate against a scalar subquery
          object, or for some backends an column expression that is
          against the ARRAY type, e.g.:

               # postgresql '5 = ANY (somearray)'
               expr = 5 == mytable.c.somearray.any_()

               # mysql '5 = ANY (SELECT value FROM table)'
               expr = 5 == select(table.c.value).scalar_subquery().any_()

          See also
          ........

          See any_(). - standalone version

          See all_(). - ALL operator

          New in version 1.1.

      -- Method: sqlalchemy.schema.Column..classmethod
               argument_for (dialect_name, argument_name, default)

          `inherited from the' DialectKWArgs.argument_for().
          `method of' DialectKWArgs.

          Add a new kind of dialect-specific keyword argument for this
          class.

          E.g.:

               Index.argument_for("mydialect", "length", None)

               some_index = Index('a', 'b', mydialect_length=5)

          The DialectKWArgs.argument_for() method is a
          per-argument way adding extra arguments to the
          DefaultDialect.construct_arguments dictionary.  This
          dictionary provides a list of argument names accepted by
          various schema-level constructs on behalf of a dialect.

          New dialects should typically specify this dictionary all at
          once as a data member of the dialect class.  The use case for
          ad-hoc addition of argument names is typically for end-user
          code that is also using a custom compilation scheme which
          consumes the additional arguments.

          Parameters:

             * ‘dialect_name’ – name of a dialect.  The dialect must be
               locatable, else a NoSuchModuleError is
               raised.  The dialect must also include an existing
               DefaultDialect.construct_arguments collection,
               indicating that it participates in the keyword-argument
               validation and default system, else ArgumentError
               is raised.  If the dialect does not include this
               collection, then any keyword argument can be specified on
               behalf of this dialect already.  All dialects packaged
               within SQLAlchemy include this collection, however for
               third party dialects, support may vary.

             * ‘argument_name’ – name of the parameter.

             * ‘default’ – default value of the parameter.

          New in version 0.9.4.

      -- Method: sqlalchemy.schema.Column..asc ()

          `inherited from the' ColumnOperators.asc(). `method
          of' ColumnOperators.

          Produce a asc() clause against the parent object.

      -- Method: sqlalchemy.schema.Column..between (cleft,
               cright, symmetric=False)

          `inherited from the' ColumnOperators.between().
          `method of' ColumnOperators.

          Produce a between() clause against the parent
          object, given the lower and upper range.

      -- Method: sqlalchemy.schema.Column..bool_op (opstring,
               precedence=0)

          `inherited from the' Operators.bool_op(). `method
          of' Operators.

          Return a custom boolean operator.

          This method is shorthand for calling Operators.op()
          and passing the Operators.op.is_comparison
          flag with True.

          See also
          ........

          See Operators.op().

      -- Method: sqlalchemy.schema.Column..cast (type_)

          `inherited from the' ColumnElement.cast(). `method
          of' ColumnElement.

          Produce a type cast, i.e.  ‘CAST(<expression> AS <type>)’.

          This is a shortcut to the cast() function.

          See also
          ........

          See Data Casts and Type Coercion.

          See cast().

          See type_coerce().

          New in version 1.0.7.

      -- Method: sqlalchemy.schema.Column..collate (collation)

          `inherited from the' ColumnOperators.collate().
          `method of' ColumnOperators.

          Produce a collate() clause against the parent
          object, given the collation string.

          See also
          ........

          See collate().

      -- Method: sqlalchemy.schema.Column..compare (other,
               **kw)

          `inherited from the' ClauseElement.compare().
          `method of' ClauseElement.

          Compare this ClauseElement to the given
          ClauseElement.

          Subclasses should override the default behavior, which is a
          straight identity comparison.

          **kw are arguments consumed by subclass ‘compare()’ methods
          and may be used to modify the criteria for comparison (see
          ColumnElement).

      -- Method: sqlalchemy.schema.Column..compile (bind=None,
               dialect=None, **kw)

          `inherited from the' ClauseElement.compile().
          `method of' ClauseElement.

          Compile this SQL expression.

          The return value is a Compiled object.  Calling
          ‘str()’ or ‘unicode()’ on the returned value will yield a
          string representation of the result.  The Compiled
          object also can return a dictionary of bind parameter names
          and values using the ‘params’ accessor.

          Parameters:

             * ‘bind’ – An ‘Engine’ or ‘Connection’ from which a
               ‘Compiled’ will be acquired.  This argument takes
               precedence over this ClauseElement.’s bound
               engine, if any.

             * ‘column_keys’ – Used for INSERT and UPDATE statements, a
               list of column names which should be present in the
               VALUES clause of the compiled statement.  If ‘None’, all
               columns from the target table object are rendered.

             * ‘dialect’ – A ‘Dialect’ instance from which a ‘Compiled’
               will be acquired.  This argument takes precedence over
               the ‘bind’ argument as well as this ClauseElement.
               ‘s bound engine, if any.

             * ‘compile_kwargs’ – optional dictionary of additional
               parameters that will be passed through to the compiler
               within all “visit” methods.  This allows any custom flag
               to be passed through to a custom compilation construct,
               for example.  It is also used for the case of passing the
               ‘literal_binds’ flag through:

                    from sqlalchemy.sql import table, column, select

                    t = table('t', column('x'))

                    s = select(t).where(t.c.x == 5)

                    print(s.compile(compile_kwargs={"literal_binds": True}))

               New in version 0.9.0.

          See also
          ........

          See How do I render SQL expressions as strings, possibly with bound parameters inlined?.

      -- Method: sqlalchemy.schema.Column..concat (other)

          `inherited from the' ColumnOperators.concat().
          `method of' ColumnOperators.

          Implement the ‘concat’ operator.

          In a column context, produces the clause ‘a || b’, or uses the
          ‘concat()’ operator on MySQL.

      -- Method: sqlalchemy.schema.Column..contains (other,
               **kwargs)

          `inherited from the' ColumnOperators.contains().
          `method of' ColumnOperators.

          Implement the ‘contains’ operator.

          Produces a LIKE expression that tests against a match for the
          middle of a string value:

               column LIKE '%' || <other> || '%'

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.contains("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.contains.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.contains.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.contains.autoescape flag is set to
               True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.contains("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE '%' || :param || '%' ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.contains("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE '%' || :param || '%' ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.contains.autoescape:

                    somecolumn.contains("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.startswith().

          See ColumnOperators.endswith().

          See ColumnOperators.like().

      -- Method: sqlalchemy.schema.Column..copy (**kw)

          Deprecated since version 1.4: The Column.copy()
          method is deprecated and will be removed in a future release.

      -- Method: sqlalchemy.schema.Column..desc ()

          `inherited from the' ColumnOperators.desc().
          `method of' ColumnOperators.

          Produce a desc() clause against the parent object.

      -- Attribute: sqlalchemy.schema.Column..dialect_kwargs

          `inherited from the' DialectKWArgs.dialect_kwargs.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          The arguments are present here in their original
          ‘<dialect>_<kwarg>’ format.  Only arguments that were actually
          passed are included; unlike the
          DialectKWArgs.dialect_options collection, which contains
          all options known by this dialect including defaults.

          The collection is also writable; keys are accepted of the form
          ‘<dialect>_<kwarg>’ where the value will be assembled into the
          list of options.

          New in version 0.9.2.

          Changed in version 0.9.4: The
          DialectKWArgs.dialect_kwargs collection is now writable.

          See also
          ........

          See DialectKWArgs.dialect_options. - nested dictionary
          form

      -- Attribute: sqlalchemy.schema.Column..dialect_options

          `inherited from the' DialectKWArgs.dialect_options.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          This is a two-level nested registry, keyed to ‘<dialect_name>’
          and ‘<argument_name>’.  For example, the ‘postgresql_where’
          argument would be locatable as:

               arg = my_object.dialect_options['postgresql']['where']

          New in version 0.9.2.

          See also
          ........

          See DialectKWArgs.dialect_kwargs. - flat dictionary
          form

      -- Method: sqlalchemy.schema.Column..distinct ()

          `inherited from the' ColumnOperators.distinct().
          `method of' ColumnOperators.

          Produce a distinct() clause against the parent
          object.

      -- Method: sqlalchemy.schema.Column..endswith (other,
               **kwargs)

          `inherited from the' ColumnOperators.endswith().
          `method of' ColumnOperators.

          Implement the ‘endswith’ operator.

          Produces a LIKE expression that tests against a match for the
          end of a string value:

               column LIKE '%' || <other>

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.endswith("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.endswith.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.endswith.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.endswith.autoescape flag is set to
               True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.endswith("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE '%' || :param ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.endswith("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE '%' || :param ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.endswith.autoescape:

                    somecolumn.endswith("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.startswith().

          See ColumnOperators.contains().

          See ColumnOperators.like().

      -- Attribute: sqlalchemy.schema.Column..expression

          `inherited from the' ColumnElement.expression.
          `attribute of' ColumnElement.

          Return a column expression.

          Part of the inspection interface; returns self.

      -- Attribute: sqlalchemy.schema.Column..foreign_keys =
               None

          A collection of all ForeignKey marker objects
          associated with this Column.

          Each object is a member of a Table.-wide
          ForeignKeyConstraint.

          See also
          ........

          See Table.foreign_keys.

      -- Method: sqlalchemy.schema.Column..get_children
               (column_tables=False, **kw)

          `inherited from the' ColumnClause.get_children().
          `method of' ColumnClause.

          Return immediate child Traversible elements of
          this Traversible.

          This is used for visit traversal.

          **kw may contain flags that change the collection that is
          returned, for example to return a subset of items in order to
          cut down on larger traversals, or to return child items from a
          different context (such as schema-level collections instead of
          clause-level).

      -- Method: sqlalchemy.schema.Column..ilike (other,
               escape=None)

          `inherited from the' ColumnOperators.ilike().
          `method of' ColumnOperators.

          Implement the ‘ilike’ operator, e.g.  case insensitive LIKE.

          In a column context, produces an expression either of the
          form:

               lower(a) LIKE lower(other)

          Or on backends that support the ILIKE operator:

               a ILIKE other

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.ilike("%foobar%"))

          Parameters:

             * ‘other’ – expression to be compared

             * ‘escape’ – optional escape character, renders the
               ‘ESCAPE’ keyword, e.g.:

                    somecolumn.ilike("foo/%bar", escape="/")

          See also
          ........

          See ColumnOperators.like().

      -- Method: sqlalchemy.schema.Column..in_ (other)

          `inherited from the' ColumnOperators.in_(). `method
          of' ColumnOperators.

          Implement the ‘in’ operator.

          In a column context, produces the clause ‘column IN <other>’.

          The given parameter ‘other’ may be:

             * A list of literal values, e.g.:

                    stmt.where(column.in_([1, 2, 3]))

               In this calling form, the list of items is converted to a
               set of bound parameters the same length as the list
               given:

                    WHERE COL IN (?, ?, ?)

             * A list of tuples may be provided if the comparison is
               against a tuple_() containing multiple
               expressions:

                    from sqlalchemy import tuple_
                    stmt.where(tuple_(col1, col2).in_([(1, 10), (2, 20), (3, 30)]))

             * An empty list, e.g.:

                    stmt.where(column.in_([]))

               In this calling form, the expression renders an “empty
               set” expression.  These expressions are tailored to
               individual backends and are generally trying to get an
               empty SELECT statement as a subquery.  Such as on SQLite,
               the expression is:

                    WHERE col IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)

               Changed in version 1.4: empty IN expressions now use an
               execution-time generated SELECT subquery in all cases.

             * A bound parameter, e.g.  see bindparam(), may be
               used if it includes the bindparam.expanding
               flag:

                    stmt.where(column.in_(bindparam('value', expanding=True)))

               In this calling form, the expression renders a special
               non-SQL placeholder expression that looks like:

                    WHERE COL IN ([EXPANDING_value])

               This placeholder expression is intercepted at statement
               execution time to be converted into the variable number
               of bound parameter form illustrated earlier.  If the
               statement were executed as:

                    connection.execute(stmt, {"value": [1, 2, 3]})

               The database would be passed a bound parameter for each
               value:

                    WHERE COL IN (?, ?, ?)

               New in version 1.2: added “expanding” bound parameters

               If an empty list is passed, a special “empty list”
               expression, which is specific to the database in use, is
               rendered.  On SQLite this would be:

                    WHERE COL IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)

               New in version 1.3: “expanding” bound parameters now
               support empty lists

             * a select() construct, which is usually a
               correlated scalar select:

                    stmt.where(
                        column.in_(
                            select(othertable.c.y).
                            where(table.c.x == othertable.c.x)
                        )
                    )

               In this calling form, see ColumnOperators.in_()
               renders as given:

                    WHERE COL IN (SELECT othertable.y
                    FROM othertable WHERE othertable.x = table.x)

          Parameters: ‘other’ – a list of literals, a select()
          construct, or a bindparam() construct that
          includes the bindparam.expanding flag set to True.

      -- Attribute: sqlalchemy.schema.Column..index = None

          The value of the Column.index parameter.

          Does not indicate if this Column is actually
          indexed or not; use Table.indexes.

          See also
          ........

          See Table.indexes.

      -- Attribute: sqlalchemy.schema.Column..info

          `inherited from the' SchemaItem.info. `attribute
          of' SchemaItem.

          Info dictionary associated with the object, allowing
          user-defined data to be associated with this SchemaItem.

          The dictionary is automatically generated when first accessed.
          It can also be specified in the constructor of some objects,
          such as Table and Column.

      -- Method: sqlalchemy.schema.Column..is_ (other)

          `inherited from the' ColumnOperators.is_(). `method
          of' ColumnOperators.

          Implement the ‘IS’ operator.

          Normally, ‘IS’ is generated automatically when comparing to a
          value of ‘None’, which resolves to ‘NULL’.  However, explicit
          usage of ‘IS’ may be desirable if comparing to boolean values
          on certain platforms.

          See also
          ........

          See ColumnOperators.is_not().

      -- Method: sqlalchemy.schema.Column..is_distinct_from
               (other)

          `inherited from the' ColumnOperators.is_distinct_from().
          `method of' ColumnOperators.

          Implement the ‘IS DISTINCT FROM’ operator.

          Renders “a IS DISTINCT FROM b” on most platforms; on some such
          as SQLite may render “a IS NOT b”.

          New in version 1.1.

      -- Method: sqlalchemy.schema.Column..is_not (other)

          `inherited from the' ColumnOperators.is_not().
          `method of' ColumnOperators.

          Implement the ‘IS NOT’ operator.

          Normally, ‘IS NOT’ is generated automatically when comparing
          to a value of ‘None’, which resolves to ‘NULL’.  However,
          explicit usage of ‘IS NOT’ may be desirable if comparing to
          boolean values on certain platforms.

          Changed in version 1.4: The ‘is_not()’ operator is renamed
          from ‘isnot()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.is_().

      -- Method: sqlalchemy.schema.Column..
               is_not_distinct_from (other)

          `inherited from the'
          ColumnOperators.is_not_distinct_from(). `method of'
          ColumnOperators.

          Implement the ‘IS NOT DISTINCT FROM’ operator.

          Renders “a IS NOT DISTINCT FROM b” on most platforms; on some
          such as SQLite may render “a IS b”.

          Changed in version 1.4: The ‘is_not_distinct_from()’ operator
          is renamed from ‘isnot_distinct_from()’ in previous releases.
          The previous name remains available for backwards
          compatibility.

          New in version 1.1.

      -- Method: sqlalchemy.schema.Column..isnot (other)

          `inherited from the' ColumnOperators.isnot().
          `method of' ColumnOperators.

          Implement the ‘IS NOT’ operator.

          Normally, ‘IS NOT’ is generated automatically when comparing
          to a value of ‘None’, which resolves to ‘NULL’.  However,
          explicit usage of ‘IS NOT’ may be desirable if comparing to
          boolean values on certain platforms.

          Changed in version 1.4: The ‘is_not()’ operator is renamed
          from ‘isnot()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.is_().

      -- Method: sqlalchemy.schema.Column..isnot_distinct_from
               (other)

          `inherited from the'
          ColumnOperators.isnot_distinct_from(). `method of'
          ColumnOperators.

          Implement the ‘IS NOT DISTINCT FROM’ operator.

          Renders “a IS NOT DISTINCT FROM b” on most platforms; on some
          such as SQLite may render “a IS b”.

          Changed in version 1.4: The ‘is_not_distinct_from()’ operator
          is renamed from ‘isnot_distinct_from()’ in previous releases.
          The previous name remains available for backwards
          compatibility.

          New in version 1.1.

      -- Attribute: sqlalchemy.schema.Column..kwargs

          `inherited from the' DialectKWArgs.kwargs.
          `attribute of' DialectKWArgs.

          A synonym for DialectKWArgs.dialect_kwargs.

      -- Method: sqlalchemy.schema.Column..label (name)

          `inherited from the' ColumnElement.label(). `method
          of' ColumnElement.

          Produce a column label, i.e.  ‘<columnname> AS <name>’.

          This is a shortcut to the label() function.

          If ‘name’ is ‘None’, an anonymous label name will be
          generated.

      -- Method: sqlalchemy.schema.Column..like (other,
               escape=None)

          `inherited from the' ColumnOperators.like().
          `method of' ColumnOperators.

          Implement the ‘like’ operator.

          In a column context, produces the expression:

               a LIKE other

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.like("%foobar%"))

          Parameters:

             * ‘other’ – expression to be compared

             * ‘escape’ – optional escape character, renders the
               ‘ESCAPE’ keyword, e.g.:

                    somecolumn.like("foo/%bar", escape="/")

          See also
          ........

          See ColumnOperators.ilike().

      -- Method: sqlalchemy.schema.Column..match (other,
               **kwargs)

          `inherited from the' ColumnOperators.match().
          `method of' ColumnOperators.

          Implements a database-specific ‘match’ operator.

          ColumnOperators.match() attempts to resolve to a
          MATCH-like function or operator provided by the backend.
          Examples include:

             * PostgreSQL - renders ‘x @@ to_tsquery(y)’

             * MySQL - renders ‘MATCH (x) AGAINST (y IN BOOLEAN MODE)’

             * Oracle - renders ‘CONTAINS(x, y)’

             * other backends may provide special implementations.

             * Backends without any special implementation will emit the
               operator as “MATCH”.  This is compatible with SQLite, for
               example.

      -- Class: memoized_attribute (fget, doc=None)

          A read-only @property that is only evaluated once.

      -- Method: sqlalchemy.schema.Column..classmethod
               memoized_instancemethod (fn)

          `inherited from the' ‘HasMemoized.memoized_instancemethod()’
          `method of' ‘HasMemoized’

          Decorate a method memoize its return value.

      -- Method: sqlalchemy.schema.Column..not_ilike (other,
               escape=None)

          `inherited from the' ColumnOperators.not_ilike().
          `method of' ColumnOperators.

          implement the ‘NOT ILIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.ilike(), i.e.  ‘~x.ilike(y)’.

          Changed in version 1.4: The ‘not_ilike()’ operator is renamed
          from ‘notilike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.ilike().

      -- Method: sqlalchemy.schema.Column..not_in (other)

          `inherited from the' ColumnOperators.not_in().
          `method of' ColumnOperators.

          implement the ‘NOT IN’ operator.

          This is equivalent to using negation with
          ColumnOperators.in_(), i.e.  ‘~x.in_(y)’.

          In the case that ‘other’ is an empty sequence, the compiler
          produces an “empty not in” expression.  This defaults to the
          expression “1 = 1” to produce true in all cases.  The
          create_engine.empty_in_strategy may be used to alter
          this behavior.

          Changed in version 1.4: The ‘not_in()’ operator is renamed
          from ‘notin_()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          Changed in version 1.2: The ColumnOperators.in_()
          and ColumnOperators.not_in() operators now produce
          a “static” expression for an empty IN sequence by default.

          See also
          ........

          See ColumnOperators.in_().

      -- Method: sqlalchemy.schema.Column..not_like (other,
               escape=None)

          `inherited from the' ColumnOperators.not_like().
          `method of' ColumnOperators.

          implement the ‘NOT LIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.like(), i.e.  ‘~x.like(y)’.

          Changed in version 1.4: The ‘not_like()’ operator is renamed
          from ‘notlike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.like().

      -- Method: sqlalchemy.schema.Column..notilike (other,
               escape=None)

          `inherited from the' ColumnOperators.notilike().
          `method of' ColumnOperators.

          implement the ‘NOT ILIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.ilike(), i.e.  ‘~x.ilike(y)’.

          Changed in version 1.4: The ‘not_ilike()’ operator is renamed
          from ‘notilike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.ilike().

      -- Method: sqlalchemy.schema.Column..notin_ (other)

          `inherited from the' ColumnOperators.notin_().
          `method of' ColumnOperators.

          implement the ‘NOT IN’ operator.

          This is equivalent to using negation with
          ColumnOperators.in_(), i.e.  ‘~x.in_(y)’.

          In the case that ‘other’ is an empty sequence, the compiler
          produces an “empty not in” expression.  This defaults to the
          expression “1 = 1” to produce true in all cases.  The
          create_engine.empty_in_strategy may be used to alter
          this behavior.

          Changed in version 1.4: The ‘not_in()’ operator is renamed
          from ‘notin_()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          Changed in version 1.2: The ColumnOperators.in_()
          and ColumnOperators.not_in() operators now produce
          a “static” expression for an empty IN sequence by default.

          See also
          ........

          See ColumnOperators.in_().

      -- Method: sqlalchemy.schema.Column..notlike (other,
               escape=None)

          `inherited from the' ColumnOperators.notlike().
          `method of' ColumnOperators.

          implement the ‘NOT LIKE’ operator.

          This is equivalent to using negation with
          ColumnOperators.like(), i.e.  ‘~x.like(y)’.

          Changed in version 1.4: The ‘not_like()’ operator is renamed
          from ‘notlike()’ in previous releases.  The previous name
          remains available for backwards compatibility.

          See also
          ........

          See ColumnOperators.like().

      -- Method: sqlalchemy.schema.Column..nulls_first ()

          `inherited from the' ColumnOperators.nulls_first().
          `method of' ColumnOperators.

          Produce a nulls_first() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_first()’ operator is
          renamed from ‘nullsfirst()’ in previous releases.  The
          previous name remains available for backwards compatibility.

      -- Method: sqlalchemy.schema.Column..nulls_last ()

          `inherited from the' ColumnOperators.nulls_last().
          `method of' ColumnOperators.

          Produce a nulls_last() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_last()’ operator is renamed
          from ‘nullslast()’ in previous releases.  The previous name
          remains available for backwards compatibility.

      -- Method: sqlalchemy.schema.Column..nullsfirst ()

          `inherited from the' ColumnOperators.nullsfirst().
          `method of' ColumnOperators.

          Produce a nulls_first() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_first()’ operator is
          renamed from ‘nullsfirst()’ in previous releases.  The
          previous name remains available for backwards compatibility.

      -- Method: sqlalchemy.schema.Column..nullslast ()

          `inherited from the' ColumnOperators.nullslast().
          `method of' ColumnOperators.

          Produce a nulls_last() clause against the parent
          object.

          Changed in version 1.4: The ‘nulls_last()’ operator is renamed
          from ‘nullslast()’ in previous releases.  The previous name
          remains available for backwards compatibility.

      -- Method: sqlalchemy.schema.Column..op (opstring,
               precedence=0, is_comparison=False, return_type=None)

          `inherited from the' Operators.op(). `method of'
          Operators.

          Produce a generic operator function.

          e.g.:

               somecolumn.op("*")(5)

          produces:

               somecolumn * 5

          This function can also be used to make bitwise operators
          explicit.  For example:

               somecolumn.op('&')(0xff)

          is a bitwise AND of the value in ‘somecolumn’.

          Parameters:

             * ‘operator’ – a string which will be output as the infix
               operator between this element and the expression passed
               to the generated function.

             * ‘precedence’ – precedence to apply to the operator, when
               parenthesizing expressions.  A lower number will cause
               the expression to be parenthesized when applied against
               another operator with higher precedence.  The default
               value of ‘0’ is lower than all operators except for the
               comma (‘,’) and ‘AS’ operators.  A value of 100 will be
               higher or equal to all operators, and -100 will be lower
               than or equal to all operators.

             * ‘is_comparison’ – if True, the operator will be
               considered as a “comparison” operator, that is which
               evaluates to a boolean true/false value, like ‘==’, ‘>’,
               etc.  This flag should be set so that ORM relationships
               can establish that the operator is a comparison operator
               when used in a custom join condition.

               New in version 0.9.2: - added the
               Operators.op.is_comparison flag.

             * ‘return_type’ – a TypeEngine class or object
               that will force the return type of an expression produced
               by this operator to be of that type.  By default,
               operators that specify Operators.op.is_comparison
               will resolve to Boolean, and those that
               do not will be of the same type as the left-hand operand.

          See also
          ........

          See Redefining and Creating New Operators.

          See Using custom operators in join conditions.

      -- Method: sqlalchemy.schema.Column..operate (op,
               *other, **kwargs)

          `inherited from the' ColumnElement.operate().
          `method of' ColumnElement.

          Operate on an argument.

          This is the lowest level of operation, raises
          ‘NotImplementedError’ by default.

          Overriding this on a subclass can allow common behavior to be
          applied to all operations.  For example, overriding
          ColumnOperators to apply ‘func.lower()’ to the left and
          right side:

               class MyComparator(ColumnOperators):
                   def operate(self, op, other):
                       return op(func.lower(self), func.lower(other))

          Parameters:

             * ‘op’ – Operator callable.

             * ‘*other’ – the ‘other’ side of the operation.  Will be a
               single scalar for most operations.

             * ‘**kwargs’ – modifiers.  These may be passed by special
               operators such as ‘ColumnOperators.contains()’.

      -- Method: sqlalchemy.schema.Column..references (column)

          Return True if this Column references the given column via
          foreign key.

      -- Method: sqlalchemy.schema.Column..regexp_match
               (pattern, flags=None)

          `inherited from the' ColumnOperators.regexp_match().
          `method of' ColumnOperators.

          Implements a database-specific ‘regexp match’ operator.

          E.g.:

               stmt = select(table.c.some_column).where(
                   table.c.some_column.regexp_match('^(b|c)')
               )

          ColumnOperators.regexp_match() attempts to resolve
          to a REGEXP-like function or operator provided by the backend,
          however the specific regular expression syntax and flags
          available are `not backend agnostic'.

          Examples include:

             * PostgreSQL - renders ‘x ~ y’ or ‘x !~ y’ when negated.

             * Oracle - renders ‘REGEXP_LIKE(x, y)’

             * SQLite - uses SQLite’s ‘REGEXP’ placeholder operator and
               calls into the Python ‘re.match()’ builtin.

             * other backends may provide special implementations.

             * Backends without any special implementation will emit the
               operator as “REGEXP” or “NOT REGEXP”.  This is compatible
               with SQLite and MySQL, for example.

          Regular expression support is currently implemented for
          Oracle, PostgreSQL, MySQL and MariaDB. Partial support is
          available for SQLite.  Support among third-party dialects may
          vary.

          Parameters:

             * ‘pattern’ – The regular expression pattern string or
               column clause.

             * ‘flags’ – Any regular expression string flags to apply.
               Flags tend to be backend specific.  It can be a string or
               a column clause.  Some backends, like PostgreSQL and
               MariaDB, may alternatively specify the flags as part of
               the pattern.  When using the ignore case flag ‘i’ in
               PostgreSQL, the ignore case regexp match operator ‘~*’ or
               ‘!~*’ will be used.

          New in version 1.4.

          See also
          ........

          See ColumnOperators.regexp_replace().

      -- Method: sqlalchemy.schema.Column..regexp_replace
               (pattern, replacement, flags=None)

          `inherited from the' ColumnOperators.regexp_replace().
          `method of' ColumnOperators.

          Implements a database-specific ‘regexp replace’ operator.

          E.g.:

               stmt = select(
                   table.c.some_column.regexp_replace(
                       'b(..)',
                       'X^AY',
                       flags='g'
                   )
               )

          ColumnOperators.regexp_replace() attempts to
          resolve to a REGEXP_REPLACE-like function provided by the
          backend, that usually emit the function ‘REGEXP_REPLACE()’.
          However, the specific regular expression syntax and flags
          available are `not backend agnostic'.

          Regular expression replacement support is currently
          implemented for Oracle, PostgreSQL, MySQL 8 or greater and
          MariaDB. Support among third-party dialects may vary.

          Parameters:

             * ‘pattern’ – The regular expression pattern string or
               column clause.

             * ‘pattern’ – The replacement string or column clause.

             * ‘flags’ – Any regular expression string flags to apply.
               Flags tend to be backend specific.  It can be a string or
               a column clause.  Some backends, like PostgreSQL and
               MariaDB, may alternatively specify the flags as part of
               the pattern.

          New in version 1.4.

          See also
          ........

          See ColumnOperators.regexp_match().

      -- Method: sqlalchemy.schema.Column..reverse_operate
               (op, other, **kwargs)

          `inherited from the' ColumnElement.reverse_operate().
          `method of' ColumnElement.

          Reverse operate on an argument.

          Usage is the same as operate().

      -- Method: sqlalchemy.schema.Column..self_group
               (against: Optional[Any] = None) -> ClauseElement

          `inherited from the' ColumnElement.self_group().
          `method of' ColumnElement.

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

      -- Method: sqlalchemy.schema.Column..shares_lineage
               (othercolumn)

          `inherited from the' ColumnElement.shares_lineage().
          `method of' ColumnElement.

          Return True if the given ColumnElement has a
          common ancestor to this ColumnElement.

      -- Method: sqlalchemy.schema.Column..startswith (other,
               **kwargs)

          `inherited from the' ColumnOperators.startswith().
          `method of' ColumnOperators.

          Implement the ‘startswith’ operator.

          Produces a LIKE expression that tests against a match for the
          start of a string value:

               column LIKE <other> || '%'

          E.g.:

               stmt = select(sometable).\
                   where(sometable.c.column.startswith("foobar"))

          Since the operator uses ‘LIKE’, wildcard characters ‘"%"’ and
          ‘"_"’ that are present inside the <other> expression will
          behave like wildcards as well.  For literal string values, the
          ColumnOperators.startswith.autoescape flag may be
          set to ‘True’ to apply escaping to occurrences of these
          characters within the string value so that they match as
          themselves and not as wildcard characters.  Alternatively, the
          ColumnOperators.startswith.escape parameter will
          establish a given character as an escape character which can
          be of use when the target expression is not a literal string.

          Parameters:

             * ‘other’ – expression to be compared.  This is usually a
               plain string value, but can also be an arbitrary SQL
               expression.  LIKE wildcard characters ‘%’ and ‘_’ are not
               escaped by default unless the
               ColumnOperators.startswith.autoescape flag is set
               to True.

             * ‘autoescape’ – boolean; when True, establishes an escape
               character within the LIKE expression, then applies it to
               all occurrences of ‘"%"’, ‘"_"’ and the escape character
               itself within the comparison value, which is assumed to
               be a literal string and not a SQL expression.

               An expression such as:

                    somecolumn.startswith("foo%bar", autoescape=True)

               Will render as:

                    somecolumn LIKE :param || '%' ESCAPE '/'

               With the value of ‘:param’ as ‘"foo/%bar"’.

             * ‘escape’ – a character which when given will render with
               the ‘ESCAPE’ keyword to establish that character as the
               escape character.  This character can then be placed
               preceding occurrences of ‘%’ and ‘_’ to allow them to act
               as themselves and not wildcard characters.

               An expression such as:

                    somecolumn.startswith("foo/%bar", escape="^")

               Will render as:

                    somecolumn LIKE :param || '%' ESCAPE '^'

               The parameter may also be combined with
               ColumnOperators.startswith.autoescape:

                    somecolumn.startswith("foo%bar^bat", escape="^", autoescape=True)

               Where above, the given literal parameter will be
               converted to ‘"foo^%bar^^bat"’ before being passed to the
               database.

          See also
          ........

          See ColumnOperators.endswith().

          See ColumnOperators.contains().

          See ColumnOperators.like().

      -- Attribute: sqlalchemy.schema.Column..unique = None

          The value of the Column.unique parameter.

          Does not indicate if this Column is actually
          subject to a unique constraint or not; use
          Table.indexes and Table.constraints.

          See also
          ........

          See Table.indexes.

          See Table.constraints.

 -- Class: sqlalchemy.schema.MetaData (bind=None, schema=None,
          quote_schema=None, naming_convention=None, info=None)

     A collection of Table objects and their associated
     schema constructs.

     Holds a collection of Table objects as well as an
     optional binding to an Engine or Connection.
     If bound, the Table objects in the collection and their
     columns may participate in implicit SQL execution.

     The Table objects themselves are stored in the
     MetaData.tables dictionary.

     MetaData is a thread-safe object for read operations.
     Construction of new tables within a single MetaData
     object, either explicitly or via reflection, may not be completely
     thread-safe.

     See also
     ........

     See Describing Databases with MetaData. - Introduction to
     database metadata

     `Class signature'

     class sqlalchemy.schema.MetaData. (see
     sqlalchemy.schema.SchemaItem)

      -- Method: sqlalchemy.schema.MetaData..__init__
               (bind=None, schema=None, quote_schema=None,
               naming_convention=None, info=None)

          Create a new MetaData object.

          Parameters:

             * ‘bind’ – An Engine or Connection to bind to.  May also be
               a string or URL instance, these are passed to
               create_engine() and this MetaData will be
               bound to the resulting engine.

               Deprecated since version 1.4: The MetaData.bind
               argument is deprecated and will be removed in
               SQLAlchemy 2.0.

             * ‘reflect’ – Optional, automatically load all tables from
               the bound database.  Defaults to False.
               MetaData.bind is required when this option is set.

             * ‘schema’ – The default schema to use for the Table,
               see Sequence, and potentially other objects
               associated with this MetaData.  Defaults to
               ‘None’.

               See also
               ........

               See Specifying a Default Schema Name with MetaData.
               - details on how the MetaData.schema
               parameter is used.

               See Table.schema.

               See Sequence.schema.

             * ‘quote_schema’ – Sets the ‘quote_schema’ flag for those
               Table, Sequence, and other objects
               which make usage of the local ‘schema’ name.

             * ‘info’ – Optional data dictionary which will be populated
               into the SchemaItem.info attribute of this
               object.

               New in version 1.0.0.

             * ‘naming_convention’ – a dictionary referring to values
               which will establish default naming conventions for
               Constraint and Index objects, for those
               objects which are not given a name explicitly.

               The keys of this dictionary may be:

                  * a constraint or Index class, e.g.  the
                    UniqueConstraint, ForeignKeyConstraint
                    class, the Index class

                  * a string mnemonic for one of the known constraint
                    classes; ‘"fk"’, ‘"pk"’, ‘"ix"’, ‘"ck"’, ‘"uq"’ for
                    foreign key, primary key, index, check, and unique
                    constraint, respectively.

                  * the string name of a user-defined “token” that can
                    be used to define new naming tokens.

               The values associated with each “constraint class” or
               “constraint mnemonic” key are string naming templates,
               such as ‘"uq_%(table_name)s_%(column_0_name)s"’, which
               describe how the name should be composed.  The values
               associated with user-defined “token” keys should be
               callables of the form ‘fn(constraint, table)’, which
               accepts the constraint/index object and Table
               as arguments, returning a string result.

               The built-in names are as follows, some of which may only
               be available for certain types of constraint:

                       * ‘%(table_name)s’ - the name of the Table
                         object associated with the constraint.

                       * ‘%(referred_table_name)s’ - the name of the
                         Table object associated with the
                         referencing target of a
                         ForeignKeyConstraint.

                       * ‘%(column_0_name)s’ - the name of the
                         Column at index position “0” within the
                         constraint.

                       * ‘%(column_0N_name)s’ - the name of all
                         Column objects in order within the
                         constraint, joined without a separator.

                       * ‘%(column_0_N_name)s’ - the name of all
                         Column objects in order within the
                         constraint, joined with an underscore as a
                         separator.

                       * ‘%(column_0_label)s’, ‘%(column_0N_label)s’,
                         ‘%(column_0_N_label)s’ - the label of either
                         the zeroth Column or all ‘Columns’,
                         separated with or without an underscore

                       * ‘%(column_0_key)s’, ‘%(column_0N_key)s’,
                         ‘%(column_0_N_key)s’ - the key of either the
                         zeroth Column or all ‘Columns’,
                         separated with or without an underscore

                       * ‘%(referred_column_0_name)s’,
                         ‘%(referred_column_0N_name)s’
                         ‘%(referred_column_0_N_name)s’,
                         ‘%(referred_column_0_key)s’,
                         ‘%(referred_column_0N_key)s’, … column tokens
                         which render the names/keys/labels of columns
                         that are referenced by a
                         ForeignKeyConstraint.

                       * ‘%(constraint_name)s’ - a special key that
                         refers to the existing name given to the
                         constraint.  When this key is present, the
                         Constraint object’s existing name
                         will be replaced with one that is composed from
                         template string that uses this token.  When
                         this token is present, it is required that the
                         Constraint is given an explicit name
                         ahead of time.

                       * user-defined: any additional token may be
                         implemented by passing it along with a
                         ‘fn(constraint, table)’ callable to the
                         naming_convention dictionary.

               New in version 1.3.0: - added new ‘%(column_0N_name)s’,
               ‘%(column_0_N_name)s’, and related tokens that produce
               concatenations of names, keys, or labels for all columns
               referred to by a given constraint.

               See also
               ........

               See Configuring Constraint Naming Conventions. -
               for detailed usage examples.

      -- Attribute: sqlalchemy.schema.MetaData..bind

          An Engine or Connection to which this
          MetaData is bound.

          Typically, a Engine is assigned to this attribute
          so that “implicit execution” may be used, or alternatively as
          a means of providing engine binding information to an ORM
          Session object:

               engine = create_engine("someurl://")
               metadata.bind = engine

          See also
          ........

          See Connectionless Execution, Implicit Execution. -
          background on “bound metadata”

      -- Method: sqlalchemy.schema.MetaData..clear ()

          Clear all Table objects from this MetaData.

      -- Method: sqlalchemy.schema.MetaData..create_all
               (bind=None, tables=None, checkfirst=True)

          Create all tables stored in this metadata.

          Conditional by default, will not attempt to recreate tables
          already present in the target database.

          Parameters:

             * ‘bind’ – A ‘Connectable’ used to access the database; if
               None, uses the existing bind on this ‘MetaData’, if any.

                    Note: the “bind” argument will be required in
                    SQLAlchemy 2.0.

             * ‘tables’ – Optional list of ‘Table’ objects, which is a
               subset of the total tables in the ‘MetaData’ (others are
               ignored).

             * ‘checkfirst’ – Defaults to True, don’t issue CREATEs for
               tables already present in the target database.

      -- Method: sqlalchemy.schema.MetaData..drop_all
               (bind=None, tables=None, checkfirst=True)

          Drop all tables stored in this metadata.

          Conditional by default, will not attempt to drop tables not
          present in the target database.

          Parameters:

             * ‘bind’ – A ‘Connectable’ used to access the database; if
               None, uses the existing bind on this ‘MetaData’, if any.

                    Note: the “bind” argument will be required in
                    SQLAlchemy 2.0.

             * ‘tables’ – Optional list of ‘Table’ objects, which is a
               subset of the total tables in the ‘MetaData’ (others are
               ignored).

             * ‘checkfirst’ – Defaults to True, only issue DROPs for
               tables confirmed to be present in the target database.

      -- Method: sqlalchemy.schema.MetaData..is_bound ()

          True if this MetaData is bound to an Engine or Connection.

      -- Method: sqlalchemy.schema.MetaData..reflect
               (bind=None, schema=None, views=False, only=None,
               extend_existing=False, autoload_replace=True,
               resolve_fks=True, **dialect_kwargs)

          Load all available table definitions from the database.

          Automatically creates ‘Table’ entries in this ‘MetaData’ for
          any table available in the database but not yet present in the
          ‘MetaData’.  May be called multiple times to pick up tables
          recently added to the database, however no special action is
          taken if a table in this ‘MetaData’ no longer exists in the
          database.

          Parameters:

             * ‘bind’ – A ‘Connectable’ used to access the database; if
               None, uses the existing bind on this ‘MetaData’, if any.

                    Note: the “bind” argument will be required in
                    SQLAlchemy 2.0.

             * ‘schema’ – Optional, query and reflect tables from an
               alternate schema.  If None, the schema associated with
               this MetaData is used, if any.

             * ‘views’ – If True, also reflect views.

             * ‘only’ – Optional.  Load only a sub-set of available
               named tables.  May be specified as a sequence of names or
               a callable.

               If a sequence of names is provided, only those tables
               will be reflected.  An error is raised if a table is
               requested but not available.  Named tables already
               present in this ‘MetaData’ are ignored.

               If a callable is provided, it will be used as a boolean
               predicate to filter the list of potential table names.
               The callable is called with a table name and this
               ‘MetaData’ instance as positional arguments and should
               return a true value for any table to reflect.

             * ‘extend_existing’ – Passed along to each Table.
               as Table.extend_existing.

               New in version 0.9.1.

             * ‘autoload_replace’ – Passed along to each Table
               as Table.autoload_replace.

               New in version 0.9.1.

             * ‘resolve_fks’ – if True, reflect Table objects
               linked to ForeignKey objects located in each
               Table.  For MetaData.reflect(), this
               has the effect of reflecting related tables that might
               otherwise not be in the list of tables being reflected,
               for example if the referenced table is in a different
               schema or is omitted via the MetaData.reflect.only
               parameter.  When False, see ForeignKey
               objects are not followed to the Table in which
               they link, however if the related table is also part of
               the list of tables that would be reflected in any case,
               the ForeignKey object will still resolve to
               its related Table after the
               MetaData.reflect() operation is complete.  Defaults
               to True.

               New in version 1.3.0.

               See also
               ........

               See Table.resolve_fks.

             * ‘**dialect_kwargs’ – Additional keyword arguments not
               mentioned above are dialect specific, and passed in the
               form ‘<dialectname>_<argname>’.  See the documentation
               regarding an individual dialect at Dialects
               for detail on documented arguments.

                    New in version 0.9.2: - Added
                    MetaData.reflect.**dialect_kwargs to support
                    dialect-level reflection options for all
                    Table objects reflected.

      -- Method: sqlalchemy.schema.MetaData..remove (table)

          Remove the given Table object from this MetaData.

      -- Attribute: sqlalchemy.schema.MetaData..sorted_tables

          Returns a list of Table objects sorted in order of
          foreign key dependency.

          The sorting will place Table objects that have
          dependencies first, before the dependencies themselves,
          representing the order in which they can be created.  To get
          the order in which the tables would be dropped, use the
          ‘reversed()’ Python built-in.

               Warning: The MetaData.sorted_tables
               attribute cannot by itself accommodate automatic
               resolution of dependency cycles between tables, which are
               usually caused by mutually dependent foreign key
               constraints.  When these cycles are detected, the foreign
               keys of these tables are omitted from consideration in
               the sort.  A warning is emitted when this condition
               occurs, which will be an exception raise in a future
               release.  Tables which are not part of the cycle will
               still be returned in dependency order.

               To resolve these cycles, the
               ForeignKeyConstraint.use_alter parameter may be
               applied to those constraints which create a cycle.
               Alternatively, the sort_tables_and_constraints()
               function will automatically return foreign key
               constraints in a separate collection when cycles are
               detected so that they may be applied to a schema
               separately.

               Changed in version 1.3.17: - a warning is emitted when
               MetaData.sorted_tables cannot perform a
               proper sort due to cyclical dependencies.  This will be
               an exception in a future release.  Additionally, the sort
               will continue to return other tables not involved in the
               cycle in dependency order which was not the case
               previously.

          See also
          ........

          See sort_tables().

          See sort_tables_and_constraints().

          See MetaData.tables.

          See Inspector.get_table_names().

          See Inspector.get_sorted_table_and_fkc_names().

      -- Attribute: sqlalchemy.schema.MetaData..tables = None

          A dictionary of Table objects keyed to their name
          or “table key”.

          The exact key is that determined by the Table.key
          attribute; for a table with no ‘Table.schema’ attribute, this
          is the same as ‘Table.name’.  For a table with a schema, it is
          typically of the form ‘schemaname.tablename’.

          See also
          ........

          See MetaData.sorted_tables.

 -- Class: sqlalchemy.schema.SchemaItem

     Base class for items that define a database schema.

     `Class signature'

     class sqlalchemy.schema.SchemaItem.
     (‘sqlalchemy.sql.expression.SchemaEventTarget’, see
     sqlalchemy.sql.visitors.Traversible)

      -- Attribute: sqlalchemy.schema.SchemaItem..info

          Info dictionary associated with the object, allowing
          user-defined data to be associated with this SchemaItem.

          The dictionary is automatically generated when first accessed.
          It can also be specified in the constructor of some objects,
          such as Table and Column.

 -- Class: sqlalchemy.schema.Table (*args, **kw)

     Represent a table in a database.

     e.g.:

          mytable = Table("mytable", metadata,
                          Column('mytable_id', Integer, primary_key=True),
                          Column('value', String(50))
                     )

     The Table object constructs a unique instance of itself
     based on its name and optional schema name within the given
     MetaData object.  Calling the Table constructor
     with the same name and same MetaData argument a second
     time will return the `same' Table object - in this way
     the Table constructor acts as a registry function.

     See also
     ........

     See Describing Databases with MetaData. - Introduction to
     database metadata

     Constructor arguments are as follows:

     Parameters:

        * ‘name’ – The name of this table as represented in the
          database.

          The table name, along with the value of the ‘schema’
          parameter, forms a key which uniquely identifies this
          Table within the owning MetaData collection.
          Additional calls to Table with the same name,
          metadata, and schema name will return the same Table
          object.

          Names which contain no upper case characters will be treated
          as case insensitive names, and will not be quoted unless they
          are a reserved word or contain special characters.  A name
          with any number of upper case characters is considered to be
          case sensitive, and will be sent as quoted.

          To enable unconditional quoting for the table name, specify
          the flag ‘quote=True’ to the constructor, or use the
          quoted_name construct to specify the name.

        * ‘metadata’ – a MetaData object which will contain
          this table.  The metadata is used as a point of association of
          this table with other tables which are referenced via foreign
          key.  It also may be used to associate this table with a
          particular ‘Connectable’.

        * ‘*args’ – Additional positional arguments are used primarily
          to add the list of Column objects contained within
          this table.  Similar to the style of a CREATE TABLE statement,
          other SchemaItem constructs may be added here,
          including PrimaryKeyConstraint, and
          ForeignKeyConstraint.

        * ‘autoload’ – Defaults to ‘False’, unless
          Table.autoload_with is set in which case it defaults to
          ‘True’; see Column objects for this table should be
          reflected from the database, possibly augmenting objects that
          were explicitly specified.  Column and other
          objects explicitly set on the table will replace corresponding
          reflected objects.

          Deprecated since version 1.4: The autoload parameter is
          deprecated and will be removed in version 2.0.  Please use the
          Table.autoload_with parameter, passing an engine or
          connection.

          See also
          ........

          See Reflecting Database Objects.

        * ‘autoload_replace’ – Defaults to ‘True’; when using
          Table.autoload in conjunction with
          Table.extend_existing, indicates that Column
          objects present in the already-existing Table
          object should be replaced with columns of the same name
          retrieved from the autoload process.  When ‘False’, columns
          already present under existing names will be omitted from the
          reflection process.

          Note that this setting does not impact Column
          objects specified programmatically within the call to
          Table that also is autoloading; those Column
          objects will always replace existing columns of the same name
          when Table.extend_existing is ‘True’.

          See also
          ........

          See Table.autoload.

          See Table.extend_existing.

        * ‘autoload_with’ – An Engine or Connection
          object, or a Inspector object as returned by
          inspect() against one, with which this
          Table object will be reflected.  When set to a non-None
          value, the autoload process will take place for this table
          against the given engine or connection.

        * ‘extend_existing’ – When ‘True’, indicates that if this
          Table is already present in the given MetaData,
          apply further arguments within the constructor to the existing
          Table.

          If Table.extend_existing or
          Table.keep_existing are not set, and the given name of
          the new Table refers to a Table that is
          already present in the target MetaData collection,
          and this Table specifies additional columns or
          other constructs or flags that modify the table’s state, an
          error is raised.  The purpose of these two mutually-exclusive
          flags is to specify what action should be taken when a
          Table is specified that matches an existing Table,
          yet specifies additional constructs.

          Table.extend_existing will also work in
          conjunction with Table.autoload to run a new
          reflection operation against the database, even if a
          Table of the same name is already present in the target
          MetaData; newly reflected Column objects
          and other options will be added into the state of the
          Table, potentially overwriting existing columns and
          options of the same name.

          As is always the case with Table.autoload,
          Column objects can be specified in the same Table
          constructor, which will take precedence.  Below, the
          existing table ‘mytable’ will be augmented with Column
          objects both reflected from the database, as well as the
          given Column named “y”:

               Table("mytable", metadata,
                           Column('y', Integer),
                           extend_existing=True,
                           autoload_with=engine
                       )

          See also
          ........

          See Table.autoload.

          See Table.autoload_replace.

          See Table.keep_existing.

        * ‘implicit_returning’ – True by default - indicates that
          RETURNING can be used by default to fetch newly inserted
          primary key values, for backends which support this.  Note
          that create_engine() also provides an
          ‘implicit_returning’ flag.

        * ‘include_columns’ – A list of strings indicating a subset of
          columns to be loaded via the ‘autoload’ operation; table
          columns who aren’t present in this list will not be
          represented on the resulting ‘Table’ object.  Defaults to
          ‘None’ which indicates all columns should be reflected.

        * ‘resolve_fks’ – Whether or not to reflect Table.
          objects related to this one via ForeignKey objects,
          when Table.autoload or Table.autoload_with
          is specified.  Defaults to True.  Set to False to disable
          reflection of related tables as ForeignKey objects
          are encountered; may be used either to save on SQL calls or to
          avoid issues with related tables that can’t be accessed.  Note
          that if a related table is already present in the
          MetaData collection, or becomes present later, a
          ForeignKey object associated with this Table
          will resolve to that table normally.

          New in version 1.3.

          See also
          ........

          See MetaData.reflect.resolve_fks.

        * ‘info’ – Optional data dictionary which will be populated into
          the SchemaItem.info attribute of this object.

        * ‘keep_existing’ – When ‘True’, indicates that if this Table is
          already present in the given MetaData, ignore
          further arguments within the constructor to the existing
          Table, and return the Table object as
          originally created.  This is to allow a function that wishes
          to define a new Table on first call, but on
          subsequent calls will return the same Table, without
          any of the declarations (particularly constraints) being
          applied a second time.

          If Table.extend_existing or
          Table.keep_existing are not set, and the given name of
          the new Table refers to a Table that is
          already present in the target MetaData collection,
          and this Table specifies additional columns or
          other constructs or flags that modify the table’s state, an
          error is raised.  The purpose of these two mutually-exclusive
          flags is to specify what action should be taken when a
          Table is specified that matches an existing Table,
          yet specifies additional constructs.

          See also
          ........

          See Table.extend_existing.

        * ‘listeners’ – A list of tuples of the form ‘(<eventname>,
          <fn>)’ which will be passed to listen() upon
          construction.  This alternate hook to listen()
          allows the establishment of a listener function specific to
          this Table before the “autoload” process begins.
          Historically this has been intended for use with the
          DDLEvents.column_reflect() event, however note that this
          event hook may now be associated with the MetaData
          object directly:

               def listen_for_reflect(table, column_info):
                   "handle the column reflection event"
                   # ...

               t = Table(
                   'sometable',
                   autoload_with=engine,
                   listeners=[
                       ('column_reflect', listen_for_reflect)
                   ])

          See also
          ........

          See DDLEvents.column_reflect().

        * ‘must_exist’ – When ‘True’, indicates that this Table must
          already be present in the given MetaData
          collection, else an exception is raised.

        * ‘prefixes’ – A list of strings to insert after CREATE in the
          CREATE TABLE statement.  They will be separated by spaces.

        * ‘quote’ – Force quoting of this table’s name on or off,
          corresponding to ‘True’ or ‘False’.  When left at its default
          of ‘None’, the column identifier will be quoted according to
          whether the name is case sensitive (identifiers with at least
          one upper case character are treated as case sensitive), or if
          it’s a reserved word.  This flag is only needed to force
          quoting of a reserved word which is not known by the
          SQLAlchemy dialect.

        * ‘quote_schema’ – same as ‘quote’ but applies to the schema
          identifier.

        * ‘schema’ – The schema name for this table, which is required
          if the table resides in a schema other than the default
          selected schema for the engine’s database connection.
          Defaults to ‘None’.

          If the owning MetaData of this Table
          specifies its own MetaData.schema parameter, then
          that schema name will be applied to this Table if
          the schema parameter here is set to ‘None’.  To set a blank
          schema name on a Table that would otherwise use the
          schema set on the owning MetaData, specify the
          special symbol BLANK_SCHEMA.

          New in version 1.0.14: Added the BLANK_SCHEMA
          symbol to allow a Table to have a blank schema name
          even when the parent MetaData specifies
          MetaData.schema.

          The quoting rules for the schema name are the same as those
          for the ‘name’ parameter, in that quoting is applied for
          reserved words or case-sensitive names; to enable
          unconditional quoting for the schema name, specify the flag
          ‘quote_schema=True’ to the constructor, or use the
          quoted_name construct to specify the name.

        * ‘comment’ – Optional string that will render an SQL comment on
          table creation.

          New in version 1.2: Added the Table.comment
          parameter to Table.

        * ‘**kw’ – Additional keyword arguments not mentioned above are
          dialect specific, and passed in the form
          ‘<dialectname>_<argname>’.  See the documentation regarding an
          individual dialect at Dialects for detail on
          documented arguments.

     `Class signature'

     class sqlalchemy.schema.Table. (see
     sqlalchemy.sql.base.DialectKWArgs,
     sqlalchemy.schema.SchemaItem,
     sqlalchemy.sql.expression.TableClause)

      -- Method: sqlalchemy.schema.Table..__init__ (*args,
               **kw)

          Constructor for Table.

          This method is a no-op.  See the top-level documentation for
          Table for constructor arguments.

      -- Method: sqlalchemy.schema.Table..add_is_dependent_on
               (table)

          Add a ‘dependency’ for this Table.

          This is another Table object which must be created first
          before this one can, or dropped after this one.

          Usually, dependencies between tables are determined via
          ForeignKey objects.  However, for other situations that create
          dependencies outside of foreign keys (rules, inheriting), this
          method can manually establish such a link.

      -- Method: sqlalchemy.schema.Table..alias (name=None,
               flat=False)

          `inherited from the' FromClause.alias(). `method
          of' FromClause.

          Return an alias of this FromClause.

          E.g.:

               a2 = some_table.alias('a2')

          The above code creates an Alias object which can
          be used as a FROM clause in any SELECT statement.

          See also
          ........

          See Using Aliases and Subqueries.

          See alias().

      -- Method: sqlalchemy.schema.Table..append_column
               (column, replace_existing=False)

          Append a Column to this Table.

          The “key” of the newly added Column, i.e.  the value
          of its ‘.key’ attribute, will then be available in the ‘.c’
          collection of this Table, and the column definition
          will be included in any CREATE TABLE, SELECT, UPDATE, etc.
          statements generated from this Table construct.

          Note that this does `not' change the definition of the table
          as it exists within any underlying database, assuming that
          table has already been created in the database.  Relational
          databases support the addition of columns to existing tables
          using the SQL ALTER command, which would need to be emitted
          for an already-existing table that doesn’t contain the newly
          added column.

          Parameters: ‘replace_existing’ – When ‘True’, allows replacing
          existing columns.  When ‘False’, the default, an warning will
          be raised if a column with the same ‘.key’ already exists.  A
          future version of sqlalchemy will instead rise a warning.

          New in version 1.4.0.

      -- Method: sqlalchemy.schema.Table..append_constraint
               (constraint)

          Append a Constraint to this Table.

          This has the effect of the constraint being included in any
          future CREATE TABLE statement, assuming specific DDL creation
          events have not been associated with the given
          Constraint object.

          Note that this does `not' produce the constraint within the
          relational database automatically, for a table that already
          exists in the database.  To add a constraint to an existing
          relational database table, the SQL ALTER command must be used.
          SQLAlchemy also provides the AddConstraint
          construct which can produce this SQL when invoked as an
          executable clause.

      -- Method: sqlalchemy.schema.Table..classmethod
               argument_for (dialect_name, argument_name, default)

          `inherited from the' DialectKWArgs.argument_for().
          `method of' DialectKWArgs.

          Add a new kind of dialect-specific keyword argument for this
          class.

          E.g.:

               Index.argument_for("mydialect", "length", None)

               some_index = Index('a', 'b', mydialect_length=5)

          The DialectKWArgs.argument_for() method is a
          per-argument way adding extra arguments to the
          DefaultDialect.construct_arguments dictionary.  This
          dictionary provides a list of argument names accepted by
          various schema-level constructs on behalf of a dialect.

          New dialects should typically specify this dictionary all at
          once as a data member of the dialect class.  The use case for
          ad-hoc addition of argument names is typically for end-user
          code that is also using a custom compilation scheme which
          consumes the additional arguments.

          Parameters:

             * ‘dialect_name’ – name of a dialect.  The dialect must be
               locatable, else a NoSuchModuleError is
               raised.  The dialect must also include an existing
               DefaultDialect.construct_arguments collection,
               indicating that it participates in the keyword-argument
               validation and default system, else ArgumentError
               is raised.  If the dialect does not include this
               collection, then any keyword argument can be specified on
               behalf of this dialect already.  All dialects packaged
               within SQLAlchemy include this collection, however for
               third party dialects, support may vary.

             * ‘argument_name’ – name of the parameter.

             * ‘default’ – default value of the parameter.

          New in version 0.9.4.

      -- Attribute: sqlalchemy.schema.Table..bind

          Return the connectable associated with this Table.

      -- Attribute: sqlalchemy.schema.Table..c

          `inherited from the' FromClause.c. `attribute of'
          FromClause.

          A named-based collection of ColumnElement objects
          maintained by this FromClause.

          The FromClause.c attribute is an alias for the
          FromClause.columns atttribute.

          Returns: a ColumnCollection.

      -- Attribute: sqlalchemy.schema.Table..columns

          `inherited from the' FromClause.columns. `attribute
          of' FromClause.

          A named-based collection of ColumnElement objects
          maintained by this FromClause.

          The columns, or c collection, is the
          gateway to the construction of SQL expressions using
          table-bound or other selectable-bound columns:

               select(mytable).where(mytable.c.somecolumn == 5)

          Returns: a ColumnCollection object.

      -- Method: sqlalchemy.schema.Table..compare (other,
               **kw)

          `inherited from the' ClauseElement.compare().
          `method of' ClauseElement.

          Compare this ClauseElement to the given
          ClauseElement.

          Subclasses should override the default behavior, which is a
          straight identity comparison.

          **kw are arguments consumed by subclass ‘compare()’ methods
          and may be used to modify the criteria for comparison (see
          ColumnElement).

      -- Method: sqlalchemy.schema.Table..compile (bind=None,
               dialect=None, **kw)

          `inherited from the' ClauseElement.compile().
          `method of' ClauseElement.

          Compile this SQL expression.

          The return value is a Compiled object.  Calling
          ‘str()’ or ‘unicode()’ on the returned value will yield a
          string representation of the result.  The Compiled
          object also can return a dictionary of bind parameter names
          and values using the ‘params’ accessor.

          Parameters:

             * ‘bind’ – An ‘Engine’ or ‘Connection’ from which a
               ‘Compiled’ will be acquired.  This argument takes
               precedence over this ClauseElement.’s bound
               engine, if any.

             * ‘column_keys’ – Used for INSERT and UPDATE statements, a
               list of column names which should be present in the
               VALUES clause of the compiled statement.  If ‘None’, all
               columns from the target table object are rendered.

             * ‘dialect’ – A ‘Dialect’ instance from which a ‘Compiled’
               will be acquired.  This argument takes precedence over
               the ‘bind’ argument as well as this ClauseElement.
               ‘s bound engine, if any.

             * ‘compile_kwargs’ – optional dictionary of additional
               parameters that will be passed through to the compiler
               within all “visit” methods.  This allows any custom flag
               to be passed through to a custom compilation construct,
               for example.  It is also used for the case of passing the
               ‘literal_binds’ flag through:

                    from sqlalchemy.sql import table, column, select

                    t = table('t', column('x'))

                    s = select(t).where(t.c.x == 5)

                    print(s.compile(compile_kwargs={"literal_binds": True}))

               New in version 0.9.0.

          See also
          ........

          See How do I render SQL expressions as strings, possibly with bound parameters inlined?.

      -- Attribute: sqlalchemy.schema.Table..constraints =
               None

          A collection of all Constraint objects associated
          with this Table.

          Includes PrimaryKeyConstraint,
          ForeignKeyConstraint, UniqueConstraint,
          CheckConstraint.  A separate collection
          Table.foreign_key_constraints refers to the collection
          of all ForeignKeyConstraint objects, and the
          Table.primary_key attribute refers to the single
          PrimaryKeyConstraint associated with the Table.

          See also
          ........

          See Table.constraints.

          See Table.primary_key.

          See Table.foreign_key_constraints.

          See Table.indexes.

          See Inspector.

      -- Method: sqlalchemy.schema.Table..corresponding_column
               (column, require_embedded=False)

          `inherited from the' Selectable.corresponding_column().
          `method of' Selectable.

          Given a ColumnElement, return the exported
          ColumnElement object from the
          Selectable.exported_columns collection of this
          Selectable which corresponds to that original
          ColumnElement via a common ancestor column.

          Parameters:

             * ‘column’ – the target ColumnElement to be
               matched.

             * ‘require_embedded’ – only return corresponding columns
               for the given ColumnElement, if the given
               ColumnElement is actually present within a
               sub-element of this Selectable.  Normally the
               column will match if it merely shares a common ancestor
               with one of the exported columns of this
               Selectable.

          See also
          ........

          See Selectable.exported_columns. - the
          ColumnCollection that is used for the operation.

          See ColumnCollection.corresponding_column(). -
          implementation method.

      -- Method: sqlalchemy.schema.Table..create (bind=None,
               checkfirst=False)

          Issue a ‘CREATE’ statement for this Table, using the
          given ‘Connectable’ for connectivity.

               Note: the “bind” argument will be required in SQLAlchemy
               2.0.

          See also
          ........

          See MetaData.create_all().

      -- Method: sqlalchemy.schema.Table..delete
               (whereclause=None, **kwargs)

          `inherited from the' TableClause.delete(). `method
          of' TableClause.

          Generate a delete() construct against this
          TableClause.

          E.g.:

               table.delete().where(table.c.id==7)

          See delete() for argument and usage information.

      -- Attribute: sqlalchemy.schema.Table..dialect_kwargs

          `inherited from the' DialectKWArgs.dialect_kwargs.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          The arguments are present here in their original
          ‘<dialect>_<kwarg>’ format.  Only arguments that were actually
          passed are included; unlike the
          DialectKWArgs.dialect_options collection, which contains
          all options known by this dialect including defaults.

          The collection is also writable; keys are accepted of the form
          ‘<dialect>_<kwarg>’ where the value will be assembled into the
          list of options.

          New in version 0.9.2.

          Changed in version 0.9.4: The
          DialectKWArgs.dialect_kwargs collection is now writable.

          See also
          ........

          See DialectKWArgs.dialect_options. - nested dictionary
          form

      -- Attribute: sqlalchemy.schema.Table..dialect_options

          `inherited from the' DialectKWArgs.dialect_options.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          This is a two-level nested registry, keyed to ‘<dialect_name>’
          and ‘<argument_name>’.  For example, the ‘postgresql_where’
          argument would be locatable as:

               arg = my_object.dialect_options['postgresql']['where']

          New in version 0.9.2.

          See also
          ........

          See DialectKWArgs.dialect_kwargs. - flat dictionary
          form

      -- Method: sqlalchemy.schema.Table..drop (bind=None,
               checkfirst=False)

          Issue a ‘DROP’ statement for this Table, using the
          given ‘Connectable’ for connectivity.

               Note: the “bind” argument will be required in SQLAlchemy
               2.0.

          See also
          ........

          See MetaData.drop_all().

      -- Attribute: sqlalchemy.schema.Table..entity_namespace

          `inherited from the' FromClause.entity_namespace.
          `attribute of' FromClause.

          Return a namespace used for name-based access in SQL
          expressions.

          This is the namespace that is used to resolve “filter_by()”
          type expressions, such as:

               stmt.filter_by(address='some address')

          It defaults to the ‘.c’ collection, however internally it can
          be overridden using the “entity_namespace” annotation to
          deliver alternative results.

      -- Method: sqlalchemy.schema.Table..exists (bind=None)

          Return True if this table exists.

          Deprecated since version 1.4: The Table.exists()
          method is deprecated and will be removed in a future release.
          Please refer to Inspector.has_table().

      -- Attribute: sqlalchemy.schema.Table..exported_columns

          `inherited from the' FromClause.exported_columns.
          `attribute of' FromClause.

          A ColumnCollection that represents the “exported”
          columns of this Selectable.

          The “exported” columns for a FromClause object are
          synonymous with the FromClause.columns collection.

          New in version 1.4.

          See also
          ........

          See Selectable.exported_columns.

          See SelectBase.exported_columns.

      -- Attribute: sqlalchemy.schema.Table..
               foreign_key_constraints

          ForeignKeyConstraint objects referred to by this
          Table.

          This list is produced from the collection of ForeignKey
          objects currently associated.

          See also
          ........

          See Table.constraints.

          See Table.foreign_keys.

          See Table.indexes.

      -- Attribute: sqlalchemy.schema.Table..foreign_keys

          `inherited from the' FromClause.foreign_keys.
          `attribute of' FromClause.

          Return the collection of ForeignKey marker objects
          which this FromClause references.

          Each ForeignKey is a member of a Table.
          -wide ForeignKeyConstraint.

          See also
          ........

          See Table.foreign_key_constraints.

      -- Method: sqlalchemy.schema.Table..get_children
               (omit_attrs=(), **kw)

          `inherited from the' ClauseElement.get_children().
          `method of' ClauseElement.

          Return immediate child Traversible elements of
          this Traversible.

          This is used for visit traversal.

          **kw may contain flags that change the collection that is
          returned, for example to return a subset of items in order to
          cut down on larger traversals, or to return child items from a
          different context (such as schema-level collections instead of
          clause-level).

      -- Attribute: sqlalchemy.schema.Table..indexes = None

          A collection of all Index objects associated with
          this Table.

          See also
          ........

          See Inspector.get_indexes().

      -- Attribute: sqlalchemy.schema.Table..info

          `inherited from the' SchemaItem.info. `attribute
          of' SchemaItem.

          Info dictionary associated with the object, allowing
          user-defined data to be associated with this SchemaItem.

          The dictionary is automatically generated when first accessed.
          It can also be specified in the constructor of some objects,
          such as Table and Column.

      -- Method: sqlalchemy.schema.Table..insert (values=None,
               inline=False, **kwargs)

          `inherited from the' TableClause.insert(). `method
          of' TableClause.

          Generate an insert() construct against this
          TableClause.

          E.g.:

               table.insert().values(name='foo')

          See insert() for argument and usage information.

      -- Method: sqlalchemy.schema.Table..is_derived_from
               (fromclause)

          `inherited from the' FromClause.is_derived_from().
          `method of' FromClause.

          Return ‘True’ if this FromClause is ‘derived’ from
          the given ‘FromClause’.

          An example would be an Alias of a Table is derived from that
          Table.

      -- Method: sqlalchemy.schema.Table..join (right,
               onclause=None, isouter=False, full=False)

          `inherited from the' FromClause.join(). `method of'
          FromClause.

          Return a Join from this FromClause to
          another ‘FromClause’.

          E.g.:

               from sqlalchemy import join

               j = user_table.join(address_table,
                               user_table.c.id == address_table.c.user_id)
               stmt = select(user_table).select_from(j)

          would emit SQL along the lines of:

               SELECT user.id, user.name FROM user
               JOIN address ON user.id = address.user_id

          Parameters:

             * ‘right’ – the right side of the join; this is any
               FromClause object such as a Table object,
               and may also be a selectable-compatible object such as an
               ORM-mapped class.

             * ‘onclause’ – a SQL expression representing the ON clause
               of the join.  If left at ‘None’, see FromClause.join()
               will attempt to join the two tables based on a
               foreign key relationship.

             * ‘isouter’ – if True, render a LEFT OUTER JOIN, instead of
               JOIN.

             * ‘full’ – if True, render a FULL OUTER JOIN, instead of
               LEFT OUTER JOIN. Implies FromClause.join.isouter.

               New in version 1.1.

          See also
          ........

          See join(). - standalone function

          See Join. - the type of object produced

      -- Attribute: sqlalchemy.schema.Table..key

          Return the ‘key’ for this Table.

          This value is used as the dictionary key within the
          MetaData.tables collection.  It is typically the same
          as that of ‘Table.name’ for a table with no ‘Table.schema’
          set; otherwise it is typically of the form
          ‘schemaname.tablename’.

      -- Attribute: sqlalchemy.schema.Table..kwargs

          `inherited from the' DialectKWArgs.kwargs.
          `attribute of' DialectKWArgs.

          A synonym for DialectKWArgs.dialect_kwargs.

      -- Method: sqlalchemy.schema.Table..lateral (name=None)

          `inherited from the' Selectable.lateral(). `method
          of' Selectable.

          Return a LATERAL alias of this Selectable.

          The return value is the Lateral construct also
          provided by the top-level lateral() function.

          New in version 1.1.

          See also
          ........

          See LATERAL correlation. - overview of usage.

      -- Class: memoized_attribute (fget, doc=None)

          A read-only @property that is only evaluated once.

      -- Method: sqlalchemy.schema.Table..classmethod
               memoized_instancemethod (fn)

          `inherited from the' ‘HasMemoized.memoized_instancemethod()’
          `method of' ‘HasMemoized’

          Decorate a method memoize its return value.

      -- Method: sqlalchemy.schema.Table..outerjoin (right,
               onclause=None, full=False)

          `inherited from the' FromClause.outerjoin().
          `method of' FromClause.

          Return a Join from this FromClause to
          another ‘FromClause’, with the “isouter” flag set to True.

          E.g.:

               from sqlalchemy import outerjoin

               j = user_table.outerjoin(address_table,
                               user_table.c.id == address_table.c.user_id)

          The above is equivalent to:

               j = user_table.join(
                   address_table,
                   user_table.c.id == address_table.c.user_id,
                   isouter=True)

          Parameters:

             * ‘right’ – the right side of the join; this is any
               FromClause object such as a Table object,
               and may also be a selectable-compatible object such as an
               ORM-mapped class.

             * ‘onclause’ – a SQL expression representing the ON clause
               of the join.  If left at ‘None’, see FromClause.join()
               will attempt to join the two tables based on a
               foreign key relationship.

             * ‘full’ – if True, render a FULL OUTER JOIN, instead of
               LEFT OUTER JOIN.

               New in version 1.1.

          See also
          ........

          See FromClause.join().

          See Join.

      -- Attribute: sqlalchemy.schema.Table..primary_key

          `inherited from the' FromClause.primary_key.
          `attribute of' FromClause.

          Return the iterable collection of Column objects
          which comprise the primary key of this
          ‘_selectable.FromClause’.

          For a Table object, this collection is represented
          by the PrimaryKeyConstraint which itself is an
          iterable collection of Column objects.

      -- Method: sqlalchemy.schema.Table..replace_selectable
               (old, alias)

          `inherited from the' Selectable.replace_selectable().
          `method of' Selectable.

          Replace all occurrences of FromClause. ‘old’ with
          the given Alias object, returning a copy of this
          FromClause.

          Deprecated since version 1.4: The
          Selectable.replace_selectable() method is deprecated,
          and will be removed in a future release.  Similar
          functionality is available via the sqlalchemy.sql.visitors
          module.

      -- Method: sqlalchemy.schema.Table..select
               (whereclause=None, **kwargs)

          `inherited from the' FromClause.select(). `method
          of' FromClause.

          Return a SELECT of this FromClause.

          e.g.:

               stmt = some_table.select().where(some_table.c.id == 5)

          Parameters:

             * ‘whereclause’ – a WHERE clause, equivalent to calling the
               Select.where() method.

               Deprecated since version 1.4: The
               FromClause.select().whereclause parameter is
               deprecated and will be removed in version 2.0.  Please
               make use of the Select.where() method to add
               WHERE criteria to the SELECT statement.

             * ‘**kwargs’ – additional keyword arguments are passed to
               the legacy constructor for Select described at
               Select.create_legacy_select().

          See also
          ........

          See select(). - general purpose method which allows for
          arbitrary column lists.

      -- Method: sqlalchemy.schema.Table..self_group (against:
               Optional[Any] = None) -> ClauseElement

          `inherited from the' ClauseElement.self_group().
          `method of' ClauseElement.

          Apply a ‘grouping’ to this ClauseElement.

          This method is overridden by subclasses to return a “grouping”
          construct, i.e.  parenthesis.  In particular it’s used by
          “binary” expressions to provide a grouping around themselves
          when placed into a larger expression, as well as by
          select() constructs when placed into the FROM clause of
          another select().  (Note that subqueries should be
          normally created using the Select.alias() method,
          as many platforms require nested SELECT statements to be
          named).

          As expressions are composed together, the application of
          self_group() is automatic - end-user code should never
          need to use this method directly.  Note that SQLAlchemy’s
          clause constructs take operator precedence into account - so
          parenthesis might not be needed, for example, in an expression
          like ‘x OR (y AND z)’ - AND takes precedence over OR.

          The base self_group() method of
          ClauseElement just returns self.

      -- Method: sqlalchemy.schema.Table..table_valued ()

          `inherited from the' FromClause.table_valued().
          `method of' FromClause.

          Return a ‘TableValuedColumn’ object for this FromClause.

          A ‘TableValuedColumn’ is a ColumnElement that
          represents a complete row in a table.  Support for this
          construct is backend dependent, and is supported in various
          forms by backends such as PostgreSQL, Oracle and SQL Server.

          E.g.:

               >>> from sqlalchemy import select, column, func, table
               >>> a = table("a", column("id"), column("x"), column("y"))
               >>> stmt = select(func.row_to_json(a.table_valued()))
               >>> print(stmt)
               SELECT row_to_json(a) AS row_to_json_1
               FROM a

          New in version 1.4.0b2.

          See also
          ........

          See Working with SQL Functions. - in the
          SQLAlchemy 1.4 / 2.0 Tutorial.

      -- Method: sqlalchemy.schema.Table..tablesample
               (sampling, name=None, seed=None)

          `inherited from the' FromClause.tablesample().
          `method of' FromClause.

          Return a TABLESAMPLE alias of this FromClause.

          The return value is the TableSample construct also
          provided by the top-level tablesample() function.

          New in version 1.1.

          See also
          ........

          See tablesample(). - usage guidelines and parameters

      -- Method: sqlalchemy.schema.Table..to_metadata
               (metadata, schema=symbol('retain_schema'),
               referred_schema_fn=None, name=None)

          Return a copy of this Table associated with a
          different MetaData.

          E.g.:

               m1 = MetaData()

               user = Table('user', m1, Column('id', Integer, primary_key=True))

               m2 = MetaData()
               user_copy = user.to_metadata(m2)

          Changed in version 1.4: The Table.to_metadata()
          function was renamed from Table.tometadata().

          Parameters:

             * ‘metadata’ – Target MetaData object, into
               which the new Table object will be created.

             * ‘schema’ – optional string name indicating the target
               schema.  Defaults to the special symbol ‘RETAIN_SCHEMA’
               which indicates that no change to the schema name should
               be made in the new Table.  If set to a string
               name, the new Table will have this new name as
               the ‘.schema’.  If set to ‘None’, the schema will be set
               to that of the schema set on the target MetaData,
               which is typically ‘None’ as well, unless set
               explicitly:

                    m2 = MetaData(schema='newschema')

                    # user_copy_one will have "newschema" as the schema name
                    user_copy_one = user.to_metadata(m2, schema=None)

                    m3 = MetaData()  # schema defaults to None

                    # user_copy_two will have None as the schema name
                    user_copy_two = user.to_metadata(m3, schema=None)

             * ‘referred_schema_fn’ – optional callable which can be
               supplied in order to provide for the schema name that
               should be assigned to the referenced table of a
               ForeignKeyConstraint.  The callable accepts this
               parent Table, the target schema that we are
               changing to, the ForeignKeyConstraint object,
               and the existing “target schema” of that constraint.  The
               function should return the string schema name that should
               be applied.  E.g.:

                    def referred_schema_fn(table, to_schema,
                                                    constraint, referred_schema):
                        if referred_schema == 'base_tables':
                            return referred_schema
                        else:
                            return to_schema

                    new_table = table.to_metadata(m2, schema="alt_schema",
                                            referred_schema_fn=referred_schema_fn)

               New in version 0.9.2.

             * ‘name’ – optional string name indicating the target table
               name.  If not specified or None, the table name is
               retained.  This allows a Table to be copied to
               the same MetaData target with a new name.

               New in version 1.0.0.

      -- Method: sqlalchemy.schema.Table..tometadata
               (metadata, schema=symbol('retain_schema'),
               referred_schema_fn=None, name=None)

          Return a copy of this Table associated with a
          different MetaData.

          Deprecated since version 1.4: Table.tometadata()
          is renamed to Table.to_metadata().

          See Table.to_metadata() for a full description.

      -- Method: sqlalchemy.schema.Table..update
               (whereclause=None, values=None, inline=False, **kwargs)

          `inherited from the' TableClause.update(). `method
          of' TableClause.

          Generate an update() construct against this
          TableClause.

          E.g.:

               table.update().where(table.c.id==7).values(name='foo')

          See update() for argument and usage information.

 -- Class: sqlalchemy.schema.ThreadLocalMetaData

     A MetaData variant that presents a different ‘bind’ in every
     thread.

     Deprecated since version 1.4: ThreadLocalMetaData is
     deprecated and will be removed in a future release.

     Makes the ‘bind’ property of the MetaData a thread-local value,
     allowing this collection of tables to be bound to different
     ‘Engine’ implementations or connections in each thread.

     The ThreadLocalMetaData starts off bound to None in each thread.
     Binds must be made explicitly by assigning to the ‘bind’ property
     or using ‘connect()’.  You can also re-bind dynamically multiple
     times per thread, just like a regular ‘MetaData’.

     `Class signature'

     class sqlalchemy.schema.ThreadLocalMetaData. (see
     sqlalchemy.schema.MetaData)

      -- Method: sqlalchemy.schema.ThreadLocalMetaData..
               __init__ ()

          Construct a ThreadLocalMetaData.

      -- Attribute: sqlalchemy.schema.ThreadLocalMetaData..
               bind

          The bound Engine or Connection for this thread.

          This property may be assigned an Engine or Connection, or
          assigned a string or URL to automatically create a basic
          Engine for this bind with ‘create_engine()’.

      -- Method: sqlalchemy.schema.ThreadLocalMetaData..
               dispose ()

          Dispose all bound engines, in all thread contexts.

      -- Method: sqlalchemy.schema.ThreadLocalMetaData..
               is_bound ()

          True if there is a bind for this thread.

4.3.2 Reflecting Database Objects
---------------------------------

A Table object can be instructed to load information about
itself from the corresponding database schema object already existing
within the database.  This process is called `reflection'.  In the most
simple case you need only specify the table name, a MetaData
object, and the ‘autoload_with’ argument:

     >>> messages = Table('messages', meta, autoload_with=engine)
     >>> [c.name for c in messages.columns]
     ['message_id', 'message_name', 'date']

The above operation will use the given engine to query the database for
information about the ‘messages’ table, and will then generate
Column, ForeignKey, and other objects corresponding to
this information as though the Table object were
hand-constructed in Python.

When tables are reflected, if a given table references another one via
foreign key, a second Table object is created within the
MetaData object representing the connection.  Below, assume
the table ‘shopping_cart_items’ references a table named
‘shopping_carts’.  Reflecting the ‘shopping_cart_items’ table has the
effect such that the ‘shopping_carts’ table will also be loaded:

     >>> shopping_cart_items = Table('shopping_cart_items', meta, autoload_with=engine)
     >>> 'shopping_carts' in meta.tables:
     True

The MetaData has an interesting “singleton-like” behavior
such that if you requested both tables individually, see MetaData
will ensure that exactly one Table object is created for each
distinct table name.  The Table constructor actually returns
to you the already-existing Table object if one already
exists with the given name.  Such as below, we can access the already
generated ‘shopping_carts’ table just by naming it:

     shopping_carts = Table('shopping_carts', meta)

Of course, it’s a good idea to use ‘autoload_with=engine’ with the above
table regardless.  This is so that the table’s attributes will be loaded
if they have not been already.  The autoload operation only occurs for
the table if it hasn’t already been loaded; once loaded, new calls to
Table with the same name will not re-issue any reflection
queries.

4.3.2.1 Overriding Reflected Columns
....................................

Individual columns can be overridden with explicit values when
reflecting tables; this is handy for specifying custom datatypes,
constraints such as primary keys that may not be configured within the
database, etc.:

     >>> mytable = Table('mytable', meta,
     ... Column('id', Integer, primary_key=True),   # override reflected 'id' to have primary key
     ... Column('mydata', Unicode(50)),    # override reflected 'mydata' to be Unicode
     ... # additional Column objects which require no change are reflected normally
     ... autoload_with=some_engine)

See also
........

See Working with Custom Types and Reflection. - illustrates how
the above column override technique applies to the use of custom
datatypes with table reflection.

4.3.2.2 Reflecting Views
........................

The reflection system can also reflect views.  Basic usage is the same
as that of a table:

     my_view = Table("some_view", metadata, autoload_with=engine)

Above, ‘my_view’ is a Table object with Column
objects representing the names and types of each column within the view
“some_view”.

Usually, it’s desired to have at least a primary key constraint when
reflecting a view, if not foreign keys as well.  View reflection doesn’t
extrapolate these constraints.

Use the “override” technique for this, specifying explicitly those
columns which are part of the primary key or have foreign key
constraints:

     my_view = Table("some_view", metadata,
                     Column("view_id", Integer, primary_key=True),
                     Column("related_thing", Integer, ForeignKey("othertable.thing_id")),
                     autoload_with=engine
     )

4.3.2.3 Reflecting All Tables at Once
.....................................

The MetaData object can also get a listing of tables and
reflect the full set.  This is achieved by using the reflect()
method.  After calling it, all located tables are present within
the MetaData object’s dictionary of tables:

     meta = MetaData()
     meta.reflect(bind=someengine)
     users_table = meta.tables['users']
     addresses_table = meta.tables['addresses']

‘metadata.reflect()’ also provides a handy way to clear or delete all
the rows in a database:

     meta = MetaData()
     meta.reflect(bind=someengine)
     for table in reversed(meta.sorted_tables):
         someengine.execute(table.delete())

4.3.2.4 Fine Grained Reflection with Inspector
..............................................

A low level interface which provides a backend-agnostic system of
loading lists of schema, table, column, and constraint descriptions from
a given database is also available.  This is known as the “Inspector”:

     from sqlalchemy import create_engine
     from sqlalchemy import inspect
     engine = create_engine('...')
     insp = inspect(engine)
     print(insp.get_table_names())

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See Inspector.Performs database schema inspection.

 -- Class: sqlalchemy.engine.reflection.Inspector (bind)

     Performs database schema inspection.

     The Inspector acts as a proxy to the reflection methods of the
     ‘Dialect’, providing a consistent interface as well as caching
     support for previously fetched metadata.

     A Inspector object is usually created via the
     inspect() function, which may be passed an Engine
     or a Connection:

          from sqlalchemy import inspect, create_engine
          engine = create_engine('...')
          insp = inspect(engine)

     Where above, the ‘Dialect’ associated with the engine may opt to
     return an Inspector subclass that provides additional
     methods specific to the dialect’s target database.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               __init__ (bind)

          Initialize a new Inspector.

          Deprecated since version 1.4: The __init__() method on
          Inspector is deprecated and will be removed in a future
          release.  Please use the inspect() function on an
          Engine or Connection in order to
          acquire an Inspector.

          Parameters: ‘bind’ – a ‘Connectable’, which is typically an
          instance of Engine or Connection.

          For a dialect-specific instance of Inspector, see
          Inspector.from_engine().

      -- Attribute: sqlalchemy.engine.reflection.Inspector..
               default_schema_name

          Return the default schema name presented by the dialect for
          the current engine’s database user.

          E.g.  this is typically ‘public’ for PostgreSQL and ‘dbo’ for
          SQL Server.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               classmethod from_engine (bind)

          Construct a new dialect-specific Inspector object from the
          given engine or connection.

          Deprecated since version 1.4: The from_engine() method on
          Inspector is deprecated and will be removed in a
          future release.  Please use the inspect() function
          on an Engine or Connection in order to
          acquire an Inspector.

          Parameters: ‘bind’ – a ‘Connectable’, which is typically an
          instance of Engine or Connection.

          This method differs from direct a direct constructor call of
          Inspector in that the ‘Dialect’ is given a chance
          to provide a dialect-specific Inspector instance,
          which may provide additional methods.

          See the example at Inspector.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               get_check_constraints (table_name, schema=None,
               **kw)

          Return information about check constraints in ‘table_name’.

          Given a string ‘table_name’ and an optional string ‘schema’,
          return check constraint information as a list of dicts with
          these keys:

             * ‘name’ - the check constraint’s name

             * ‘sqltext’ - the check constraint’s SQL expression

             * ‘dialect_options’ - may or may not be present; a
               dictionary with additional dialect-specific options for
               this CHECK constraint

               New in version 1.3.8.

          Parameters:

             * ‘table_name’ – string name of the table.  For special
               quoting, use quoted_name.

             * ‘schema’ – string schema name; if omitted, uses the
               default schema of the database connection.  For special
               quoting, use quoted_name.

          New in version 1.1.0.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               get_columns (table_name, schema=None, **kw)

          Return information about columns in ‘table_name’.

          Given a string ‘table_name’ and an optional string ‘schema’,
          return column information as a list of dicts with these keys:

             * ‘name’ - the column’s name

             * ‘type’ - the type of this column; an instance of
               TypeEngine.

             * ‘nullable’ - boolean flag if the column is NULL or NOT
               NULL

             * ‘default’ - the column’s server default value - this is
               returned as a string SQL expression.

             * ‘autoincrement’ - indicates that the column is auto
               incremented - this is returned as a boolean or ‘auto’

             * ‘comment’ - (optional) the comment on the column.  Only
               some dialects return this key

             * ‘computed’ - (optional) when present it indicates that
               this column is computed by the database.  Only some
               dialects return this key.  Returned as a dict with the
               keys:

                  * ‘sqltext’ - the expression used to generate this
                    column returned as a string SQL expression

                  * ‘persisted’ - (optional) boolean that indicates if
                    the column is stored in the table

               New in version 1.3.16: - added support for computed
               reflection.

             * ‘identity’ - (optional) when present it indicates that
               this column is a generated always column.  Only some
               dialects return this key.  For a list of keywords on this
               dict see Identity.

               New in version 1.4: - added support for identity column
               reflection.

             * ‘dialect_options’ - (optional) a dict with dialect
               specific options

          Parameters:

             * ‘table_name’ – string name of the table.  For special
               quoting, use quoted_name.

             * ‘schema’ – string schema name; if omitted, uses the
               default schema of the database connection.  For special
               quoting, use quoted_name.

          Returns: list of dictionaries, each representing the
          definition of a database column.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               get_foreign_keys (table_name, schema=None, **kw)

          Return information about foreign_keys in ‘table_name’.

          Given a string ‘table_name’, and an optional string ‘schema’,
          return foreign key information as a list of dicts with these
          keys:

             * ‘constrained_columns’ - a list of column names that make
               up the foreign key

             * ‘referred_schema’ - the name of the referred schema

             * ‘referred_table’ - the name of the referred table

             * ‘referred_columns’ - a list of column names in the
               referred table that correspond to constrained_columns

             * ‘name’ - optional name of the foreign key constraint.

          Parameters:

             * ‘table_name’ – string name of the table.  For special
               quoting, use quoted_name.

             * ‘schema’ – string schema name; if omitted, uses the
               default schema of the database connection.  For special
               quoting, use quoted_name.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               get_indexes (table_name, schema=None, **kw)

          Return information about indexes in ‘table_name’.

          Given a string ‘table_name’ and an optional string ‘schema’,
          return index information as a list of dicts with these keys:

             * ‘name’ - the index’s name

             * ‘column_names’ - list of column names in order

             * ‘unique’ - boolean

             * ‘column_sorting’ - optional dict mapping column names to
               tuple of sort keywords, which may include ‘asc’, ‘desc’,
               ‘nulls_first’, ‘nulls_last’.

               New in version 1.3.5.

             * ‘dialect_options’ - dict of dialect-specific index
               options.  May not be present for all dialects.

               New in version 1.0.0.

          Parameters:

             * ‘table_name’ – string name of the table.  For special
               quoting, use quoted_name.

             * ‘schema’ – string schema name; if omitted, uses the
               default schema of the database connection.  For special
               quoting, use quoted_name.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               get_pk_constraint (table_name, schema=None, **kw)

          Return information about primary key constraint on
          ‘table_name’.

          Given a string ‘table_name’, and an optional string ‘schema’,
          return primary key information as a dictionary with these
          keys:

             * ‘constrained_columns’ - a list of column names that make
               up the primary key

             * ‘name’ - optional name of the primary key constraint.

          Parameters:

             * ‘table_name’ – string name of the table.  For special
               quoting, use quoted_name.

             * ‘schema’ – string schema name; if omitted, uses the
               default schema of the database connection.  For special
               quoting, use quoted_name.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               get_schema_names ()

          Return all schema names.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               get_sequence_names (schema=None)

          Return all sequence names in ‘schema’.

          Parameters: ‘schema’ – Optional, retrieve names from a
          non-default schema.  For special quoting, use
          quoted_name.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               get_sorted_table_and_fkc_names (schema=None)

          Return dependency-sorted table and foreign key constraint
          names in referred to within a particular schema.

          This will yield 2-tuples of ‘(tablename, [(tname, fkname),
          (tname, fkname), ...])’ consisting of table names in CREATE
          order grouped with the foreign key constraint names that are
          not detected as belonging to a cycle.  The final element will
          be ‘(None, [(tname, fkname), (tname, fkname), ..])’ which will
          consist of remaining foreign key constraint names that would
          require a separate CREATE step after-the-fact, based on
          dependencies between tables.

          New in version 1.0.-.

          See also
          ........

          See Inspector.get_table_names().

          See sort_tables_and_constraints(). - similar method
          which works with an already-given MetaData.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               get_table_comment (table_name, schema=None, **kw)

          Return information about the table comment for ‘table_name’.

          Given a string ‘table_name’ and an optional string ‘schema’,
          return table comment information as a dictionary with these
          keys:

             *
               ‘text’ -

                    text of the comment.

          Raises ‘NotImplementedError’ for a dialect that does not
          support comments.

          New in version 1.2.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               get_table_names (schema=None)

          Return all table names in referred to within a particular
          schema.

          The names are expected to be real tables only, not views.
          Views are instead returned using the
          Inspector.get_view_names() method.

          Parameters: ‘schema’ – Schema name.  If ‘schema’ is left at
          ‘None’, the database’s default schema is used, else the named
          schema is searched.  If the database does not support named
          schemas, behavior is undefined if ‘schema’ is not passed as
          ‘None’.  For special quoting, use quoted_name.

          See also
          ........

          See Inspector.get_sorted_table_and_fkc_names().

          See MetaData.sorted_tables.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               get_table_options (table_name, schema=None, **kw)

          Return a dictionary of options specified when the table of the
          given name was created.

          This currently includes some options that apply to MySQL
          tables.

          Parameters:

             * ‘table_name’ – string name of the table.  For special
               quoting, use quoted_name.

             * ‘schema’ – string schema name; if omitted, uses the
               default schema of the database connection.  For special
               quoting, use quoted_name.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               get_temp_table_names ()

          Return a list of temporary table names for the current bind.

          This method is unsupported by most dialects; currently only
          SQLite implements it.

          New in version 1.0.0.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               get_temp_view_names ()

          Return a list of temporary view names for the current bind.

          This method is unsupported by most dialects; currently only
          SQLite implements it.

          New in version 1.0.0.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               get_unique_constraints (table_name, schema=None,
               **kw)

          Return information about unique constraints in ‘table_name’.

          Given a string ‘table_name’ and an optional string ‘schema’,
          return unique constraint information as a list of dicts with
          these keys:

             * ‘name’ - the unique constraint’s name

             * ‘column_names’ - list of column names in order

          Parameters:

             * ‘table_name’ – string name of the table.  For special
               quoting, use quoted_name.

             * ‘schema’ – string schema name; if omitted, uses the
               default schema of the database connection.  For special
               quoting, use quoted_name.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               get_view_definition (view_name, schema=None)

          Return definition for ‘view_name’.

          Parameters: ‘schema’ – Optional, retrieve names from a
          non-default schema.  For special quoting, use
          quoted_name.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               get_view_names (schema=None)

          Return all view names in ‘schema’.

          Parameters: ‘schema’ – Optional, retrieve names from a
          non-default schema.  For special quoting, use
          quoted_name.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               has_sequence (sequence_name, schema=None)

          Return True if the backend has a table of the given name.

          Parameters:

             * ‘sequence_name’ – name of the table to check

             * ‘schema’ – schema name to query, if not the default
               schema.

          New in version 1.4.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               has_table (table_name, schema=None)

          Return True if the backend has a table of the given name.

          Parameters:

             * ‘table_name’ – name of the table to check

             * ‘schema’ – schema name to query, if not the default
               schema.

          New in version 1.4.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               reflect_table (table, include_columns,
               exclude_columns=(), resolve_fks=True, _extend_on=None)

          Given a Table object, load its internal constructs
          based on introspection.

          This is the underlying method used by most dialects to produce
          table reflection.  Direct usage is like:

               from sqlalchemy import create_engine, MetaData, Table
               from sqlalchemy import inspect

               engine = create_engine('...')
               meta = MetaData()
               user_table = Table('user', meta)
               insp = inspect(engine)
               insp.reflect_table(user_table, None)

          Changed in version 1.4: Renamed from ‘reflecttable’ to
          ‘reflect_table’

          Parameters:

             * ‘table’ – a Table instance.

             * ‘include_columns’ – a list of string column names to
               include in the reflection process.  If ‘None’, all
               columns are reflected.

      -- Method: sqlalchemy.engine.reflection.Inspector..
               reflecttable (*args, **kwargs)

          See reflect_table.  This method name is deprecated

          Deprecated since version 1.4: The
          Inspector.reflecttable() method is considered legacy as
          of the 1.x series of SQLAlchemy and will be removed in 2.0.
          The Inspector.reflecttable() method was renamed
          to Inspector.reflect_table().  This deprecated
          alias will be removed in a future release.  (Background on
          SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

4.3.2.5 Reflecting with Database-Agnostic Types
...............................................

When the columns of a table are reflected, using either the
Table.autoload_with parameter of Table or the
Inspector.get_columns() method of Inspector, the
datatypes will be as specific as possible to the target database.  This
means that if an “integer” datatype is reflected from a MySQL database,
the type will be represented by the
sqlalchemy.dialects.mysql.INTEGER class, which includes
MySQL-specific attributes such as “display_width”.  Or on PostgreSQL, a
PostgreSQL-specific datatype such as
sqlalchemy.dialects.postgresql.INTERVAL or
sqlalchemy.dialects.postgresql.ENUM may be returned.

There is a use case for reflection which is that a given Table
is to be transferred to a different vendor database.  To suit this
use case, there is a technique by which these vendor-specific datatypes
can be converted on the fly to be instance of SQLAlchemy
backend-agnostic datatypes, for the examples above types such as
Integer, Interval and Enum.  This may be
achieved by intercepting the column reflection using the
DDLEvents.column_reflect() event in conjunction with the
TypeEngine.as_generic() method.

Given a table in MySQL (chosen because MySQL has a lot of
vendor-specific datatypes and options):

     CREATE TABLE IF NOT EXISTS my_table (
         id INTEGER PRIMARY KEY AUTO_INCREMENT,
         data1 VARCHAR(50) CHARACTER SET latin1,
         data2 MEDIUMINT(4),
         data3 TINYINT(2)
     )

The above table includes MySQL-only integer types ‘MEDIUMINT’ and
‘TINYINT’ as well as a ‘VARCHAR’ that includes the MySQL-only ‘CHARACTER
SET’ option.  If we reflect this table normally, it produces a
Table object that will contain those MySQL-specific datatypes and
options:

     >>> from sqlalchemy import MetaData, Table, create_engine
     >>> mysql_engine = create_engine("mysql://scott:tiger@localhost/test")
     >>> metadata = MetaData()
     >>> my_mysql_table = Table("my_table", metadata, autoload_with=mysql_engine)

The above example reflects the above table schema into a new
Table object.  We can then, for demonstration purposes, print out
the MySQL-specific “CREATE TABLE” statement using the CreateTable
construct:

     >>> from sqlalchemy.schema import CreateTable
     >>> print(CreateTable(my_mysql_table).compile(mysql_engine))
     {opensql}CREATE TABLE my_table (
     id INTEGER(11) NOT NULL AUTO_INCREMENT,
     data1 VARCHAR(50) CHARACTER SET latin1,
     data2 MEDIUMINT(4),
     data3 TINYINT(2),
     PRIMARY KEY (id)
     )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

Above, the MySQL-specific datatypes and options were maintained.  If we
wanted a Table that we could instead transfer cleanly to
another database vendor, replacing the special datatypes
sqlalchemy.dialects.mysql.MEDIUMINT and
sqlalchemy.dialects.mysql.TINYINT with Integer, we can
choose instead to “genericize” the datatypes on this table, or otherwise
change them in any way we’d like, by establishing a handler using the
DDLEvents.column_reflect() event.  The custom handler will
make use of the TypeEngine.as_generic() method to convert
the above MySQL-specific type objects into generic ones, by replacing
the ‘"type"’ entry within the column dictionary entry that is passed to
the event handler.  The format of this dictionary is described at
Inspector.get_columns():

     >>> from sqlalchemy import event
     >>> metadata = MetaData()

     >>> @event.listens_for(metadata, "column_reflect")
     >>> def genericize_datatypes(inspector, tablename, column_dict):
     ...     column_dict["type"] = column_dict["type"].as_generic()

     >>> my_generic_table = Table("my_table", metadata, autoload_with=mysql_engine)

We now get a new Table that is generic and uses
Integer for those datatypes.  We can now emit a “CREATE TABLE”
statement for example on a PostgreSQL database:

     >>> pg_engine = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
     >>> my_generic_table.create(pg_engine)
     {opensql}CREATE TABLE my_table (
         id SERIAL NOT NULL,
         data1 VARCHAR(50),
         data2 INTEGER,
         data3 INTEGER,
         PRIMARY KEY (id)
     )

Noting above also that SQLAlchemy will usually make a decent guess for
other behaviors, such as that the MySQL ‘AUTO_INCREMENT’ directive is
represented in PostgreSQL most closely using the ‘SERIAL’
auto-incrementing datatype.

New in version 1.4: Added the TypeEngine.as_generic()
method and additionally improved the use of the
DDLEvents.column_reflect() event such that it may be applied to a
MetaData object for convenience.

4.3.2.6 Limitations of Reflection
.................................

It’s important to note that the reflection process recreates
Table metadata using only information which is represented in the
relational database.  This process by definition cannot restore aspects
of a schema that aren’t actually stored in the database.  State which is
not available from reflection includes but is not limited to:

   * Client side defaults, either Python functions or SQL expressions
     defined using the ‘default’ keyword of Column. (note this
     is separate from ‘server_default’, which specifically is what’s
     available via reflection).

   * Column information, e.g.  data that might have been placed into the
     Column.info dictionary

   * The value of the ‘.quote’ setting for Column or
     Table.

   * The association of a particular Sequence with a given
     Column.

The relational database also in many cases reports on table metadata in
a different format than what was specified in SQLAlchemy.  The
Table objects returned from reflection cannot be always relied upon
to produce the identical DDL as the original Python-defined Table
objects.  Areas where this occurs includes server defaults,
column-associated sequences and various idiosyncrasies regarding
constraints and datatypes.  Server side defaults may be returned with
cast directives (typically PostgreSQL will include a ‘::<type>’ cast) or
different quoting patterns than originally specified.

Another category of limitation includes schema structures for which
reflection is only partially or not yet defined.  Recent improvements to
reflection allow things like views, indexes and foreign key options to
be reflected.  As of this writing, structures like CHECK constraints,
table comments, and triggers are not reflected.

4.3.3 Column INSERT/UPDATE Defaults
-----------------------------------

Column INSERT and UPDATE defaults refer to functions that create a
`default value' for a particular column in a row as an INSERT or UPDATE
statement is proceeding against that row, in the case where `no value
was provided to the INSERT or UPDATE statement for that column'.  That
is, if a table has a column called “timestamp”, and an INSERT statement
proceeds which does not include a value for this column, an INSERT
default would create a new value, such as the current time, that is used
as the value to be INSERTed into the “timestamp” column.  If the
statement `does' include a value for this column, then the default does
`not' take place.

Column defaults can be server-side functions or constant values which
are defined in the database along with the schema in DDL, or as SQL
expressions which are rendered directly within an INSERT or UPDATE
statement emitted by SQLAlchemy; they may also be client-side Python
functions or constant values which are invoked by SQLAlchemy before data
is passed to the database.

     Note: A column default handler should not be confused with a
     construct that intercepts and modifies incoming values for INSERT
     and UPDATE statements which `are' provided to the statement as it
     is invoked.  This is known as data marshalling, where a column
     value is modified in some way by the application before being sent
     to the database.  SQLAlchemy provides a few means of achieving this
     which include using custom datatypes, SQL execution events
     and in the ORM custom validators
     as well as attribute events.  Column defaults are only
     invoked when there is `no value present' for a column in a SQL DML
     statement.

SQLAlchemy provides an array of features regarding default generation
functions which take place for non-present values during INSERT and
UPDATE statements.  Options include:

   * Scalar values used as defaults during INSERT and UPDATE operations

   * Python functions which execute upon INSERT and UPDATE operations

   * SQL expressions which are embedded in INSERT statements (or in some
     cases execute beforehand)

   * SQL expressions which are embedded in UPDATE statements

   * Server side default values used during INSERT

   * Markers for server-side triggers used during UPDATE

The general rule for all insert/update defaults is that they only take
effect if no value for a particular column is passed as an ‘execute()’
parameter; otherwise, the given value is used.

4.3.3.1 Scalar Defaults
.......................

The simplest kind of default is a scalar value used as the default value
of a column:

     Table("mytable", meta,
         Column("somecolumn", Integer, default=12)
     )

Above, the value “12” will be bound as the column value during an INSERT
if no other value is supplied.

A scalar value may also be associated with an UPDATE statement, though
this is not very common (as UPDATE statements are usually looking for
dynamic defaults):

     Table("mytable", meta,
         Column("somecolumn", Integer, onupdate=25)
     )

4.3.3.2 Python-Executed Functions
.................................

The Column.default and Column.onupdate keyword
arguments also accept Python functions.  These functions are invoked at
the time of insert or update if no other value for that column is
supplied, and the value returned is used for the column’s value.  Below
illustrates a crude “sequence” that assigns an incrementing counter to a
primary key column:

     # a function which counts upwards
     i = 0
     def mydefault():
         global i
         i += 1
         return i

     t = Table("mytable", meta,
         Column('id', Integer, primary_key=True, default=mydefault),
     )

It should be noted that for real “incrementing sequence” behavior, the
built-in capabilities of the database should normally be used, which may
include sequence objects or other autoincrementing capabilities.  For
primary key columns, SQLAlchemy will in most cases use these
capabilities automatically.  See the API documentation for Column
including the Column.autoincrement flag, as well as the
section on Sequence later in this chapter for background on
standard primary key generation techniques.

To illustrate onupdate, we assign the Python ‘datetime’ function ‘now’
to the Column.onupdate attribute:

     import datetime

     t = Table("mytable", meta,
         Column('id', Integer, primary_key=True),

         # define 'last_updated' to be populated with datetime.now()
         Column('last_updated', DateTime, onupdate=datetime.datetime.now),
     )

When an update statement executes and no value is passed for
‘last_updated’, the ‘datetime.datetime.now()’ Python function is
executed and its return value used as the value for ‘last_updated’.
Notice that we provide ‘now’ as the function itself without calling it
(i.e.  there are no parenthesis following) - SQLAlchemy will execute the
function at the time the statement executes.

4.3.3.3 Context-Sensitive Default Functions
...........................................

The Python functions used by Column.default and
Column.onupdate may also make use of the current statement’s
context in order to determine a value.  The ‘context’ of a statement is
an internal SQLAlchemy object which contains all information about the
statement being executed, including its source expression, the
parameters associated with it and the cursor.  The typical use case for
this context with regards to default generation is to have access to the
other values being inserted or updated on the row.  To access the
context, provide a function that accepts a single ‘context’ argument:

     def mydefault(context):
         return context.get_current_parameters()['counter'] + 12

     t = Table('mytable', meta,
         Column('counter', Integer),
         Column('counter_plus_twelve', Integer, default=mydefault, onupdate=mydefault)
     )

The above default generation function is applied so that it will execute
for all INSERT and UPDATE statements where a value for
‘counter_plus_twelve’ was otherwise not provided, and the value will be
that of whatever value is present in the execution for the ‘counter’
column, plus the number 12.

For a single statement that is being executed using “executemany” style,
e.g.  with multiple parameter sets passed to Connection.execute(),
the user-defined function is called once for each set of
parameters.  For the use case of a multi-valued Insert
construct (e.g.  with more than one VALUES clause set up via the
Insert.values() method), the user-defined function is also called
once for each set of parameters.

When the function is invoked, the special method
DefaultExecutionContext.get_current_parameters() is available
from the context object (an subclass of DefaultExecutionContext).
This method returns a dictionary of column-key to values that
represents the full set of values for the INSERT or UPDATE statement.
In the case of a multi-valued INSERT construct, the subset of parameters
that corresponds to the individual VALUES clause is isolated from the
full parameter dictionary and returned alone.

New in version 1.2: Added
DefaultExecutionContext.get_current_parameters() method, which
improves upon the still-present
DefaultExecutionContext.current_parameters attribute by offering
the service of organizing multiple VALUES clauses into individual
parameter dictionaries.

4.3.3.4 Client-Invoked SQL Expressions
......................................

The Column.default and Column.onupdate keywords
may also be passed SQL expressions, which are in most cases rendered
inline within the INSERT or UPDATE statement:

     t = Table("mytable", meta,
         Column('id', Integer, primary_key=True),

         # define 'create_date' to default to now()
         Column('create_date', DateTime, default=func.now()),

         # define 'key' to pull its default from the 'keyvalues' table
         Column('key', String(20), default=select(keyvalues.c.key).where(keyvalues.c.type='type1')),

         # define 'last_modified' to use the current_timestamp SQL function on update
         Column('last_modified', DateTime, onupdate=func.utc_timestamp())
         )

Above, the ‘create_date’ column will be populated with the result of the
‘now()’ SQL function (which, depending on backend, compiles into ‘NOW()’
or ‘CURRENT_TIMESTAMP’ in most cases) during an INSERT statement, and
the ‘key’ column with the result of a SELECT subquery from another
table.  The ‘last_modified’ column will be populated with the value of
the SQL ‘UTC_TIMESTAMP()’ MySQL function when an UPDATE statement is
emitted for this table.

     Note: When using SQL functions with the ‘func’ construct, we “call”
     the named function, e.g.  with parenthesis as in ‘func.now()’.
     This differs from when we specify a Python callable as a default
     such as ‘datetime.datetime’, where we pass the function itself, but
     we don’t invoke it ourselves.  In the case of a SQL function,
     invoking ‘func.now()’ returns the SQL expression object that will
     render the “NOW” function into the SQL being emitted.

Default and update SQL expressions specified by Column.default
and Column.onupdate are invoked explicitly by
SQLAlchemy when an INSERT or UPDATE statement occurs, typically rendered
inline within the DML statement except in certain cases listed below.
This is different than a “server side” default, which is part of the
table’s DDL definition, e.g.  as part of the “CREATE TABLE” statement,
which are likely more common.  For server side defaults, see the next
section Server-invoked DDL-Explicit Default Expressions.

When a SQL expression indicated by Column.default is used
with primary key columns, there are some cases where SQLAlchemy must
“pre-execute” the default generation SQL function, meaning it is invoked
in a separate SELECT statement, and the resulting value is passed as a
parameter to the INSERT. This only occurs for primary key columns for an
INSERT statement that is being asked to return this primary key value,
where RETURNING or ‘cursor.lastrowid’ may not be used.  An Insert
construct that specifies the insert.inline flag will
always render default expressions inline.

When the statement is executed with a single set of parameters (that is,
it is not an “executemany” style execution), the returned
CursorResult will contain a collection accessible via
CursorResult.postfetch_cols() which contains a list of all
Column objects which had an inline-executed default.  Similarly,
all parameters which were bound to the statement, including all Python
and SQL expressions which were pre-executed, are present in the
CursorResult.last_inserted_params() or
CursorResult.last_updated_params() collections on
CursorResult.  The CursorResult.inserted_primary_key
collection contains a list of primary key values for the row inserted (a
list so that single-column and composite-column primary keys are
represented in the same format).

4.3.3.5 Server-invoked DDL-Explicit Default Expressions
.......................................................

A variant on the SQL expression default is the
Column.server_default, which gets placed in the CREATE TABLE
statement during a Table.create() operation:

     t = Table('test', meta,
         Column('abc', String(20), server_default='abc'),
         Column('created_at', DateTime, server_default=func.sysdate()),
         Column('index_value', Integer, server_default=text("0"))
     )

A create call for the above table will produce:

     CREATE TABLE test (
         abc varchar(20) default 'abc',
         created_at datetime default sysdate,
         index_value integer default 0
     )

The above example illustrates the two typical use cases for
Column.server_default, that of the SQL function (SYSDATE in the
above example) as well as a server-side constant value (the integer “0”
in the above example).  It is advisable to use the text()
construct for any literal SQL values as opposed to passing the raw
value, as SQLAlchemy does not typically perform any quoting or escaping
on these values.

Like client-generated expressions, see Column.server_default can
accommodate SQL expressions in general, however it is expected that
these will usually be simple functions and expressions, and not the more
complex cases like an embedded SELECT.

4.3.3.6 Marking Implicitly Generated Values, timestamps, and Triggered Columns
..............................................................................

Columns which generate a new value on INSERT or UPDATE based on other
server-side database mechanisms, such as database-specific
auto-generating behaviors such as seen with TIMESTAMP columns on some
platforms, as well as custom triggers that invoke upon INSERT or UPDATE
to generate a new value, may be called out using FetchedValue
as a marker:

     from sqlalchemy.schema import FetchedValue

     t = Table('test', meta,
         Column('id', Integer, primary_key=True),
         Column('abc', TIMESTAMP, server_default=FetchedValue()),
         Column('def', String(20), server_onupdate=FetchedValue())
     )

The FetchedValue indicator does not affect the rendered DDL
for the CREATE TABLE. Instead, it marks the column as one that will have
a new value populated by the database during the process of an INSERT or
UPDATE statement, and for supporting databases may be used to indicate
that the column should be part of a RETURNING or OUTPUT clause for the
statement.  Tools such as the SQLAlchemy ORM then make use of this
marker in order to know how to get at the value of the column after such
an operation.  In particular, the ValuesBase.return_defaults()
method can be used with an Insert or Update
construct to indicate that these values should be returned.

For details on using FetchedValue with the ORM, see
Fetching Server-Generated Defaults.

     Warning: The Column.server_onupdate directive `does
     not' currently produce MySQL’s “ON UPDATE CURRENT_TIMESTAMP()”
     clause.  See Rendering ON UPDATE CURRENT TIMESTAMP for MySQL / MariaDB’s explicit_defaults_for_timestamp
     for background
     on how to produce this clause.

See also
........

See Fetching Server-Generated Defaults.

4.3.3.7 Defining Sequences
..........................

SQLAlchemy represents database sequences using the Sequence
object, which is considered to be a special case of “column default”.
It only has an effect on databases which have explicit support for
sequences, which currently includes PostgreSQL, Oracle, MariaDB 10.3 or
greater, and Firebird.  The Sequence object is otherwise
ignored.

The Sequence may be placed on any column as a “default”
generator to be used during INSERT operations, and can also be
configured to fire off during UPDATE operations if desired.  It is most
commonly used in conjunction with a single integer primary key column:

     table = Table("cartitems", meta,
         Column(
             "cart_id",
             Integer,
             Sequence('cart_id_seq', metadata=meta), primary_key=True),
         Column("description", String(40)),
         Column("createdate", DateTime())
     )

Where above, the table “cartitems” is associated with a sequence named
“cart_id_seq”.  When INSERT statements take place for “cartitems”, and
no value is passed for the “cart_id” column, the “cart_id_seq” sequence
will be used to generate a value.  Typically, the sequence function is
embedded in the INSERT statement, which is combined with RETURNING so
that the newly generated value can be returned to the Python code:

     INSERT INTO cartitems (cart_id, description, createdate)
     VALUES (next_val(cart_id_seq), 'some description', '2015-10-15 12:00:15')
     RETURNING cart_id

When the Sequence is associated with a Column as
its `Python-side' default generator, the Sequence will also
be subject to “CREATE SEQUENCE” and “DROP SEQUENCE” DDL when similar DDL
is emitted for the owning Table.  This is a limited scope
convenience feature that does not accommodate for inheritance of other
aspects of the MetaData, such as the default schema.
Therefore, it is best practice that for a Sequence which is
local to a certain Column. / see Table, that it be
explicitly associated with the MetaData using the
Sequence.metadata parameter.  See the section Associating a Sequence with the MetaData
for more background on this.

4.3.3.8 Associating a Sequence on a SERIAL column
.................................................

PostgreSQL’s SERIAL datatype is an auto-incrementing type that implies
the implicit creation of a PostgreSQL sequence when CREATE TABLE is
emitted.  If a Column specifies an explicit Sequence
object which also specifies a ‘True’ value for the
Sequence.optional boolean flag, the Sequence will not
take effect under PostgreSQL, and the SERIAL datatype will proceed
normally.  Instead, the Sequence will only take effect when
used against other sequence-supporting databases, currently Oracle and
Firebird.

4.3.3.9 Executing a Sequence Standalone
.......................................

A SEQUENCE is a first class schema object in SQL and can be used to
generate values independently in the database.  If you have a
Sequence object, it can be invoked with its “next value”
instruction by passing it directly to a SQL execution method:

     with my_engine.connect() as conn:
         seq = Sequence('some_sequence')
         nextid = conn.execute(seq)

In order to embed the “next value” function of a Sequence
inside of a SQL statement like a SELECT or INSERT, use the
Sequence.next_value() method, which will render at statement
compilation time a SQL function that is appropriate for the target
backend:

     >>> my_seq = Sequence('some_sequence')
     >>> stmt = select(my_seq.next_value())
     >>> print(stmt.compile(dialect=postgresql.dialect()))
     SELECT nextval('some_sequence') AS next_value_1

4.3.3.10 Associating a Sequence with the MetaData
.................................................

For many years, the SQLAlchemy documentation referred to the example of
associating a Sequence with a table as follows:

     table = Table("cartitems", meta,
         Column("cart_id", Integer, Sequence('cart_id_seq'),
                primary_key=True),
         Column("description", String(40)),
         Column("createdate", DateTime())
     )

While the above is a prominent idiomatic pattern, it is recommended that
the Sequence in most cases be explicitly associated with the
MetaData, using the Sequence.metadata parameter:

     table = Table("cartitems", meta,
         Column(
             "cart_id",
             Integer,
             Sequence('cart_id_seq', metadata=meta), primary_key=True),
         Column("description", String(40)),
         Column("createdate", DateTime())
     )

The Sequence object is a first class schema construct that
can exist independently of any table in a database, and can also be
shared among tables.  Therefore SQLAlchemy does not implicitly modify
the Sequence when it is associated with a Column
object as either the Python-side or server-side default generator.
While the CREATE SEQUENCE / DROP SEQUENCE DDL is emitted for a
Sequence defined as a Python side generator at the same time the
table itself is subject to CREATE or DROP, this is a convenience feature
that does not imply that the Sequence is fully associated
with the MetaData object.

Explicitly associating the Sequence with MetaData
allows for the following behaviors:

   * The Sequence will inherit the MetaData.schema
     parameter specified to the target MetaData, which
     affects the production of CREATE / DROP DDL, if any.

   * The Sequence.create() and Sequence.drop().
     methods automatically use the engine bound to the MetaData
     object, if any.

   * The MetaData.create_all() and MetaData.drop_all()
     methods will emit CREATE / DROP for this Sequence,
     even if the Sequence is not associated with any
     Table. / see Column that’s a member of this
     MetaData.

Since the vast majority of cases that deal with Sequence
expect that Sequence to be fully “owned” by the associated
Table and that options like default schema are propagated,
setting the Sequence.metadata parameter should be
considered a best practice.

4.3.3.11 Associating a Sequence as the Server Side Default
..........................................................

     Note: The following technique is known to work only with the
     PostgreSQL database.  It does not work with Oracle.

The preceding sections illustrate how to associate a Sequence
with a Column as the `Python side default generator':

     Column(
         "cart_id", Integer, Sequence('cart_id_seq', metadata=meta),
         primary_key=True)

In the above case, the Sequence will automatically be
subject to CREATE SEQUENCE / DROP SEQUENCE DDL when the related
Table is subject to CREATE / DROP. However, the sequence will `not'
be present as the server-side default for the column when CREATE TABLE
is emitted.

If we want the sequence to be used as a server-side default, meaning it
takes place even if we emit INSERT commands to the table from the SQL
command line, we can use the Column.server_default parameter
in conjunction with the value-generation function of the sequence,
available from the Sequence.next_value() method.  Below we
illustrate the same Sequence being associated with the
Column both as the Python-side default generator as well as the
server-side default generator:

     cart_id_seq = Sequence('cart_id_seq', metadata=meta)
     table = Table("cartitems", meta,
         Column(
             "cart_id", Integer, cart_id_seq,
             server_default=cart_id_seq.next_value(), primary_key=True),
         Column("description", String(40)),
         Column("createdate", DateTime())
     )

or with the ORM:

     class CartItem(Base):
         __tablename__ = 'cartitems'

         cart_id_seq = Sequence('cart_id_seq', metadata=Base.metadata)
         cart_id = Column(
             Integer, cart_id_seq,
             server_default=cart_id_seq.next_value(), primary_key=True)
         description = Column(String(40))
         createdate = Column(DateTime)

When the “CREATE TABLE” statement is emitted, on PostgreSQL it would be
emitted as:

     CREATE TABLE cartitems (
         cart_id INTEGER DEFAULT nextval('cart_id_seq') NOT NULL,
         description VARCHAR(40),
         createdate TIMESTAMP WITHOUT TIME ZONE,
         PRIMARY KEY (cart_id)
     )

Placement of the Sequence in both the Python-side and
server-side default generation contexts ensures that the “primary key
fetch” logic works in all cases.  Typically, sequence-enabled databases
also support RETURNING for INSERT statements, which is used
automatically by SQLAlchemy when emitting this statement.  However if
RETURNING is not used for a particular insert, then SQLAlchemy would
prefer to “pre-execute” the sequence outside of the INSERT statement
itself, which only works if the sequence is included as the Python-side
default generator function.

The example also associates the Sequence with the enclosing
MetaData directly, which again ensures that the
Sequence is fully associated with the parameters of the
MetaData collection including the default schema, if any.

See also
........

See Sequences/SERIAL/IDENTITY. - in the PostgreSQL dialect
documentation

See RETURNING Support. - in the Oracle dialect documentation

4.3.3.12 Computed Columns (GENERATED ALWAYS AS)
...............................................

New in version 1.3.11.

The Computed construct allows a Column to be
declared in DDL as a “GENERATED ALWAYS AS” column, that is, one which
has a value that is computed by the database server.  The construct
accepts a SQL expression typically declared textually using a string or
the text() construct, in a similar manner as that of
CheckConstraint.  The SQL expression is then interpreted by the
database server in order to determine the value for the column within a
row.

Example:

     from sqlalchemy import Table, Column, MetaData, Integer, Computed

     metadata = MetaData()

     square = Table(
         "square",
         metadata,
         Column("id", Integer, primary_key=True),
         Column("side", Integer),
         Column("area", Integer, Computed("side * side")),
         Column("perimeter", Integer, Computed("4 * side")),
     )

The DDL for the ‘square’ table when run on a PostgreSQL 12 backend will
look like:

     CREATE TABLE square (
         id SERIAL NOT NULL,
         side INTEGER,
         area INTEGER GENERATED ALWAYS AS (side * side) STORED,
         perimeter INTEGER GENERATED ALWAYS AS (4 * side) STORED,
         PRIMARY KEY (id)
     )

Whether the value is persisted upon INSERT and UPDATE, or if it is
calculated on fetch, is an implementation detail of the database; the
former is known as “stored” and the latter is known as “virtual”.  Some
database implementations support both, but some only support one or the
other.  The optional Computed.persisted flag may be
specified as ‘True’ or ‘False’ to indicate if the “STORED” or “VIRTUAL”
keyword should be rendered in DDL, however this will raise an error if
the keyword is not supported by the target backend; leaving it unset
will use a working default for the target backend.

The Computed construct is a subclass of the
FetchedValue object, and will set itself up as both the “server
default” and “server onupdate” generator for the target Column,
meaning it will be treated as a default generating column when
INSERT and UPDATE statements are generated, as well as that it will be
fetched as a generating column when using the ORM. This includes that it
will be part of the RETURNING clause of the database for databases which
support RETURNING and the generated values are to be eagerly fetched.

     Note: A Column that is defined with the Computed
     construct may not store any value outside of that which the
     server applies to it; SQLAlchemy’s behavior when a value is passed
     for such a column to be written in INSERT or UPDATE is currently
     that the value will be ignored.

“GENERATED ALWAYS AS” is currently known to be supported by:

   * MySQL version 5.7 and onwards

   * MariaDB 10.x series and onwards

   * PostgreSQL as of version 12

   * Oracle - with the caveat that RETURNING does not work correctly
     with UPDATE (a warning will be emitted to this effect when the
     UPDATE..RETURNING that includes a computed column is rendered)

   * Microsoft SQL Server

   * SQLite as of version 3.31

   * Firebird

When Computed is used with an unsupported backend, if the
target dialect does not support it, a CompileError is raised
when attempting to render the construct.  Otherwise, if the dialect
supports it but the particular database server version in use does not,
then a subclass of DBAPIError, usually
OperationalError, is raised when the DDL is emitted to the
database.

See also
........

See Computed.

4.3.3.13 Identity Columns (GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY)
.........................................................................

New in version 1.4.

The Identity construct allows a Column to be
declared as an identity column and rendered in DDL as “GENERATED {
ALWAYS | BY DEFAULT } AS IDENTITY”.  An identity column has its value
automatically generated by the database server using an incrementing (or
decrementing) sequence.  The construct shares most of its option to
control the database behaviour with Sequence.

Example:

     from sqlalchemy import Table, Column, MetaData, Integer, Computed

     metadata = MetaData()

     data = Table(
         "data",
         metadata,
         Column('id', Integer, Identity(start=42, cycle=True), primary_key=True),
         Column('data', String)
     )

The DDL for the ‘data’ table when run on a PostgreSQL 12 backend will
look like:

     CREATE TABLE data (
         id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 42 CYCLE) NOT NULL,
         data VARCHAR,
         PRIMARY KEY (id)
     )

The database will generate a value for the ‘id’ column upon insert,
starting from ‘42’, if the statement did not already contain a value for
the ‘id’ column.  An identity column can also require that the database
generates the value of the column, ignoring the value passed with the
statement or raising an error, depending on the backend.  To activate
this mode, set the parameter Identity.always to ‘True’ in
the Identity construct.  Updating the previous example to
include this parameter will generate the following DDL:

     CREATE TABLE data (
         id INTEGER GENERATED ALWAYS AS IDENTITY (START WITH 42 CYCLE) NOT NULL,
         data VARCHAR,
         PRIMARY KEY (id)
     )

The Identity construct is a subclass of the
FetchedValue object, and will set itself up as the “server
default” generator for the target Column, meaning it will be
treated as a default generating column when INSERT statements are
generated, as well as that it will be fetched as a generating column
when using the ORM. This includes that it will be part of the RETURNING
clause of the database for databases which support RETURNING and the
generated values are to be eagerly fetched.

The Identity construct is currently known to be supported
by:

   * PostgreSQL as of version 10.

   * Oracle as of version 12.  It also supports passing ‘always=None’ to
     enable the default generated mode and the parameter ‘on_null=True’
     to specify “ON NULL” in conjunction with a “BY DEFAULT” identity
     column.

   * Microsoft SQL Server.  MSSQL uses a custom syntax that only
     supports the ‘start’ and ‘increment’ parameters, and ignores all
     other.

When Identity is used with an unsupported backend, it is
ignored, and the default SQLAlchemy logic for autoincrementing columns
is used.

An error is raised when a Column specifies both an
Identity and also sets Column.autoincrement to
‘False’.

See also
........

See Identity.

4.3.3.14 Default Objects API
............................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See ColumnDefault.A plain default value on a column.

See Computed.Defines a generated column, i.e.  “GENERATED ALWAYS AS” syntax.

See DefaultClause.A DDL-specified DEFAULT column value.

See DefaultGenerator.Base class for column `default' values.

See FetchedValue.A marker for a transparent database-side default.

See Identity.Defines an identity column, i.e.  “GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY” syntax.

See Sequence.Represents a named database sequence.

 -- Class: sqlalchemy.schema.Computed (sqltext, persisted=None)

     Defines a generated column, i.e.  “GENERATED ALWAYS AS” syntax.

     The Computed construct is an inline construct added to
     the argument list of a Column object:

          from sqlalchemy import Computed

          Table('square', meta,
              Column('side', Float, nullable=False),
              Column('area', Float, Computed('side * side'))
          )

     See the linked documentation below for complete details.

     New in version 1.3.11.

     See also
     ........

     See Computed Columns (GENERATED ALWAYS AS).

     `Class signature'

     class sqlalchemy.schema.Computed. (see
     sqlalchemy.schema.FetchedValue,
     sqlalchemy.schema.SchemaItem)

      -- Method: sqlalchemy.schema.Computed..__init__
               (sqltext, persisted=None)

          Construct a GENERATED ALWAYS AS DDL construct to accompany a
          Column.

          Parameters:

             * ‘sqltext’ – A string containing the column generation
               expression, which will be used verbatim, or a SQL
               expression construct, such as a text() object.
               If given as a string, the object is converted to a
               text() object.

                    Warning: The Computed.sqltext argument
                    to Computed can be passed as a Python
                    string argument, which will be treated as `trusted
                    SQL text' and rendered as given.  `DO NOT PASS
                    UNTRUSTED INPUT TO THIS PARAMETER'.

             * ‘persisted’ – Optional, controls how this column should
               be persisted by the database.  Possible values are:

                  * ‘None’, the default, it will use the default
                    persistence defined by the database.

                  * ‘True’, will render ‘GENERATED ALWAYS AS ...
                    STORED’, or the equivalent for the target database
                    if supported.

                  * ‘False’, will render ‘GENERATED ALWAYS AS ...
                    VIRTUAL’, or the equivalent for the target database
                    if supported.

               Specifying ‘True’ or ‘False’ may raise an error when the
               DDL is emitted to the target database if the database
               does not support that persistence option.  Leaving this
               parameter at its default of ‘None’ is guaranteed to
               succeed for all databases that support ‘GENERATED ALWAYS
               AS’.

      -- Method: sqlalchemy.schema.Computed..copy
               (target_table=None, **kw)

          Deprecated since version 1.4: The Computed.copy()
          method is deprecated and will be removed in a future release.

 -- Class: sqlalchemy.schema.ColumnDefault (arg, **kwargs)

     A plain default value on a column.

     This could correspond to a constant, a callable function, or a SQL
     clause.

     ColumnDefault is generated automatically whenever the
     ‘default’, ‘onupdate’ arguments of Column are used.  A
     ColumnDefault can be passed positionally as well.

     For example, the following:

          Column('foo', Integer, default=50)

     Is equivalent to:

          Column('foo', Integer, ColumnDefault(50))

     `Class signature'

     class sqlalchemy.schema.ColumnDefault. (see
     sqlalchemy.schema.DefaultGenerator)

 -- Class: sqlalchemy.schema.DefaultClause (arg, for_update=False,
          _reflected=False)

     A DDL-specified DEFAULT column value.

     DefaultClause is a FetchedValue that also
     generates a “DEFAULT” clause when “CREATE TABLE” is emitted.

     DefaultClause is generated automatically whenever the
     ‘server_default’, ‘server_onupdate’ arguments of Column
     are used.  A DefaultClause can be passed positionally
     as well.

     For example, the following:

          Column('foo', Integer, server_default="50")

     Is equivalent to:

          Column('foo', Integer, DefaultClause("50"))

     `Class signature'

     class sqlalchemy.schema.DefaultClause. (see
     sqlalchemy.schema.FetchedValue)

 -- Class: sqlalchemy.schema.DefaultGenerator (for_update=False)

     Base class for column `default' values.

     `Class signature'

     class sqlalchemy.schema.DefaultGenerator. (see
     sqlalchemy.schema.SchemaItem)

 -- Class: sqlalchemy.schema.FetchedValue (for_update=False)

     A marker for a transparent database-side default.

     Use FetchedValue when the database is configured to
     provide some automatic default for a column.

     E.g.:

          Column('foo', Integer, FetchedValue())

     Would indicate that some trigger or default generator will create a
     new value for the ‘foo’ column during an INSERT.

     See also
     ........

     See Marking Implicitly Generated Values, timestamps, and Triggered Columns.

     `Class signature'

     class sqlalchemy.schema.FetchedValue.
     (‘sqlalchemy.sql.expression.SchemaEventTarget’)

 -- Class: sqlalchemy.schema.Sequence (name, start=None, increment=None,
          minvalue=None, maxvalue=None, nominvalue=None,
          nomaxvalue=None, cycle=None, schema=None, cache=None,
          order=None, data_type=None, optional=False, quote=None,
          metadata=None, quote_schema=None, for_update=False)

     Represents a named database sequence.

     The Sequence object represents the name and
     configurational parameters of a database sequence.  It also
     represents a construct that can be “executed” by a SQLAlchemy
     Engine or Connection, rendering the appropriate
     “next value” function for the target database and returning a
     result.

     The Sequence is typically associated with a primary key
     column:

          some_table = Table(
              'some_table', metadata,
              Column('id', Integer, Sequence('some_table_seq'),
              primary_key=True)
          )

     When CREATE TABLE is emitted for the above Table, if the
     target platform supports sequences, a CREATE SEQUENCE statement
     will be emitted as well.  For platforms that don’t support
     sequences, the Sequence construct is ignored.

     See also
     ........

     See Defining Sequences.

     See CreateSequence.

     See DropSequence.

     `Class signature'

     class sqlalchemy.schema.Sequence.
     (‘sqlalchemy.schema.IdentityOptions’,
     ‘sqlalchemy.sql.roles.StatementRole’, see
     sqlalchemy.schema.DefaultGenerator)

      -- Method: sqlalchemy.schema.Sequence..__init__ (name,
               start=None, increment=None, minvalue=None, maxvalue=None,
               nominvalue=None, nomaxvalue=None, cycle=None,
               schema=None, cache=None, order=None, data_type=None,
               optional=False, quote=None, metadata=None,
               quote_schema=None, for_update=False)

          Construct a Sequence object.

          Parameters:

             * ‘name’ – the name of the sequence.

             * ‘start’ – the starting index of the sequence.  This value
               is used when the CREATE SEQUENCE command is emitted to
               the database as the value of the “START WITH” clause.  If
               ‘None’, the clause is omitted, which on most platforms
               indicates a starting value of 1.

             * ‘increment’ – the increment value of the sequence.  This
               value is used when the CREATE SEQUENCE command is emitted
               to the database as the value of the “INCREMENT BY”
               clause.  If ‘None’, the clause is omitted, which on most
               platforms indicates an increment of 1.

             * ‘minvalue’ – the minimum value of the sequence.  This
               value is used when the CREATE SEQUENCE command is emitted
               to the database as the value of the “MINVALUE” clause.
               If ‘None’, the clause is omitted, which on most platforms
               indicates a minvalue of 1 and -2^63-1 for ascending and
               descending sequences, respectively.

               New in version 1.0.7.

             * ‘maxvalue’ – the maximum value of the sequence.  This
               value is used when the CREATE SEQUENCE command is emitted
               to the database as the value of the “MAXVALUE” clause.
               If ‘None’, the clause is omitted, which on most platforms
               indicates a maxvalue of 2^63-1 and -1 for ascending and
               descending sequences, respectively.

               New in version 1.0.7.

             * ‘nominvalue’ – no minimum value of the sequence.  This
               value is used when the CREATE SEQUENCE command is emitted
               to the database as the value of the “NO MINVALUE” clause.
               If ‘None’, the clause is omitted, which on most platforms
               indicates a minvalue of 1 and -2^63-1 for ascending and
               descending sequences, respectively.

               New in version 1.0.7.

             * ‘nomaxvalue’ – no maximum value of the sequence.  This
               value is used when the CREATE SEQUENCE command is emitted
               to the database as the value of the “NO MAXVALUE” clause.
               If ‘None’, the clause is omitted, which on most platforms
               indicates a maxvalue of 2^63-1 and -1 for ascending and
               descending sequences, respectively.

               New in version 1.0.7.

             * ‘cycle’ – allows the sequence to wrap around when the
               maxvalue or minvalue has been reached by an ascending or
               descending sequence respectively.  This value is used
               when the CREATE SEQUENCE command is emitted to the
               database as the “CYCLE” clause.  If the limit is reached,
               the next number generated will be the minvalue or
               maxvalue, respectively.  If cycle=False (the default) any
               calls to nextval after the sequence has reached its
               maximum value will return an error.

               New in version 1.0.7.

             * ‘schema’ – optional schema name for the sequence, if
               located in a schema other than the default.  The rules
               for selecting the schema name when a MetaData
               is also present are the same as that of
               Table.schema.

             * ‘cache’ – optional integer value; number of future values
               in the sequence which are calculated in advance.  Renders
               the CACHE keyword understood by Oracle and PostgreSQL.

               New in version 1.1.12.

             * ‘order’ – optional boolean value; if ‘True’, renders the
               ORDER keyword, understood by Oracle, indicating the
               sequence is definitively ordered.  May be necessary to
               provide deterministic ordering using Oracle RAC.

               New in version 1.1.12.

             * ‘data_type’ – The type to be returned by the sequence,
               for dialects that allow us to choose between INTEGER,
               BIGINT, etc.  (e.g., mssql).

               New in version 1.4.0.

             * ‘optional’ – boolean value, when ‘True’, indicates that
               this Sequence object only needs to be
               explicitly generated on backends that don’t provide
               another way to generate primary key identifiers.
               Currently, it essentially means, “don’t create this
               sequence on the PostgreSQL backend, where the SERIAL
               keyword creates a sequence for us automatically”.

             * ‘quote’ – boolean value, when ‘True’ or ‘False’,
               explicitly forces quoting of the Sequence.name
               on or off.  When left at its default of ‘None’,
               normal quoting rules based on casing and reserved words
               take place.

             * ‘quote_schema’ – Set the quoting preferences for the
               ‘schema’ name.

             * ‘metadata’ – optional MetaData object which
               this Sequence will be associated with.  A
               Sequence that is associated with a
               MetaData gains the following capabilities:

                  * The Sequence will inherit the
                    MetaData.schema parameter specified to the
                    target MetaData, which affects the
                    production of CREATE / DROP DDL, if any.

                  * The Sequence.create() and
                    Sequence.drop() methods automatically use the
                    engine bound to the MetaData object, if
                    any.

                  * The MetaData.create_all() and
                    MetaData.drop_all() methods will emit CREATE /
                    DROP for this Sequence, even if the
                    Sequence is not associated with any
                    Table. / see Column that’s a member of
                    this MetaData.

               The above behaviors can only occur if the Sequence
               is explicitly associated with the MetaData
               via this parameter.

               See also
               ........

               See Associating a Sequence with the MetaData. -
               full discussion of the Sequence.metadata
               parameter.

             * ‘for_update’ – Indicates this Sequence, when
               associated with a Column, should be invoked for
               UPDATE statements on that column’s table, rather than for
               INSERT statements, when no value is otherwise present for
               that column in the statement.

      -- Attribute: sqlalchemy.schema.Sequence..bind

      -- Method: sqlalchemy.schema.Sequence..create
               (bind=None, checkfirst=True)

          Creates this sequence in the database.

               Note: the “bind” argument will be required in SQLAlchemy
               2.0.

      -- Method: sqlalchemy.schema.Sequence..drop (bind=None,
               checkfirst=True)

          Drops this sequence from the database.

               Note: the “bind” argument will be required in SQLAlchemy
               2.0.

      -- Method: sqlalchemy.schema.Sequence..next_value ()

          Return a next_value function element which will
          render the appropriate increment function for this
          Sequence within any SQL expression.

 -- Class: sqlalchemy.schema.Identity (always=False, on_null=None,
          start=None, increment=None, minvalue=None, maxvalue=None,
          nominvalue=None, nomaxvalue=None, cycle=None, cache=None,
          order=None)

     Defines an identity column, i.e.  “GENERATED { ALWAYS | BY DEFAULT
     } AS IDENTITY” syntax.

     The Identity construct is an inline construct added to
     the argument list of a Column object:

          from sqlalchemy import Identity

          Table('foo', meta,
              Column('id', Integer, Identity())
              Column('description', Text),
          )

     See the linked documentation below for complete details.

     New in version 1.4.

     See also
     ........

     See Identity Columns (GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY).

     `Class signature'

     class sqlalchemy.schema.Identity.
     (‘sqlalchemy.schema.IdentityOptions’, see
     sqlalchemy.schema.FetchedValue,
     sqlalchemy.schema.SchemaItem)

      -- Method: sqlalchemy.schema.Identity..__init__
               (always=False, on_null=None, start=None, increment=None,
               minvalue=None, maxvalue=None, nominvalue=None,
               nomaxvalue=None, cycle=None, cache=None, order=None)

          Construct a GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY DDL
          construct to accompany a Column.

          See the Sequence documentation for a complete
          description of most parameters.

               Note: MSSQL supports this construct as the preferred
               alternative to generate an IDENTITY on a column, but it
               uses non standard syntax that only support
               Identity.start and Identity.increment.
               All other parameters are ignored.

          Parameters:

             * ‘always’ – A boolean, that indicates the type of identity
               column.  If ‘False’ is specified, the default, then the
               user-specified value takes precedence.  If ‘True’ is
               specified, a user-specified value is not accepted ( on
               some backends, like PostgreSQL, OVERRIDING SYSTEM VALUE,
               or similar, may be specified in an INSERT to override the
               sequence value).  Some backends also have a default value
               for this parameter, ‘None’ can be used to omit rendering
               this part in the DDL. It will be treated as ‘False’ if a
               backend does not have a default value.

             * ‘on_null’ – Set to ‘True’ to specify ON NULL in
               conjunction with a ‘always=False’ identity column.  This
               option is only supported on some backends, like Oracle.

             * ‘start’ – the starting index of the sequence.

             * ‘increment’ – the increment value of the sequence.

             * ‘minvalue’ – the minimum value of the sequence.

             * ‘maxvalue’ – the maximum value of the sequence.

             * ‘nominvalue’ – no minimum value of the sequence.

             * ‘nomaxvalue’ – no maximum value of the sequence.

             * ‘cycle’ – allows the sequence to wrap around when the
               maxvalue or minvalue has been reached.

             * ‘cache’ – optional integer value; number of future values
               in the sequence which are calculated in advance.

             * ‘order’ – optional boolean value; if true, renders the
               ORDER keyword.

      -- Method: sqlalchemy.schema.Identity..copy (**kw)

          Deprecated since version 1.4: The Identity.copy()
          method is deprecated and will be removed in a future release.

4.3.4 Defining Constraints and Indexes
--------------------------------------

This section will discuss SQL constraints and indexes.  In SQLAlchemy
the key classes include ForeignKeyConstraint and Index.

4.3.4.1 Defining Foreign Keys
.............................

A `foreign key' in SQL is a table-level construct that constrains one or
more columns in that table to only allow values that are present in a
different set of columns, typically but not always located on a
different table.  We call the columns which are constrained the `foreign
key' columns and the columns which they are constrained towards the
`referenced' columns.  The referenced columns almost always define the
primary key for their owning table, though there are exceptions to this.
The foreign key is the “joint” that connects together pairs of rows
which have a relationship with each other, and SQLAlchemy assigns very
deep importance to this concept in virtually every area of its
operation.

In SQLAlchemy as well as in DDL, foreign key constraints can be defined
as additional attributes within the table clause, or for single-column
foreign keys they may optionally be specified within the definition of a
single column.  The single column foreign key is more common, and at the
column level is specified by constructing a ForeignKey object
as an argument to a Column object:

     user_preference = Table('user_preference', metadata,
         Column('pref_id', Integer, primary_key=True),
         Column('user_id', Integer, ForeignKey("user.user_id"), nullable=False),
         Column('pref_name', String(40), nullable=False),
         Column('pref_value', String(100))
     )

Above, we define a new table ‘user_preference’ for which each row must
contain a value in the ‘user_id’ column that also exists in the ‘user’
table’s ‘user_id’ column.

The argument to ForeignKey is most commonly a string of the
form `<tablename>.<columnname>', or for a table in a remote schema or
“owner” of the form `<schemaname>.<tablename>.<columnname>'.  It may
also be an actual Column object, which as we’ll see later is
accessed from an existing Table object via its ‘c’
collection:

     ForeignKey(user.c.user_id)

The advantage to using a string is that the in-python linkage between
‘user’ and ‘user_preference’ is resolved only when first needed, so that
table objects can be easily spread across multiple modules and defined
in any order.

Foreign keys may also be defined at the table level, using the
ForeignKeyConstraint object.  This object can describe a single- or
multi-column foreign key.  A multi-column foreign key is known as a
`composite' foreign key, and almost always references a table that has a
composite primary key.  Below we define a table ‘invoice’ which has a
composite primary key:

     invoice = Table('invoice', metadata,
         Column('invoice_id', Integer, primary_key=True),
         Column('ref_num', Integer, primary_key=True),
         Column('description', String(60), nullable=False)
     )

And then a table ‘invoice_item’ with a composite foreign key referencing
‘invoice’:

     invoice_item = Table('invoice_item', metadata,
         Column('item_id', Integer, primary_key=True),
         Column('item_name', String(60), nullable=False),
         Column('invoice_id', Integer, nullable=False),
         Column('ref_num', Integer, nullable=False),
         ForeignKeyConstraint(['invoice_id', 'ref_num'], ['invoice.invoice_id', 'invoice.ref_num'])
     )

It’s important to note that the ForeignKeyConstraint is the
only way to define a composite foreign key.  While we could also have
placed individual ForeignKey objects on both the
‘invoice_item.invoice_id’ and ‘invoice_item.ref_num’ columns, SQLAlchemy
would not be aware that these two values should be paired together - it
would be two individual foreign key constraints instead of a single
composite foreign key referencing two columns.

4.3.4.2 Creating/Dropping Foreign Key Constraints via ALTER
...........................................................

The behavior we’ve seen in tutorials and elsewhere involving foreign
keys with DDL illustrates that the constraints are typically rendered
“inline” within the CREATE TABLE statement, such as:

     CREATE TABLE addresses (
         id INTEGER NOT NULL,
         user_id INTEGER,
         email_address VARCHAR NOT NULL,
         PRIMARY KEY (id),
         CONSTRAINT user_id_fk FOREIGN KEY(user_id) REFERENCES users (id)
     )

The ‘CONSTRAINT .. FOREIGN KEY’ directive is used to create the
constraint in an “inline” fashion within the CREATE TABLE definition.
The MetaData.create_all() and MetaData.drop_all()
methods do this by default, using a topological sort of all the
Table objects involved such that tables are created and dropped in
order of their foreign key dependency (this sort is also available via
the MetaData.sorted_tables accessor).

This approach can’t work when two or more foreign key constraints are
involved in a “dependency cycle”, where a set of tables are mutually
dependent on each other, assuming the backend enforces foreign keys
(always the case except on SQLite, MySQL/MyISAM). The methods will
therefore break out constraints in such a cycle into separate ALTER
statements, on all backends other than SQLite which does not support
most forms of ALTER. Given a schema like:

     node = Table(
         'node', metadata,
         Column('node_id', Integer, primary_key=True),
         Column(
             'primary_element', Integer,
             ForeignKey('element.element_id')
         )
     )

     element = Table(
         'element', metadata,
         Column('element_id', Integer, primary_key=True),
         Column('parent_node_id', Integer),
         ForeignKeyConstraint(
             ['parent_node_id'], ['node.node_id'],
             name='fk_element_parent_node_id'
         )
     )

When we call upon MetaData.create_all() on a backend such as
the PostgreSQL backend, the cycle between these two tables is resolved
and the constraints are created separately:

     >>> with engine.connect() as conn:
     ...    metadata.create_all(conn, checkfirst=False)
     {opensql}CREATE TABLE element (
         element_id SERIAL NOT NULL,
         parent_node_id INTEGER,
         PRIMARY KEY (element_id)
     )

     CREATE TABLE node (
         node_id SERIAL NOT NULL,
         primary_element INTEGER,
         PRIMARY KEY (node_id)
     )

     ALTER TABLE element ADD CONSTRAINT fk_element_parent_node_id
         FOREIGN KEY(parent_node_id) REFERENCES node (node_id)
     ALTER TABLE node ADD FOREIGN KEY(primary_element)
         REFERENCES element (element_id)
     {stop}

In order to emit DROP for these tables, the same logic applies, however
note here that in SQL, to emit DROP CONSTRAINT requires that the
constraint has a name.  In the case of the ‘'node'’ table above, we
haven’t named this constraint; the system will therefore attempt to emit
DROP for only those constraints that are named:

     >>> with engine.connect() as conn:
     ...    metadata.drop_all(conn, checkfirst=False)
     {opensql}ALTER TABLE element DROP CONSTRAINT fk_element_parent_node_id
     DROP TABLE node
     DROP TABLE element
     {stop}

In the case where the cycle cannot be resolved, such as if we hadn’t
applied a name to either constraint here, we will receive the following
error:

     sqlalchemy.exc.CircularDependencyError: Can't sort tables for DROP;
     an unresolvable foreign key dependency exists between tables:
     element, node.  Please ensure that the ForeignKey and ForeignKeyConstraint
     objects involved in the cycle have names so that they can be dropped
     using DROP CONSTRAINT.

This error only applies to the DROP case as we can emit “ADD CONSTRAINT”
in the CREATE case without a name; the database typically assigns one
automatically.

The ForeignKeyConstraint.use_alter and
ForeignKey.use_alter keyword arguments can be used to manually
resolve dependency cycles.  We can add this flag only to the ‘'element'’
table as follows:

     element = Table(
         'element', metadata,
         Column('element_id', Integer, primary_key=True),
         Column('parent_node_id', Integer),
         ForeignKeyConstraint(
             ['parent_node_id'], ['node.node_id'],
             use_alter=True, name='fk_element_parent_node_id'
         )
     )

in our CREATE DDL we will see the ALTER statement only for this
constraint, and not the other one:

     >>> with engine.connect() as conn:
     ...    metadata.create_all(conn, checkfirst=False)
     {opensql}CREATE TABLE element (
         element_id SERIAL NOT NULL,
         parent_node_id INTEGER,
         PRIMARY KEY (element_id)
     )

     CREATE TABLE node (
         node_id SERIAL NOT NULL,
         primary_element INTEGER,
         PRIMARY KEY (node_id),
         FOREIGN KEY(primary_element) REFERENCES element (element_id)
     )

     ALTER TABLE element ADD CONSTRAINT fk_element_parent_node_id
     FOREIGN KEY(parent_node_id) REFERENCES node (node_id)
     {stop}

ForeignKeyConstraint.use_alter and
ForeignKey.use_alter, when used in conjunction with a drop
operation, will require that the constraint is named, else an error like
the following is generated:

     sqlalchemy.exc.CompileError: Can't emit DROP CONSTRAINT for constraint
     ForeignKeyConstraint(...); it has no name

Changed in version 1.0.0: - The DDL system invoked by
MetaData.create_all() and MetaData.drop_all() will now
automatically resolve mutually dependent foreign keys between tables
declared by ForeignKeyConstraint and ForeignKey
objects, without the need to explicitly set the
ForeignKeyConstraint.use_alter flag.

Changed in version 1.0.0: - The ForeignKeyConstraint.use_alter
flag can be used with an un-named constraint; only the DROP
operation will emit a specific error when actually called upon.

See also
........

See Configuring Constraint Naming Conventions.

See sort_tables_and_constraints().

4.3.4.3 ON UPDATE and ON DELETE
...............................

Most databases support `cascading' of foreign key values, that is the
when a parent row is updated the new value is placed in child rows, or
when the parent row is deleted all corresponding child rows are set to
null or deleted.  In data definition language these are specified using
phrases like “ON UPDATE CASCADE”, “ON DELETE CASCADE”, and “ON DELETE
SET NULL”, corresponding to foreign key constraints.  The phrase after
“ON UPDATE” or “ON DELETE” may also other allow other phrases that are
specific to the database in use.  The ForeignKey and
ForeignKeyConstraint objects support the generation of this clause
via the ‘onupdate’ and ‘ondelete’ keyword arguments.  The value is any
string which will be output after the appropriate “ON UPDATE” or “ON
DELETE” phrase:

     child = Table('child', meta,
         Column('id', Integer,
                 ForeignKey('parent.id', onupdate="CASCADE", ondelete="CASCADE"),
                 primary_key=True
         )
     )

     composite = Table('composite', meta,
         Column('id', Integer, primary_key=True),
         Column('rev_id', Integer),
         Column('note_id', Integer),
         ForeignKeyConstraint(
                     ['rev_id', 'note_id'],
                     ['revisions.id', 'revisions.note_id'],
                     onupdate="CASCADE", ondelete="SET NULL"
         )
     )

Note that these clauses require ‘InnoDB’ tables when used with MySQL.
They may also not be supported on other databases.

See also
........

For background on integration of ‘ON DELETE CASCADE’ with ORM
relationship() constructs, see the following sections:

Using foreign key ON DELETE cascade with ORM relationships.

See Using foreign key ON DELETE with many-to-many relationships.

4.3.4.4 UNIQUE Constraint
.........................

Unique constraints can be created anonymously on a single column using
the ‘unique’ keyword on Column.  Explicitly named unique
constraints and/or those with multiple columns are created via the
UniqueConstraint table-level construct.

     from sqlalchemy import UniqueConstraint

     meta = MetaData()
     mytable = Table('mytable', meta,

         # per-column anonymous unique constraint
         Column('col1', Integer, unique=True),

         Column('col2', Integer),
         Column('col3', Integer),

         # explicit/composite unique constraint.  'name' is optional.
         UniqueConstraint('col2', 'col3', name='uix_1')
         )

4.3.4.5 CHECK Constraint
........................

Check constraints can be named or unnamed and can be created at the
Column or Table level, using the CheckConstraint construct.
The text of the check constraint is passed directly through to the
database, so there is limited “database independent” behavior.  Column
level check constraints generally should only refer to the column to
which they are placed, while table level constraints can refer to any
columns in the table.

Note that some databases do not actively support check constraints such
as MySQL.

     from sqlalchemy import CheckConstraint

     meta = MetaData()
     mytable = Table('mytable', meta,

         # per-column CHECK constraint
         Column('col1', Integer, CheckConstraint('col1>5')),

         Column('col2', Integer),
         Column('col3', Integer),

         # table level CHECK constraint.  'name' is optional.
         CheckConstraint('col2 > col3 + 5', name='check1')
         )

     {sql}mytable.create(engine)
     CREATE TABLE mytable (
         col1 INTEGER  CHECK (col1>5),
         col2 INTEGER,
         col3 INTEGER,
         CONSTRAINT check1  CHECK (col2 > col3 + 5)
     ){stop}

4.3.4.6 PRIMARY KEY Constraint
..............................

The primary key constraint of any Table object is implicitly
present, based on the Column objects that are marked with the
Column.primary_key flag.  The PrimaryKeyConstraint
object provides explicit access to this constraint, which includes the
option of being configured directly:

     from sqlalchemy import PrimaryKeyConstraint

     my_table = Table('mytable', metadata,
                 Column('id', Integer),
                 Column('version_id', Integer),
                 Column('data', String(50)),
                 PrimaryKeyConstraint('id', 'version_id', name='mytable_pk')
             )

See also
........

See PrimaryKeyConstraint. - detailed API documentation.

4.3.4.7 Setting up Constraints when using the Declarative ORM Extension
.......................................................................

The Table is the SQLAlchemy Core construct that allows one to
define table metadata, which among other things can be used by the
SQLAlchemy ORM as a target to map a class.  The Declarative
extension allows the Table object to be created
automatically, given the contents of the table primarily as a mapping of
Column objects.

To apply table-level constraint objects such as
ForeignKeyConstraint to a table defined using Declarative, use the
‘__table_args__’ attribute, described at Table Configuration.

4.3.4.8 Configuring Constraint Naming Conventions
.................................................

Relational databases typically assign explicit names to all constraints
and indexes.  In the common case that a table is created using ‘CREATE
TABLE’ where constraints such as CHECK, UNIQUE, and PRIMARY KEY
constraints are produced inline with the table definition, the database
usually has a system in place in which names are automatically assigned
to these constraints, if a name is not otherwise specified.  When an
existing database table is altered in a database using a command such as
‘ALTER TABLE’, this command typically needs to specify explicit names
for new constraints as well as be able to specify the name of an
existing constraint that is to be dropped or modified.

Constraints can be named explicitly using the Constraint.name
parameter, and for indexes the Index.name parameter.
However, in the case of constraints this parameter is optional.  There
are also the use cases of using the Column.unique and
Column.index parameters which create UniqueConstraint
and Index objects without an explicit name being
specified.

The use case of alteration of existing tables and constraints can be
handled by schema migration tools such as Alembic(1).  However, neither
Alembic nor SQLAlchemy currently create names for constraint objects
where the name is otherwise unspecified, leading to the case where being
able to alter existing constraints means that one must reverse-engineer
the naming system used by the relational database to auto-assign names,
or that care must be taken to ensure that all constraints are named.

In contrast to having to assign explicit names to all Constraint
and Index objects, automated naming schemes can be
constructed using events.  This approach has the advantage that
constraints will get a consistent naming scheme without the need for
explicit name parameters throughout the code, and also that the
convention takes place just as well for those constraints and indexes
produced by the Column.unique and Column.index
parameters.  As of SQLAlchemy 0.9.2 this event-based approach is
included, and can be configured using the argument
MetaData.naming_convention.

   ---------- Footnotes ----------

   (1) https://alembic.sqlalchemy.org/

4.3.4.9 Configuring a Naming Convention for a MetaData Collection
.................................................................

MetaData.naming_convention refers to a dictionary which
accepts the Index class or individual Constraint
classes as keys, and Python string templates as values.  It also accepts
a series of string-codes as alternative keys, ‘"fk"’, ‘"pk"’, ‘"ix"’,
‘"ck"’, ‘"uq"’ for foreign key, primary key, index, check, and unique
constraint, respectively.  The string templates in this dictionary are
used whenever a constraint or index is associated with this
MetaData object that does not have an existing name given
(including one exception case where an existing name can be further
embellished).

An example naming convention that suits basic cases is as follows:

     convention = {
       "ix": 'ix_%(column_0_label)s',
       "uq": "uq_%(table_name)s_%(column_0_name)s",
       "ck": "ck_%(table_name)s_%(constraint_name)s",
       "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
       "pk": "pk_%(table_name)s"
     }

     metadata = MetaData(naming_convention=convention)

The above convention will establish names for all constraints within the
target MetaData collection.  For example, we can observe the
name produced when we create an unnamed UniqueConstraint:

     >>> user_table = Table('user', metadata,
     ...                 Column('id', Integer, primary_key=True),
     ...                 Column('name', String(30), nullable=False),
     ...                 UniqueConstraint('name')
     ... )
     >>> list(user_table.constraints)[1].name
     'uq_user_name'

This same feature takes effect even if we just use the
Column.unique flag:

     >>> user_table = Table('user', metadata,
     ...                  Column('id', Integer, primary_key=True),
     ...                  Column('name', String(30), nullable=False, unique=True)
     ...     )
     >>> list(user_table.constraints)[1].name
     'uq_user_name'

A key advantage to the naming convention approach is that the names are
established at Python construction time, rather than at DDL emit time.
The effect this has when using Alembic’s ‘--autogenerate’ feature is
that the naming convention will be explicit when a new migration script
is generated:

     def upgrade():
         op.create_unique_constraint("uq_user_name", "user", ["name"])

The above ‘"uq_user_name"’ string was copied from the
UniqueConstraint object that ‘--autogenerate’ located in our
metadata.

The tokens available include ‘%(table_name)s’,
‘%(referred_table_name)s’, ‘%(column_0_name)s’, ‘%(column_0_label)s’,
‘%(column_0_key)s’, ‘%(referred_column_0_name)s’, and
‘%(constraint_name)s’, as well as multiple-column versions of each
including ‘%(column_0N_name)s’, ‘%(column_0_N_name)s’,
‘%(referred_column_0_N_name)s’ which render all column names separated
with or without an underscore.  The documentation for
MetaData.naming_convention has further detail on each of these
conventions.

4.3.4.10 The Default Naming Convention
......................................

The default value for MetaData.naming_convention handles
the long-standing SQLAlchemy behavior of assigning a name to a
Index object that is created using the Column.index
parameter:

     >>> from sqlalchemy.sql.schema import DEFAULT_NAMING_CONVENTION
     >>> DEFAULT_NAMING_CONVENTION
     immutabledict({'ix': 'ix_%(column_0_label)s'})

4.3.4.11 Truncation of Long Names
.................................

When a generated name, particularly those that use the multiple-column
tokens, is too long for the identifier length limit of the target
database (for example, PostgreSQL has a limit of 63 characters), the
name will be deterministically truncated using a 4-character suffix
based on the md5 hash of the long name.  For example, the naming
convention below will generate very long names given the column names in
use:

     metadata = MetaData(naming_convention={
         "uq": "uq_%(table_name)s_%(column_0_N_name)s"
     })

     long_names = Table(
         'long_names', metadata,
         Column('information_channel_code', Integer, key='a'),
         Column('billing_convention_name', Integer, key='b'),
         Column('product_identifier', Integer, key='c'),
         UniqueConstraint('a', 'b', 'c')
     )

On the PostgreSQL dialect, names longer than 63 characters will be
truncated as in the following example:

     CREATE TABLE long_names (
         information_channel_code INTEGER,
         billing_convention_name INTEGER,
         product_identifier INTEGER,
         CONSTRAINT uq_long_names_information_channel_code_billing_conventi_a79e
         UNIQUE (information_channel_code, billing_convention_name, product_identifier)
     )

The above suffix ‘a79e’ is based on the md5 hash of the long name and
will generate the same value every time to produce consistent names for
a given schema.

4.3.4.12 Creating Custom Tokens for Naming Conventions
......................................................

New tokens can also be added, by specifying an additional token and a
callable within the naming_convention dictionary.  For example, if we
wanted to name our foreign key constraints using a GUID scheme, we could
do that as follows:

     import uuid

     def fk_guid(constraint, table):
         str_tokens = [
             table.name,
         ] + [
             element.parent.name for element in constraint.elements
         ] + [
             element.target_fullname for element in constraint.elements
         ]
         guid = uuid.uuid5(uuid.NAMESPACE_OID, "_".join(str_tokens).encode('ascii'))
         return str(guid)

     convention = {
         "fk_guid": fk_guid,
         "ix": 'ix_%(column_0_label)s',
         "fk": "fk_%(fk_guid)s",
     }

Above, when we create a new ForeignKeyConstraint, we will get
a name as follows:

     >>> metadata = MetaData(naming_convention=convention)

     >>> user_table = Table('user', metadata,
     ...         Column('id', Integer, primary_key=True),
     ...         Column('version', Integer, primary_key=True),
     ...         Column('data', String(30))
     ...     )
     >>> address_table = Table('address', metadata,
     ...        Column('id', Integer, primary_key=True),
     ...        Column('user_id', Integer),
     ...        Column('user_version_id', Integer)
     ...    )
     >>> fk = ForeignKeyConstraint(['user_id', 'user_version_id'],
     ...                ['user.id', 'user.version'])
     >>> address_table.append_constraint(fk)
     >>> fk.name
     fk_0cd51ab5-8d70-56e8-a83c-86661737766d

See also
........

See MetaData.naming_convention. - for additional usage details
as well as a listing of all available naming components.

The Importance of Naming Constraints(1) - in the Alembic documentation.

New in version 1.3.0: added multi-column naming tokens such as
‘%(column_0_N_name)s’.  Generated names that go beyond the character
limit for the target database will be deterministically truncated.

   ---------- Footnotes ----------

   (1) https://alembic.sqlalchemy.org/en/latest/naming.html

4.3.4.13 Naming CHECK Constraints
.................................

The CheckConstraint object is configured against an
arbitrary SQL expression, which can have any number of columns present,
and additionally is often configured using a raw SQL string.  Therefore
a common convention to use with CheckConstraint is one
where we expect the object to have a name already, and we then enhance
it with other convention elements.  A typical convention is
‘"ck_%(table_name)s_%(constraint_name)s"’:

     metadata = MetaData(
         naming_convention={"ck": "ck_%(table_name)s_%(constraint_name)s"}
     )

     Table('foo', metadata,
         Column('value', Integer),
         CheckConstraint('value > 5', name='value_gt_5')
     )

The above table will produce the name ‘ck_foo_value_gt_5’:

     CREATE TABLE foo (
         value INTEGER,
         CONSTRAINT ck_foo_value_gt_5 CHECK (value > 5)
     )

CheckConstraint also supports the ‘%(columns_0_name)s’
token; we can make use of this by ensuring we use a Column or
column() element within the constraint’s expression, either
by declaring the constraint separate from the table:

     metadata = MetaData(
         naming_convention={"ck": "ck_%(table_name)s_%(column_0_name)s"}
     )

     foo = Table('foo', metadata,
         Column('value', Integer)
     )

     CheckConstraint(foo.c.value > 5)

or by using a column() inline:

     from sqlalchemy import column

     metadata = MetaData(
         naming_convention={"ck": "ck_%(table_name)s_%(column_0_name)s"}
     )

     foo = Table('foo', metadata,
         Column('value', Integer),
         CheckConstraint(column('value') > 5)
     )

Both will produce the name ‘ck_foo_value’:

     CREATE TABLE foo (
         value INTEGER,
         CONSTRAINT ck_foo_value CHECK (value > 5)
     )

The determination of the name of “column zero” is performed by scanning
the given expression for column objects.  If the expression has more
than one column present, the scan does use a deterministic search,
however the structure of the expression will determine which column is
noted as “column zero”.

New in version 1.0.0: The CheckConstraint object now
supports the ‘column_0_name’ naming convention token.

4.3.4.14 Configuring Naming for Boolean, Enum, and other schema types
.....................................................................

The SchemaType class refers to type objects such as
Boolean and Enum which generate a CHECK constraint
accompanying the type.  The name for the constraint here is most
directly set up by sending the “name” parameter, e.g.  see
Boolean.name:

     Table('foo', metadata,
         Column('flag', Boolean(name='ck_foo_flag'))
     )

The naming convention feature may be combined with these types as well,
normally by using a convention which includes ‘%(constraint_name)s’ and
then applying a name to the type:

     metadata = MetaData(
         naming_convention={"ck": "ck_%(table_name)s_%(constraint_name)s"}
     )

     Table('foo', metadata,
         Column('flag', Boolean(name='flag_bool'))
     )

The above table will produce the constraint name ‘ck_foo_flag_bool’:

     CREATE TABLE foo (
         flag BOOL,
         CONSTRAINT ck_foo_flag_bool CHECK (flag IN (0, 1))
     )

The SchemaType classes use special internal symbols so that
the naming convention is only determined at DDL compile time.  On
PostgreSQL, there’s a native BOOLEAN type, so the CHECK constraint of
Boolean is not needed; we are safe to set up a
Boolean type without a name, even though a naming convention is in
place for check constraints.  This convention will only be consulted for
the CHECK constraint if we run against a database without a native
BOOLEAN type like SQLite or MySQL.

The CHECK constraint may also make use of the ‘column_0_name’ token,
which works nicely with SchemaType since these constraints
have only one column:

     metadata = MetaData(
         naming_convention={"ck": "ck_%(table_name)s_%(column_0_name)s"}
     )

     Table('foo', metadata,
         Column('flag', Boolean())
     )

The above schema will produce:

     CREATE TABLE foo (
         flag BOOL,
         CONSTRAINT ck_foo_flag CHECK (flag IN (0, 1))
     )

Changed in version 1.0: Constraint naming conventions that don’t include
‘%(constraint_name)s’ again work with SchemaType
constraints.

4.3.4.15 Constraints API
........................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See CheckConstraint.A table- or column-level CHECK constraint.

See ColumnCollectionConstraint.A constraint that proxies a ColumnCollection.

See ColumnCollectionMixin.

See Constraint.A table-level SQL constraint.

See conv.Mark a string indicating that a name has already been converted by a naming convention.

See ForeignKey.Defines a dependency between two columns.

See ForeignKeyConstraint.A table-level FOREIGN KEY constraint.

See PrimaryKeyConstraint.A table-level PRIMARY KEY constraint.

See UniqueConstraint.A table-level UNIQUE constraint.

 -- Class: sqlalchemy.schema.Constraint (name=None, deferrable=None,
          initially=None, _create_rule=None, info=None,
          _type_bound=False, **dialect_kw)

     A table-level SQL constraint.

     Constraint serves as the base class for the series of
     constraint objects that can be associated with Table
     objects, including PrimaryKeyConstraint,
     ForeignKeyConstraint. See UniqueConstraint, and
     CheckConstraint.

     `Class signature'

     class sqlalchemy.schema.Constraint. (see
     sqlalchemy.sql.base.DialectKWArgs,
     sqlalchemy.schema.SchemaItem)

      -- Method: sqlalchemy.schema.Constraint..__init__
               (name=None, deferrable=None, initially=None,
               _create_rule=None, info=None, _type_bound=False,
               **dialect_kw)

          Create a SQL constraint.

          Parameters:

             * ‘name’ – Optional, the in-database name of this
               ‘Constraint’.

             * ‘deferrable’ – Optional bool.  If set, emit DEFERRABLE or
               NOT DEFERRABLE when issuing DDL for this constraint.

             * ‘initially’ – Optional string.  If set, emit INITIALLY
               <value> when issuing DDL for this constraint.

             * ‘info’ – Optional data dictionary which will be populated
               into the SchemaItem.info attribute of this
               object.

               New in version 1.0.0.

             * ‘**dialect_kw’ – Additional keyword arguments are dialect
               specific, and passed in the form
               ‘<dialectname>_<argname>’.  See the documentation
               regarding an individual dialect at Dialects
               for detail on documented arguments.

             * ‘_create_rule’ – used internally by some datatypes that
               also create constraints.

             * ‘_type_bound’ – used internally to indicate that this
               constraint is associated with a specific datatype.

      -- Method: sqlalchemy.schema.Constraint..copy (**kw)

          Deprecated since version 1.4: The Constraint.copy()
          method is deprecated and will be removed in a future
          release.

 -- Class: sqlalchemy.schema.ColumnCollectionMixin (*columns, **kw)

      -- Attribute: sqlalchemy.schema.ColumnCollectionMixin..
               columns = None

          A ColumnCollection of Column objects.

          This collection represents the columns which are referred to
          by this object.

 -- Class: sqlalchemy.schema.ColumnCollectionConstraint (*columns, **kw)

     A constraint that proxies a ColumnCollection.

     `Class signature'

     class sqlalchemy.schema.ColumnCollectionConstraint.
     (see sqlalchemy.schema.ColumnCollectionMixin,
     sqlalchemy.schema.Constraint)

      -- Method: sqlalchemy.schema.ColumnCollectionConstraint..
               __init__ (*columns, **kw)

          Parameters:

             * ‘*columns’ – A sequence of column names or Column
               objects.

             * ‘name’ – Optional, the in-database name of this
               constraint.

             * ‘deferrable’ – Optional bool.  If set, emit DEFERRABLE or
               NOT DEFERRABLE when issuing DDL for this constraint.

             * ‘initially’ – Optional string.  If set, emit INITIALLY
               <value> when issuing DDL for this constraint.

             * ‘**kw’ – other keyword arguments including
               dialect-specific arguments are propagated to the
               Constraint superclass.

      -- Method: sqlalchemy.schema.ColumnCollectionConstraint..
               classmethod argument_for (dialect_name,
               argument_name, default)

          `inherited from the' DialectKWArgs.argument_for().
          `method of' DialectKWArgs.

          Add a new kind of dialect-specific keyword argument for this
          class.

          E.g.:

               Index.argument_for("mydialect", "length", None)

               some_index = Index('a', 'b', mydialect_length=5)

          The DialectKWArgs.argument_for() method is a
          per-argument way adding extra arguments to the
          DefaultDialect.construct_arguments dictionary.  This
          dictionary provides a list of argument names accepted by
          various schema-level constructs on behalf of a dialect.

          New dialects should typically specify this dictionary all at
          once as a data member of the dialect class.  The use case for
          ad-hoc addition of argument names is typically for end-user
          code that is also using a custom compilation scheme which
          consumes the additional arguments.

          Parameters:

             * ‘dialect_name’ – name of a dialect.  The dialect must be
               locatable, else a NoSuchModuleError is
               raised.  The dialect must also include an existing
               DefaultDialect.construct_arguments collection,
               indicating that it participates in the keyword-argument
               validation and default system, else ArgumentError
               is raised.  If the dialect does not include this
               collection, then any keyword argument can be specified on
               behalf of this dialect already.  All dialects packaged
               within SQLAlchemy include this collection, however for
               third party dialects, support may vary.

             * ‘argument_name’ – name of the parameter.

             * ‘default’ – default value of the parameter.

          New in version 0.9.4.

      -- Attribute: sqlalchemy.schema.ColumnCollectionConstraint..
               columns = None

          A ColumnCollection representing the set of columns
          for this constraint.

      -- Method: sqlalchemy.schema.ColumnCollectionConstraint..
               contains_column (col)

          Return True if this constraint contains the given column.

          Note that this object also contains an attribute ‘.columns’
          which is a ColumnCollection of Column
          objects.

      -- Method: sqlalchemy.schema.ColumnCollectionConstraint..
               copy (target_table=None, **kw)

          Deprecated since version 1.4: The
          ColumnCollectionConstraint.copy() method is deprecated
          and will be removed in a future release.

      -- Attribute: sqlalchemy.schema.ColumnCollectionConstraint..
               dialect_kwargs

          `inherited from the' DialectKWArgs.dialect_kwargs.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          The arguments are present here in their original
          ‘<dialect>_<kwarg>’ format.  Only arguments that were actually
          passed are included; unlike the
          DialectKWArgs.dialect_options collection, which contains
          all options known by this dialect including defaults.

          The collection is also writable; keys are accepted of the form
          ‘<dialect>_<kwarg>’ where the value will be assembled into the
          list of options.

          New in version 0.9.2.

          Changed in version 0.9.4: The
          DialectKWArgs.dialect_kwargs collection is now writable.

          See also
          ........

          See DialectKWArgs.dialect_options. - nested dictionary
          form

      -- Attribute: sqlalchemy.schema.ColumnCollectionConstraint..
               dialect_options

          `inherited from the' DialectKWArgs.dialect_options.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          This is a two-level nested registry, keyed to ‘<dialect_name>’
          and ‘<argument_name>’.  For example, the ‘postgresql_where’
          argument would be locatable as:

               arg = my_object.dialect_options['postgresql']['where']

          New in version 0.9.2.

          See also
          ........

          See DialectKWArgs.dialect_kwargs. - flat dictionary
          form

      -- Attribute: sqlalchemy.schema.ColumnCollectionConstraint..
               info

          `inherited from the' SchemaItem.info. `attribute
          of' SchemaItem.

          Info dictionary associated with the object, allowing
          user-defined data to be associated with this SchemaItem.

          The dictionary is automatically generated when first accessed.
          It can also be specified in the constructor of some objects,
          such as Table and Column.

      -- Attribute: sqlalchemy.schema.ColumnCollectionConstraint..
               kwargs

          `inherited from the' DialectKWArgs.kwargs.
          `attribute of' DialectKWArgs.

          A synonym for DialectKWArgs.dialect_kwargs.

 -- Class: sqlalchemy.schema.CheckConstraint (sqltext, name=None,
          deferrable=None, initially=None, table=None, info=None,
          _create_rule=None, _autoattach=True, _type_bound=False, **kw)

     A table- or column-level CHECK constraint.

     Can be included in the definition of a Table or Column.

     `Class signature'

     class sqlalchemy.schema.CheckConstraint. (see
     sqlalchemy.schema.ColumnCollectionConstraint)

      -- Method: sqlalchemy.schema.CheckConstraint..__init__
               (sqltext, name=None, deferrable=None, initially=None,
               table=None, info=None, _create_rule=None,
               _autoattach=True, _type_bound=False, **kw)

          Construct a CHECK constraint.

          Parameters:

             * ‘sqltext’ – A string containing the constraint
               definition, which will be used verbatim, or a SQL
               expression construct.  If given as a string, the object
               is converted to a text() object.  If the
               textual string includes a colon character, escape this
               using a backslash:

                    CheckConstraint(r"foo ~ E'a(?\:b|c)d")

                    Warning: The CheckConstraint.sqltext
                    argument to CheckConstraint can be
                    passed as a Python string argument, which will be
                    treated as `trusted SQL text' and rendered as given.
                    `DO NOT PASS UNTRUSTED INPUT TO THIS PARAMETER'.

             * ‘name’ – Optional, the in-database name of the
               constraint.

             * ‘deferrable’ – Optional bool.  If set, emit DEFERRABLE or
               NOT DEFERRABLE when issuing DDL for this constraint.

             * ‘initially’ – Optional string.  If set, emit INITIALLY
               <value> when issuing DDL for this constraint.

             * ‘info’ – Optional data dictionary which will be populated
               into the SchemaItem.info attribute of this
               object.

               New in version 1.0.0.

      -- Method: sqlalchemy.schema.CheckConstraint..
               classmethod argument_for (dialect_name,
               argument_name, default)

          `inherited from the' DialectKWArgs.argument_for().
          `method of' DialectKWArgs.

          Add a new kind of dialect-specific keyword argument for this
          class.

          E.g.:

               Index.argument_for("mydialect", "length", None)

               some_index = Index('a', 'b', mydialect_length=5)

          The DialectKWArgs.argument_for() method is a
          per-argument way adding extra arguments to the
          DefaultDialect.construct_arguments dictionary.  This
          dictionary provides a list of argument names accepted by
          various schema-level constructs on behalf of a dialect.

          New dialects should typically specify this dictionary all at
          once as a data member of the dialect class.  The use case for
          ad-hoc addition of argument names is typically for end-user
          code that is also using a custom compilation scheme which
          consumes the additional arguments.

          Parameters:

             * ‘dialect_name’ – name of a dialect.  The dialect must be
               locatable, else a NoSuchModuleError is
               raised.  The dialect must also include an existing
               DefaultDialect.construct_arguments collection,
               indicating that it participates in the keyword-argument
               validation and default system, else ArgumentError
               is raised.  If the dialect does not include this
               collection, then any keyword argument can be specified on
               behalf of this dialect already.  All dialects packaged
               within SQLAlchemy include this collection, however for
               third party dialects, support may vary.

             * ‘argument_name’ – name of the parameter.

             * ‘default’ – default value of the parameter.

          New in version 0.9.4.

      -- Method: sqlalchemy.schema.CheckConstraint..
               contains_column (col)

          `inherited from the'
          ColumnCollectionConstraint.contains_column(). `method
          of' ColumnCollectionConstraint.

          Return True if this constraint contains the given column.

          Note that this object also contains an attribute ‘.columns’
          which is a ColumnCollection of Column
          objects.

      -- Method: sqlalchemy.schema.CheckConstraint..copy
               (target_table=None, **kw)

          Deprecated since version 1.4: The
          CheckConstraint.copy() method is deprecated and will be
          removed in a future release.

      -- Attribute: sqlalchemy.schema.CheckConstraint..
               dialect_kwargs

          `inherited from the' DialectKWArgs.dialect_kwargs.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          The arguments are present here in their original
          ‘<dialect>_<kwarg>’ format.  Only arguments that were actually
          passed are included; unlike the
          DialectKWArgs.dialect_options collection, which contains
          all options known by this dialect including defaults.

          The collection is also writable; keys are accepted of the form
          ‘<dialect>_<kwarg>’ where the value will be assembled into the
          list of options.

          New in version 0.9.2.

          Changed in version 0.9.4: The
          DialectKWArgs.dialect_kwargs collection is now writable.

          See also
          ........

          See DialectKWArgs.dialect_options. - nested dictionary
          form

      -- Attribute: sqlalchemy.schema.CheckConstraint..
               dialect_options

          `inherited from the' DialectKWArgs.dialect_options.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          This is a two-level nested registry, keyed to ‘<dialect_name>’
          and ‘<argument_name>’.  For example, the ‘postgresql_where’
          argument would be locatable as:

               arg = my_object.dialect_options['postgresql']['where']

          New in version 0.9.2.

          See also
          ........

          See DialectKWArgs.dialect_kwargs. - flat dictionary
          form

      -- Attribute: sqlalchemy.schema.CheckConstraint..info

          `inherited from the' SchemaItem.info. `attribute
          of' SchemaItem.

          Info dictionary associated with the object, allowing
          user-defined data to be associated with this SchemaItem.

          The dictionary is automatically generated when first accessed.
          It can also be specified in the constructor of some objects,
          such as Table and Column.

      -- Attribute: sqlalchemy.schema.CheckConstraint..
               kwargs

          `inherited from the' DialectKWArgs.kwargs.
          `attribute of' DialectKWArgs.

          A synonym for DialectKWArgs.dialect_kwargs.

 -- Class: sqlalchemy.schema.ForeignKey (column, _constraint=None,
          use_alter=False, name=None, onupdate=None, ondelete=None,
          deferrable=None, initially=None, link_to_name=False,
          match=None, info=None, **dialect_kw)

     Defines a dependency between two columns.

     ‘ForeignKey’ is specified as an argument to a Column
     object, e.g.:

          t = Table("remote_table", metadata,
              Column("remote_id", ForeignKey("main_table.id"))
          )

     Note that ‘ForeignKey’ is only a marker object that defines a
     dependency between two columns.  The actual constraint is in all
     cases represented by the ForeignKeyConstraint object.
     This object will be generated automatically when a ‘ForeignKey’ is
     associated with a Column which in turn is associated
     with a Table.  Conversely, when
     ForeignKeyConstraint is applied to a Table,
     ‘ForeignKey’ markers are automatically generated to be present on
     each associated Column, which are also associated with
     the constraint object.

     Note that you cannot define a “composite” foreign key constraint,
     that is a constraint between a grouping of multiple parent/child
     columns, using ‘ForeignKey’ objects.  To define this grouping, the
     ForeignKeyConstraint object must be used, and applied to
     the Table.  The associated ‘ForeignKey’ objects are
     created automatically.

     The ‘ForeignKey’ objects associated with an individual
     Column object are available in the ‘foreign_keys’ collection
     of that column.

     Further examples of foreign key configuration are in Defining Foreign Keys.

     `Class signature'

     class sqlalchemy.schema.ForeignKey. (see
     sqlalchemy.sql.base.DialectKWArgs,
     sqlalchemy.schema.SchemaItem)

      -- Method: sqlalchemy.schema.ForeignKey..__init__
               (column, _constraint=None, use_alter=False, name=None,
               onupdate=None, ondelete=None, deferrable=None,
               initially=None, link_to_name=False, match=None,
               info=None, **dialect_kw)

          Construct a column-level FOREIGN KEY.

          The ForeignKey object when constructed generates a
          ForeignKeyConstraint which is associated with the
          parent Table object’s collection of constraints.

          Parameters:

             * ‘column’ – A single target column for the key
               relationship.  A Column object or a column
               name as a string: ‘tablename.columnkey’ or
               ‘schema.tablename.columnkey’.  ‘columnkey’ is the ‘key’
               which has been assigned to the column (defaults to the
               column name itself), unless ‘link_to_name’ is ‘True’ in
               which case the rendered name of the column is used.

             * ‘name’ – Optional string.  An in-database name for the
               key if ‘constraint’ is not provided.

             * ‘onupdate’ – Optional string.  If set, emit ON UPDATE
               <value> when issuing DDL for this constraint.  Typical
               values include CASCADE, DELETE and RESTRICT.

             * ‘ondelete’ – Optional string.  If set, emit ON DELETE
               <value> when issuing DDL for this constraint.  Typical
               values include CASCADE, DELETE and RESTRICT.

             * ‘deferrable’ – Optional bool.  If set, emit DEFERRABLE or
               NOT DEFERRABLE when issuing DDL for this constraint.

             * ‘initially’ – Optional string.  If set, emit INITIALLY
               <value> when issuing DDL for this constraint.

             * ‘link_to_name’ – if True, the string name given in
               ‘column’ is the rendered name of the referenced column,
               not its locally assigned ‘key’.

             * ‘use_alter’ – passed to the underlying
               ForeignKeyConstraint to indicate the constraint
               should be generated/dropped externally from the CREATE
               TABLE/ DROP TABLE statement.  See
               ForeignKeyConstraint.use_alter for further
               description.

               See also
               ........

               See ForeignKeyConstraint.use_alter.

               See Creating/Dropping Foreign Key Constraints via ALTER.

             * ‘match’ – Optional string.  If set, emit MATCH <value>
               when issuing DDL for this constraint.  Typical values
               include SIMPLE, PARTIAL and FULL.

             * ‘info’ – Optional data dictionary which will be populated
               into the SchemaItem.info attribute of this
               object.

               New in version 1.0.0.

             * ‘**dialect_kw’ – Additional keyword arguments are dialect
               specific, and passed in the form
               ‘<dialectname>_<argname>’.  The arguments are ultimately
               handled by a corresponding ForeignKeyConstraint.
               See the documentation regarding an individual
               dialect at Dialects for detail on documented
               arguments.

               New in version 0.9.2.

      -- Method: sqlalchemy.schema.ForeignKey..classmethod
               argument_for (dialect_name, argument_name, default)

          `inherited from the' DialectKWArgs.argument_for().
          `method of' DialectKWArgs.

          Add a new kind of dialect-specific keyword argument for this
          class.

          E.g.:

               Index.argument_for("mydialect", "length", None)

               some_index = Index('a', 'b', mydialect_length=5)

          The DialectKWArgs.argument_for() method is a
          per-argument way adding extra arguments to the
          DefaultDialect.construct_arguments dictionary.  This
          dictionary provides a list of argument names accepted by
          various schema-level constructs on behalf of a dialect.

          New dialects should typically specify this dictionary all at
          once as a data member of the dialect class.  The use case for
          ad-hoc addition of argument names is typically for end-user
          code that is also using a custom compilation scheme which
          consumes the additional arguments.

          Parameters:

             * ‘dialect_name’ – name of a dialect.  The dialect must be
               locatable, else a NoSuchModuleError is
               raised.  The dialect must also include an existing
               DefaultDialect.construct_arguments collection,
               indicating that it participates in the keyword-argument
               validation and default system, else ArgumentError
               is raised.  If the dialect does not include this
               collection, then any keyword argument can be specified on
               behalf of this dialect already.  All dialects packaged
               within SQLAlchemy include this collection, however for
               third party dialects, support may vary.

             * ‘argument_name’ – name of the parameter.

             * ‘default’ – default value of the parameter.

          New in version 0.9.4.

      -- Attribute: sqlalchemy.schema.ForeignKey..column

          Return the target Column referenced by this
          ForeignKey.

          If no target column has been established, an exception is
          raised.

          Changed in version 0.9.0: Foreign key target column resolution
          now occurs as soon as both the ForeignKey object and the
          remote Column to which it refers are both associated with the
          same MetaData object.

      -- Method: sqlalchemy.schema.ForeignKey..copy
               (schema=None)

          Deprecated since version 1.4: The ForeignKey.copy()
          method is deprecated and will be removed in a future
          release.

      -- Attribute: sqlalchemy.schema.ForeignKey..
               dialect_kwargs

          `inherited from the' DialectKWArgs.dialect_kwargs.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          The arguments are present here in their original
          ‘<dialect>_<kwarg>’ format.  Only arguments that were actually
          passed are included; unlike the
          DialectKWArgs.dialect_options collection, which contains
          all options known by this dialect including defaults.

          The collection is also writable; keys are accepted of the form
          ‘<dialect>_<kwarg>’ where the value will be assembled into the
          list of options.

          New in version 0.9.2.

          Changed in version 0.9.4: The
          DialectKWArgs.dialect_kwargs collection is now writable.

          See also
          ........

          See DialectKWArgs.dialect_options. - nested dictionary
          form

      -- Attribute: sqlalchemy.schema.ForeignKey..
               dialect_options

          `inherited from the' DialectKWArgs.dialect_options.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          This is a two-level nested registry, keyed to ‘<dialect_name>’
          and ‘<argument_name>’.  For example, the ‘postgresql_where’
          argument would be locatable as:

               arg = my_object.dialect_options['postgresql']['where']

          New in version 0.9.2.

          See also
          ........

          See DialectKWArgs.dialect_kwargs. - flat dictionary
          form

      -- Method: sqlalchemy.schema.ForeignKey..get_referent
               (table)

          Return the Column in the given Table
          referenced by this ForeignKey.

          Returns None if this ForeignKey does not reference
          the given Table.

      -- Attribute: sqlalchemy.schema.ForeignKey..info

          `inherited from the' SchemaItem.info. `attribute
          of' SchemaItem.

          Info dictionary associated with the object, allowing
          user-defined data to be associated with this SchemaItem.

          The dictionary is automatically generated when first accessed.
          It can also be specified in the constructor of some objects,
          such as Table and Column.

      -- Attribute: sqlalchemy.schema.ForeignKey..kwargs

          `inherited from the' DialectKWArgs.kwargs.
          `attribute of' DialectKWArgs.

          A synonym for DialectKWArgs.dialect_kwargs.

      -- Method: sqlalchemy.schema.ForeignKey..references
               (table)

          Return True if the given Table is referenced by
          this ForeignKey.

      -- Attribute: sqlalchemy.schema.ForeignKey..
               target_fullname

          Return a string based ‘column specification’ for this
          ForeignKey.

          This is usually the equivalent of the string-based
          “tablename.colname” argument first passed to the object’s
          constructor.

 -- Class: sqlalchemy.schema.ForeignKeyConstraint (columns, refcolumns,
          name=None, onupdate=None, ondelete=None, deferrable=None,
          initially=None, use_alter=False, link_to_name=False,
          match=None, table=None, info=None, **dialect_kw)

     A table-level FOREIGN KEY constraint.

     Defines a single column or composite FOREIGN KEY … REFERENCES
     constraint.  For a no-frills, single column foreign key, adding a
     ForeignKey to the definition of a Column is a
     shorthand equivalent for an unnamed, single column
     ForeignKeyConstraint.

     Examples of foreign key configuration are in Defining Foreign Keys.

     `Class signature'

     class sqlalchemy.schema.ForeignKeyConstraint. (see
     sqlalchemy.schema.ColumnCollectionConstraint)

      -- Method: sqlalchemy.schema.ForeignKeyConstraint..
               __init__ (columns, refcolumns, name=None,
               onupdate=None, ondelete=None, deferrable=None,
               initially=None, use_alter=False, link_to_name=False,
               match=None, table=None, info=None, **dialect_kw)

          Construct a composite-capable FOREIGN KEY.

          Parameters:

             * ‘columns’ – A sequence of local column names.  The named
               columns must be defined and present in the parent Table.
               The names should match the ‘key’ given to each column
               (defaults to the name) unless ‘link_to_name’ is True.

             * ‘refcolumns’ – A sequence of foreign column names or
               Column objects.  The columns must all be located within
               the same Table.

             * ‘name’ – Optional, the in-database name of the key.

             * ‘onupdate’ – Optional string.  If set, emit ON UPDATE
               <value> when issuing DDL for this constraint.  Typical
               values include CASCADE, DELETE and RESTRICT.

             * ‘ondelete’ – Optional string.  If set, emit ON DELETE
               <value> when issuing DDL for this constraint.  Typical
               values include CASCADE, DELETE and RESTRICT.

             * ‘deferrable’ – Optional bool.  If set, emit DEFERRABLE or
               NOT DEFERRABLE when issuing DDL for this constraint.

             * ‘initially’ – Optional string.  If set, emit INITIALLY
               <value> when issuing DDL for this constraint.

             * ‘link_to_name’ – if True, the string name given in
               ‘column’ is the rendered name of the referenced column,
               not its locally assigned ‘key’.

             * ‘use_alter’ – If True, do not emit the DDL for this
               constraint as part of the CREATE TABLE definition.
               Instead, generate it via an ALTER TABLE statement issued
               after the full collection of tables have been created,
               and drop it via an ALTER TABLE statement before the full
               collection of tables are dropped.

               The use of ForeignKeyConstraint.use_alter is
               particularly geared towards the case where two or more
               tables are established within a mutually-dependent
               foreign key constraint relationship; however, the
               MetaData.create_all() and MetaData.drop_all()
               methods will perform this resolution automatically,
               so the flag is normally not needed.

               Changed in version 1.0.0: Automatic resolution of foreign
               key cycles has been added, removing the need to use the
               ForeignKeyConstraint.use_alter in typical
               use cases.

               See also
               ........

               See Creating/Dropping Foreign Key Constraints via ALTER.

             * ‘match’ – Optional string.  If set, emit MATCH <value>
               when issuing DDL for this constraint.  Typical values
               include SIMPLE, PARTIAL and FULL.

             * ‘info’ – Optional data dictionary which will be populated
               into the SchemaItem.info attribute of this
               object.

               New in version 1.0.0.

             * ‘**dialect_kw’ – Additional keyword arguments are dialect
               specific, and passed in the form
               ‘<dialectname>_<argname>’.  See the documentation
               regarding an individual dialect at Dialects
               for detail on documented arguments.

                    New in version 0.9.2.

      -- Method: sqlalchemy.schema.ForeignKeyConstraint..
               classmethod argument_for (dialect_name, argument_name,
               default)

          `inherited from the' DialectKWArgs.argument_for().
          `method of' DialectKWArgs.

          Add a new kind of dialect-specific keyword argument for this
          class.

          E.g.:

               Index.argument_for("mydialect", "length", None)

               some_index = Index('a', 'b', mydialect_length=5)

          The DialectKWArgs.argument_for() method is a
          per-argument way adding extra arguments to the
          DefaultDialect.construct_arguments dictionary.  This
          dictionary provides a list of argument names accepted by
          various schema-level constructs on behalf of a dialect.

          New dialects should typically specify this dictionary all at
          once as a data member of the dialect class.  The use case for
          ad-hoc addition of argument names is typically for end-user
          code that is also using a custom compilation scheme which
          consumes the additional arguments.

          Parameters:

             * ‘dialect_name’ – name of a dialect.  The dialect must be
               locatable, else a NoSuchModuleError is
               raised.  The dialect must also include an existing
               DefaultDialect.construct_arguments collection,
               indicating that it participates in the keyword-argument
               validation and default system, else ArgumentError
               is raised.  If the dialect does not include this
               collection, then any keyword argument can be specified on
               behalf of this dialect already.  All dialects packaged
               within SQLAlchemy include this collection, however for
               third party dialects, support may vary.

             * ‘argument_name’ – name of the parameter.

             * ‘default’ – default value of the parameter.

          New in version 0.9.4.

      -- Attribute: sqlalchemy.schema.ForeignKeyConstraint..
               column_keys

          Return a list of string keys representing the local columns in
          this ForeignKeyConstraint.

          This list is either the original string arguments sent to the
          constructor of the ForeignKeyConstraint, or if the
          constraint has been initialized with Column
          objects, is the string ‘.key’ of each element.

          New in version 1.0.0.

      -- Attribute: sqlalchemy.schema.ForeignKeyConstraint..
               columns = None

          A ColumnCollection representing the set of columns
          for this constraint.

      -- Method: sqlalchemy.schema.ForeignKeyConstraint..
               contains_column (col)

          `inherited from the'
          ColumnCollectionConstraint.contains_column(). `method
          of' ColumnCollectionConstraint.

          Return True if this constraint contains the given column.

          Note that this object also contains an attribute ‘.columns’
          which is a ColumnCollection of Column
          objects.

      -- Method: sqlalchemy.schema.ForeignKeyConstraint..copy
               (schema=None, target_table=None, **kw)

          Deprecated since version 1.4: The
          ForeignKeyConstraint.copy() method is deprecated and
          will be removed in a future release.

      -- Attribute: sqlalchemy.schema.ForeignKeyConstraint..
               dialect_kwargs

          `inherited from the' DialectKWArgs.dialect_kwargs.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          The arguments are present here in their original
          ‘<dialect>_<kwarg>’ format.  Only arguments that were actually
          passed are included; unlike the
          DialectKWArgs.dialect_options collection, which contains
          all options known by this dialect including defaults.

          The collection is also writable; keys are accepted of the form
          ‘<dialect>_<kwarg>’ where the value will be assembled into the
          list of options.

          New in version 0.9.2.

          Changed in version 0.9.4: The
          DialectKWArgs.dialect_kwargs collection is now writable.

          See also
          ........

          See DialectKWArgs.dialect_options. - nested dictionary
          form

      -- Attribute: sqlalchemy.schema.ForeignKeyConstraint..
               dialect_options

          `inherited from the' DialectKWArgs.dialect_options.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          This is a two-level nested registry, keyed to ‘<dialect_name>’
          and ‘<argument_name>’.  For example, the ‘postgresql_where’
          argument would be locatable as:

               arg = my_object.dialect_options['postgresql']['where']

          New in version 0.9.2.

          See also
          ........

          See DialectKWArgs.dialect_kwargs. - flat dictionary
          form

      -- Attribute: sqlalchemy.schema.ForeignKeyConstraint..
               elements = None

          A sequence of ForeignKey objects.

          Each ForeignKey represents a single referring
          column/referred column pair.

          This collection is intended to be read-only.

      -- Attribute: sqlalchemy.schema.ForeignKeyConstraint..
               info

          `inherited from the' SchemaItem.info. `attribute
          of' SchemaItem.

          Info dictionary associated with the object, allowing
          user-defined data to be associated with this SchemaItem.

          The dictionary is automatically generated when first accessed.
          It can also be specified in the constructor of some objects,
          such as Table and Column.

      -- Attribute: sqlalchemy.schema.ForeignKeyConstraint..
               kwargs

          `inherited from the' DialectKWArgs.kwargs.
          `attribute of' DialectKWArgs.

          A synonym for DialectKWArgs.dialect_kwargs.

      -- Attribute: sqlalchemy.schema.ForeignKeyConstraint..
               referred_table

          The Table object to which this
          ForeignKeyConstraint references.

          This is a dynamically calculated attribute which may not be
          available if the constraint and/or parent table is not yet
          associated with a metadata collection that contains the
          referred table.

          New in version 1.0.0.

 -- Class: sqlalchemy.schema.PrimaryKeyConstraint (*columns, **kw)

     A table-level PRIMARY KEY constraint.

     The PrimaryKeyConstraint object is present automatically
     on any Table object; it is assigned a set of
     Column objects corresponding to those marked with the
     Column.primary_key flag:

          >>> my_table = Table('mytable', metadata,
          ...                 Column('id', Integer, primary_key=True),
          ...                 Column('version_id', Integer, primary_key=True),
          ...                 Column('data', String(50))
          ...     )
          >>> my_table.primary_key
          PrimaryKeyConstraint(
              Column('id', Integer(), table=<mytable>,
                     primary_key=True, nullable=False),
              Column('version_id', Integer(), table=<mytable>,
                     primary_key=True, nullable=False)
          )

     The primary key of a Table can also be specified by
     using a PrimaryKeyConstraint object explicitly; in this
     mode of usage, the “name” of the constraint can also be specified,
     as well as other options which may be recognized by dialects:

          my_table = Table('mytable', metadata,
                      Column('id', Integer),
                      Column('version_id', Integer),
                      Column('data', String(50)),
                      PrimaryKeyConstraint('id', 'version_id',
                                           name='mytable_pk')
                  )

     The two styles of column-specification should generally not be
     mixed.  An warning is emitted if the columns present in the
     PrimaryKeyConstraint don’t match the columns that were marked
     as ‘primary_key=True’, if both are present; in this case, the
     columns are taken strictly from the PrimaryKeyConstraint
     declaration, and those columns otherwise marked as
     ‘primary_key=True’ are ignored.  This behavior is intended to be
     backwards compatible with previous behavior.

     Changed in version 0.9.2: Using a mixture of columns within a
     PrimaryKeyConstraint in addition to columns marked as
     ‘primary_key=True’ now emits a warning if the lists don’t match.
     The ultimate behavior of ignoring those columns marked with the
     flag only is currently maintained for backwards compatibility; this
     warning may raise an exception in a future release.

     For the use case where specific options are to be specified on the
     PrimaryKeyConstraint, but the usual style of using
     ‘primary_key=True’ flags is still desirable, an empty
     PrimaryKeyConstraint may be specified, which will take on the
     primary key column collection from the Table based on
     the flags:

          my_table = Table('mytable', metadata,
                      Column('id', Integer, primary_key=True),
                      Column('version_id', Integer, primary_key=True),
                      Column('data', String(50)),
                      PrimaryKeyConstraint(name='mytable_pk',
                                           mssql_clustered=True)
                  )

     New in version 0.9.2: an empty PrimaryKeyConstraint may
     now be specified for the purposes of establishing keyword arguments
     with the constraint, independently of the specification of “primary
     key” columns within the Table itself; columns marked as
     ‘primary_key=True’ will be gathered into the empty constraint’s
     column collection.

     `Class signature'

     class sqlalchemy.schema.PrimaryKeyConstraint. (see
     sqlalchemy.schema.ColumnCollectionConstraint)

      -- Method: sqlalchemy.schema.PrimaryKeyConstraint..
               classmethod argument_for (dialect_name, argument_name,
               default)

          `inherited from the' DialectKWArgs.argument_for().
          `method of' DialectKWArgs.

          Add a new kind of dialect-specific keyword argument for this
          class.

          E.g.:

               Index.argument_for("mydialect", "length", None)

               some_index = Index('a', 'b', mydialect_length=5)

          The DialectKWArgs.argument_for() method is a
          per-argument way adding extra arguments to the
          DefaultDialect.construct_arguments dictionary.  This
          dictionary provides a list of argument names accepted by
          various schema-level constructs on behalf of a dialect.

          New dialects should typically specify this dictionary all at
          once as a data member of the dialect class.  The use case for
          ad-hoc addition of argument names is typically for end-user
          code that is also using a custom compilation scheme which
          consumes the additional arguments.

          Parameters:

             * ‘dialect_name’ – name of a dialect.  The dialect must be
               locatable, else a NoSuchModuleError is
               raised.  The dialect must also include an existing
               DefaultDialect.construct_arguments collection,
               indicating that it participates in the keyword-argument
               validation and default system, else ArgumentError
               is raised.  If the dialect does not include this
               collection, then any keyword argument can be specified on
               behalf of this dialect already.  All dialects packaged
               within SQLAlchemy include this collection, however for
               third party dialects, support may vary.

             * ‘argument_name’ – name of the parameter.

             * ‘default’ – default value of the parameter.

          New in version 0.9.4.

      -- Method: sqlalchemy.schema.PrimaryKeyConstraint..
               contains_column (col)

          `inherited from the'
          ColumnCollectionConstraint.contains_column(). `method
          of' ColumnCollectionConstraint.

          Return True if this constraint contains the given column.

          Note that this object also contains an attribute ‘.columns’
          which is a ColumnCollection of Column
          objects.

      -- Method: sqlalchemy.schema.PrimaryKeyConstraint..copy
               (target_table=None, **kw)

          `inherited from the' ColumnCollectionConstraint.copy().
          `method of' ColumnCollectionConstraint.

          Deprecated since version 1.4: The
          ColumnCollectionConstraint.copy() method is deprecated
          and will be removed in a future release.

      -- Attribute: sqlalchemy.schema.PrimaryKeyConstraint..
               dialect_kwargs

          `inherited from the' DialectKWArgs.dialect_kwargs.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          The arguments are present here in their original
          ‘<dialect>_<kwarg>’ format.  Only arguments that were actually
          passed are included; unlike the
          DialectKWArgs.dialect_options collection, which contains
          all options known by this dialect including defaults.

          The collection is also writable; keys are accepted of the form
          ‘<dialect>_<kwarg>’ where the value will be assembled into the
          list of options.

          New in version 0.9.2.

          Changed in version 0.9.4: The
          DialectKWArgs.dialect_kwargs collection is now writable.

          See also
          ........

          See DialectKWArgs.dialect_options. - nested dictionary
          form

      -- Attribute: sqlalchemy.schema.PrimaryKeyConstraint..
               dialect_options

          `inherited from the' DialectKWArgs.dialect_options.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          This is a two-level nested registry, keyed to ‘<dialect_name>’
          and ‘<argument_name>’.  For example, the ‘postgresql_where’
          argument would be locatable as:

               arg = my_object.dialect_options['postgresql']['where']

          New in version 0.9.2.

          See also
          ........

          See DialectKWArgs.dialect_kwargs. - flat dictionary
          form

      -- Attribute: sqlalchemy.schema.PrimaryKeyConstraint..
               info

          `inherited from the' SchemaItem.info. `attribute
          of' SchemaItem.

          Info dictionary associated with the object, allowing
          user-defined data to be associated with this SchemaItem.

          The dictionary is automatically generated when first accessed.
          It can also be specified in the constructor of some objects,
          such as Table and Column.

      -- Attribute: sqlalchemy.schema.PrimaryKeyConstraint..
               kwargs

          `inherited from the' DialectKWArgs.kwargs.
          `attribute of' DialectKWArgs.

          A synonym for DialectKWArgs.dialect_kwargs.

 -- Class: sqlalchemy.schema.UniqueConstraint (*columns, **kw)

     A table-level UNIQUE constraint.

     Defines a single column or composite UNIQUE constraint.  For a
     no-frills, single column constraint, adding ‘unique=True’ to the
     ‘Column’ definition is a shorthand equivalent for an unnamed,
     single column UniqueConstraint.

     `Class signature'

     class sqlalchemy.schema.UniqueConstraint. (see
     sqlalchemy.schema.ColumnCollectionConstraint)

      -- Method: sqlalchemy.schema.UniqueConstraint..
               __init__ (*columns, **kw)

          `inherited from the'
          ‘sqlalchemy.schema.ColumnCollectionConstraint.__init__’
          `method of' ColumnCollectionConstraint.

          Parameters:

             * ‘*columns’ – A sequence of column names or Column
               objects.

             * ‘name’ – Optional, the in-database name of this
               constraint.

             * ‘deferrable’ – Optional bool.  If set, emit DEFERRABLE or
               NOT DEFERRABLE when issuing DDL for this constraint.

             * ‘initially’ – Optional string.  If set, emit INITIALLY
               <value> when issuing DDL for this constraint.

             * ‘**kw’ – other keyword arguments including
               dialect-specific arguments are propagated to the
               Constraint superclass.

      -- Method: sqlalchemy.schema.UniqueConstraint..
               classmethod argument_for (dialect_name,
               argument_name, default)

          `inherited from the' DialectKWArgs.argument_for().
          `method of' DialectKWArgs.

          Add a new kind of dialect-specific keyword argument for this
          class.

          E.g.:

               Index.argument_for("mydialect", "length", None)

               some_index = Index('a', 'b', mydialect_length=5)

          The DialectKWArgs.argument_for() method is a
          per-argument way adding extra arguments to the
          DefaultDialect.construct_arguments dictionary.  This
          dictionary provides a list of argument names accepted by
          various schema-level constructs on behalf of a dialect.

          New dialects should typically specify this dictionary all at
          once as a data member of the dialect class.  The use case for
          ad-hoc addition of argument names is typically for end-user
          code that is also using a custom compilation scheme which
          consumes the additional arguments.

          Parameters:

             * ‘dialect_name’ – name of a dialect.  The dialect must be
               locatable, else a NoSuchModuleError is
               raised.  The dialect must also include an existing
               DefaultDialect.construct_arguments collection,
               indicating that it participates in the keyword-argument
               validation and default system, else ArgumentError
               is raised.  If the dialect does not include this
               collection, then any keyword argument can be specified on
               behalf of this dialect already.  All dialects packaged
               within SQLAlchemy include this collection, however for
               third party dialects, support may vary.

             * ‘argument_name’ – name of the parameter.

             * ‘default’ – default value of the parameter.

          New in version 0.9.4.

      -- Method: sqlalchemy.schema.UniqueConstraint..
               contains_column (col)

          `inherited from the'
          ColumnCollectionConstraint.contains_column(). `method
          of' ColumnCollectionConstraint.

          Return True if this constraint contains the given column.

          Note that this object also contains an attribute ‘.columns’
          which is a ColumnCollection of Column
          objects.

      -- Method: sqlalchemy.schema.UniqueConstraint..copy
               (target_table=None, **kw)

          `inherited from the' ColumnCollectionConstraint.copy().
          `method of' ColumnCollectionConstraint.

          Deprecated since version 1.4: The
          ColumnCollectionConstraint.copy() method is deprecated
          and will be removed in a future release.

      -- Attribute: sqlalchemy.schema.UniqueConstraint..
               dialect_kwargs

          `inherited from the' DialectKWArgs.dialect_kwargs.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          The arguments are present here in their original
          ‘<dialect>_<kwarg>’ format.  Only arguments that were actually
          passed are included; unlike the
          DialectKWArgs.dialect_options collection, which contains
          all options known by this dialect including defaults.

          The collection is also writable; keys are accepted of the form
          ‘<dialect>_<kwarg>’ where the value will be assembled into the
          list of options.

          New in version 0.9.2.

          Changed in version 0.9.4: The
          DialectKWArgs.dialect_kwargs collection is now writable.

          See also
          ........

          See DialectKWArgs.dialect_options. - nested dictionary
          form

      -- Attribute: sqlalchemy.schema.UniqueConstraint..
               dialect_options

          `inherited from the' DialectKWArgs.dialect_options.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          This is a two-level nested registry, keyed to ‘<dialect_name>’
          and ‘<argument_name>’.  For example, the ‘postgresql_where’
          argument would be locatable as:

               arg = my_object.dialect_options['postgresql']['where']

          New in version 0.9.2.

          See also
          ........

          See DialectKWArgs.dialect_kwargs. - flat dictionary
          form

      -- Attribute: sqlalchemy.schema.UniqueConstraint..info

          `inherited from the' SchemaItem.info. `attribute
          of' SchemaItem.

          Info dictionary associated with the object, allowing
          user-defined data to be associated with this SchemaItem.

          The dictionary is automatically generated when first accessed.
          It can also be specified in the constructor of some objects,
          such as Table and Column.

      -- Attribute: sqlalchemy.schema.UniqueConstraint..
               kwargs

          `inherited from the' DialectKWArgs.kwargs.
          `attribute of' DialectKWArgs.

          A synonym for DialectKWArgs.dialect_kwargs.

 -- Function: sqlalchemy.schema.conv (value, quote=None)

     Mark a string indicating that a name has already been converted by
     a naming convention.

     This is a string subclass that indicates a name that should not be
     subject to any further naming conventions.

     E.g.  when we create a Constraint using a naming
     convention as follows:

          m = MetaData(naming_convention={
              "ck": "ck_%(table_name)s_%(constraint_name)s"
          })
          t = Table('t', m, Column('x', Integer),
                          CheckConstraint('x > 5', name='x5'))

     The name of the above constraint will be rendered as ‘"ck_t_x5"’.
     That is, the existing name ‘x5’ is used in the naming convention as
     the ‘constraint_name’ token.

     In some situations, such as in migration scripts, we may be
     rendering the above CheckConstraint with a name that’s
     already been converted.  In order to make sure the name isn’t
     double-modified, the new name is applied using the conv()
     marker.  We can use this explicitly as follows:

          m = MetaData(naming_convention={
              "ck": "ck_%(table_name)s_%(constraint_name)s"
          })
          t = Table('t', m, Column('x', Integer),
                          CheckConstraint('x > 5', name=conv('ck_t_x5')))

     Where above, the conv() marker indicates that the
     constraint name here is final, and the name will render as
     ‘"ck_t_x5"’ and not ‘"ck_t_ck_t_x5"’

     New in version 0.9.4.

     See also
     ........

     See Configuring Constraint Naming Conventions.

4.3.4.16 Indexes
................

Indexes can be created anonymously (using an auto-generated name
‘ix_<column label>’) for a single column using the inline ‘index’
keyword on Column, which also modifies the usage of ‘unique’
to apply the uniqueness to the index itself, instead of adding a
separate UNIQUE constraint.  For indexes with specific names or which
encompass more than one column, use the Index construct,
which requires a name.

Below we illustrate a Table with several Index
objects associated.  The DDL for “CREATE INDEX” is issued right after
the create statements for the table:

     meta = MetaData()
     mytable = Table('mytable', meta,
         # an indexed column, with index "ix_mytable_col1"
         Column('col1', Integer, index=True),

         # a uniquely indexed column with index "ix_mytable_col2"
         Column('col2', Integer, index=True, unique=True),

         Column('col3', Integer),
         Column('col4', Integer),

         Column('col5', Integer),
         Column('col6', Integer),
         )

     # place an index on col3, col4
     Index('idx_col34', mytable.c.col3, mytable.c.col4)

     # place a unique index on col5, col6
     Index('myindex', mytable.c.col5, mytable.c.col6, unique=True)

     {sql}mytable.create(engine)
     CREATE TABLE mytable (
         col1 INTEGER,
         col2 INTEGER,
         col3 INTEGER,
         col4 INTEGER,
         col5 INTEGER,
         col6 INTEGER
     )
     CREATE INDEX ix_mytable_col1 ON mytable (col1)
     CREATE UNIQUE INDEX ix_mytable_col2 ON mytable (col2)
     CREATE UNIQUE INDEX myindex ON mytable (col5, col6)
     CREATE INDEX idx_col34 ON mytable (col3, col4){stop}

Note in the example above, the Index construct is created
externally to the table which it corresponds, using Column
objects directly.  Index also supports “inline” definition
inside the Table, using string names to identify columns:

     meta = MetaData()
     mytable = Table('mytable', meta,
         Column('col1', Integer),

         Column('col2', Integer),

         Column('col3', Integer),
         Column('col4', Integer),

         # place an index on col1, col2
         Index('idx_col12', 'col1', 'col2'),

         # place a unique index on col3, col4
         Index('idx_col34', 'col3', 'col4', unique=True)
     )

The Index object also supports its own ‘create()’ method:

     i = Index('someindex', mytable.c.col5)
     {sql}i.create(engine)
     CREATE INDEX someindex ON mytable (col5){stop}

4.3.4.17 Functional Indexes
...........................

Index supports SQL and function expressions, as supported by
the target backend.  To create an index against a column using a
descending value, the ColumnElement.desc() modifier may be
used:

     from sqlalchemy import Index

     Index('someindex', mytable.c.somecol.desc())

Or with a backend that supports functional indexes such as PostgreSQL, a
“case insensitive” index can be created using the ‘lower()’ function:

     from sqlalchemy import func, Index

     Index('someindex', func.lower(mytable.c.somecol))

4.3.4.18 Index API
..................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See Index.A table-level INDEX.

 -- Class: sqlalchemy.schema.Index (name, *expressions, **kw)

     A table-level INDEX.

     Defines a composite (one or more column) INDEX.

     E.g.:

          sometable = Table("sometable", metadata,
                          Column("name", String(50)),
                          Column("address", String(100))
                      )

          Index("some_index", sometable.c.name)

     For a no-frills, single column index, adding Column also
     supports ‘index=True’:

          sometable = Table("sometable", metadata,
                          Column("name", String(50), index=True)
                      )

     For a composite index, multiple columns can be specified:

          Index("some_index", sometable.c.name, sometable.c.address)

     Functional indexes are supported as well, typically by using the
     func construct in conjunction with table-bound
     Column objects:

          Index("some_index", func.lower(sometable.c.name))

     An Index can also be manually associated with a
     Table, either through inline declaration or using
     Table.append_constraint().  When this approach is used, the
     names of the indexed columns can be specified as strings:

          Table("sometable", metadata,
                          Column("name", String(50)),
                          Column("address", String(100)),
                          Index("some_index", "name", "address")
                  )

     To support functional or expression-based indexes in this form, the
     text() construct may be used:

          from sqlalchemy import text

          Table("sometable", metadata,
                          Column("name", String(50)),
                          Column("address", String(100)),
                          Index("some_index", text("lower(name)"))
                  )

     New in version 0.9.5: the text() construct may be used
     to specify Index expressions, provided the Index
     is explicitly associated with the Table.

     See also
     ........

     See Indexes. - General information on Index.

     See PostgreSQL-Specific Index Options. -
     PostgreSQL-specific options available for the Index
     construct.

     See MySQL / MariaDB- Specific Index Options. -
     MySQL-specific options available for the Index
     construct.

     See Clustered Index Support. - MSSQL-specific options
     available for the Index construct.

     `Class signature'

     class sqlalchemy.schema.Index. (see
     sqlalchemy.sql.base.DialectKWArgs,
     sqlalchemy.schema.ColumnCollectionMixin,
     sqlalchemy.schema.SchemaItem)

      -- Method: sqlalchemy.schema.Index..__init__ (name,
               *expressions, **kw)

          Construct an index object.

          Parameters:

             * ‘name’ – The name of the index

             * ‘*expressions’ – Column expressions to include in the
               index.  The expressions are normally instances of
               Column, but may also be arbitrary SQL expressions
               which ultimately refer to a Column.

             * ‘unique=False’ – Keyword only argument; if True, create a
               unique index.

             * ‘quote=None’ – Keyword only argument; whether to apply
               quoting to the name of the index.  Works in the same
               manner as that of Column.quote.

             * ‘info=None’ – Optional data dictionary which will be
               populated into the SchemaItem.info attribute
               of this object.

               New in version 1.0.0.

             * ‘**kw’ – Additional keyword arguments not mentioned above
               are dialect specific, and passed in the form
               ‘<dialectname>_<argname>’.  See the documentation
               regarding an individual dialect at Dialects
               for detail on documented arguments.

      -- Method: sqlalchemy.schema.Index..classmethod
               argument_for (dialect_name, argument_name, default)

          `inherited from the' DialectKWArgs.argument_for().
          `method of' DialectKWArgs.

          Add a new kind of dialect-specific keyword argument for this
          class.

          E.g.:

               Index.argument_for("mydialect", "length", None)

               some_index = Index('a', 'b', mydialect_length=5)

          The DialectKWArgs.argument_for() method is a
          per-argument way adding extra arguments to the
          DefaultDialect.construct_arguments dictionary.  This
          dictionary provides a list of argument names accepted by
          various schema-level constructs on behalf of a dialect.

          New dialects should typically specify this dictionary all at
          once as a data member of the dialect class.  The use case for
          ad-hoc addition of argument names is typically for end-user
          code that is also using a custom compilation scheme which
          consumes the additional arguments.

          Parameters:

             * ‘dialect_name’ – name of a dialect.  The dialect must be
               locatable, else a NoSuchModuleError is
               raised.  The dialect must also include an existing
               DefaultDialect.construct_arguments collection,
               indicating that it participates in the keyword-argument
               validation and default system, else ArgumentError
               is raised.  If the dialect does not include this
               collection, then any keyword argument can be specified on
               behalf of this dialect already.  All dialects packaged
               within SQLAlchemy include this collection, however for
               third party dialects, support may vary.

             * ‘argument_name’ – name of the parameter.

             * ‘default’ – default value of the parameter.

          New in version 0.9.4.

      -- Attribute: sqlalchemy.schema.Index..bind

          Return the connectable associated with this Index.

      -- Method: sqlalchemy.schema.Index..create (bind=None,
               checkfirst=False)

          Issue a ‘CREATE’ statement for this Index, using
          the given ‘Connectable’ for connectivity.

          See also
          ........

          See MetaData.create_all().

      -- Attribute: sqlalchemy.schema.Index..dialect_kwargs

          `inherited from the' DialectKWArgs.dialect_kwargs.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          The arguments are present here in their original
          ‘<dialect>_<kwarg>’ format.  Only arguments that were actually
          passed are included; unlike the
          DialectKWArgs.dialect_options collection, which contains
          all options known by this dialect including defaults.

          The collection is also writable; keys are accepted of the form
          ‘<dialect>_<kwarg>’ where the value will be assembled into the
          list of options.

          New in version 0.9.2.

          Changed in version 0.9.4: The
          DialectKWArgs.dialect_kwargs collection is now writable.

          See also
          ........

          See DialectKWArgs.dialect_options. - nested dictionary
          form

      -- Attribute: sqlalchemy.schema.Index..dialect_options

          `inherited from the' DialectKWArgs.dialect_options.
          `attribute of' DialectKWArgs.

          A collection of keyword arguments specified as
          dialect-specific options to this construct.

          This is a two-level nested registry, keyed to ‘<dialect_name>’
          and ‘<argument_name>’.  For example, the ‘postgresql_where’
          argument would be locatable as:

               arg = my_object.dialect_options['postgresql']['where']

          New in version 0.9.2.

          See also
          ........

          See DialectKWArgs.dialect_kwargs. - flat dictionary
          form

      -- Method: sqlalchemy.schema.Index..drop (bind=None,
               checkfirst=False)

          Issue a ‘DROP’ statement for this Index, using the
          given ‘Connectable’ for connectivity.

          See also
          ........

          See MetaData.drop_all().

      -- Attribute: sqlalchemy.schema.Index..info

          `inherited from the' SchemaItem.info. `attribute
          of' SchemaItem.

          Info dictionary associated with the object, allowing
          user-defined data to be associated with this SchemaItem.

          The dictionary is automatically generated when first accessed.
          It can also be specified in the constructor of some objects,
          such as Table and Column.

      -- Attribute: sqlalchemy.schema.Index..kwargs

          `inherited from the' DialectKWArgs.kwargs.
          `attribute of' DialectKWArgs.

          A synonym for DialectKWArgs.dialect_kwargs.

4.3.5 Customizing DDL
---------------------

In the preceding sections we’ve discussed a variety of schema constructs
including Table, ForeignKeyConstraint,
CheckConstraint, and Sequence.  Throughout, we’ve
relied upon the ‘create()’ and create_all() methods of
Table and MetaData in order to issue data definition
language (DDL) for all constructs.  When issued, a pre-determined order
of operations is invoked, and DDL to create each table is created
unconditionally including all constraints and other objects associated
with it.  For more complex scenarios where database-specific DDL is
required, SQLAlchemy offers two techniques which can be used to add any
DDL based on any condition, either accompanying the standard generation
of tables or by itself.

4.3.5.1 Custom DDL
..................

Custom DDL phrases are most easily achieved using the DDL
construct.  This construct works like all the other DDL elements except
it accepts a string which is the text to be emitted:

     event.listen(
         metadata,
         "after_create",
         DDL("ALTER TABLE users ADD CONSTRAINT "
             "cst_user_name_length "
             " CHECK (length(user_name) >= 8)")
     )

A more comprehensive method of creating libraries of DDL constructs is
to use custom compilation - see Custom SQL Constructs and Compilation Extension
for details.

4.3.5.2 Controlling DDL Sequences
.................................

The DDL construct introduced previously also has the ability
to be invoked conditionally based on inspection of the database.  This
feature is available using the DDLElement.execute_if()
method.  For example, if we wanted to create a trigger but only on the
PostgreSQL backend, we could invoke this as:

     mytable = Table(
         'mytable', metadata,
         Column('id', Integer, primary_key=True),
         Column('data', String(50))
     )

     func = DDL(
         "CREATE FUNCTION my_func() "
         "RETURNS TRIGGER AS $$ "
         "BEGIN "
         "NEW.data := 'ins'; "
         "RETURN NEW; "
         "END; $$ LANGUAGE PLPGSQL"
     )

     trigger = DDL(
         "CREATE TRIGGER dt_ins BEFORE INSERT ON mytable "
         "FOR EACH ROW EXECUTE PROCEDURE my_func();"
     )

     event.listen(
         mytable,
         'after_create',
         func.execute_if(dialect='postgresql')
     )

     event.listen(
         mytable,
         'after_create',
         trigger.execute_if(dialect='postgresql')
     )

The DDLElement.execute_if.dialect keyword also accepts a
tuple of string dialect names:

     event.listen(
         mytable,
         "after_create",
         trigger.execute_if(dialect=('postgresql', 'mysql'))
     )
     event.listen(
         mytable,
         "before_drop",
         trigger.execute_if(dialect=('postgresql', 'mysql'))
     )

The DDLElement.execute_if() method can also work against a
callable function that will receive the database connection in use.  In
the example below, we use this to conditionally create a CHECK
constraint, first looking within the PostgreSQL catalogs to see if it
exists:

     def should_create(ddl, target, connection, **kw):
         row = connection.execute(
             "select conname from pg_constraint where conname='%s'" %
             ddl.element.name).scalar()
         return not bool(row)

     def should_drop(ddl, target, connection, **kw):
         return not should_create(ddl, target, connection, **kw)

     event.listen(
         users,
         "after_create",
         DDL(
             "ALTER TABLE users ADD CONSTRAINT "
             "cst_user_name_length CHECK (length(user_name) >= 8)"
         ).execute_if(callable_=should_create)
     )
     event.listen(
         users,
         "before_drop",
         DDL(
             "ALTER TABLE users DROP CONSTRAINT cst_user_name_length"
         ).execute_if(callable_=should_drop)
     )

     {sql}users.create(engine)
     CREATE TABLE users (
         user_id SERIAL NOT NULL,
         user_name VARCHAR(40) NOT NULL,
         PRIMARY KEY (user_id)
     )

     select conname from pg_constraint where conname='cst_user_name_length'
     ALTER TABLE users ADD CONSTRAINT cst_user_name_length  CHECK (length(user_name) >= 8){stop}

     {sql}users.drop(engine)
     select conname from pg_constraint where conname='cst_user_name_length'
     ALTER TABLE users DROP CONSTRAINT cst_user_name_length
     DROP TABLE users{stop}

4.3.5.3 Using the built-in DDLElement Classes
.............................................

The ‘sqlalchemy.schema’ package contains SQL expression constructs that
provide DDL expressions.  For example, to produce a ‘CREATE TABLE’
statement:

     from sqlalchemy.schema import CreateTable
     with engine.connect() as conn:
     {sql}    conn.execute(CreateTable(mytable))
     CREATE TABLE mytable (
         col1 INTEGER,
         col2 INTEGER,
         col3 INTEGER,
         col4 INTEGER,
         col5 INTEGER,
         col6 INTEGER
     ){stop}

Above, the CreateTable construct works like any other
expression construct (such as ‘select()’, ‘table.insert()’, etc.).  All
of SQLAlchemy’s DDL oriented constructs are subclasses of the
DDLElement base class; this is the base of all the objects
corresponding to CREATE and DROP as well as ALTER, not only in
SQLAlchemy but in Alembic Migrations as well.  A full reference of
available constructs is in DDL Expression Constructs API.

User-defined DDL constructs may also be created as subclasses of
DDLElement itself.  The documentation in Custom SQL Constructs and Compilation Extension
has several examples of this.

The event-driven DDL system described in the previous section
Controlling DDL Sequences is available with other
DDLElement objects as well.  However, when dealing with the
built-in constructs such as CreateIndex,
CreateSequence, etc, the event system is of `limited' use, as
methods like Table.create() and
MetaData.create_all() will invoke these constructs unconditionally.
In a future SQLAlchemy release, the DDL event system including
conditional execution will taken into account for built-in constructs
that currently invoke in all cases.

We can illustrate an event-driven example with the AddConstraint
and DropConstraint constructs, as the event-driven
system will work for CHECK and UNIQUE constraints, using these as we did
in our previous example of DDLElement.execute_if():

     def should_create(ddl, target, connection, **kw):
         row = connection.execute(
             "select conname from pg_constraint where conname='%s'" %
             ddl.element.name).scalar()
         return not bool(row)

     def should_drop(ddl, target, connection, **kw):
         return not should_create(ddl, target, connection, **kw)

     event.listen(
         users,
         "after_create",
         AddConstraint(constraint).execute_if(callable_=should_create)
     )
     event.listen(
         users,
         "before_drop",
         DropConstraint(constraint).execute_if(callable_=should_drop)
     )

     {sql}users.create(engine)
     CREATE TABLE users (
         user_id SERIAL NOT NULL,
         user_name VARCHAR(40) NOT NULL,
         PRIMARY KEY (user_id)
     )

     select conname from pg_constraint where conname='cst_user_name_length'
     ALTER TABLE users ADD CONSTRAINT cst_user_name_length  CHECK (length(user_name) >= 8){stop}

     {sql}users.drop(engine)
     select conname from pg_constraint where conname='cst_user_name_length'
     ALTER TABLE users DROP CONSTRAINT cst_user_name_length
     DROP TABLE users{stop}

While the above example is against the built-in AddConstraint
and DropConstraint objects, the main usefulness of
DDL events for now remains focused on the use of the DDL
construct itself, as well as with user-defined subclasses of
DDLElement that aren’t already part of the
MetaData.create_all(), Table.create(), and corresponding
“drop” processes.

4.3.5.4 DDL Expression Constructs API
.....................................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See _CreateDropBase.Base class for DDL constructs that represent CREATE and DROP or equivalents.

See AddConstraint.Represent an ALTER TABLE ADD CONSTRAINT statement.

See CreateColumn.Represent a Column as rendered in a CREATE TABLE statement, via the
               CreateTable construct.

See CreateIndex.Represent a CREATE INDEX statement.

See CreateSchema.Represent a CREATE SCHEMA statement.

See CreateSequence.Represent a CREATE SEQUENCE statement.

See CreateTable.Represent a CREATE TABLE statement.

See DDL.A literal DDL statement.

See DDLElement.Base class for DDL expression constructs.

See DropConstraint.Represent an ALTER TABLE DROP CONSTRAINT statement.

See DropIndex.Represent a DROP INDEX statement.

See DropSchema.Represent a DROP SCHEMA statement.

See DropSequence.Represent a DROP SEQUENCE statement.

See DropTable.Represent a DROP TABLE statement.

See sort_tables.(tables[,Sort a collection of Table objects based on dependency.
skip_fn,
extra_dependencies])

See sort_tables_and_constraints.(tables[,Sort a collection of Table. / see ForeignKeyConstraint objects.
filter_fn,
extra_dependencies,
_warn_for_cycles])

 -- Function: sqlalchemy.schema.sort_tables (tables, skip_fn=None,
          extra_dependencies=None)

     Sort a collection of Table objects based on dependency.

     This is a dependency-ordered sort which will emit Table
     objects such that they will follow their dependent Table
     objects.  Tables are dependent on another based on the presence of
     ForeignKeyConstraint objects as well as explicit
     dependencies added by Table.add_is_dependent_on().

          Warning: The sort_tables() function cannot by
          itself accommodate automatic resolution of dependency cycles
          between tables, which are usually caused by mutually dependent
          foreign key constraints.  When these cycles are detected, the
          foreign keys of these tables are omitted from consideration in
          the sort.  A warning is emitted when this condition occurs,
          which will be an exception raise in a future release.  Tables
          which are not part of the cycle will still be returned in
          dependency order.

          To resolve these cycles, the
          ForeignKeyConstraint.use_alter parameter may be applied
          to those constraints which create a cycle.  Alternatively, the
          sort_tables_and_constraints() function will
          automatically return foreign key constraints in a separate
          collection when cycles are detected so that they may be
          applied to a schema separately.

          Changed in version 1.3.17: - a warning is emitted when
          sort_tables() cannot perform a proper sort due to
          cyclical dependencies.  This will be an exception in a future
          release.  Additionally, the sort will continue to return other
          tables not involved in the cycle in dependency order which was
          not the case previously.

     Parameters:

        * ‘tables’ – a sequence of Table objects.

        * ‘skip_fn’ – optional callable which will be passed a
          ForeignKey object; if it returns True, this constraint
          will not be considered as a dependency.  Note this is
          `different' from the same parameter in
          sort_tables_and_constraints(), which is instead passed
          the owning ForeignKeyConstraint object.

        * ‘extra_dependencies’ – a sequence of 2-tuples of tables which
          will also be considered as dependent on each other.

     See also
     ........

     See sort_tables_and_constraints().

     See MetaData.sorted_tables. - uses this function to sort

 -- Function: sqlalchemy.schema.sort_tables_and_constraints (tables,
          filter_fn=None, extra_dependencies=None,
          _warn_for_cycles=False)

     Sort a collection of Table. / see ForeignKeyConstraint
     objects.

     This is a dependency-ordered sort which will emit tuples of
     ‘(Table, [ForeignKeyConstraint, ...])’ such that each Table
     follows its dependent Table objects.  Remaining
     ForeignKeyConstraint objects that are separate due to
     dependency rules not satisfied by the sort are emitted afterwards
     as ‘(None, [ForeignKeyConstraint ...])’.

     Tables are dependent on another based on the presence of
     ForeignKeyConstraint objects, explicit dependencies added by
     Table.add_is_dependent_on(), as well as dependencies
     stated here using the sort_tables_and_constraints.skip_fn
     and/or sort_tables_and_constraints.extra_dependencies
     parameters.

     Parameters:

        * ‘tables’ – a sequence of Table objects.

        * ‘filter_fn’ – optional callable which will be passed a
          ForeignKeyConstraint object, and returns a value based on
          whether this constraint should definitely be included or
          excluded as an inline constraint, or neither.  If it returns
          False, the constraint will definitely be included as a
          dependency that cannot be subject to ALTER; if True, it will
          `only' be included as an ALTER result at the end.  Returning
          None means the constraint is included in the table-based
          result unless it is detected as part of a dependency cycle.

        * ‘extra_dependencies’ – a sequence of 2-tuples of tables which
          will also be considered as dependent on each other.

     New in version 1.0.0.

     See also
     ........

     See sort_tables().

 -- Class: sqlalchemy.schema.DDLElement

     Base class for DDL expression constructs.

     This class is the base for the general purpose DDL
     class, as well as the various create/drop clause constructs such as
     CreateTable, DropTable,
     AddConstraint, etc.

     DDLElement integrates closely with SQLAlchemy events,
     introduced in Events.  An instance of one is itself an
     event receiving callable:

          event.listen(
              users,
              'after_create',
              AddConstraint(constraint).execute_if(dialect='postgresql')
          )

     See also
     ........

     See DDL.

     See DDLEvents.

     See Events.

     See Controlling DDL Sequences.

     `Class signature'

     class sqlalchemy.schema.DDLElement.
     (‘sqlalchemy.sql.roles.DDLRole’, see
     sqlalchemy.sql.expression.Executable,
     ‘sqlalchemy.schema._DDLCompiles’)

      -- Method: sqlalchemy.schema.DDLElement..__call__
               (target, bind, **kw)

          Execute the DDL as a ddl_listener.

      -- Method: sqlalchemy.schema.DDLElement..against
               (target)

          Return a copy of this DDLElement which will
          include the given target.

          This essentially applies the given item to the ‘.target’
          attribute of the returned DDLElement object.  This
          target is then usable by event handlers and compilation
          routines in order to provide services such as tokenization of
          a DDL string in terms of a particular Table.

          When a DDLElement object is established as an
          event handler for the DDLEvents.before_create()
          or DDLEvents.after_create() events, and the event
          then occurs for a given target such as a Constraint
          or Table, that target is established with a copy of
          the DDLElement object using this method, which
          then proceeds to the DDLElement.execute() method
          in order to invoke the actual DDL instruction.

          Parameters: ‘target’ – a SchemaItem that will be
          the subject of a DDL operation.

          Returns: a copy of this DDLElement with the
          ‘.target’ attribute assigned to the given SchemaItem.

          See also
          ........

          See DDL. - uses tokenization against the “target” when
          processing the DDL string.

      -- Attribute: sqlalchemy.schema.DDLElement..bind

      -- Attribute: sqlalchemy.schema.DDLElement..callable_ =
               None

      -- Attribute: sqlalchemy.schema.DDLElement..dialect =
               None

      -- Method: sqlalchemy.schema.DDLElement..execute
               (bind=None, target=None)

          Execute this DDL immediately.

          Deprecated since version 1.4: The DDLElement.execute()
          method is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  All statement
          execution in SQLAlchemy 2.0 is performed by the
          Connection.execute() method of Connection, or
          in the ORM by the Session.execute() method of
          Session.  (Background on SQLAlchemy 2.0 at:
          Migrating to SQLAlchemy 2.0)

          Executes the DDL statement in isolation using the supplied
          ‘Connectable’ or ‘Connectable’ assigned to the ‘.bind’
          property, if not supplied.  If the DDL has a conditional ‘on’
          criteria, it will be invoked with None as the event.

          Parameters:

             * ‘bind’ – Optional, an ‘Engine’ or ‘Connection’.  If not
               supplied, a valid ‘Connectable’ must be present in the
               ‘.bind’ property.

             * ‘target’ – Optional, defaults to None.  The target
               SchemaItem for the execute call.  This is
               equivalent to passing the SchemaItem to the
               DDLElement.against() method and then
               invoking DDLElement.execute() upon the
               resulting DDLElement object.  See
               DDLElement.against() for further detail.

      -- Method: sqlalchemy.schema.DDLElement..execute_if
               (dialect=None, callable_=None, state=None)

          Return a callable that will execute this DDLElement
          conditionally within an event handler.

          Used to provide a wrapper for event listening:

               event.listen(
                           metadata,
                           'before_create',
                           DDL("my_ddl").execute_if(dialect='postgresql')
                       )

          Parameters:

             * ‘dialect’ – May be a string, tuple or a callable
               predicate.  If a string, it will be compared to the name
               of the executing database dialect:

                    DDL('something').execute_if(dialect='postgresql')

               If a tuple, specifies multiple dialect names:

                    DDL('something').execute_if(dialect=('postgresql', 'mysql'))

             * ‘callable_’ – A callable, which will be invoked with four
               positional arguments as well as optional keyword
               arguments:

                    ddl: This DDL element.

                    target: The Table or MetaData
                    object which is the target of this event.  May be
                    None if the DDL is executed explicitly.

                    bind: The Connection being used for DDL
                    execution

                    tables: Optional keyword argument - a list of Table
                    objects which are to be created/ dropped within a
                    MetaData.create_all() or drop_all() method call.

                    state: Optional keyword argument - will be the
                    ‘state’ argument passed to this function.

                    checkfirst: Keyword argument, will be True if the
                    ‘checkfirst’ flag was set during the call to
                    ‘create()’, ‘create_all()’, ‘drop()’, ‘drop_all()’.

               If the callable returns a True value, the DDL statement
               will be executed.

             * ‘state’ – any value which will be passed to the callable_
               as the ‘state’ keyword argument.

          See also
          ........

          See DDLEvents.

          See Events.

      -- Attribute: sqlalchemy.schema.DDLElement..on = None

      -- Attribute: sqlalchemy.schema.DDLElement..target =
               None

 -- Class: sqlalchemy.schema.DDL (statement, context=None, bind=None)

     A literal DDL statement.

     Specifies literal SQL DDL to be executed by the database.  DDL
     objects function as DDL event listeners, and can be subscribed to
     those events listed in DDLEvents, using either
     Table or MetaData objects as targets.  Basic
     templating support allows a single DDL instance to handle
     repetitive tasks for multiple tables.

     Examples:

          from sqlalchemy import event, DDL

          tbl = Table('users', metadata, Column('uid', Integer))
          event.listen(tbl, 'before_create', DDL('DROP TRIGGER users_trigger'))

          spow = DDL('ALTER TABLE %(table)s SET secretpowers TRUE')
          event.listen(tbl, 'after_create', spow.execute_if(dialect='somedb'))

          drop_spow = DDL('ALTER TABLE users SET secretpowers FALSE')
          connection.execute(drop_spow)

     When operating on Table events, the following ‘statement’ string
     substitutions are available:

          %(table)s  - the Table name, with any required quoting applied
          %(schema)s - the schema name, with any required quoting applied
          %(fullname)s - the Table name including schema, quoted if needed

     The DDL’s “context”, if any, will be combined with the standard
     substitutions noted above.  Keys present in the context will
     override the standard substitutions.

     `Class signature'

     class sqlalchemy.schema.DDL. (see
     sqlalchemy.schema.DDLElement)

      -- Method: sqlalchemy.schema.DDL..__init__ (statement,
               context=None, bind=None)

          Create a DDL statement.

          Parameters:

             * ‘statement’ – A string or unicode string to be executed.
               Statements will be processed with Python’s string
               formatting operator.  See the ‘context’ argument and the
               ‘execute_at’ method.

               A literal ‘%’ in a statement must be escaped as ‘%%’.

               SQL bind parameters are not available in DDL statements.

             * ‘context’ – Optional dictionary, defaults to None.  These
               values will be available for use in string substitutions
               on the DDL statement.

             * ‘bind’ – Optional.  A ‘Connectable’, used by default when
               ‘execute()’ is invoked without a bind argument.

               Deprecated since version 1.4: The DDL.bind
               argument is deprecated and will be removed in SQLAlchemy
               2.0.

          See also
          ........

          See DDLEvents.

          See Events.

 -- Class: sqlalchemy.schema._CreateDropBase (element, bind=None,
          if_exists=False, if_not_exists=False, _legacy_bind=None)

     Base class for DDL constructs that represent CREATE and DROP or
     equivalents.

     The common theme of _CreateDropBase is a single ‘element’ attribute
     which refers to the element to be created or dropped.

     `Class signature'

     class ‘sqlalchemy.schema._CreateDropBase’ (see
     sqlalchemy.schema.DDLElement)

 -- Class: sqlalchemy.schema.CreateTable (element, bind=None,
          include_foreign_key_constraints=None, if_not_exists=False)

     Represent a CREATE TABLE statement.

     `Class signature'

     class sqlalchemy.schema.CreateTable.
     (‘sqlalchemy.schema._CreateDropBase’)

      -- Method: sqlalchemy.schema.CreateTable..__init__
               (element, bind=None,
               include_foreign_key_constraints=None,
               if_not_exists=False)

          Create a CreateTable construct.

          Parameters:

             * ‘element’ – a Table that’s the subject of the
               CREATE

             * ‘on’ – See the description for ‘on’ in DDL.

             * ‘bind’ – See the description for ‘bind’ in DDL.

          Deprecated since version 1.4: The CreateTable.bind
          argument is deprecated and will be removed in SQLAlchemy
          2.0.

          Parameters:

             * ‘include_foreign_key_constraints’ – optional sequence of
               ForeignKeyConstraint objects that will be
               included inline within the CREATE construct; if omitted,
               all foreign key constraints that do not specify
               use_alter=True are included.

               New in version 1.0.0.

             * ‘if_not_exists’ – if True, an IF NOT EXISTS operator will
               be applied to the construct.

               New in version 1.4.0b2.

 -- Class: sqlalchemy.schema.DropTable (element, bind=None,
          if_exists=False)

     Represent a DROP TABLE statement.

     `Class signature'

     class sqlalchemy.schema.DropTable.
     (‘sqlalchemy.schema._CreateDropBase’)

      -- Method: sqlalchemy.schema.DropTable..__init__
               (element, bind=None, if_exists=False)

          Create a DropTable construct.

          Parameters:

             * ‘element’ – a Table that’s the subject of the
               DROP.

             * ‘on’ – See the description for ‘on’ in DDL.

             * ‘bind’ – See the description for ‘bind’ in DDL.

          Deprecated since version 1.4: The DropTable.bind
          argument is deprecated and will be removed in SQLAlchemy 2.0.

          Parameters: ‘if_exists’ – if True, an IF EXISTS operator will
          be applied to the construct.

          New in version 1.4.0b2.

 -- Class: sqlalchemy.schema.CreateColumn (element)

     Represent a Column as rendered in a CREATE TABLE
     statement, via the CreateTable construct.

     This is provided to support custom column DDL within the generation
     of CREATE TABLE statements, by using the compiler extension
     documented in Custom SQL Constructs and Compilation Extension
     to extend CreateColumn.

     Typical integration is to examine the incoming Column
     object, and to redirect compilation if a particular flag or
     condition is found:

          from sqlalchemy import schema
          from sqlalchemy.ext.compiler import compiles

          @compiles(schema.CreateColumn)
          def compile(element, compiler, **kw):
              column = element.element

              if "special" not in column.info:
                  return compiler.visit_create_column(element, **kw)

              text = "%s SPECIAL DIRECTIVE %s" % (
                      column.name,
                      compiler.type_compiler.process(column.type)
                  )
              default = compiler.get_column_default_string(column)
              if default is not None:
                  text += " DEFAULT " + default

              if not column.nullable:
                  text += " NOT NULL"

              if column.constraints:
                  text += " ".join(
                              compiler.process(const)
                              for const in column.constraints)
              return text

     The above construct can be applied to a Table as
     follows:

          from sqlalchemy import Table, Metadata, Column, Integer, String
          from sqlalchemy import schema

          metadata = MetaData()

          table = Table('mytable', MetaData(),
                  Column('x', Integer, info={"special":True}, primary_key=True),
                  Column('y', String(50)),
                  Column('z', String(20), info={"special":True})
              )

          metadata.create_all(conn)

     Above, the directives we’ve added to the Column.info
     collection will be detected by our custom compilation scheme:

          CREATE TABLE mytable (
                  x SPECIAL DIRECTIVE INTEGER NOT NULL,
                  y VARCHAR(50),
                  z SPECIAL DIRECTIVE VARCHAR(20),
              PRIMARY KEY (x)
          )

     The CreateColumn construct can also be used to skip
     certain columns when producing a ‘CREATE TABLE’.  This is
     accomplished by creating a compilation rule that conditionally
     returns ‘None’.  This is essentially how to produce the same effect
     as using the ‘system=True’ argument on Column, which
     marks a column as an implicitly-present “system” column.

     For example, suppose we wish to produce a Table which
     skips rendering of the PostgreSQL ‘xmin’ column against the
     PostgreSQL backend, but on other backends does render it, in
     anticipation of a triggered rule.  A conditional compilation rule
     could skip this name only on PostgreSQL:

          from sqlalchemy.schema import CreateColumn

          @compiles(CreateColumn, "postgresql")
          def skip_xmin(element, compiler, **kw):
              if element.element.name == 'xmin':
                  return None
              else:
                  return compiler.visit_create_column(element, **kw)

          my_table = Table('mytable', metadata,
                      Column('id', Integer, primary_key=True),
                      Column('xmin', Integer)
                  )

     Above, a CreateTable construct will generate a ‘CREATE
     TABLE’ which only includes the ‘id’ column in the string; the
     ‘xmin’ column will be omitted, but only against the PostgreSQL
     backend.

     `Class signature'

     class sqlalchemy.schema.CreateColumn.
     (‘sqlalchemy.schema._DDLCompiles’)

 -- Class: sqlalchemy.schema.CreateSequence (element, bind=None,
          if_exists=False, if_not_exists=False, _legacy_bind=None)

     Represent a CREATE SEQUENCE statement.

     `Class signature'

     class sqlalchemy.schema.CreateSequence.
     (‘sqlalchemy.schema._CreateDropBase’)

 -- Class: sqlalchemy.schema.DropSequence (element, bind=None,
          if_exists=False, if_not_exists=False, _legacy_bind=None)

     Represent a DROP SEQUENCE statement.

     `Class signature'

     class sqlalchemy.schema.DropSequence.
     (‘sqlalchemy.schema._CreateDropBase’)

 -- Class: sqlalchemy.schema.CreateIndex (element, bind=None,
          if_not_exists=False)

     Represent a CREATE INDEX statement.

     `Class signature'

     class sqlalchemy.schema.CreateIndex.
     (‘sqlalchemy.schema._CreateDropBase’)

      -- Method: sqlalchemy.schema.CreateIndex..__init__
               (element, bind=None, if_not_exists=False)

          Create a ‘Createindex’ construct.

          Parameters:

             * ‘element’ – a Index that’s the subject of the
               CREATE.

             * ‘on’ – See the description for ‘on’ in DDL.

             * ‘bind’ – See the description for ‘bind’ in DDL.

          Deprecated since version 1.4: The CreateIndex.bind
          argument is deprecated and will be removed in SQLAlchemy
          2.0.

          Parameters: ‘if_not_exists’ – if True, an IF NOT EXISTS
          operator will be applied to the construct.

          New in version 1.4.0b2.

 -- Class: sqlalchemy.schema.DropIndex (element, bind=None,
          if_exists=False)

     Represent a DROP INDEX statement.

     `Class signature'

     class sqlalchemy.schema.DropIndex.
     (‘sqlalchemy.schema._CreateDropBase’)

      -- Method: sqlalchemy.schema.DropIndex..__init__
               (element, bind=None, if_exists=False)

          Create a DropIndex construct.

          Parameters:

             * ‘element’ – a Index that’s the subject of the
               DROP.

             * ‘on’ – See the description for ‘on’ in DDL.

             * ‘bind’ – See the description for ‘bind’ in DDL.

          Deprecated since version 1.4: The DropIndex.bind
          argument is deprecated and will be removed in SQLAlchemy 2.0.

          Parameters: ‘if_exists’ – if True, an IF EXISTS operator will
          be applied to the construct.

          New in version 1.4.0b2.

 -- Class: sqlalchemy.schema.AddConstraint (element, *args, **kw)

     Represent an ALTER TABLE ADD CONSTRAINT statement.

     `Class signature'

     class sqlalchemy.schema.AddConstraint.
     (‘sqlalchemy.schema._CreateDropBase’)

 -- Class: sqlalchemy.schema.DropConstraint (element, cascade=False,
          **kw)

     Represent an ALTER TABLE DROP CONSTRAINT statement.

     `Class signature'

     class sqlalchemy.schema.DropConstraint.
     (‘sqlalchemy.schema._CreateDropBase’)

 -- Class: sqlalchemy.schema.CreateSchema (name, quote=None, **kw)

     Represent a CREATE SCHEMA statement.

     The argument here is the string name of the schema.

     `Class signature'

     class sqlalchemy.schema.CreateSchema.
     (‘sqlalchemy.schema._CreateDropBase’)

      -- Method: sqlalchemy.schema.CreateSchema..__init__
               (name, quote=None, **kw)

          Create a new CreateSchema construct.

 -- Class: sqlalchemy.schema.DropSchema (name, quote=None,
          cascade=False, **kw)

     Represent a DROP SCHEMA statement.

     The argument here is the string name of the schema.

     `Class signature'

     class sqlalchemy.schema.DropSchema.
     (‘sqlalchemy.schema._CreateDropBase’)

      -- Method: sqlalchemy.schema.DropSchema..__init__
               (name, quote=None, cascade=False, **kw)

          Create a new DropSchema construct.

4.4 Column and Data Types
=========================

4.4.1 Column and Data Types
---------------------------

SQLAlchemy provides abstractions for most common database data types,
and a mechanism for specifying your own custom data types.

The methods and attributes of type objects are rarely used directly.
Type objects are supplied to Table definitions and can be
supplied as type hints to ‘functions’ for occasions where the database
driver returns an incorrect type.

     >>> users = Table('users', metadata,
     ...               Column('id', Integer, primary_key=True),
     ...               Column('login', String(32))
     ...              )

SQLAlchemy will use the ‘Integer’ and ‘String(32)’ type information when
issuing a ‘CREATE TABLE’ statement and will use it again when reading
back rows ‘SELECTed’ from the database.  Functions that accept a type
(such as Column()) will typically accept a type class or
instance; ‘Integer’ is equivalent to ‘Integer()’ with no construction
arguments in this case.

4.4.1.1 Generic Types
.....................

Generic types specify a column that can read, write and store a
particular type of Python data.  SQLAlchemy will choose the best
database column type available on the target database when issuing a
‘CREATE TABLE’ statement.  For complete control over which column type
is emitted in ‘CREATE TABLE’, such as ‘VARCHAR’ see SQL Standard and Multiple Vendor Types
and the other sections of this chapter.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See BigInteger.A type for bigger ‘int’ integers.

See Boolean.A bool datatype.

See Date.A type for ‘datetime.date()’ objects.

See DateTime.A type for ‘datetime.datetime()’ objects.

See Enum.Generic Enum Type.

See Float.Type representing floating point types, such as ‘FLOAT’ or ‘REAL’.

See Integer.A type for ‘int’ integers.

See Interval.A type for ‘datetime.timedelta()’ objects.

See LargeBinary.A type for large binary byte data.

See MatchType.Refers to the return type of the MATCH operator.

See Numeric.A type for fixed precision numbers, such as ‘NUMERIC’ or ‘DECIMAL’.

See PickleType.Holds Python objects, which are serialized using pickle.

See SchemaType.Mark a type as possibly requiring schema-level DDL for usage.

See SmallInteger.A type for smaller ‘int’ integers.

See String.The base for all string and character types.

See Text.A variably sized string type.

See Time.A type for ‘datetime.time()’ objects.

See Unicode.A variable length Unicode string type.

See UnicodeText.An unbounded-length Unicode string type.

 -- Class: sqlalchemy.types.BigInteger

     A type for bigger ‘int’ integers.

     Typically generates a ‘BIGINT’ in DDL, and otherwise acts like a
     normal Integer on the Python side.

     `Class signature'

     class sqlalchemy.types.BigInteger. (see
     sqlalchemy.types.Integer)

 -- Class: sqlalchemy.types.Boolean (create_constraint=False, name=None,
          _create_events=True)

     A bool datatype.

     Boolean typically uses BOOLEAN or SMALLINT on the DDL
     side, and on the Python side deals in ‘True’ or ‘False’.

     The Boolean datatype currently has two levels of
     assertion that the values persisted are simple true/false values.
     For all backends, only the Python values ‘None’, ‘True’, ‘False’,
     ‘1’ or ‘0’ are accepted as parameter values.  For those backends
     that don’t support a “native boolean” datatype, an option exists to
     also create a CHECK constraint on the target column

     Changed in version 1.2: the Boolean datatype now
     asserts that incoming Python values are already in pure boolean
     form.

     `Class signature'

     class sqlalchemy.types.Boolean.
     (‘sqlalchemy.types.Emulated’, see sqlalchemy.types.TypeEngine,
     see sqlalchemy.types.SchemaType)

      -- Method: sqlalchemy.types.Boolean..__init__
               (create_constraint=False, name=None, _create_events=True)

          Construct a Boolean.

          Parameters:

             * ‘create_constraint’ – defaults to False.  If the boolean
               is generated as an int/smallint, also create a CHECK
               constraint on the table that ensures 1 or 0 as a value.

                    Note: it is strongly recommended that the CHECK
                    constraint have an explicit name in order to support
                    schema-management concerns.  This can be established
                    either by setting the Boolean.name
                    parameter or by setting up an appropriate naming
                    convention; see Configuring Constraint Naming Conventions
                    for background.

               Changed in version 1.4: - this flag now defaults to
               False, meaning no CHECK constraint is generated for a
               non-native enumerated type.

             * ‘name’ – if a CHECK constraint is generated, specify the
               name of the constraint.

      -- Method: sqlalchemy.types.Boolean..bind_processor
               (dialect)

          Return a conversion function for processing bind values.

          Returns a callable which will receive a bind parameter value
          as the sole positional argument and will return a value to
          send to the DB-API.

          If processing is not necessary, the method should return
          ‘None’.

          Parameters: ‘dialect’ – Dialect instance in use.

      -- Method: sqlalchemy.types.Boolean..literal_processor
               (dialect)

          Return a conversion function for processing literal values
          that are to be rendered directly without using binds.

          This function is used when the compiler makes use of the
          “literal_binds” flag, typically used in DDL generation as well
          as in certain scenarios where backends don’t accept bound
          parameters.

          New in version 0.9.0.

      -- Attribute: sqlalchemy.types.Boolean..python_type

      -- Method: sqlalchemy.types.Boolean..result_processor
               (dialect, coltype)

          Return a conversion function for processing result row values.

          Returns a callable which will receive a result row column
          value as the sole positional argument and will return a value
          to return to the user.

          If processing is not necessary, the method should return
          ‘None’.

          Parameters:

             * ‘dialect’ – Dialect instance in use.

             * ‘coltype’ – DBAPI coltype argument received in
               cursor.description.

 -- Class: sqlalchemy.types.Date

     A type for ‘datetime.date()’ objects.

     `Class signature'

     class sqlalchemy.types.Date.
     (‘sqlalchemy.types._LookupExpressionAdapter’, see
     sqlalchemy.types.TypeEngine)

      -- Method: sqlalchemy.types.Date..get_dbapi_type
               (dbapi)

          Return the corresponding type object from the underlying
          DB-API, if any.

          This can be useful for calling ‘setinputsizes()’, for example.

      -- Attribute: sqlalchemy.types.Date..python_type

 -- Class: sqlalchemy.types.DateTime (timezone=False)

     A type for ‘datetime.datetime()’ objects.

     Date and time types return objects from the Python ‘datetime’
     module.  Most DBAPIs have built in support for the datetime module,
     with the noted exception of SQLite.  In the case of SQLite, date
     and time types are stored as strings which are then converted back
     to datetime objects when rows are returned.

     For the time representation within the datetime type, some backends
     include additional options, such as timezone support and fractional
     seconds support.  For fractional seconds, use the dialect-specific
     datatype, such as TIME.  For timezone support, use at
     least the TIMESTAMP datatype, if not the
     dialect-specific datatype object.

     `Class signature'

     class sqlalchemy.types.DateTime.
     (‘sqlalchemy.types._LookupExpressionAdapter’, see
     sqlalchemy.types.TypeEngine)

      -- Method: sqlalchemy.types.DateTime..__init__
               (timezone=False)

          Construct a new DateTime.

          Parameters: ‘timezone’ – boolean.  Indicates that the datetime
          type should enable timezone support, if available on the `base
          date/time-holding type only'.  It is recommended to make use
          of the TIMESTAMP datatype directly when using this
          flag, as some databases include separate generic
          date/time-holding types distinct from the timezone-capable
          TIMESTAMP datatype, such as Oracle.

      -- Method: sqlalchemy.types.DateTime..get_dbapi_type
               (dbapi)

          Return the corresponding type object from the underlying
          DB-API, if any.

          This can be useful for calling ‘setinputsizes()’, for example.

      -- Attribute: sqlalchemy.types.DateTime..python_type

 -- Class: sqlalchemy.types.Enum (*enums, **kw)

     Generic Enum Type.

     The Enum type provides a set of possible string values
     which the column is constrained towards.

     The Enum type will make use of the backend’s native
     “ENUM” type if one is available; otherwise, it uses a VARCHAR
     datatype.  An option also exists to automatically produce a CHECK
     constraint when the VARCHAR (so called “non-native”) variant is
     produced; see the Enum.create_constraint flag.

     The Enum type also provides in-Python validation of
     string values during both read and write operations.  When reading
     a value from the database in a result set, the string value is
     always checked against the list of possible values and a
     ‘LookupError’ is raised if no match is found.  When passing a value
     to the database as a plain string within a SQL statement, if the
     Enum.validate_strings parameter is set to True, a
     ‘LookupError’ is raised for any string value that’s not located in
     the given list of possible values; note that this impacts usage of
     LIKE expressions with enumerated values (an unusual use case).

     Changed in version 1.1: the Enum type now provides
     in-Python validation of input values as well as on data being
     returned by the database.

     The source of enumerated values may be a list of string values, or
     alternatively a PEP-435-compliant enumerated class.  For the
     purposes of the Enum datatype, this class need only
     provide a ‘__members__’ method.

     When using an enumerated class, the enumerated objects are used
     both for input and output, rather than strings as is the case with
     a plain-string enumerated type:

          import enum
          class MyEnum(enum.Enum):
              one = 1
              two = 2
              three = 3

          t = Table(
              'data', MetaData(),
              Column('value', Enum(MyEnum))
          )

          connection.execute(t.insert(), {"value": MyEnum.two})
          assert connection.scalar(t.select()) is MyEnum.two

     Above, the string names of each element, e.g.  “one”, “two”,
     “three”, are persisted to the database; the values of the Python
     Enum, here indicated as integers, are `not' used; the value of each
     enum can therefore be any kind of Python object whether or not it
     is persistable.

     In order to persist the values and not the names, the
     Enum.values_callable parameter may be used.  The value of
     this parameter is a user-supplied callable, which is intended to be
     used with a PEP-435-compliant enumerated class and returns a list
     of string values to be persisted.  For a simple enumeration that
     uses string values, a callable such as ‘lambda x: [e.value for e in
     x]’ is sufficient.

     New in version 1.1: - support for PEP-435-style enumerated classes.

     See also
     ........

     See ENUM. - PostgreSQL-specific type, which has additional
     functionality.

     See ENUM. - MySQL-specific type

     `Class signature'

     class sqlalchemy.types.Enum.
     (‘sqlalchemy.types.Emulated’, see sqlalchemy.types.String,
     sqlalchemy.types.SchemaType)

      -- Method: sqlalchemy.types.Enum..__init__ (*enums,
               **kw)

          Construct an enum.

          Keyword arguments which don’t apply to a specific backend are
          ignored by that backend.

          Parameters:

             * ‘*enums’ – either exactly one PEP-435 compliant
               enumerated type or one or more string or unicode
               enumeration labels.  If unicode labels are present, the
               ‘convert_unicode’ flag is auto-enabled.

               New in version 1.1: a PEP-435 style enumerated class may
               be passed.

             * ‘convert_unicode’ – Enable unicode-aware bind parameter
               and result-set processing for this Enum’s data.  This is
               set automatically based on the presence of unicode label
               strings.

               Deprecated since version 1.3: The
               Enum.convert_unicode parameter is deprecated and
               will be removed in a future release.  All modern DBAPIs
               now support Python Unicode directly and this parameter is
               unnecessary.

             * ‘create_constraint’ – defaults to False.  When creating a
               non-native enumerated type, also build a CHECK constraint
               on the database against the valid values.

                    Note: it is strongly recommended that the CHECK
                    constraint have an explicit name in order to support
                    schema-management concerns.  This can be established
                    either by setting the Enum.name
                    parameter or by setting up an appropriate naming
                    convention; see Configuring Constraint Naming Conventions
                    for background.

               Changed in version 1.4: - this flag now defaults to
               False, meaning no CHECK constraint is generated for a
               non-native enumerated type.

             * ‘metadata’ – Associate this type directly with a
               ‘MetaData’ object.  For types that exist on the target
               database as an independent schema construct (PostgreSQL),
               this type will be created and dropped within
               ‘create_all()’ and ‘drop_all()’ operations.  If the type
               is not associated with any ‘MetaData’ object, it will
               associate itself with each ‘Table’ in which it is used,
               and will be created when any of those individual tables
               are created, after a check is performed for its
               existence.  The type is only dropped when ‘drop_all()’ is
               called for that ‘Table’ object’s metadata, however.

             * ‘name’ – The name of this type.  This is required for
               PostgreSQL and any future supported database which
               requires an explicitly named type, or an explicitly named
               constraint in order to generate the type and/or a table
               that uses it.  If a PEP-435 enumerated class was used,
               its name (converted to lower case) is used by default.

             * ‘native_enum’ – Use the database’s native ENUM type when
               available.  Defaults to True.  When False, uses VARCHAR +
               check constraint for all backends.  The VARCHAR length
               can be controlled with Enum.length.

             * ‘length’ – Allows specifying a custom length for the
               VARCHAR when Enum.native_enum is False.  By
               default it uses the length of the longest value.

               New in version 1.3.16.

             * ‘schema’ – Schema name of this type.  For types that
               exist on the target database as an independent schema
               construct (PostgreSQL), this parameter specifies the
               named schema in which the type is present.

                    Note: The ‘schema’ of the Enum type does
                    not by default make use of the ‘schema’ established
                    on the owning Table.  If this behavior is
                    desired, set the ‘inherit_schema’ flag to ‘True’.

             * ‘quote’ – Set explicit quoting preferences for the type’s
               name.

             * ‘inherit_schema’ – When ‘True’, the “schema” from the
               owning Table will be copied to the “schema”
               attribute of this Enum, replacing whatever
               value was passed for the ‘schema’ attribute.  This also
               takes effect when using the Table.to_metadata()
               operation.

             * ‘validate_strings’ – when True, string values that are
               being passed to the database in a SQL statement will be
               checked for validity against the list of enumerated
               values.  Unrecognized values will result in a
               ‘LookupError’ being raised.

               New in version 1.1.0b2.

             * ‘values_callable’ – A callable which will be passed the
               PEP-435 compliant enumerated type, which should then
               return a list of string values to be persisted.  This
               allows for alternate usages such as using the string
               value of an enum to be persisted to the database instead
               of its name.

               New in version 1.2.3.

             * ‘sort_key_function’ – a Python callable which may be used
               as the “key” argument in the Python ‘sorted()’ built-in.
               The SQLAlchemy ORM requires that primary key columns
               which are mapped must be sortable in some way.  When
               using an unsortable enumeration object such as a Python 3
               ‘Enum’ object, this parameter may be used to set a
               default sort key function for the objects.  By default,
               the database value of the enumeration is used as the
               sorting function.

               New in version 1.3.8.

      -- Method: sqlalchemy.types.Enum..create (bind=None,
               checkfirst=False)

          `inherited from the' SchemaType.create(). `method
          of' SchemaType.

          Issue CREATE DDL for this type, if applicable.

      -- Method: sqlalchemy.types.Enum..drop (bind=None,
               checkfirst=False)

          `inherited from the' SchemaType.drop(). `method
          of' SchemaType.

          Issue DROP DDL for this type, if applicable.

 -- Class: sqlalchemy.types.Float (precision=None, asdecimal=False,
          decimal_return_scale=None)

     Type representing floating point types, such as ‘FLOAT’ or ‘REAL’.

     This type returns Python ‘float’ objects by default, unless the
     Float.asdecimal flag is set to True, in which case
     they are coerced to ‘decimal.Decimal’ objects.

          Note: The Float type is designed to receive data
          from a database type that is explicitly known to be a floating
          point type (e.g.  ‘FLOAT’, ‘REAL’, others) and not a decimal
          type (e.g.  ‘DECIMAL’, ‘NUMERIC’, others).  If the database
          column on the server is in fact a Numeric type, such as
          ‘DECIMAL’ or ‘NUMERIC’, use the Numeric type or a
          subclass, otherwise numeric coercion between ‘float’/‘Decimal’
          may or may not function as expected.

     `Class signature'

     class sqlalchemy.types.Float. (see
     sqlalchemy.types.Numeric)

      -- Method: sqlalchemy.types.Float..__init__
               (precision=None, asdecimal=False,
               decimal_return_scale=None)

          Construct a Float.

          Parameters:

             * ‘precision’ – the numeric precision for use in DDL
               ‘CREATE TABLE’.

             * ‘asdecimal’ – the same flag as that of Numeric,
               but defaults to ‘False’.  Note that setting this
               flag to ‘True’ results in floating point conversion.

             * ‘decimal_return_scale’ – Default scale to use when
               converting from floats to Python decimals.  Floating
               point values will typically be much longer due to decimal
               inaccuracy, and most floating point database types don’t
               have a notion of “scale”, so by default the float type
               looks for the first ten decimal places when converting.
               Specifying this value will override that length.  Note
               that the MySQL float types, which do include “scale”,
               will use “scale” as the default for decimal_return_scale,
               if not otherwise specified.

               New in version 0.9.0.

      -- Method: sqlalchemy.types.Float..result_processor
               (dialect, coltype)

          Return a conversion function for processing result row values.

          Returns a callable which will receive a result row column
          value as the sole positional argument and will return a value
          to return to the user.

          If processing is not necessary, the method should return
          ‘None’.

          Parameters:

             * ‘dialect’ – Dialect instance in use.

             * ‘coltype’ – DBAPI coltype argument received in
               cursor.description.

 -- Class: sqlalchemy.types.Integer

     A type for ‘int’ integers.

     `Class signature'

     class sqlalchemy.types.Integer.
     (‘sqlalchemy.types._LookupExpressionAdapter’, see
     sqlalchemy.types.TypeEngine)

      -- Method: sqlalchemy.types.Integer..get_dbapi_type
               (dbapi)

          Return the corresponding type object from the underlying
          DB-API, if any.

          This can be useful for calling ‘setinputsizes()’, for example.

      -- Method: sqlalchemy.types.Integer..literal_processor
               (dialect)

          Return a conversion function for processing literal values
          that are to be rendered directly without using binds.

          This function is used when the compiler makes use of the
          “literal_binds” flag, typically used in DDL generation as well
          as in certain scenarios where backends don’t accept bound
          parameters.

          New in version 0.9.0.

      -- Attribute: sqlalchemy.types.Integer..python_type

 -- Class: sqlalchemy.types.Interval (native=True,
          second_precision=None, day_precision=None)

     A type for ‘datetime.timedelta()’ objects.

     The Interval type deals with ‘datetime.timedelta’ objects.  In
     PostgreSQL, the native ‘INTERVAL’ type is used; for others, the
     value is stored as a date which is relative to the “epoch” (Jan.
     1, 1970).

     Note that the ‘Interval’ type does not currently provide date
     arithmetic operations on platforms which do not support interval
     types natively.  Such operations usually require transformation of
     both sides of the expression (such as, conversion of both sides
     into integer epoch values first) which currently is a manual
     procedure (such as via expression.func).

     `Class signature'

     class sqlalchemy.types.Interval.
     (‘sqlalchemy.types.Emulated’, ‘sqlalchemy.types._AbstractInterval’,
     see sqlalchemy.types.TypeDecorator)

      -- Method: sqlalchemy.types.Interval..__init__
               (native=True, second_precision=None, day_precision=None)

          Construct an Interval object.

          Parameters:

             * ‘native’ – when True, use the actual INTERVAL type
               provided by the database, if supported (currently
               PostgreSQL, Oracle).  Otherwise, represent the interval
               data as an epoch value regardless.

             * ‘second_precision’ – For native interval types which
               support a “fractional seconds precision” parameter, i.e.
               Oracle and PostgreSQL

             * ‘day_precision’ – for native interval types which support
               a “day precision” parameter, i.e.  Oracle.

      -- Method: sqlalchemy.types.Interval..
               adapt_to_emulated (impltype, **kw)

          Given an impl class, adapt this type to the impl assuming
          “emulated”.

          The impl should also be an “emulated” version of this type,
          most likely the same class as this type itself.

          e.g.: sqltypes.Enum adapts to the Enum class.

      -- Method: sqlalchemy.types.Interval..bind_processor
               (dialect)

          Return a conversion function for processing bind values.

          Returns a callable which will receive a bind parameter value
          as the sole positional argument and will return a value to
          send to the DB-API.

          If processing is not necessary, the method should return
          ‘None’.

          Parameters: ‘dialect’ – Dialect instance in use.

      -- Attribute: sqlalchemy.types.Interval..impl

          alias of ‘sqlalchemy.sql.sqltypes.DateTime’

      -- Attribute: sqlalchemy.types.Interval..python_type

      -- Method: sqlalchemy.types.Interval..result_processor
               (dialect, coltype)

          Return a conversion function for processing result row values.

          Returns a callable which will receive a result row column
          value as the sole positional argument and will return a value
          to return to the user.

          If processing is not necessary, the method should return
          ‘None’.

          Parameters:

             * ‘dialect’ – Dialect instance in use.

             * ‘coltype’ – DBAPI coltype argument received in
               cursor.description.

 -- Class: sqlalchemy.types.LargeBinary (length=None)

     A type for large binary byte data.

     The LargeBinary type corresponds to a large and/or
     unlengthed binary type for the target platform, such as BLOB on
     MySQL and BYTEA for PostgreSQL. It also handles the necessary
     conversions for the DBAPI.

     `Class signature'

     class sqlalchemy.types.LargeBinary.
     (‘sqlalchemy.types._Binary’)

      -- Method: sqlalchemy.types.LargeBinary..__init__
               (length=None)

          Construct a LargeBinary type.

          Parameters: ‘length’ – optional, a length for the column for
          use in DDL statements, for those binary types that accept a
          length, such as the MySQL BLOB type.

 -- Class: sqlalchemy.types.MatchType (create_constraint=False,
          name=None, _create_events=True)

     Refers to the return type of the MATCH operator.

     As the ColumnOperators.match() is probably the most
     open-ended operator in generic SQLAlchemy Core, we can’t assume the
     return type at SQL evaluation time, as MySQL returns a floating
     point, not a boolean, and other backends might do something
     different.  So this type acts as a placeholder, currently
     subclassing Boolean.  The type allows dialects to inject
     result-processing functionality if needed, and on MySQL will return
     floating-point values.

     New in version 1.0.0.

     `Class signature'

     class sqlalchemy.types.MatchType. (see
     sqlalchemy.types.Boolean)

 -- Class: sqlalchemy.types.Numeric (precision=None, scale=None,
          decimal_return_scale=None, asdecimal=True)

     A type for fixed precision numbers, such as ‘NUMERIC’ or ‘DECIMAL’.

     This type returns Python ‘decimal.Decimal’ objects by default,
     unless the Numeric.asdecimal flag is set to False, in
     which case they are coerced to Python ‘float’ objects.

          Note: The Numeric type is designed to receive data
          from a database type that is explicitly known to be a decimal
          type (e.g.  ‘DECIMAL’, ‘NUMERIC’, others) and not a floating
          point type (e.g.  ‘FLOAT’, ‘REAL’, others).  If the database
          column on the server is in fact a floating-point type, such as
          ‘FLOAT’ or ‘REAL’, use the Float type or a
          subclass, otherwise numeric coercion between ‘float’/‘Decimal’
          may or may not function as expected.

          Note: The Python ‘decimal.Decimal’ class is generally slow
          performing; cPython 3.3 has now switched to use the
          cdecimal(1) library natively.  For older Python versions, the
          ‘cdecimal’ library can be patched into any application where
          it will replace the ‘decimal’ library fully, however this
          needs to be applied globally and before any other modules have
          been imported, as follows:

               import sys
               import cdecimal
               sys.modules["decimal"] = cdecimal

          Note that the ‘cdecimal’ and ‘decimal’ libraries are `not
          compatible with each other', so patching ‘cdecimal’ at the
          global level is the only way it can be used effectively with
          various DBAPIs that hardcode to import the ‘decimal’ library.

     `Class signature'

     class sqlalchemy.types.Numeric.
     (‘sqlalchemy.types._LookupExpressionAdapter’, see
     sqlalchemy.types.TypeEngine)

      -- Method: sqlalchemy.types.Numeric..__init__
               (precision=None, scale=None, decimal_return_scale=None,
               asdecimal=True)

          Construct a Numeric.

          Parameters:

             * ‘precision’ – the numeric precision for use in DDL
               ‘CREATE TABLE’.

             * ‘scale’ – the numeric scale for use in DDL ‘CREATE
               TABLE’.

             * ‘asdecimal’ – default True.  Return whether or not values
               should be sent as Python Decimal objects, or as floats.
               Different DBAPIs send one or the other based on datatypes
               - the Numeric type will ensure that return values are one
               or the other across DBAPIs consistently.

             * ‘decimal_return_scale’ – Default scale to use when
               converting from floats to Python decimals.  Floating
               point values will typically be much longer due to decimal
               inaccuracy, and most floating point database types don’t
               have a notion of “scale”, so by default the float type
               looks for the first ten decimal places when converting.
               Specifying this value will override that length.  Types
               which do include an explicit “.scale” value, such as the
               base Numeric as well as the MySQL float
               types, will use the value of “.scale” as the default for
               decimal_return_scale, if not otherwise specified.

               New in version 0.9.0.

          When using the ‘Numeric’ type, care should be taken to ensure
          that the asdecimal setting is appropriate for the DBAPI in use
          - when Numeric applies a conversion from Decimal->float or
          float-> Decimal, this conversion incurs an additional
          performance overhead for all result columns received.

          DBAPIs that return Decimal natively (e.g.  psycopg2) will have
          better accuracy and higher performance with a setting of
          ‘True’, as the native translation to Decimal reduces the
          amount of floating- point issues at play, and the Numeric type
          itself doesn’t need to apply any further conversions.
          However, another DBAPI which returns floats natively `will'
          incur an additional conversion overhead, and is still subject
          to floating point data loss - in which case ‘asdecimal=False’
          will at least remove the extra conversion overhead.

      -- Method: sqlalchemy.types.Numeric..bind_processor
               (dialect)

          Return a conversion function for processing bind values.

          Returns a callable which will receive a bind parameter value
          as the sole positional argument and will return a value to
          send to the DB-API.

          If processing is not necessary, the method should return
          ‘None’.

          Parameters: ‘dialect’ – Dialect instance in use.

      -- Method: sqlalchemy.types.Numeric..get_dbapi_type
               (dbapi)

          Return the corresponding type object from the underlying
          DB-API, if any.

          This can be useful for calling ‘setinputsizes()’, for example.

      -- Method: sqlalchemy.types.Numeric..literal_processor
               (dialect)

          Return a conversion function for processing literal values
          that are to be rendered directly without using binds.

          This function is used when the compiler makes use of the
          “literal_binds” flag, typically used in DDL generation as well
          as in certain scenarios where backends don’t accept bound
          parameters.

          New in version 0.9.0.

      -- Attribute: sqlalchemy.types.Numeric..python_type

      -- Method: sqlalchemy.types.Numeric..result_processor
               (dialect, coltype)

          Return a conversion function for processing result row values.

          Returns a callable which will receive a result row column
          value as the sole positional argument and will return a value
          to return to the user.

          If processing is not necessary, the method should return
          ‘None’.

          Parameters:

             * ‘dialect’ – Dialect instance in use.

             * ‘coltype’ – DBAPI coltype argument received in
               cursor.description.

 -- Class: sqlalchemy.types.PickleType (protocol=5, pickler=None,
          comparator=None)

     Holds Python objects, which are serialized using pickle.

     PickleType builds upon the Binary type to apply Python’s
     ‘pickle.dumps()’ to incoming objects, and ‘pickle.loads()’ on the
     way out, allowing any pickleable Python object to be stored as a
     serialized binary field.

     To allow ORM change events to propagate for elements associated
     with PickleType, see Mutation Tracking.

     `Class signature'

     class sqlalchemy.types.PickleType. (see
     sqlalchemy.types.TypeDecorator)

      -- Method: sqlalchemy.types.PickleType..__init__
               (protocol=5, pickler=None, comparator=None)

          Construct a PickleType.

          Parameters:

             * ‘protocol’ – defaults to ‘pickle.HIGHEST_PROTOCOL’.

             * ‘pickler’ – defaults to cPickle.pickle or pickle.pickle
               if cPickle is not available.  May be any object with
               pickle-compatible ‘dumps’ and ‘loads’ methods.

             * ‘comparator’ – a 2-arg callable predicate used to compare
               values of this type.  If left as ‘None’, the Python
               “equals” operator is used to compare values.

      -- Method: sqlalchemy.types.PickleType..bind_processor
               (dialect)

          Provide a bound value processing function for the given
          Dialect.

          This is the method that fulfills the TypeEngine
          contract for bound value conversion.  TypeDecorator
          will wrap a user-defined implementation of
          ‘process_bind_param()’ here.

          User-defined code can override this method directly, though
          its likely best to use ‘process_bind_param()’ so that the
          processing provided by ‘self.impl’ is maintained.

          Parameters: ‘dialect’ – Dialect instance in use.

          This method is the reverse counterpart to the
          result_processor() method of this class.

      -- Method: sqlalchemy.types.PickleType..compare_values
               (x, y)

          Given two values, compare them for equality.

          By default this calls upon TypeEngine.compare_values()
          of the underlying “impl”, which in turn usually uses the
          Python equals operator ‘==’.

          This function is used by the ORM to compare an original-loaded
          value with an intercepted “changed” value, to determine if a
          net change has occurred.

      -- Attribute: sqlalchemy.types.PickleType..impl

          alias of ‘sqlalchemy.sql.sqltypes.LargeBinary’

      -- Method: sqlalchemy.types.PickleType..
               result_processor (dialect, coltype)

          Provide a result value processing function for the given
          Dialect.

          This is the method that fulfills the TypeEngine
          contract for result value conversion.  TypeDecorator
          will wrap a user-defined implementation of
          ‘process_result_value()’ here.

          User-defined code can override this method directly, though
          its likely best to use ‘process_result_value()’ so that the
          processing provided by ‘self.impl’ is maintained.

          Parameters:

             * ‘dialect’ – Dialect instance in use.

             * ‘coltype’ – A SQLAlchemy data type

          This method is the reverse counterpart to the
          bind_processor() method of this class.

 -- Class: sqlalchemy.types.SchemaType (name=None, schema=None,
          metadata=None, inherit_schema=False, quote=None,
          _create_events=True)

     Mark a type as possibly requiring schema-level DDL for usage.

     Supports types that must be explicitly created/dropped (i.e.  PG
     ENUM type) as well as types that are complimented by table or
     schema level constraints, triggers, and other rules.

     SchemaType classes can also be targets for the
     DDLEvents.before_parent_attach() and
     DDLEvents.after_parent_attach() events, where the events
     fire off surrounding the association of the type object with a
     parent Column.

     See also
     ........

     See Enum.

     See Boolean.

     `Class signature'

     class sqlalchemy.types.SchemaType.
     (‘sqlalchemy.sql.expression.SchemaEventTarget’)

      -- Method: sqlalchemy.types.SchemaType..adapt
               (impltype, **kw)

      -- Attribute: sqlalchemy.types.SchemaType..bind

      -- Method: sqlalchemy.types.SchemaType..copy (**kw)

      -- Method: sqlalchemy.types.SchemaType..create
               (bind=None, checkfirst=False)

          Issue CREATE DDL for this type, if applicable.

      -- Method: sqlalchemy.types.SchemaType..drop
               (bind=None, checkfirst=False)

          Issue DROP DDL for this type, if applicable.

 -- Class: sqlalchemy.types.SmallInteger

     A type for smaller ‘int’ integers.

     Typically generates a ‘SMALLINT’ in DDL, and otherwise acts like a
     normal Integer on the Python side.

     `Class signature'

     class sqlalchemy.types.SmallInteger. (see
     sqlalchemy.types.Integer)

 -- Class: sqlalchemy.types.String (length=None, collation=None,
          convert_unicode=False, unicode_error=None,
          _warn_on_bytestring=False, _expect_unicode=False)

     The base for all string and character types.

     In SQL, corresponds to VARCHAR. Can also take Python unicode
     objects and encode to the database’s encoding in bind params (and
     the reverse for result sets.)

     The ‘length’ field is usually required when the ‘String’ type is
     used within a CREATE TABLE statement, as VARCHAR requires a length
     on most databases.

     `Class signature'

     class sqlalchemy.types.String. (see
     sqlalchemy.types.Concatenable,
     sqlalchemy.types.TypeEngine)

      -- Attribute: sqlalchemy.types.String..RETURNS_BYTES =
               symbol('RETURNS_BYTES')

      -- Attribute: sqlalchemy.types.String..
               RETURNS_CONDITIONAL = symbol('RETURNS_CONDITIONAL')

      -- Attribute: sqlalchemy.types.String..RETURNS_UNICODE =
               symbol('RETURNS_UNICODE')

      -- Attribute: sqlalchemy.types.String..RETURNS_UNKNOWN =
               symbol('RETURNS_UNKNOWN')

      -- Method: sqlalchemy.types.String..__init__
               (length=None, collation=None, convert_unicode=False,
               unicode_error=None, _warn_on_bytestring=False,
               _expect_unicode=False)

          Create a string-holding type.

          Parameters:

             * ‘length’ – optional, a length for the column for use in
               DDL and CAST expressions.  May be safely omitted if no
               ‘CREATE TABLE’ will be issued.  Certain databases may
               require a ‘length’ for use in DDL, and will raise an
               exception when the ‘CREATE TABLE’ DDL is issued if a
               ‘VARCHAR’ with no length is included.  Whether the value
               is interpreted as bytes or characters is database
               specific.

             * ‘collation’ – Optional, a column-level collation for use
               in DDL and CAST expressions.  Renders using the COLLATE
               keyword supported by SQLite, MySQL, and PostgreSQL. E.g.:

                    >>> from sqlalchemy import cast, select, String
                    >>> print(select(cast('some string', String(collation='utf8'))))
                    SELECT CAST(:param_1 AS VARCHAR COLLATE utf8) AS anon_1

             * ‘convert_unicode’ – When set to ‘True’, the String
               type will assume that input is to be passed as Python
               Unicode objects under Python 2, and results returned as
               Python Unicode objects.  In the rare circumstance that
               the DBAPI does not support Python unicode under Python 2,
               SQLAlchemy will use its own encoder/decoder functionality
               on strings, referring to the value of the
               create_engine.encoding parameter parameter passed
               to create_engine() as the encoding.

               Deprecated since version 1.3: The
               String.convert_unicode parameter is deprecated and
               will be removed in a future release.  All modern DBAPIs
               now support Python Unicode directly and this parameter is
               unnecessary.

               For the extremely rare case that Python Unicode is to be
               encoded/decoded by SQLAlchemy on a backend that `does'
               natively support Python Unicode, the string value
               ‘"force"’ can be passed here which will cause
               SQLAlchemy’s encode/decode services to be used
               unconditionally.

                    Note: SQLAlchemy’s unicode-conversion flags and
                    features only apply to Python 2; in Python 3, all
                    string objects are Unicode objects.  For this
                    reason, as well as the fact that virtually all
                    modern DBAPIs now support Unicode natively even
                    under Python 2, the String.convert_unicode
                    flag is inherently a legacy feature.

                    Note: In the vast majority of cases, the
                    Unicode or UnicodeText datatypes
                    should be used for a Column that expects
                    to store non-ascii data.  These datatypes will
                    ensure that the correct types are used on the
                    database side as well as set up the correct Unicode
                    behaviors under Python 2.

               See also
               ........

               See create_engine.convert_unicode. - see
               Engine.-wide parameter

             * ‘unicode_error’ – Optional, a method to use to handle
               Unicode conversion errors.  Behaves like the ‘errors’
               keyword argument to the standard library’s
               ‘string.decode()’ functions, requires that
               String.convert_unicode is set to ‘"force"’

               Deprecated since version 1.3: The
               String.unicode_errors parameter is deprecated and
               will be removed in a future release.  This parameter is
               unnecessary for modern Python DBAPIs and degrades
               performance significantly.

      -- Method: sqlalchemy.types.String..bind_processor
               (dialect)

          Return a conversion function for processing bind values.

          Returns a callable which will receive a bind parameter value
          as the sole positional argument and will return a value to
          send to the DB-API.

          If processing is not necessary, the method should return
          ‘None’.

          Parameters: ‘dialect’ – Dialect instance in use.

      -- Method: sqlalchemy.types.String..get_dbapi_type
               (dbapi)

          Return the corresponding type object from the underlying
          DB-API, if any.

          This can be useful for calling ‘setinputsizes()’, for example.

      -- Method: sqlalchemy.types.String..literal_processor
               (dialect)

          Return a conversion function for processing literal values
          that are to be rendered directly without using binds.

          This function is used when the compiler makes use of the
          “literal_binds” flag, typically used in DDL generation as well
          as in certain scenarios where backends don’t accept bound
          parameters.

          New in version 0.9.0.

      -- Attribute: sqlalchemy.types.String..python_type

      -- Method: sqlalchemy.types.String..result_processor
               (dialect, coltype)

          Return a conversion function for processing result row values.

          Returns a callable which will receive a result row column
          value as the sole positional argument and will return a value
          to return to the user.

          If processing is not necessary, the method should return
          ‘None’.

          Parameters:

             * ‘dialect’ – Dialect instance in use.

             * ‘coltype’ – DBAPI coltype argument received in
               cursor.description.

 -- Class: sqlalchemy.types.Text (length=None, collation=None,
          convert_unicode=False, unicode_error=None,
          _warn_on_bytestring=False, _expect_unicode=False)

     A variably sized string type.

     In SQL, usually corresponds to CLOB or TEXT. Can also take Python
     unicode objects and encode to the database’s encoding in bind
     params (and the reverse for result sets.)  In general, TEXT objects
     do not have a length; while some databases will accept a length
     argument here, it will be rejected by others.

     `Class signature'

     class sqlalchemy.types.Text. (see
     sqlalchemy.types.String)

 -- Class: sqlalchemy.types.Time (timezone=False)

     A type for ‘datetime.time()’ objects.

     `Class signature'

     class sqlalchemy.types.Time.
     (‘sqlalchemy.types._LookupExpressionAdapter’, see
     sqlalchemy.types.TypeEngine)

      -- Method: sqlalchemy.types.Time..get_dbapi_type
               (dbapi)

          Return the corresponding type object from the underlying
          DB-API, if any.

          This can be useful for calling ‘setinputsizes()’, for example.

      -- Attribute: sqlalchemy.types.Time..python_type

 -- Class: sqlalchemy.types.Unicode (length=None, **kwargs)

     A variable length Unicode string type.

     The Unicode type is a String subclass that
     assumes input and output as Python ‘unicode’ data, and in that
     regard is equivalent to the usage of the ‘convert_unicode’ flag
     with the String type.  However, unlike plain
     String, it also implies an underlying column type that is
     explicitly supporting of non-ASCII data, such as ‘NVARCHAR’ on
     Oracle and SQL Server.  This can impact the output of ‘CREATE
     TABLE’ statements and ‘CAST’ functions at the dialect level, and
     can also affect the handling of bound parameters in some specific
     DBAPI scenarios.

     The encoding used by the Unicode type is usually
     determined by the DBAPI itself; most modern DBAPIs feature support
     for Python ‘unicode’ objects as bound values and result set values,
     and the encoding should be configured as detailed in the notes for
     the target DBAPI in the Dialects section.

     For those DBAPIs which do not support, or are not configured to
     accommodate Python ‘unicode’ objects directly, SQLAlchemy does the
     encoding and decoding outside of the DBAPI. The encoding in this
     scenario is determined by the ‘encoding’ flag passed to
     create_engine().

     When using the Unicode type, it is only appropriate to
     pass Python ‘unicode’ objects, and not plain ‘str’.  If a plain
     ‘str’ is passed under Python 2, a warning is emitted.  If you
     notice your application emitting these warnings but you’re not sure
     of the source of them, the Python ‘warnings’ filter, documented at
     ‘http://docs.python.org/library/warnings.html’, can be used to turn
     these warnings into exceptions which will illustrate a stack trace:

          import warnings
          warnings.simplefilter('error')

     For an application that wishes to pass plain bytestrings and Python
     ‘unicode’ objects to the ‘Unicode’ type equally, the bytestrings
     must first be decoded into unicode.  The recipe at Coercing Encoded Strings to Unicode
     illustrates how this is done.

     See also
     ........

     See UnicodeText. - unlengthed textual counterpart to
     Unicode.

     `Class signature'

     class sqlalchemy.types.Unicode. (see
     sqlalchemy.types.String)

      -- Method: sqlalchemy.types.Unicode..__init__
               (length=None, **kwargs)

          Create a Unicode object.

          Parameters are the same as that of String, with the
          exception that ‘convert_unicode’ defaults to ‘True’.

 -- Class: sqlalchemy.types.UnicodeText (length=None, **kwargs)

     An unbounded-length Unicode string type.

     See Unicode for details on the unicode behavior of this
     object.

     Like Unicode, usage the UnicodeText type
     implies a unicode-capable type being used on the backend, such as
     ‘NCLOB’, ‘NTEXT’.

     `Class signature'

     class sqlalchemy.types.UnicodeText. (see
     sqlalchemy.types.Text)

      -- Method: sqlalchemy.types.UnicodeText..__init__
               (length=None, **kwargs)

          Create a Unicode-converting Text type.

          Parameters are the same as that of TextClause, with
          the exception that ‘convert_unicode’ defaults to ‘True’.

   ---------- Footnotes ----------

   (1) http://pypi.python.org/pypi/cdecimal/

4.4.1.2 SQL Standard and Multiple Vendor Types
..............................................

This category of types refers to types that are either part of the SQL
standard, or are potentially found within a subset of database backends.
Unlike the “generic” types, the SQL standard/multi-vendor types have
`no' guarantee of working on all backends, and will only work on those
backends that explicitly support them by name.  That is, the type will
always emit its exact name in DDL with ‘CREATE TABLE’ is issued.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See ARRAY.Represent a SQL Array type.

See BIGINT.The SQL BIGINT type.

See BINARY.The SQL BINARY type.

See BLOB.The SQL BLOB type.

See BOOLEAN.The SQL BOOLEAN type.

See CHAR.The SQL CHAR type.

See CLOB.The CLOB type.

See DATE.The SQL DATE type.

See DATETIME.The SQL DATETIME type.

See DECIMAL.The SQL DECIMAL type.

See FLOAT.The SQL FLOAT type.

See INT.alias of ‘sqlalchemy.sql.sqltypes.INTEGER’

See INTEGER.The SQL INT or INTEGER type.

See JSON.Represent a SQL JSON type.

See NCHAR.The SQL NCHAR type.

See NUMERIC.The SQL NUMERIC type.

See NVARCHAR.The SQL NVARCHAR type.

See REAL.The SQL REAL type.

See SMALLINT.The SQL SMALLINT type.

See TEXT.The SQL TEXT type.

See TIME.The SQL TIME type.

See TIMESTAMP.The SQL TIMESTAMP type.

See VARBINARY.The SQL VARBINARY type.

See VARCHAR.The SQL VARCHAR type.

 -- Class: sqlalchemy.types.ARRAY (item_type, as_tuple=False,
          dimensions=None, zero_indexes=False)

     Represent a SQL Array type.

          Note: This type serves as the basis for all ARRAY operations.
          However, currently `only the PostgreSQL backend has support
          for SQL arrays in SQLAlchemy'.  It is recommended to use the
          PostgreSQL-specific
          sqlalchemy.dialects.postgresql.ARRAY type directly when
          using ARRAY types with PostgreSQL, as it provides additional
          operators specific to that backend.

     ARRAY is part of the Core in support of various SQL
     standard functions such as array_agg which explicitly
     involve arrays; however, with the exception of the PostgreSQL
     backend and possibly some third-party dialects, no other SQLAlchemy
     built-in dialect has support for this type.

     An ARRAY type is constructed given the “type” of
     element:

          mytable = Table("mytable", metadata,
                  Column("data", ARRAY(Integer))
              )

     The above type represents an N-dimensional array, meaning a
     supporting backend such as PostgreSQL will interpret values with
     any number of dimensions automatically.  To produce an INSERT
     construct that passes in a 1-dimensional array of integers:

          connection.execute(
                  mytable.insert(),
                  data=[1,2,3]
          )

     The ARRAY type can be constructed given a fixed number
     of dimensions:

          mytable = Table("mytable", metadata,
                  Column("data", ARRAY(Integer, dimensions=2))
              )

     Sending a number of dimensions is optional, but recommended if the
     datatype is to represent arrays of more than one dimension.  This
     number is used:

        * When emitting the type declaration itself to the database,
          e.g.  ‘INTEGER[][]’

        * When translating Python values to database values, and vice
          versa, e.g.  an ARRAY of Unicode objects uses this
          number to efficiently access the string values inside of array
          structures without resorting to per-row type inspection

        * When used with the Python ‘getitem’ accessor, the number of
          dimensions serves to define the kind of type that the ‘[]’
          operator should return, e.g.  for an ARRAY of INTEGER with two
          dimensions:

               >>> expr = table.c.column[5]  # returns ARRAY(Integer, dimensions=1)
               >>> expr = expr[6]  # returns Integer

     For 1-dimensional arrays, an ARRAY instance with no
     dimension parameter will generally assume single-dimensional
     behaviors.

     SQL expressions of type ARRAY have support for “index”
     and “slice” behavior.  The Python ‘[]’ operator works normally
     here, given integer indexes or slices.  Arrays default to 1-based
     indexing.  The operator produces binary expression constructs which
     will produce the appropriate SQL, both for SELECT statements:

          select(mytable.c.data[5], mytable.c.data[2:7])

     as well as UPDATE statements when the Update.values()
     method is used:

          mytable.update().values({
              mytable.c.data[5]: 7,
              mytable.c.data[2:7]: [1, 2, 3]
          })

     The ARRAY type also provides for the operators
     Comparator.any() and Comparator.all().  The
     PostgreSQL-specific version of ARRAY also provides
     additional operators.

     New in version 1.1.0.

     See also
     ........

     See sqlalchemy.dialects.postgresql.ARRAY.

     `Class signature'

     class sqlalchemy.types.ARRAY.
     (‘sqlalchemy.sql.expression.SchemaEventTarget’, see
     sqlalchemy.types.Indexable,
     sqlalchemy.types.Concatenable,
     sqlalchemy.types.TypeEngine)

      -- Class: Comparator (expr)

          Define comparison operations for ARRAY.

          More operators are available on the dialect-specific form of
          this type.  See Comparator.

          `Class signature'

          class sqlalchemy.types.ARRAY.Comparator.
          (‘sqlalchemy.types.Comparator’, ‘sqlalchemy.types.Comparator’)

           -- Method: sqlalchemy.types.ARRAY.Comparator..all
                    (other, operator=None)

               Return ‘other operator ALL (array)’ clause.

               Argument places are switched, because ALL requires array
               expression to be on the right hand-side.

               E.g.:

                    from sqlalchemy.sql import operators

                    conn.execute(
                        select(table.c.data).where(
                                table.c.data.all(7, operator=operators.lt)
                            )
                    )

               Parameters:

                  * ‘other’ – expression to be compared

                  * ‘operator’ – an operator object from the
                    ‘sqlalchemy.sql.operators’ package, defaults to
                    ‘eq()’.

               See also
               ........

               See all_().

               See Comparator.any().

           -- Method: sqlalchemy.types.ARRAY.Comparator..any
                    (other, operator=None)

               Return ‘other operator ANY (array)’ clause.

               Argument places are switched, because ANY requires array
               expression to be on the right hand-side.

               E.g.:

                    from sqlalchemy.sql import operators

                    conn.execute(
                        select(table.c.data).where(
                                table.c.data.any(7, operator=operators.lt)
                            )
                    )

               Parameters:

                  * ‘other’ – expression to be compared

                  * ‘operator’ – an operator object from the
                    ‘sqlalchemy.sql.operators’ package, defaults to
                    ‘eq()’.

               See also
               ........

               See any_().

               See Comparator.all().

           -- Method: sqlalchemy.types.ARRAY.Comparator..
                    contains (*arg, **kw)

               Implement the ‘contains’ operator.

               Produces a LIKE expression that tests against a match for
               the middle of a string value:

                    column LIKE '%' || <other> || '%'

               E.g.:

                    stmt = select(sometable).\
                        where(sometable.c.column.contains("foobar"))

               Since the operator uses ‘LIKE’, wildcard characters ‘"%"’
               and ‘"_"’ that are present inside the <other> expression
               will behave like wildcards as well.  For literal string
               values, the ColumnOperators.contains.autoescape
               flag may be set to ‘True’ to apply escaping to
               occurrences of these characters within the string value
               so that they match as themselves and not as wildcard
               characters.  Alternatively, the
               ColumnOperators.contains.escape parameter will
               establish a given character as an escape character which
               can be of use when the target expression is not a literal
               string.

               Parameters:

                  * ‘other’ – expression to be compared.  This is
                    usually a plain string value, but can also be an
                    arbitrary SQL expression.  LIKE wildcard characters
                    ‘%’ and ‘_’ are not escaped by default unless the
                    ColumnOperators.contains.autoescape flag
                    is set to True.

                  * ‘autoescape’ – boolean; when True, establishes an
                    escape character within the LIKE expression, then
                    applies it to all occurrences of ‘"%"’, ‘"_"’ and
                    the escape character itself within the comparison
                    value, which is assumed to be a literal string and
                    not a SQL expression.

                    An expression such as:

                         somecolumn.contains("foo%bar", autoescape=True)

                    Will render as:

                         somecolumn LIKE '%' || :param || '%' ESCAPE '/'

                    With the value of ‘:param’ as ‘"foo/%bar"’.

                  * ‘escape’ – a character which when given will render
                    with the ‘ESCAPE’ keyword to establish that
                    character as the escape character.  This character
                    can then be placed preceding occurrences of ‘%’ and
                    ‘_’ to allow them to act as themselves and not
                    wildcard characters.

                    An expression such as:

                         somecolumn.contains("foo/%bar", escape="^")

                    Will render as:

                         somecolumn LIKE '%' || :param || '%' ESCAPE '^'

                    The parameter may also be combined with
                    ColumnOperators.contains.autoescape:

                         somecolumn.contains("foo%bar^bat", escape="^", autoescape=True)

                    Where above, the given literal parameter will be
                    converted to ‘"foo^%bar^^bat"’ before being passed
                    to the database.

               See also
               ........

               See ColumnOperators.startswith().

               See ColumnOperators.endswith().

               See ColumnOperators.like().

      -- Method: sqlalchemy.types.ARRAY..__init__ (item_type,
               as_tuple=False, dimensions=None, zero_indexes=False)

          Construct an ARRAY.

          E.g.:

               Column('myarray', ARRAY(Integer))

          Arguments are:

          Parameters:

             * ‘item_type’ – The data type of items of this array.  Note
               that dimensionality is irrelevant here, so
               multi-dimensional arrays like ‘INTEGER[][]’, are
               constructed as ‘ARRAY(Integer)’, not as
               ‘ARRAY(ARRAY(Integer))’ or such.

             * ‘as_tuple=False’ – Specify whether return results should
               be converted to tuples from lists.  This parameter is not
               generally needed as a Python list corresponds well to a
               SQL array.

             * ‘dimensions’ – if non-None, the ARRAY will assume a fixed
               number of dimensions.  This impacts how the array is
               declared on the database, how it goes about interpreting
               Python and result values, as well as how expression
               behavior in conjunction with the “getitem” operator
               works.  See the description at ARRAY for
               additional detail.

             * ‘zero_indexes=False’ – when True, index values will be
               converted between Python zero-based and SQL one-based
               indexes, e.g.  a value of one will be added to all index
               values before passing to the database.

      -- Attribute: sqlalchemy.types.ARRAY..
               comparator_factory

          alias of ‘sqlalchemy.sql.sqltypes.ARRAY.Comparator’

      -- Method: sqlalchemy.types.ARRAY..compare_values (x,
               y)

          Compare two values for equality.

      -- Attribute: sqlalchemy.types.ARRAY..hashable

          Flag, if False, means values from this type aren’t hashable.

          Used by the ORM when uniquing result lists.

      -- Attribute: sqlalchemy.types.ARRAY..python_type

      -- Attribute: sqlalchemy.types.ARRAY..zero_indexes =
               False

          If True, Python zero-based indexes should be interpreted as
          one-based on the SQL expression side.

 -- Class: sqlalchemy.types.BIGINT

     The SQL BIGINT type.

     `Class signature'

     class sqlalchemy.types.BIGINT. (see
     sqlalchemy.types.BigInteger)

 -- Class: sqlalchemy.types.BINARY (length=None)

     The SQL BINARY type.

     `Class signature'

     class sqlalchemy.types.BINARY.
     (‘sqlalchemy.types._Binary’)

 -- Class: sqlalchemy.types.BLOB (length=None)

     The SQL BLOB type.

     `Class signature'

     class sqlalchemy.types.BLOB. (see
     sqlalchemy.types.LargeBinary)

 -- Class: sqlalchemy.types.BOOLEAN (create_constraint=False, name=None,
          _create_events=True)

     The SQL BOOLEAN type.

     `Class signature'

     class sqlalchemy.types.BOOLEAN. (see
     sqlalchemy.types.Boolean)

 -- Class: sqlalchemy.types.CHAR (length=None, collation=None,
          convert_unicode=False, unicode_error=None,
          _warn_on_bytestring=False, _expect_unicode=False)

     The SQL CHAR type.

     `Class signature'

     class sqlalchemy.types.CHAR. (see
     sqlalchemy.types.String)

 -- Class: sqlalchemy.types.CLOB (length=None, collation=None,
          convert_unicode=False, unicode_error=None,
          _warn_on_bytestring=False, _expect_unicode=False)

     The CLOB type.

     This type is found in Oracle and Informix.

     `Class signature'

     class sqlalchemy.types.CLOB. (see
     sqlalchemy.types.Text)

 -- Class: sqlalchemy.types.DATE

     The SQL DATE type.

     `Class signature'

     class sqlalchemy.types.DATE. (see
     sqlalchemy.types.Date)

 -- Class: sqlalchemy.types.DATETIME (timezone=False)

     The SQL DATETIME type.

     `Class signature'

     class sqlalchemy.types.DATETIME. (see
     sqlalchemy.types.DateTime)

 -- Class: sqlalchemy.types.DECIMAL (precision=None, scale=None,
          decimal_return_scale=None, asdecimal=True)

     The SQL DECIMAL type.

     `Class signature'

     class sqlalchemy.types.DECIMAL. (see
     sqlalchemy.types.Numeric)

 -- Class: sqlalchemy.types.FLOAT (precision=None, asdecimal=False,
          decimal_return_scale=None)

     The SQL FLOAT type.

     `Class signature'

     class sqlalchemy.types.FLOAT. (see
     sqlalchemy.types.Float)

 -- Attribute: sqlalchemy.types...sqlalchemy.types.INT

     alias of ‘sqlalchemy.sql.sqltypes.INTEGER’

 -- Class: sqlalchemy.types.JSON (none_as_null=False)

     Represent a SQL JSON type.

          Note: JSON is provided as a facade for
          vendor-specific JSON types.  Since it supports JSON SQL
          operations, it only works on backends that have an actual JSON
          type, currently:

             * PostgreSQL - see
               sqlalchemy.dialects.postgresql.JSON and
               sqlalchemy.dialects.postgresql.JSONB for
               backend-specific notes

             * MySQL - see sqlalchemy.dialects.mysql.JSON.
               for backend-specific notes

             * SQLite as of version 3.9 - see
               sqlalchemy.dialects.sqlite.JSON for
               backend-specific notes

             * Microsoft SQL Server 2016 and later - see
               sqlalchemy.dialects.mssql.JSON for
               backend-specific notes

     JSON is part of the Core in support of the growing
     popularity of native JSON datatypes.

     The JSON type stores arbitrary JSON format data, e.g.:

          data_table = Table('data_table', metadata,
              Column('id', Integer, primary_key=True),
              Column('data', JSON)
          )

          with engine.connect() as conn:
              conn.execute(
                  data_table.insert(),
                  data = {"key1": "value1", "key2": "value2"}
              )

     `JSON-Specific Expression Operators'

     The JSON datatype provides these additional SQL
     operations:

        * Keyed index operations:

               data_table.c.data['some key']

        * Integer index operations:

               data_table.c.data[3]

        * Path index operations:

               data_table.c.data[('key_1', 'key_2', 5, ..., 'key_n')]

        * Data casters for specific JSON element types, subsequent to an
          index or path operation being invoked:

               data_table.c.data["some key"].as_integer()

          New in version 1.3.11.

     Additional operations may be available from the dialect-specific
     versions of JSON, such as
     sqlalchemy.dialects.postgresql.JSON and
     sqlalchemy.dialects.postgresql.JSONB which both offer
     additional PostgreSQL-specific operations.

     `Casting JSON Elements to Other Types'

     Index operations, i.e.  those invoked by calling upon the
     expression using the Python bracket operator as in
     ‘some_column['some key']’, return an expression object whose type
     defaults to JSON by default, so that further
     JSON-oriented instructions may be called upon the result type.
     However, it is likely more common that an index operation is
     expected to return a specific scalar element, such as a string or
     integer.  In order to provide access to these elements in a
     backend-agnostic way, a series of data casters are provided:

        * Comparator.as_string(). - return the element as a
          string

        * Comparator.as_boolean(). - return the element as a
          boolean

        * Comparator.as_float(). - return the element as a
          float

        * Comparator.as_integer(). - return the element as
          an integer

     These data casters are implemented by supporting dialects in order
     to assure that comparisons to the above types will work as
     expected, such as:

          # integer comparison
          data_table.c.data["some_integer_key"].as_integer() == 5

          # boolean comparison
          data_table.c.data["some_boolean"].as_boolean() == True

     New in version 1.3.11: Added type-specific casters for the basic
     JSON data element types.

          Note: The data caster functions are new in version 1.3.11, and
          supersede the previous documented approaches of using CAST;
          for reference, this looked like:

               from sqlalchemy import cast, type_coerce
               from sqlalchemy import String, JSON
               cast(
                   data_table.c.data['some_key'], String
               ) == type_coerce(55, JSON)

          The above case now works directly as:

               data_table.c.data['some_key'].as_integer() == 5

          For details on the previous comparison approach within the
          1.3.x series, see the documentation for SQLAlchemy 1.2 or the
          included HTML files in the doc/ directory of the version’s
          distribution.

     `Detecting Changes in JSON columns when using the ORM'

     The JSON type, when used with the SQLAlchemy ORM, does
     not detect in-place mutations to the structure.  In order to detect
     these, the sqlalchemy.ext.mutable extension must be
     used.  This extension will allow “in-place” changes to the
     datastructure to produce events which will be detected by the unit
     of work.  See the example at HSTORE for a simple
     example involving a dictionary.

     `Support for JSON null vs.  SQL NULL'

     When working with NULL values, the JSON type recommends
     the use of two specific constants in order to differentiate between
     a column that evaluates to SQL NULL, e.g.  no value, vs.  the
     JSON-encoded string of ‘"null"’.  To insert or select against a
     value that is SQL NULL, use the constant null():

          from sqlalchemy import null
          conn.execute(table.insert(), json_value=null())

     To insert or select against a value that is JSON ‘"null"’, use the
     constant JSON.NULL:

          conn.execute(table.insert(), json_value=JSON.NULL)

     The JSON type supports a flag JSON.none_as_null
     which when set to True will result in the Python constant
     ‘None’ evaluating to the value of SQL NULL, and when set to False
     results in the Python constant ‘None’ evaluating to the value of
     JSON ‘"null"’.  The Python value ‘None’ may be used in conjunction
     with either JSON.NULL and null() in order
     to indicate NULL values, but care must be taken as to the value of
     the JSON.none_as_null in these cases.

     `Customizing the JSON Serializer'

     The JSON serializer and deserializer used by JSON
     defaults to Python’s ‘json.dumps’ and ‘json.loads’ functions; in
     the case of the psycopg2 dialect, psycopg2 may be using its own
     custom loader function.

     In order to affect the serializer / deserializer, they are
     currently configurable at the create_engine() level via
     the create_engine.json_serializer and
     create_engine.json_deserializer parameters.  For example, to
     turn off ‘ensure_ascii’:

          engine = create_engine(
              "sqlite://",
              json_serializer=lambda obj: json.dumps(obj, ensure_ascii=False))

     Changed in version 1.3.7: SQLite dialect’s ‘json_serializer’ and
     ‘json_deserializer’ parameters renamed from ‘_json_serializer’ and
     ‘_json_deserializer’.

     See also
     ........

     See sqlalchemy.dialects.postgresql.JSON.

     See sqlalchemy.dialects.postgresql.JSONB.

     See sqlalchemy.dialects.mysql.JSON.

     See sqlalchemy.dialects.sqlite.JSON.

     New in version 1.1.

     `Class signature'

     class sqlalchemy.types.JSON. (see
     sqlalchemy.types.Indexable, sqlalchemy.types.TypeEngine)

      -- Class: Comparator (expr)

          Define comparison operations for JSON.

          `Class signature'

          class sqlalchemy.types.JSON.Comparator.
          (‘sqlalchemy.types.Comparator’, ‘sqlalchemy.types.Comparator’)

           -- Method: sqlalchemy.types.JSON.Comparator..
                    as_boolean ()

               Cast an indexed value as boolean.

               e.g.:

                    stmt = select(
                        mytable.c.json_column['some_data'].as_boolean()
                    ).where(
                        mytable.c.json_column['some_data'].as_boolean() == True
                    )

               New in version 1.3.11.

           -- Method: sqlalchemy.types.JSON.Comparator..
                    as_float ()

               Cast an indexed value as float.

               e.g.:

                    stmt = select(
                        mytable.c.json_column['some_data'].as_float()
                    ).where(
                        mytable.c.json_column['some_data'].as_float() == 29.75
                    )

               New in version 1.3.11.

           -- Method: sqlalchemy.types.JSON.Comparator..
                    as_integer ()

               Cast an indexed value as integer.

               e.g.:

                    stmt = select(
                        mytable.c.json_column['some_data'].as_integer()
                    ).where(
                        mytable.c.json_column['some_data'].as_integer() == 5
                    )

               New in version 1.3.11.

           -- Method: sqlalchemy.types.JSON.Comparator..
                    as_json ()

               Cast an indexed value as JSON.

               e.g.:

                    stmt = select(mytable.c.json_column['some_data'].as_json())

               This is typically the default behavior of indexed
               elements in any case.

               Note that comparison of full JSON structures may not be
               supported by all backends.

               New in version 1.3.11.

           -- Method: sqlalchemy.types.JSON.Comparator..
                    as_numeric (precision, scale, asdecimal=True)

               Cast an indexed value as numeric/decimal.

               e.g.:

                    stmt = select(
                        mytable.c.json_column['some_data'].as_numeric(10, 6)
                    ).where(
                        mytable.c.
                        json_column['some_data'].as_numeric(10, 6) == 29.75
                    )

               New in version 1.4.0b2.

           -- Method: sqlalchemy.types.JSON.Comparator..
                    as_string ()

               Cast an indexed value as string.

               e.g.:

                    stmt = select(
                        mytable.c.json_column['some_data'].as_string()
                    ).where(
                        mytable.c.json_column['some_data'].as_string() ==
                        'some string'
                    )

               New in version 1.3.11.

      -- Class: JSONElementType

          Common function for index / path elements in a JSON
          expression.

          `Class signature'

          class sqlalchemy.types.JSON.JSONElementType.
          (see sqlalchemy.types.TypeEngine)

           -- Method: sqlalchemy.types.JSON.JSONElementType..
                    bind_processor (dialect)

               Return a conversion function for processing bind values.

               Returns a callable which will receive a bind parameter
               value as the sole positional argument and will return a
               value to send to the DB-API.

               If processing is not necessary, the method should return
               ‘None’.

               Parameters: ‘dialect’ – Dialect instance in use.

           -- Method: sqlalchemy.types.JSON.JSONElementType..
                    literal_processor (dialect)

               Return a conversion function for processing literal
               values that are to be rendered directly without using
               binds.

               This function is used when the compiler makes use of the
               “literal_binds” flag, typically used in DDL generation as
               well as in certain scenarios where backends don’t accept
               bound parameters.

               New in version 0.9.0.

           -- Method: sqlalchemy.types.JSON.JSONElementType..
                    string_bind_processor (dialect)

           -- Method: sqlalchemy.types.JSON.JSONElementType..
                    string_literal_processor (dialect)

      -- Class: JSONIndexType

          Placeholder for the datatype of a JSON index value.

          This allows execution-time processing of JSON index values for
          special syntaxes.

          `Class signature'

          class sqlalchemy.types.JSON.JSONIndexType.
          (‘sqlalchemy.types.JSONElementType’)

      -- Class: JSONIntIndexType

          Placeholder for the datatype of a JSON index value.

          This allows execution-time processing of JSON index values for
          special syntaxes.

          `Class signature'

          class sqlalchemy.types.JSON.JSONIntIndexType.
          (‘sqlalchemy.types.JSONIndexType’)

      -- Class: JSONPathType

          Placeholder type for JSON path operations.

          This allows execution-time processing of a path-based index
          value into a specific SQL syntax.

          `Class signature'

          class sqlalchemy.types.JSON.JSONPathType.
          (‘sqlalchemy.types.JSONElementType’)

      -- Class: JSONStrIndexType

          Placeholder for the datatype of a JSON index value.

          This allows execution-time processing of JSON index values for
          special syntaxes.

          `Class signature'

          class sqlalchemy.types.JSON.JSONStrIndexType.
          (‘sqlalchemy.types.JSONIndexType’)

      -- Attribute: sqlalchemy.types.JSON..NULL =
               symbol('JSON_NULL')

          Describe the json value of NULL.

          This value is used to force the JSON value of ‘"null"’ to be
          used as the value.  A value of Python ‘None’ will be
          recognized either as SQL NULL or JSON ‘"null"’, based on the
          setting of the JSON.none_as_null flag; the
          JSON.NULL constant can be used to always resolve to
          JSON ‘"null"’ regardless of this setting.  This is in contrast
          to the null() construct, which always resolves to
          SQL NULL. E.g.:

               from sqlalchemy import null
               from sqlalchemy.dialects.postgresql import JSON

               # will *always* insert SQL NULL
               obj1 = MyObject(json_value=null())

               # will *always* insert JSON string "null"
               obj2 = MyObject(json_value=JSON.NULL)

               session.add_all([obj1, obj2])
               session.commit()

          In order to set JSON NULL as a default value for a column, the
          most transparent method is to use text():

               Table(
                   'my_table', metadata,
                   Column('json_data', JSON, default=text("'null'"))
               )

          While it is possible to use JSON.NULL in this
          context, the JSON.NULL value will be returned as
          the value of the column, which in the context of the ORM or
          other repurposing of the default value, may not be desirable.
          Using a SQL expression means the value will be re-fetched from
          the database within the context of retrieving generated
          defaults.

      -- Method: sqlalchemy.types.JSON..__init__
               (none_as_null=False)

          Construct a JSON type.

          Parameters: ‘none_as_null=False’ – if True, persist the value
          ‘None’ as a SQL NULL value, not the JSON encoding of ‘null’.
          Note that when this flag is False, the null()
          construct can still be used to persist a NULL value:

               from sqlalchemy import null
               conn.execute(table.insert(), data=null())

               Note: JSON.none_as_null does `not' apply to
               the values passed to Column.default and
               Column.server_default; a value of ‘None’ passed for
               these parameters means “no default present”.

          See also
          ........

          See JSON.NULL.

      -- Method: sqlalchemy.types.JSON..bind_processor
               (dialect)

          Return a conversion function for processing bind values.

          Returns a callable which will receive a bind parameter value
          as the sole positional argument and will return a value to
          send to the DB-API.

          If processing is not necessary, the method should return
          ‘None’.

          Parameters: ‘dialect’ – Dialect instance in use.

      -- Attribute: sqlalchemy.types.JSON..comparator_factory

          alias of ‘sqlalchemy.sql.sqltypes.JSON.Comparator’

      -- Attribute: sqlalchemy.types.JSON..python_type

      -- Method: sqlalchemy.types.JSON..result_processor
               (dialect, coltype)

          Return a conversion function for processing result row values.

          Returns a callable which will receive a result row column
          value as the sole positional argument and will return a value
          to return to the user.

          If processing is not necessary, the method should return
          ‘None’.

          Parameters:

             * ‘dialect’ – Dialect instance in use.

             * ‘coltype’ – DBAPI coltype argument received in
               cursor.description.

      -- Attribute: sqlalchemy.types.JSON..
               should_evaluate_none

          If True, the Python constant ‘None’ is considered to be
          handled explicitly by this type.

          The ORM uses this flag to indicate that a positive value of
          ‘None’ is passed to the column in an INSERT statement, rather
          than omitting the column from the INSERT statement which has
          the effect of firing off column-level defaults.  It also
          allows types which have special behavior for Python None, such
          as a JSON type, to indicate that they’d like to handle the
          None value explicitly.

          To set this flag on an existing type, use the
          TypeEngine.evaluates_none() method.

          See also
          ........

          See TypeEngine.evaluates_none().

          New in version 1.1.

 -- Class: sqlalchemy.types.INTEGER

     The SQL INT or INTEGER type.

     `Class signature'

     class sqlalchemy.types.INTEGER. (see
     sqlalchemy.types.Integer)

 -- Class: sqlalchemy.types.NCHAR (length=None, **kwargs)

     The SQL NCHAR type.

     `Class signature'

     class sqlalchemy.types.NCHAR. (see
     sqlalchemy.types.Unicode)

 -- Class: sqlalchemy.types.NVARCHAR (length=None, **kwargs)

     The SQL NVARCHAR type.

     `Class signature'

     class sqlalchemy.types.NVARCHAR. (see
     sqlalchemy.types.Unicode)

 -- Class: sqlalchemy.types.NUMERIC (precision=None, scale=None,
          decimal_return_scale=None, asdecimal=True)

     The SQL NUMERIC type.

     `Class signature'

     class sqlalchemy.types.NUMERIC. (see
     sqlalchemy.types.Numeric)

 -- Class: sqlalchemy.types.REAL (precision=None, asdecimal=False,
          decimal_return_scale=None)

     The SQL REAL type.

     `Class signature'

     class sqlalchemy.types.REAL. (see
     sqlalchemy.types.Float)

 -- Class: sqlalchemy.types.SMALLINT

     The SQL SMALLINT type.

     `Class signature'

     class sqlalchemy.types.SMALLINT. (see
     sqlalchemy.types.SmallInteger)

 -- Class: sqlalchemy.types.TEXT (length=None, collation=None,
          convert_unicode=False, unicode_error=None,
          _warn_on_bytestring=False, _expect_unicode=False)

     The SQL TEXT type.

     `Class signature'

     class sqlalchemy.types.TEXT. (see
     sqlalchemy.types.Text)

 -- Class: sqlalchemy.types.TIME (timezone=False)

     The SQL TIME type.

     `Class signature'

     class sqlalchemy.types.TIME. (see
     sqlalchemy.types.Time)

 -- Class: sqlalchemy.types.TIMESTAMP (timezone=False)

     The SQL TIMESTAMP type.

     TIMESTAMP datatypes have support for timezone storage
     on some backends, such as PostgreSQL and Oracle.  Use the
     ‘TIMESTAMP.timezone’ argument in order to enable “TIMESTAMP WITH
     TIMEZONE” for these backends.

     `Class signature'

     class sqlalchemy.types.TIMESTAMP. (see
     sqlalchemy.types.DateTime)

      -- Method: sqlalchemy.types.TIMESTAMP..__init__
               (timezone=False)

          Construct a new TIMESTAMP.

          Parameters: ‘timezone’ – boolean.  Indicates that the
          TIMESTAMP type should enable timezone support, if available on
          the target database.  On a per-dialect basis is similar to
          “TIMESTAMP WITH TIMEZONE”.  If the target database does not
          support timezones, this flag is ignored.

      -- Method: sqlalchemy.types.TIMESTAMP..get_dbapi_type
               (dbapi)

          Return the corresponding type object from the underlying
          DB-API, if any.

          This can be useful for calling ‘setinputsizes()’, for example.

 -- Class: sqlalchemy.types.VARBINARY (length=None)

     The SQL VARBINARY type.

     `Class signature'

     class sqlalchemy.types.VARBINARY.
     (‘sqlalchemy.types._Binary’)

 -- Class: sqlalchemy.types.VARCHAR (length=None, collation=None,
          convert_unicode=False, unicode_error=None,
          _warn_on_bytestring=False, _expect_unicode=False)

     The SQL VARCHAR type.

     `Class signature'

     class sqlalchemy.types.VARCHAR. (see
     sqlalchemy.types.String)

4.4.1.3 Vendor-Specific Types
.............................

Database-specific types are also available for import from each
database’s dialect module.  See the Dialects reference for
the database you’re interested in.

For example, MySQL has a ‘BIGINT’ type and PostgreSQL has an ‘INET’
type.  To use these, import them from the module explicitly:

     from sqlalchemy.dialects import mysql

     table = Table('foo', metadata,
         Column('id', mysql.BIGINT),
         Column('enumerates', mysql.ENUM('a', 'b', 'c'))
     )

Or some PostgreSQL types:

     from sqlalchemy.dialects import postgresql

     table = Table('foo', metadata,
         Column('ipaddress', postgresql.INET),
         Column('elements', postgresql.ARRAY(String))
     )

Each dialect provides the full set of typenames supported by that
backend within its ‘__all__’ collection, so that a simple ‘import *’ or
similar will import all supported types as implemented for that backend:

     from sqlalchemy.dialects.postgresql import *

     t = Table('mytable', metadata,
                Column('id', INTEGER, primary_key=True),
                Column('name', VARCHAR(300)),
                Column('inetaddr', INET)
     )

Where above, the INTEGER and VARCHAR types are ultimately from
sqlalchemy.types, and INET is specific to the PostgreSQL dialect.

Some dialect level types have the same name as the SQL standard type,
but also provide additional arguments.  For example, MySQL implements
the full range of character and string types including additional
arguments such as ‘collation’ and ‘charset’:

     from sqlalchemy.dialects.mysql import VARCHAR, TEXT

     table = Table('foo', meta,
         Column('col1', VARCHAR(200, collation='binary')),
         Column('col2', TEXT(charset='latin1'))
     )

4.4.2 Custom Types
------------------

A variety of methods exist to redefine the behavior of existing types as
well as to provide new ones.

4.4.2.1 Overriding Type Compilation
...................................

A frequent need is to force the “string” version of a type, that is the
one rendered in a CREATE TABLE statement or other SQL function like
CAST, to be changed.  For example, an application may want to force the
rendering of ‘BINARY’ for all platforms except for one, in which is
wants ‘BLOB’ to be rendered.  Usage of an existing generic type, in this
case LargeBinary, is preferred for most use cases.  But to
control types more accurately, a compilation directive that is
per-dialect can be associated with any type:

     from sqlalchemy.ext.compiler import compiles
     from sqlalchemy.types import BINARY

     @compiles(BINARY, "sqlite")
     def compile_binary_sqlite(type_, compiler, **kw):
         return "BLOB"

The above code allows the usage of BINARY, which will
produce the string ‘BINARY’ against all backends except SQLite, in which
case it will produce ‘BLOB’.

See the section Changing Compilation of Types, a subsection
of Custom SQL Constructs and Compilation Extension, for
additional examples.

4.4.2.2 Augmenting Existing Types
.................................

The TypeDecorator allows the creation of custom types which
add bind-parameter and result-processing behavior to an existing type
object.  It is used when additional in-Python marshalling of data to
and/or from the database is required.

     Note: The bind- and result-processing of TypeDecorator
     is `in addition' to the processing already performed by the hosted
     type, which is customized by SQLAlchemy on a per-DBAPI basis to
     perform processing specific to that DBAPI. While it is possible to
     replace this handling for a given type through direct subclassing,
     it is never needed in practice and SQLAlchemy no longer supports
     this as a public use case.

ORM Tip
.......

The TypeDecorator can be used to provide a consistent means
of converting some type of value as it is passed into and out of the
database.  When using the ORM, a similar technique exists for converting
user data from arbitrary formats which is to use the validates()
decorator.  This technique may be more appropriate when data coming
into an ORM model needs to be normalized in some way that is specific to
the business case and isn’t as generic as a datatype.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See TypeDecorator.Allows the creation of types which add additional functionality to an existing type.

 -- Class: sqlalchemy.types.TypeDecorator (*args, **kwargs)

     Allows the creation of types which add additional functionality to
     an existing type.

     This method is preferred to direct subclassing of SQLAlchemy’s
     built-in types as it ensures that all required functionality of the
     underlying type is kept in place.

     Typical usage:

          import sqlalchemy.types as types

          class MyType(types.TypeDecorator):
              '''Prefixes Unicode values with "PREFIX:" on the way in and
              strips it off on the way out.
              '''

              impl = types.Unicode

              def process_bind_param(self, value, dialect):
                  return "PREFIX:" + value

              def process_result_value(self, value, dialect):
                  return value[7:]

              def copy(self, **kw):
                  return MyType(self.impl.length)

     The class-level ‘impl’ attribute is required, and can reference any
     TypeEngine class.  Alternatively, the
     load_dialect_impl() method can be used to provide different
     type classes based on the dialect given; in this case, the ‘impl’
     variable can reference ‘TypeEngine’ as a placeholder.

     Types that receive a Python type that isn’t similar to the ultimate
     type used may want to define the
     TypeDecorator.coerce_compared_value() method.  This is used
     to give the expression system a hint when coercing Python objects
     into bind parameters within expressions.  Consider this expression:

          mytable.c.somecol + datetime.date(2009, 5, 15)

     Above, if “somecol” is an ‘Integer’ variant, it makes sense that
     we’re doing date arithmetic, where above is usually interpreted by
     databases as adding a number of days to the given date.  The
     expression system does the right thing by not attempting to coerce
     the “date()” value into an integer-oriented bind parameter.

     However, in the case of ‘TypeDecorator’, we are usually changing an
     incoming Python type to something new - ‘TypeDecorator’ by default
     will “coerce” the non-typed side to be the same type as itself.
     Such as below, we define an “epoch” type that stores a date value
     as an integer:

          class MyEpochType(types.TypeDecorator):
              impl = types.Integer

              epoch = datetime.date(1970, 1, 1)

              def process_bind_param(self, value, dialect):
                  return (value - self.epoch).days

              def process_result_value(self, value, dialect):
                  return self.epoch + timedelta(days=value)

     Our expression of ‘somecol + date’ with the above type will coerce
     the “date” on the right side to also be treated as ‘MyEpochType’.

     This behavior can be overridden via the
     TypeDecorator.coerce_compared_value() method, which returns
     a type that should be used for the value of the expression.  Below
     we set it such that an integer value will be treated as an
     ‘Integer’, and any other value is assumed to be a date and will be
     treated as a ‘MyEpochType’:

          def coerce_compared_value(self, op, value):
              if isinstance(value, int):
                  return Integer()
              else:
                  return self

          Warning: Note that the `behavior of coerce_compared_value is
          not inherited by default from that of the base type'.  If the
          TypeDecorator is augmenting a type that requires
          special logic for certain types of operators, this method
          `must' be overridden.  A key example is when decorating the
          JSON and JSONB types; the default
          rules of TypeEngine.coerce_compared_value()
          should be used in order to deal with operators like index
          operations:

               class MyJsonType(TypeDecorator):
                   impl = postgresql.JSON

                   def coerce_compared_value(self, op, value):
                       return self.impl.coerce_compared_value(op, value)

          Without the above step, index operations such as
          ‘mycol['foo']’ will cause the index value ‘'foo'’ to be JSON
          encoded.

     `Class signature'

     class sqlalchemy.types.TypeDecorator.
     (‘sqlalchemy.sql.expression.SchemaEventTarget’, see
     sqlalchemy.types.TypeEngine)

      -- Class: Comparator (expr)

          A Comparator that is specific to
          TypeDecorator.

          User-defined TypeDecorator classes should not
          typically need to modify this.

          `Class signature'

          class sqlalchemy.types.TypeDecorator.Comparator.
          (‘sqlalchemy.types.Comparator’)

           -- Method: sqlalchemy.types.TypeDecorator.Comparator..
                    operate (op, *other, **kwargs)

               Operate on an argument.

               This is the lowest level of operation, raises
               ‘NotImplementedError’ by default.

               Overriding this on a subclass can allow common behavior
               to be applied to all operations.  For example, overriding
               ColumnOperators to apply ‘func.lower()’ to
               the left and right side:

                    class MyComparator(ColumnOperators):
                        def operate(self, op, other):
                            return op(func.lower(self), func.lower(other))

               Parameters:

                  * ‘op’ – Operator callable.

                  * ‘*other’ – the ‘other’ side of the operation.  Will
                    be a single scalar for most operations.

                  * ‘**kwargs’ – modifiers.  These may be passed by
                    special operators such as
                    ‘ColumnOperators.contains()’.

           -- Method: sqlalchemy.types.TypeDecorator.Comparator..
                    reverse_operate (op, other, **kwargs)

               Reverse operate on an argument.

               Usage is the same as operate().

      -- Method: sqlalchemy.types.TypeDecorator..__init__
               (*args, **kwargs)

          Construct a TypeDecorator.

          Arguments sent here are passed to the constructor of the class
          assigned to the ‘impl’ class level attribute, assuming the
          ‘impl’ is a callable, and the resulting object is assigned to
          the ‘self.impl’ instance attribute (thus overriding the class
          attribute of the same name).

          If the class level ‘impl’ is not a callable (the unusual
          case), it will be assigned to the same instance attribute
          ‘as-is’, ignoring those arguments passed to the constructor.

          Subclasses can override this to customize the generation of
          ‘self.impl’ entirely.

      -- Method: sqlalchemy.types.TypeDecorator..
               bind_expression (bindparam)

          Given a bind value (i.e.  a BindParameter
          instance), return a SQL expression in its place.

          This is typically a SQL function that wraps the existing bound
          parameter within the statement.  It is used for special data
          types that require literals being wrapped in some special
          database function in order to coerce an application-level
          value into a database-specific format.  It is the SQL analogue
          of the TypeEngine.bind_processor() method.

          The method is evaluated at statement compile time, as opposed
          to statement construction time.

          Note that this method, when implemented, should always return
          the exact same structure, without any conditional logic, as it
          may be used in an executemany() call against an arbitrary
          number of bound parameter sets.

          See also
          ........

          See Applying SQL-level Bind/Result Processing.

      -- Method: sqlalchemy.types.TypeDecorator..
               bind_processor (dialect)

          Provide a bound value processing function for the given
          Dialect.

          This is the method that fulfills the TypeEngine
          contract for bound value conversion.  TypeDecorator
          will wrap a user-defined implementation of
          process_bind_param() here.

          User-defined code can override this method directly, though
          its likely best to use process_bind_param() so
          that the processing provided by ‘self.impl’ is maintained.

          Parameters: ‘dialect’ – Dialect instance in use.

          This method is the reverse counterpart to the
          result_processor() method of this class.

      -- Method: sqlalchemy.types.TypeDecorator..
               coerce_compared_value (op, value)

          Suggest a type for a ‘coerced’ Python value in an expression.

          By default, returns self.  This method is called by the
          expression system when an object using this type is on the
          left or right side of an expression against a plain Python
          object which does not yet have a SQLAlchemy type assigned:

               expr = table.c.somecolumn + 35

          Where above, if ‘somecolumn’ uses this type, this method will
          be called with the value ‘operator.add’ and ‘35’.  The return
          value is whatever SQLAlchemy type should be used for ‘35’ for
          this particular operation.

      -- Attribute: sqlalchemy.types.TypeDecorator..
               coerce_to_is_types = (<class 'NoneType'>,)

          Specify those Python types which should be coerced at the
          expression level to “IS <constant>” when compared using ‘==’
          (and same for ‘IS NOT’ in conjunction with ‘!=’).

          For most SQLAlchemy types, this includes ‘NoneType’, as well
          as ‘bool’.

          TypeDecorator modifies this list to only include
          ‘NoneType’, as typedecorator implementations that deal with
          boolean types are common.

          Custom TypeDecorator classes can override this
          attribute to return an empty tuple, in which case no values
          will be coerced to constants.

      -- Method: sqlalchemy.types.TypeDecorator..
               column_expression (column)

          Given a SELECT column expression, return a wrapping SQL
          expression.

          This is typically a SQL function that wraps a column
          expression as rendered in the columns clause of a SELECT
          statement.  It is used for special data types that require
          columns to be wrapped in some special database function in
          order to coerce the value before being sent back to the
          application.  It is the SQL analogue of the
          TypeEngine.result_processor() method.

          The method is evaluated at statement compile time, as opposed
          to statement construction time.

          See also
          ........

          See Applying SQL-level Bind/Result Processing.

      -- Attribute: sqlalchemy.types.TypeDecorator..
               comparator_factory

          A Comparator class which will apply to operations
          performed by owning ColumnElement objects.

          The comparator_factory attribute is a hook
          consulted by the core expression system when column and SQL
          expression operations are performed.  When a Comparator
          class is associated with this attribute, it allows
          custom re-definition of all existing operators, as well as
          definition of new operators.  Existing operators include those
          provided by Python operator overloading such as
          ‘ColumnOperators.__add__()’ and ‘ColumnOperators.__eq__()’,
          those provided as standard attributes of ‘ColumnOperators’
          such as ‘ColumnOperators.like()’ and ‘ColumnOperators.in_()’.

          Rudimentary usage of this hook is allowed through simple
          subclassing of existing types, or alternatively by using
          TypeDecorator.  See the documentation section
          Redefining and Creating New Operators for examples.

      -- Method: sqlalchemy.types.TypeDecorator..
               compare_values (x, y)

          Given two values, compare them for equality.

          By default this calls upon TypeEngine.compare_values()
          of the underlying “impl”, which in turn usually uses the
          Python equals operator ‘==’.

          This function is used by the ORM to compare an original-loaded
          value with an intercepted “changed” value, to determine if a
          net change has occurred.

      -- Method: sqlalchemy.types.TypeDecorator..copy (**kw)

          Produce a copy of this TypeDecorator instance.

          This is a shallow copy and is provided to fulfill part of the
          TypeEngine contract.  It usually does not need to
          be overridden unless the user-defined TypeDecorator
          has local state that should be deep-copied.

      -- Method: sqlalchemy.types.TypeDecorator..
               get_dbapi_type (dbapi)

          Return the DBAPI type object represented by this
          TypeDecorator.

          By default this calls upon TypeEngine.get_dbapi_type()
          of the underlying “impl”.

      -- Method: sqlalchemy.types.TypeDecorator..
               literal_processor (dialect)

          Provide a literal processing function for the given
          Dialect.

          Subclasses here will typically override
          TypeDecorator.process_literal_param() instead of this
          method directly.

          By default, this method makes use of
          TypeDecorator.process_bind_param() if that method is
          implemented, where
          TypeDecorator.process_literal_param() is not.  The
          rationale here is that TypeDecorator typically
          deals with Python conversions of data that are above the layer
          of database presentation.  With the value converted by
          TypeDecorator.process_bind_param(), the underlying type
          will then handle whether it needs to be presented to the DBAPI
          as a bound parameter or to the database as an inline SQL
          value.

          New in version 0.9.0.

      -- Method: sqlalchemy.types.TypeDecorator..
               load_dialect_impl (dialect)

          Return a TypeEngine object corresponding to a
          dialect.

          This is an end-user override hook that can be used to provide
          differing types depending on the given dialect.  It is used by
          the TypeDecorator implementation of
          type_engine() to help determine what type should
          ultimately be returned for a given TypeDecorator.

          By default returns ‘self.impl’.

      -- Method: sqlalchemy.types.TypeDecorator..
               process_bind_param (value, dialect)

          Receive a bound parameter value to be converted.

          Subclasses override this method to return the value that
          should be passed along to the underlying TypeEngine
          object, and from there to the DBAPI ‘execute()’ method.

          The operation could be anything desired to perform custom
          behavior, such as transforming or serializing data.  This
          could also be used as a hook for validating logic.

          This operation should be designed with the reverse operation
          in mind, which would be the process_result_value method of
          this class.

          Parameters:

             * ‘value’ – Data to operate upon, of any type expected by
               this method in the subclass.  Can be ‘None’.

             * ‘dialect’ – the Dialect in use.

      -- Method: sqlalchemy.types.TypeDecorator..
               process_literal_param (value, dialect)

          Receive a literal parameter value to be rendered inline within
          a statement.

          This method is used when the compiler renders a literal value
          without using binds, typically within DDL such as in the
          “server default” of a column or an expression within a CHECK
          constraint.

          The returned string will be rendered into the output string.

          New in version 0.9.0.

      -- Method: sqlalchemy.types.TypeDecorator..
               process_result_value (value, dialect)

          Receive a result-row column value to be converted.

          Subclasses should implement this method to operate on data
          fetched from the database.

          Subclasses override this method to return the value that
          should be passed back to the application, given a value that
          is already processed by the underlying TypeEngine
          object, originally from the DBAPI cursor method ‘fetchone()’
          or similar.

          The operation could be anything desired to perform custom
          behavior, such as transforming or serializing data.  This
          could also be used as a hook for validating logic.

          Parameters:

             * ‘value’ – Data to operate upon, of any type expected by
               this method in the subclass.  Can be ‘None’.

             * ‘dialect’ – the Dialect in use.

          This operation should be designed to be reversible by the
          “process_bind_param” method of this class.

      -- Method: sqlalchemy.types.TypeDecorator..
               result_processor (dialect, coltype)

          Provide a result value processing function for the given
          Dialect.

          This is the method that fulfills the TypeEngine
          contract for result value conversion.  TypeDecorator
          will wrap a user-defined implementation of
          process_result_value() here.

          User-defined code can override this method directly, though
          its likely best to use process_result_value() so
          that the processing provided by ‘self.impl’ is maintained.

          Parameters:

             * ‘dialect’ – Dialect instance in use.

             * ‘coltype’ – A SQLAlchemy data type

          This method is the reverse counterpart to the
          bind_processor() method of this class.

      -- Method: sqlalchemy.types.TypeDecorator..type_engine
               (dialect)

          Return a dialect-specific TypeEngine instance for
          this TypeDecorator.

          In most cases this returns a dialect-adapted form of the
          TypeEngine type represented by ‘self.impl’.  Makes usage
          of ‘dialect_impl()’.  Behavior can be customized here by
          overriding load_dialect_impl().

4.4.2.3 TypeDecorator Recipes
.............................

A few key TypeDecorator recipes follow.

4.4.2.4 Coercing Encoded Strings to Unicode
...........................................

A common source of confusion regarding the Unicode type is
that it is intended to deal `only' with Python ‘unicode’ objects on the
Python side, meaning values passed to it as bind parameters must be of
the form ‘u'some string'’ if using Python 2 and not 3.  The
encoding/decoding functions it performs are only to suit what the DBAPI
in use requires, and are primarily a private implementation detail.

The use case of a type that can safely receive Python bytestrings, that
is strings that contain non-ASCII characters and are not ‘u''’ objects
in Python 2, can be achieved using a TypeDecorator which
coerces as needed:

     from sqlalchemy.types import TypeDecorator, Unicode

     class CoerceUTF8(TypeDecorator):
         """Safely coerce Python bytestrings to Unicode
         before passing off to the database."""

         impl = Unicode

         def process_bind_param(self, value, dialect):
             if isinstance(value, str):
                 value = value.decode('utf-8')
             return value

4.4.2.5 Rounding Numerics
.........................

Some database connectors like those of SQL Server choke if a Decimal is
passed with too many decimal places.  Here’s a recipe that rounds them
down:

     from sqlalchemy.types import TypeDecorator, Numeric
     from decimal import Decimal

     class SafeNumeric(TypeDecorator):
         """Adds quantization to Numeric."""

         impl = Numeric

         def __init__(self, *arg, **kw):
             TypeDecorator.__init__(self, *arg, **kw)
             self.quantize_int = - self.impl.scale
             self.quantize = Decimal(10) ** self.quantize_int

         def process_bind_param(self, value, dialect):
             if isinstance(value, Decimal) and \
                 value.as_tuple()[2] < self.quantize_int:
                 value = value.quantize(self.quantize)
             return value

4.4.2.6 Store Timezone Aware Timestamps as Timezone Naive UTC
.............................................................

Timestamps in databases should always be stored in a timezone-agnostic
way.  For most databases, this means ensuring a timestamp is first in
the UTC timezone before it is stored, then storing it as timezone-naive
(that is, without any timezone associated with it; UTC is assumed to be
the “implicit” timezone).  Alternatively, database-specific types like
PostgreSQLs “TIMESTAMP WITH TIMEZONE” are often preferred for their
richer functionality; however, storing as plain UTC will work on all
databases and drivers.  When a timezone-intelligent database type is not
an option or is not preferred, the TypeDecorator can be
used to create a datatype that convert timezone aware timestamps into
timezone naive and back again.  Below, Python’s built-in
‘datetime.timezone.utc’ timezone is used to normalize and denormalize:

     import datetime

     class TZDateTime(TypeDecorator):
         impl = DateTime

         def process_bind_param(self, value, dialect):
             if value is not None:
                 if not value.tzinfo:
                     raise TypeError("tzinfo is required")
                 value = value.astimezone(datetime.timezone.utc).replace(
                     tzinfo=None
                 )
             return value

         def process_result_value(self, value, dialect):
             if value is not None:
                 value = value.replace(tzinfo=datetime.timezone.utc)
             return value

4.4.2.7 Backend-agnostic GUID Type
..................................

Receives and returns Python uuid() objects.  Uses the PG UUID type when
using PostgreSQL, CHAR(32) on other backends, storing them in
stringified hex format.  Can be modified to store binary in CHAR(16) if
desired:

     from sqlalchemy.types import TypeDecorator, CHAR
     from sqlalchemy.dialects.postgresql import UUID
     import uuid

     class GUID(TypeDecorator):
         """Platform-independent GUID type.

         Uses PostgreSQL's UUID type, otherwise uses
         CHAR(32), storing as stringified hex values.

         """
         impl = CHAR

         def load_dialect_impl(self, dialect):
             if dialect.name == 'postgresql':
                 return dialect.type_descriptor(UUID())
             else:
                 return dialect.type_descriptor(CHAR(32))

         def process_bind_param(self, value, dialect):
             if value is None:
                 return value
             elif dialect.name == 'postgresql':
                 return str(value)
             else:
                 if not isinstance(value, uuid.UUID):
                     return "%.32x" % uuid.UUID(value).int
                 else:
                     # hexstring
                     return "%.32x" % value.int

         def process_result_value(self, value, dialect):
             if value is None:
                 return value
             else:
                 if not isinstance(value, uuid.UUID):
                     value = uuid.UUID(value)
                 return value

4.4.2.8 Marshal JSON Strings
............................

This type uses ‘simplejson’ to marshal Python data structures to/from
JSON. Can be modified to use Python’s builtin json encoder:

     from sqlalchemy.types import TypeDecorator, VARCHAR
     import json

     class JSONEncodedDict(TypeDecorator):
         """Represents an immutable structure as a json-encoded string.

         Usage::

             JSONEncodedDict(255)

         """

         impl = VARCHAR

         def process_bind_param(self, value, dialect):
             if value is not None:
                 value = json.dumps(value)

             return value

         def process_result_value(self, value, dialect):
             if value is not None:
                 value = json.loads(value)
             return value

4.4.2.9 Adding Mutability
.........................

The ORM by default will not detect “mutability” on such a type as above
- meaning, in-place changes to values will not be detected and will not
be flushed.  Without further steps, you instead would need to replace
the existing value with a new one on each parent object to detect
changes:

     obj.json_value["key"] = "value"  # will *not* be detected by the ORM

     obj.json_value = {"key": "value"}  # *will* be detected by the ORM

The above limitation may be fine, as many applications may not require
that the values are ever mutated once created.  For those which do have
this requirement, support for mutability is best applied using the
‘sqlalchemy.ext.mutable’ extension.  For a dictionary-oriented JSON
structure, we can apply this as:

     json_type = MutableDict.as_mutable(JSONEncodedDict)

     class MyClass(Base):
         #  ...

         json_data = Column(json_type)

See also
........

See Mutation Tracking.

4.4.2.10 Dealing with Comparison Operations
...........................................

The default behavior of TypeDecorator is to coerce the
“right hand side” of any expression into the same type.  For a type like
JSON, this means that any operator used must make sense in terms of
JSON. For some cases, users may wish for the type to behave like JSON in
some circumstances, and as plain text in others.  One example is if one
wanted to handle the LIKE operator for the JSON type.  LIKE makes no
sense against a JSON structure, but it does make sense against the
underlying textual representation.  To get at this with a type like
‘JSONEncodedDict’, we need to `coerce' the column to a textual form
using cast() or type_coerce() before attempting
to use this operator:

     from sqlalchemy import type_coerce, String

     stmt = select(my_table).where(
         type_coerce(my_table.c.json_data, String).like('%foo%'))

TypeDecorator provides a built-in system for working up
type translations like these based on operators.  If we wanted to
frequently use the LIKE operator with our JSON object interpreted as a
string, we can build it into the type by overriding the
TypeDecorator.coerce_compared_value() method:

     from sqlalchemy.sql import operators
     from sqlalchemy import String

     class JSONEncodedDict(TypeDecorator):

         impl = VARCHAR

         def coerce_compared_value(self, op, value):
             if op in (operators.like_op, operators.not_like_op):
                 return String()
             else:
                 return self

         def process_bind_param(self, value, dialect):
             if value is not None:
                 value = json.dumps(value)

             return value

         def process_result_value(self, value, dialect):
             if value is not None:
                 value = json.loads(value)
             return value

Above is just one approach to handling an operator like “LIKE”.  Other
applications may wish to raise ‘NotImplementedError’ for operators that
have no meaning with a JSON object such as “LIKE”, rather than
automatically coercing to text.

4.4.2.11 Applying SQL-level Bind/Result Processing
..................................................

As seen in the section Augmenting Existing Types, SQLAlchemy
allows Python functions to be invoked both when parameters are sent to a
statement, as well as when result rows are loaded from the database, to
apply transformations to the values as they are sent to or from the
database.  It is also possible to define SQL-level transformations as
well.  The rationale here is when only the relational database contains
a particular series of functions that are necessary to coerce incoming
and outgoing data between an application and persistence format.
Examples include using database-defined encryption/decryption functions,
as well as stored procedures that handle geographic data.  The PostGIS
extension to PostgreSQL includes an extensive array of SQL functions
that are necessary for coercing data into particular formats.

Any TypeEngine, UserDefinedType or
TypeDecorator subclass can include implementations of
TypeEngine.bind_expression() and/or
TypeEngine.column_expression(), which when defined to return a
non-‘None’ value should return a ColumnElement expression to
be injected into the SQL statement, either surrounding bound parameters
or a column expression.  For example, to build a ‘Geometry’ type which
will apply the PostGIS function ‘ST_GeomFromText’ to all outgoing values
and the function ‘ST_AsText’ to all incoming data, we can create our own
subclass of UserDefinedType which provides these methods in
conjunction with func:

     from sqlalchemy import func
     from sqlalchemy.types import UserDefinedType

     class Geometry(UserDefinedType):
         def get_col_spec(self):
             return "GEOMETRY"

         def bind_expression(self, bindvalue):
             return func.ST_GeomFromText(bindvalue, type_=self)

         def column_expression(self, col):
             return func.ST_AsText(col, type_=self)

We can apply the ‘Geometry’ type into Table metadata and use
it in a select() construct:

     geometry = Table('geometry', metadata,
                   Column('geom_id', Integer, primary_key=True),
                   Column('geom_data', Geometry)
                 )

     print(select(geometry).where(
       geometry.c.geom_data == 'LINESTRING(189412 252431,189631 259122)'))

The resulting SQL embeds both functions as appropriate.  ‘ST_AsText’ is
applied to the columns clause so that the return value is run through
the function before passing into a result set, and ‘ST_GeomFromText’ is
run on the bound parameter so that the passed-in value is converted:

     SELECT geometry.geom_id, ST_AsText(geometry.geom_data) AS geom_data_1
     FROM geometry
     WHERE geometry.geom_data = ST_GeomFromText(:geom_data_2)

The TypeEngine.column_expression() method interacts with
the mechanics of the compiler such that the SQL expression does not
interfere with the labeling of the wrapped expression.  Such as, if we
rendered a select() against a label() of our
expression, the string label is moved to the outside of the wrapped
expression:

     print(select(geometry.c.geom_data.label('my_data')))

Output:

     SELECT ST_AsText(geometry.geom_data) AS my_data
     FROM geometry

Another example is we decorate BYTEA to provide a
‘PGPString’, which will make use of the PostgreSQL ‘pgcrypto’ extension
to encrypt/decrypt values transparently:

     from sqlalchemy import create_engine, String, select, func, \
             MetaData, Table, Column, type_coerce, TypeDecorator

     from sqlalchemy.dialects.postgresql import BYTEA

     class PGPString(TypeDecorator):
         impl = BYTEA

         def __init__(self, passphrase):
             super(PGPString, self).__init__()
             self.passphrase = passphrase

         def bind_expression(self, bindvalue):
             # convert the bind's type from PGPString to
             # String, so that it's passed to psycopg2 as is without
             # a dbapi.Binary wrapper
             bindvalue = type_coerce(bindvalue, String)
             return func.pgp_sym_encrypt(bindvalue, self.passphrase)

         def column_expression(self, col):
             return func.pgp_sym_decrypt(col, self.passphrase)

     metadata = MetaData()
     message = Table('message', metadata,
                     Column('username', String(50)),
                     Column('message',
                         PGPString("this is my passphrase")),
                 )

     engine = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
     with engine.begin() as conn:
         metadata.create_all(conn)

         conn.execute(message.insert(), username="some user",
                                     message="this is my message")

         print(conn.scalar(
                 select(message.c.message).\
                     where(message.c.username == "some user")
             ))

The ‘pgp_sym_encrypt’ and ‘pgp_sym_decrypt’ functions are applied to the
INSERT and SELECT statements:

     INSERT INTO message (username, message)
       VALUES (%(username)s, pgp_sym_encrypt(%(message)s, %(pgp_sym_encrypt_1)s))
       {'username': 'some user', 'message': 'this is my message',
         'pgp_sym_encrypt_1': 'this is my passphrase'}

     SELECT pgp_sym_decrypt(message.message, %(pgp_sym_decrypt_1)s) AS message_1
       FROM message
       WHERE message.username = %(username_1)s
       {'pgp_sym_decrypt_1': 'this is my passphrase', 'username_1': 'some user'}

See also
........

See PostGIS Integration.

4.4.2.12 Redefining and Creating New Operators
..............................................

SQLAlchemy Core defines a fixed set of expression operators available to
all column expressions.  Some of these operations have the effect of
overloading Python’s built-in operators; examples of such operators
include ColumnOperators.__eq__(). (‘table.c.somecolumn ==
'foo'’), see ColumnOperators.__invert__(). (‘~table.c.flag’), and
ColumnOperators.__add__(). (‘table.c.x + table.c.y’).  Other
operators are exposed as explicit methods on column expressions, such as
ColumnOperators.in_(). (‘table.c.value.in_(['x', 'y'])’) and
ColumnOperators.like(). (‘table.c.value.like('%ed%')’).

The Core expression constructs in all cases consult the type of the
expression in order to determine the behavior of existing operators, as
well as to locate additional operators that aren’t part of the built-in
set.  The TypeEngine base class defines a root “comparison”
implementation Comparator, and many specific types provide
their own sub-implementations of this class.  User-defined
Comparator implementations can be built directly into a simple
subclass of a particular type in order to override or define new
operations.  Below, we create a Integer subclass which
overrides the ColumnOperators.__add__() operator:

     from sqlalchemy import Integer

     class MyInt(Integer):
         class comparator_factory(Integer.Comparator):
             def __add__(self, other):
                 return self.op("goofy")(other)

The above configuration creates a new class ‘MyInt’, which establishes
the TypeEngine.comparator_factory attribute as referring to
a new class, subclassing the Comparator class associated
with the Integer type.

Usage:

     >>> sometable = Table("sometable", metadata, Column("data", MyInt))
     >>> print(sometable.c.data + 5)
     sometable.data goofy :data_1

The implementation for ColumnOperators.__add__() is
consulted by an owning SQL expression, by instantiating the
Comparator with itself as the ‘expr’ attribute.  The mechanics of
the expression system are such that operations continue recursively
until an expression object produces a new SQL expression construct.
Above, we could just as well have said ‘self.expr.op("goofy")(other)’
instead of ‘self.op("goofy")(other)’.

When using Operators.op() for comparison operations that
return a boolean result, the Operators.op.is_comparison flag
should be set to ‘True’:

     class MyInt(Integer):
         class comparator_factory(Integer.Comparator):
             def is_frobnozzled(self, other):
                 return self.op("--is_frobnozzled->", is_comparison=True)(other)

New methods added to a Comparator are exposed on an owning
SQL expression using a ‘__getattr__’ scheme, which exposes methods added
to Comparator onto the owning ColumnElement.
For example, to add a ‘log()’ function to integers:

     from sqlalchemy import Integer, func

     class MyInt(Integer):
         class comparator_factory(Integer.Comparator):
             def log(self, other):
                 return func.log(self.expr, other)

Using the above type:

     >>> print(sometable.c.data.log(5))
     log(:log_1, :log_2)

Unary operations are also possible.  For example, to add an
implementation of the PostgreSQL factorial operator, we combine the
UnaryExpression construct along with a custom_op
to produce the factorial expression:

     from sqlalchemy import Integer
     from sqlalchemy.sql.expression import UnaryExpression
     from sqlalchemy.sql import operators

     class MyInteger(Integer):
         class comparator_factory(Integer.Comparator):
             def factorial(self):
                 return UnaryExpression(self.expr,
                             modifier=operators.custom_op("!"),
                             type_=MyInteger)

Using the above type:

     >>> from sqlalchemy.sql import column
     >>> print(column('x', MyInteger).factorial())
     x !

See also
........

See Operators.op().

See TypeEngine.comparator_factory.

4.4.2.13 Creating New Types
...........................

The UserDefinedType class is provided as a simple base
class for defining entirely new database types.  Use this to represent
native database types not known by SQLAlchemy.  If only Python
translation behavior is needed, use TypeDecorator instead.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See UserDefinedType.Base for user defined types.

 -- Class: sqlalchemy.types.UserDefinedType

     Base for user defined types.

     This should be the base of new types.  Note that for most cases,
     see TypeDecorator is probably more appropriate:

          import sqlalchemy.types as types

          class MyType(types.UserDefinedType):
              def __init__(self, precision = 8):
                  self.precision = precision

              def get_col_spec(self, **kw):
                  return "MYTYPE(%s)" % self.precision

              def bind_processor(self, dialect):
                  def process(value):
                      return value
                  return process

              def result_processor(self, dialect, coltype):
                  def process(value):
                      return value
                  return process

     Once the type is made, it’s immediately usable:

          table = Table('foo', meta,
              Column('id', Integer, primary_key=True),
              Column('data', MyType(16))
              )

     The ‘get_col_spec()’ method will in most cases receive a keyword
     argument ‘type_expression’ which refers to the owning expression of
     the type as being compiled, such as a Column or
     cast() construct.  This keyword is only sent if the method
     accepts keyword arguments (e.g.  ‘**kw’) in its argument signature;
     introspection is used to check for this in order to support legacy
     forms of this function.

     New in version 1.0.0: the owning expression is passed to the
     ‘get_col_spec()’ method via the keyword argument ‘type_expression’,
     if it receives ‘**kw’ in its signature.

     `Class signature'

     class sqlalchemy.types.UserDefinedType. (see
     sqlalchemy.types.TypeEngine)

      -- Method: sqlalchemy.types.UserDefinedType..
               coerce_compared_value (op, value)

          Suggest a type for a ‘coerced’ Python value in an expression.

          Default behavior for UserDefinedType is the same
          as that of TypeDecorator; by default it returns
          ‘self’, assuming the compared value should be coerced into the
          same type as this one.  See
          TypeDecorator.coerce_compared_value() for more detail.

4.4.2.14 Working with Custom Types and Reflection
.................................................

It is important to note that database types which are modified to have
additional in-Python behaviors, including types based on
TypeDecorator as well as other user-defined subclasses of
datatypes, do not have any representation within a database schema.
When using database the introspection features described at
Reflecting Database Objects, SQLAlchemy makes use of a fixed
mapping which links the datatype information reported by a database
server to a SQLAlchemy datatype object.  For example, if we look inside
of a PostgreSQL schema at the definition for a particular database
column, we might receive back the string ‘"VARCHAR"’.  SQLAlchemy’s
PostgreSQL dialect has a hardcoded mapping which links the string name
‘"VARCHAR"’ to the SQLAlchemy VARCHAR class, and that’s how
when we emit a statement like ‘Table('my_table', m,
autoload_with=engine)’, the Column object within it would
have an instance of VARCHAR present inside of it.

The implication of this is that if a Table object makes use
of type objects that don’t correspond directly to the database-native
type name, if we create a new Table object against a new
MetaData collection for this database table elsewhere using
reflection, it will not have this datatype.  For example:

     >>> from sqlalchemy import Table, Column, MetaData, create_engine, PickleType, Integer
     >>> metadata = MetaData()
     >>> my_table = Table("my_table", metadata, Column('id', Integer), Column("data", PickleType))
     >>> engine = create_engine("sqlite://", echo='debug')
     >>> my_table.create(engine)
     INFO sqlalchemy.engine.base.Engine
     CREATE TABLE my_table (
         id INTEGER,
         data BLOB
     )

Above, we made use of PickleType, which is a
TypeDecorator that works on top of the LargeBinary
datatype, which on SQLite corresponds to the database type ‘BLOB’.  In
the CREATE TABLE, we see that the ‘BLOB’ datatype is used.  The SQLite
database knows nothing about the PickleType we’ve used.

If we look at the datatype of ‘my_table.c.data.type’, as this is a
Python object that was created by us directly, it is PickleType:

     >>> my_table.c.data.type
     PickleType()

However, if we create another instance of Table using
reflection, the use of PickleType is not represented in the
SQLite database we’ve created; we instead get back BLOB:

     >>> metadata_two = MetaData()
     >>> my_reflected_table = Table("my_table", metadata_two, autoload_with=engine)
     INFO sqlalchemy.engine.base.Engine PRAGMA main.table_info("my_table")
     INFO sqlalchemy.engine.base.Engine ()
     DEBUG sqlalchemy.engine.base.Engine Col ('cid', 'name', 'type', 'notnull', 'dflt_value', 'pk')
     DEBUG sqlalchemy.engine.base.Engine Row (0, 'id', 'INTEGER', 0, None, 0)
     DEBUG sqlalchemy.engine.base.Engine Row (1, 'data', 'BLOB', 0, None, 0)

     >>> my_reflected_table.c.data.type
     BLOB()

Typically, when an application defines explicit Table
metadata with custom types, there is no need to use table reflection
because the necessary Table metadata is already present.
However, for the case where an application, or a combination of them,
need to make use of both explicit Table metadata which
includes custom, Python-level datatypes, as well as Table
objects which set up their Column objects as reflected from
the database, which nevertheless still need to exhibit the additional
Python behaviors of the custom datatypes, additional steps must be taken
to allow this.

The most straightforward is to override specific columns as described at
Overriding Reflected Columns.  In this technique, we simply
use reflection in combination with explicit Column objects
for those columns for which we want to use a custom or decorated
datatype:

     >>> metadata_three = MetaData()
     >>> my_reflected_table = Table("my_table", metadata_three, Column("data", PickleType), autoload_with=engine)

The ‘my_reflected_table’ object above is reflected, and will load the
definition of the “id” column from the SQLite database.  But for the
“data” column, we’ve overridden the reflected object with an explicit
Column definition that includes our desired in-Python
datatype, the PickleType.  The reflection process will leave
this Column object intact:

     >>> my_reflected_table.c.data.type
     PickleType()

A more elaborate way to convert from database-native type objects to
custom datatypes is to use the DDLEvents.column_reflect()
event handler.  If for example we knew that we wanted all BLOB
datatypes to in fact be PickleType, we could set up a
rule across the board:

     from sqlalchemy import BLOB
     from sqlalchemy import event
     from sqlalchemy import PickleType
     from sqlalchemy import Table

     @event.listens_for(Table, "column_reflect")
     def _setup_pickletype(inspector, table, column_info):
         if isinstance(column_info["type"], BLOB):
             column_info["type"] = PickleType()

When the above code is invoked `before' any table reflection occurs
(note also it should be invoked `only once' in the application, as it is
a global rule), upon reflecting any Table that includes a
column with a BLOB datatype, the resulting datatype will be
stored in the Column object as PickleType.

In practice, the above event-based approach would likely have additional
rules in order to affect only those columns where the datatype is
important, such as a lookup table of table names and possibly column
names, or other heuristics in order to accurately determine which
columns should be established with an in Python datatype.

4.4.3 Base Type API
-------------------

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See Concatenable.A mixin that marks a type as supporting ‘concatenation’, typically strings.

See Indexable.A mixin that marks a type as supporting indexing operations, such as array or JSON
               structures.

See NullType.An unknown type.

See TypeEngine.The ultimate base class for all SQL datatypes.

See Variant.A wrapping type that selects among a variety of implementations based on dialect in use.

 -- Class: sqlalchemy.types.TypeEngine

     The ultimate base class for all SQL datatypes.

     Common subclasses of TypeEngine include String,
     see Integer, and Boolean.

     For an overview of the SQLAlchemy typing system, see Column and Data Types.

     See also
     ........

     See Column and Data Types.

     `Class signature'

     class sqlalchemy.types.TypeEngine. (see
     sqlalchemy.sql.visitors.Traversible)

      -- Class: Comparator (expr)

          Base class for custom comparison operations defined at the
          type level.  See TypeEngine.comparator_factory.

          `Class signature'

          class sqlalchemy.types.TypeEngine.Comparator.
          (see sqlalchemy.sql.expression.ColumnOperators)

           -- Attribute: sqlalchemy.types.TypeEngine.Comparator..
                    default_comparator = None

           -- Method: sqlalchemy.types.TypeEngine.Comparator..
                    operate (op, *other, **kwargs)

               Operate on an argument.

               This is the lowest level of operation, raises
               ‘NotImplementedError’ by default.

               Overriding this on a subclass can allow common behavior
               to be applied to all operations.  For example, overriding
               ColumnOperators to apply ‘func.lower()’ to
               the left and right side:

                    class MyComparator(ColumnOperators):
                        def operate(self, op, other):
                            return op(func.lower(self), func.lower(other))

               Parameters:

                  * ‘op’ – Operator callable.

                  * ‘*other’ – the ‘other’ side of the operation.  Will
                    be a single scalar for most operations.

                  * ‘**kwargs’ – modifiers.  These may be passed by
                    special operators such as
                    ‘ColumnOperators.contains()’.

           -- Method: sqlalchemy.types.TypeEngine.Comparator..
                    reverse_operate (op, other, **kwargs)

               Reverse operate on an argument.

               Usage is the same as operate().

      -- Method: sqlalchemy.types.TypeEngine..adapt (cls,
               **kw)

          Produce an “adapted” form of this type, given an “impl” class
          to work with.

          This method is used internally to associate generic types with
          “implementation” types that are specific to a particular
          dialect.

      -- Method: sqlalchemy.types.TypeEngine..as_generic
               (allow_nulltype=False)

          Return an instance of the generic type corresponding to this
          type using heuristic rule.  The method may be overridden if
          this heuristic rule is not sufficient.

               >>> from sqlalchemy.dialects.mysql import INTEGER
               >>> INTEGER(display_width=4).as_generic()
               Integer()

               >>> from sqlalchemy.dialects.mysql import NVARCHAR
               >>> NVARCHAR(length=100).as_generic()
               Unicode(length=100)

          New in version 1.4.0b2.

          See also
          ........

          See Reflecting with Database-Agnostic Types. -
          describes the use of TypeEngine.as_generic() in
          conjunction with the ‘DDLEvents.column_reflect()’ event, which
          is its intended use.

      -- Method: sqlalchemy.types.TypeEngine..bind_expression
               (bindvalue)

          Given a bind value (i.e.  a BindParameter
          instance), return a SQL expression in its place.

          This is typically a SQL function that wraps the existing bound
          parameter within the statement.  It is used for special data
          types that require literals being wrapped in some special
          database function in order to coerce an application-level
          value into a database-specific format.  It is the SQL analogue
          of the TypeEngine.bind_processor() method.

          The method is evaluated at statement compile time, as opposed
          to statement construction time.

          Note that this method, when implemented, should always return
          the exact same structure, without any conditional logic, as it
          may be used in an executemany() call against an arbitrary
          number of bound parameter sets.

          See also
          ........

          See Applying SQL-level Bind/Result Processing.

      -- Method: sqlalchemy.types.TypeEngine..bind_processor
               (dialect)

          Return a conversion function for processing bind values.

          Returns a callable which will receive a bind parameter value
          as the sole positional argument and will return a value to
          send to the DB-API.

          If processing is not necessary, the method should return
          ‘None’.

          Parameters: ‘dialect’ – Dialect instance in use.

      -- Method: sqlalchemy.types.TypeEngine..
               coerce_compared_value (op, value)

          Suggest a type for a ‘coerced’ Python value in an expression.

          Given an operator and value, gives the type a chance to return
          a type which the value should be coerced into.

          The default behavior here is conservative; if the right-hand
          side is already coerced into a SQL type based on its Python
          type, it is usually left alone.

          End-user functionality extension here should generally be via
          TypeDecorator, which provides more liberal
          behavior in that it defaults to coercing the other side of the
          expression into this type, thus applying special Python
          conversions above and beyond those needed by the DBAPI to both
          ides.  It also provides the public method
          TypeDecorator.coerce_compared_value() which is intended
          for end-user customization of this behavior.

      -- Method: sqlalchemy.types.TypeEngine..
               column_expression (colexpr)

          Given a SELECT column expression, return a wrapping SQL
          expression.

          This is typically a SQL function that wraps a column
          expression as rendered in the columns clause of a SELECT
          statement.  It is used for special data types that require
          columns to be wrapped in some special database function in
          order to coerce the value before being sent back to the
          application.  It is the SQL analogue of the
          TypeEngine.result_processor() method.

          The method is evaluated at statement compile time, as opposed
          to statement construction time.

          See also
          ........

          See Applying SQL-level Bind/Result Processing.

      -- Attribute: sqlalchemy.types.TypeEngine..
               comparator_factory

          A Comparator class which will apply to operations
          performed by owning ColumnElement objects.

          The comparator_factory attribute is a hook
          consulted by the core expression system when column and SQL
          expression operations are performed.  When a Comparator
          class is associated with this attribute, it allows
          custom re-definition of all existing operators, as well as
          definition of new operators.  Existing operators include those
          provided by Python operator overloading such as
          ‘ColumnOperators.__add__()’ and ‘ColumnOperators.__eq__()’,
          those provided as standard attributes of ‘ColumnOperators’
          such as ‘ColumnOperators.like()’ and ‘ColumnOperators.in_()’.

          Rudimentary usage of this hook is allowed through simple
          subclassing of existing types, or alternatively by using
          TypeDecorator.  See the documentation section
          Redefining and Creating New Operators for examples.

          `Class signature'

          class sqlalchemy.types.TypeEngine.Comparator.
          (see sqlalchemy.sql.expression.ColumnOperators)

          alias of ‘sqlalchemy.sql.type_api.TypeEngine.Comparator’

      -- Method: sqlalchemy.types.TypeEngine..
               compare_against_backend (dialect, conn_type)

          Compare this type against the given backend type.

          This function is currently not implemented for SQLAlchemy
          types, and for all built in types will return ‘None’.
          However, it can be implemented by a user-defined type where it
          can be consumed by schema comparison tools such as Alembic
          autogenerate.

          A future release of SQLAlchemy will potentially implement this
          method for builtin types as well.

          The function should return True if this type is equivalent to
          the given type; the type is typically reflected from the
          database so should be database specific.  The dialect in use
          is also passed.  It can also return False to assert that the
          type is not equivalent.

          Parameters:

             * ‘dialect’ – a Dialect that is involved in
               the comparison.

             * ‘conn_type’ – the type object reflected from the backend.

          New in version 1.0.3.

      -- Method: sqlalchemy.types.TypeEngine..compare_values
               (x, y)

          Compare two values for equality.

      -- Method: sqlalchemy.types.TypeEngine..compile
               (dialect=None)

          Produce a string-compiled form of this TypeEngine.

          When called with no arguments, uses a “default” dialect to
          produce a string result.

          Parameters: ‘dialect’ – a Dialect instance.

      -- Method: sqlalchemy.types.TypeEngine..dialect_impl
               (dialect)

          Return a dialect-specific implementation for this
          TypeEngine.

      -- Method: sqlalchemy.types.TypeEngine..evaluates_none
               ()

          Return a copy of this type which has the
          should_evaluate_none flag set to True.

          E.g.:

               Table(
                   'some_table', metadata,
                   Column(
                       String(50).evaluates_none(),
                       nullable=True,
                       server_default='no value')
               )

          The ORM uses this flag to indicate that a positive value of
          ‘None’ is passed to the column in an INSERT statement, rather
          than omitting the column from the INSERT statement which has
          the effect of firing off column-level defaults.  It also
          allows for types which have special behavior associated with
          the Python None value to indicate that the value doesn’t
          necessarily translate into SQL NULL; a prime example of this
          is a JSON type which may wish to persist the JSON value
          ‘'null'’.

          In all cases, the actual NULL SQL value can be always be
          persisted in any column by using the null. SQL
          construct in an INSERT statement or associated with an
          ORM-mapped attribute.

               Note: The “evaluates none” flag does `not' apply to a
               value of ‘None’ passed to Column.default or
               Column.server_default; in these cases, ‘None’
               still means “no default”.

          New in version 1.1.

          See also
          ........

          See Forcing NULL on a column with a default. - in the
          ORM documentation

          See JSON.none_as_null. - PostgreSQL JSON interaction
          with this flag.

          See TypeEngine.should_evaluate_none. - class-level
          flag

      -- Method: sqlalchemy.types.TypeEngine..get_dbapi_type
               (dbapi)

          Return the corresponding type object from the underlying
          DB-API, if any.

          This can be useful for calling ‘setinputsizes()’, for example.

      -- Attribute: sqlalchemy.types.TypeEngine..hashable =
               True

          Flag, if False, means values from this type aren’t hashable.

          Used by the ORM when uniquing result lists.

      -- Method: sqlalchemy.types.TypeEngine..
               literal_processor (dialect)

          Return a conversion function for processing literal values
          that are to be rendered directly without using binds.

          This function is used when the compiler makes use of the
          “literal_binds” flag, typically used in DDL generation as well
          as in certain scenarios where backends don’t accept bound
          parameters.

          New in version 0.9.0.

      -- Attribute: sqlalchemy.types.TypeEngine..python_type

          Return the Python type object expected to be returned by
          instances of this type, if known.

          Basically, for those types which enforce a return type, or are
          known across the board to do such for all common DBAPIs (like
          ‘int’ for example), will return that type.

          If a return type is not defined, raises ‘NotImplementedError’.

          Note that any type also accommodates NULL in SQL which means
          you can also get back ‘None’ from any type in practice.

      -- Method: sqlalchemy.types.TypeEngine..
               result_processor (dialect, coltype)

          Return a conversion function for processing result row values.

          Returns a callable which will receive a result row column
          value as the sole positional argument and will return a value
          to return to the user.

          If processing is not necessary, the method should return
          ‘None’.

          Parameters:

             * ‘dialect’ – Dialect instance in use.

             * ‘coltype’ – DBAPI coltype argument received in
               cursor.description.

      -- Attribute: sqlalchemy.types.TypeEngine..
               should_evaluate_none = False

          If True, the Python constant ‘None’ is considered to be
          handled explicitly by this type.

          The ORM uses this flag to indicate that a positive value of
          ‘None’ is passed to the column in an INSERT statement, rather
          than omitting the column from the INSERT statement which has
          the effect of firing off column-level defaults.  It also
          allows types which have special behavior for Python None, such
          as a JSON type, to indicate that they’d like to handle the
          None value explicitly.

          To set this flag on an existing type, use the
          TypeEngine.evaluates_none() method.

          See also
          ........

          See TypeEngine.evaluates_none().

          New in version 1.1.

      -- Attribute: sqlalchemy.types.TypeEngine..
               sort_key_function = None

          A sorting function that can be passed as the key to sorted.

          The default value of ‘None’ indicates that the values stored
          by this type are self-sorting.

          New in version 1.3.8.

      -- Method: sqlalchemy.types.TypeEngine..with_variant
               (type_, dialect_name)

          Produce a new type object that will utilize the given type
          when applied to the dialect of the given name.

          e.g.:

               from sqlalchemy.types import String
               from sqlalchemy.dialects import mysql

               s = String()

               s = s.with_variant(mysql.VARCHAR(collation='foo'), 'mysql')

          The construction of TypeEngine.with_variant() is
          always from the “fallback” type to that which is dialect
          specific.  The returned type is an instance of Variant,
          which itself provides a Variant.with_variant()
          that can be called repeatedly.

          Parameters:

             * ‘type_’ – a TypeEngine that will be selected
               as a variant from the originating type, when a dialect of
               the given name is in use.

             * ‘dialect_name’ – base name of the dialect which uses this
               type.  (i.e.  ‘'postgresql'’, ‘'mysql'’, etc.)

 -- Class: sqlalchemy.types.Concatenable

     A mixin that marks a type as supporting ‘concatenation’, typically
     strings.

      -- Class: Comparator (expr)

          `Class signature'

          class sqlalchemy.types.Concatenable.Comparator.
          (‘sqlalchemy.types.Comparator’)

      -- Attribute: sqlalchemy.types.Concatenable..
               comparator_factory

          alias of ‘sqlalchemy.sql.sqltypes.Concatenable.Comparator’

 -- Class: sqlalchemy.types.Indexable

     A mixin that marks a type as supporting indexing operations, such
     as array or JSON structures.

     New in version 1.1.0.

      -- Class: Comparator (expr)

          `Class signature'

          class sqlalchemy.types.Indexable.Comparator.
          (‘sqlalchemy.types.Comparator’)

      -- Attribute: sqlalchemy.types.Indexable..
               comparator_factory

          alias of ‘sqlalchemy.sql.sqltypes.Indexable.Comparator’

 -- Class: sqlalchemy.types.NullType

     An unknown type.

     NullType is used as a default type for those cases
     where a type cannot be determined, including:

        * During table reflection, when the type of a column is not
          recognized by the Dialect.

        * When constructing SQL expressions using plain Python objects
          of unknown types (e.g.  ‘somecolumn == my_special_object’)

        * When a new Column is created, and the given type is
          passed as ‘None’ or is not passed at all.

     The NullType can be used within SQL expression
     invocation without issue, it just has no behavior either at the
     expression construction level or at the bind-parameter/result
     processing level.  NullType will result in a
     CompileError if the compiler is asked to render the type
     itself, such as if it is used in a cast() operation or
     within a schema creation operation such as that invoked by
     MetaData.create_all() or the CreateTable
     construct.

     `Class signature'

     class sqlalchemy.types.NullType. (see
     sqlalchemy.types.TypeEngine)

 -- Class: sqlalchemy.types.Variant (base, mapping)

     A wrapping type that selects among a variety of implementations
     based on dialect in use.

     The Variant type is typically constructed using the
     TypeEngine.with_variant() method.

     See also
     ........

     TypeEngine.with_variant() for an example of use.

     `Class signature'

     class sqlalchemy.types.Variant. (see
     sqlalchemy.types.TypeDecorator)

      -- Method: sqlalchemy.types.Variant..__init__ (base,
               mapping)

          Construct a new Variant.

          Parameters:

             * ‘base’ – the base ‘fallback’ type

             * ‘mapping’ – dictionary of string dialect names to
               TypeEngine instances.

      -- Method: sqlalchemy.types.Variant..with_variant
               (type_, dialect_name)

          Return a new Variant which adds the given type +
          dialect name to the mapping, in addition to the mapping
          present in this Variant.

          Parameters:

             * ‘type_’ – a TypeEngine that will be selected
               as a variant from the originating type, when a dialect of
               the given name is in use.

             * ‘dialect_name’ – base name of the dialect which uses this
               type.  (i.e.  ‘'postgresql'’, ‘'mysql'’, etc.)

4.5 Engine and Connection Use
=============================

4.5.1 Engine Configuration
--------------------------

The Engine is the starting point for any SQLAlchemy
application.  It’s “home base” for the actual database and its DBAPI,
delivered to the SQLAlchemy application through a connection pool and a
Dialect, which describes how to talk to a specific kind of
database/DBAPI combination.

The general structure can be illustrated as follows:

Where above, an Engine references both a Dialect
and a Pool, which together interpret the DBAPI’s
module functions as well as the behavior of the database.

Creating an engine is just a matter of issuing a single call, see
create_engine():

     from sqlalchemy import create_engine
     engine = create_engine('postgresql://scott:tiger@localhost:5432/mydatabase')

The above engine creates a Dialect object tailored towards
PostgreSQL, as well as a Pool object which will establish a
DBAPI connection at ‘localhost:5432’ when a connection request is first
received.  Note that the Engine and its underlying
Pool do `not' establish the first actual DBAPI connection until
the Engine.connect() method is called, or an operation which
is dependent on this method such as Engine.execute() is
invoked.  In this way, see Engine and Pool can be
said to have a `lazy initialization' behavior.

The Engine, once created, can either be used directly to
interact with the database, or can be passed to a Session
object to work with the ORM. This section covers the details of
configuring an Engine.  The next section, see Working with Engines and Connections,
will detail the usage API of the
Engine and similar, typically for non-ORM applications.

4.5.1.1 Supported Databases
...........................

SQLAlchemy includes many Dialect implementations for
various backends.  Dialects for the most common databases are included
with SQLAlchemy; a handful of others require an additional install of a
separate dialect.

See the section Dialects for information on the various
backends available.

4.5.1.2 Database Urls
.....................

The create_engine() function produces an Engine
object based on a URL. These URLs follow RFC-1738(1), and usually can
include username, password, hostname, database name as well as optional
keyword arguments for additional configuration.  In some cases a file
path is accepted, and in others a “data source name” replaces the “host”
and “database” portions.  The typical form of a database URL is:

     dialect+driver://username:password@host:port/database

Dialect names include the identifying name of the SQLAlchemy dialect, a
name such as ‘sqlite’, ‘mysql’, ‘postgresql’, ‘oracle’, or ‘mssql’.  The
drivername is the name of the DBAPI to be used to connect to the
database using all lowercase letters.  If not specified, a “default”
DBAPI will be imported if available - this default is typically the most
widely known driver available for that backend.

As the URL is like any other URL, `special characters such as those that
may be used in the password need to be URL encoded to be parsed
correctly.'.  Below is an example of a URL that includes the password
‘"kx%jj5/g"’, where the percent sign and slash characters are
represented as ‘%25’ and ‘%2F’, respectively:

     postgresql+pg8000://dbuser:kx%25jj5%2Fg@pghost10/appdb

The encoding for the above password can be generated using
urllib.parse(2):

     >>> import urllib.parse
     >>> urllib.parse.quote_plus("kx%jj5/g")
     'kx%25jj5%2Fg'

Examples for common connection styles follow below.  For a full index of
detailed information on all included dialects as well as links to
third-party dialects, see Dialects.

   ---------- Footnotes ----------

   (1) http://rfc.net/rfc1738.html

   (2) https://docs.python.org/3/library/urllib.parse.html

4.5.1.3 PostgreSQL
..................

The PostgreSQL dialect uses psycopg2 as the default DBAPI. pg8000 is
also available as a pure-Python substitute:

     # default
     engine = create_engine('postgresql://scott:tiger@localhost/mydatabase')

     # psycopg2
     engine = create_engine('postgresql+psycopg2://scott:tiger@localhost/mydatabase')

     # pg8000
     engine = create_engine('postgresql+pg8000://scott:tiger@localhost/mydatabase')

More notes on connecting to PostgreSQL at PostgreSQL.

4.5.1.4 MySQL
.............

The MySQL dialect uses mysql-python as the default DBAPI. There are many
MySQL DBAPIs available, including MySQL-connector-python and OurSQL:

     # default
     engine = create_engine('mysql://scott:tiger@localhost/foo')

     # mysqlclient (a maintained fork of MySQL-Python)
     engine = create_engine('mysql+mysqldb://scott:tiger@localhost/foo')

     # PyMySQL
     engine = create_engine('mysql+pymysql://scott:tiger@localhost/foo')

More notes on connecting to MySQL at MySQL and MariaDB.

4.5.1.5 Oracle
..............

The Oracle dialect uses cx_oracle as the default DBAPI:

     engine = create_engine('oracle://scott:tiger@127.0.0.1:1521/sidname')

     engine = create_engine('oracle+cx_oracle://scott:tiger@tnsname')

More notes on connecting to Oracle at Oracle.

4.5.1.6 Microsoft SQL Server
............................

The SQL Server dialect uses pyodbc as the default DBAPI. pymssql is also
available:

     # pyodbc
     engine = create_engine('mssql+pyodbc://scott:tiger@mydsn')

     # pymssql
     engine = create_engine('mssql+pymssql://scott:tiger@hostname:port/dbname')

More notes on connecting to SQL Server at Microsoft SQL Server.

4.5.1.7 SQLite
..............

SQLite connects to file-based databases, using the Python built-in
module ‘sqlite3’ by default.

As SQLite connects to local files, the URL format is slightly different.
The “file” portion of the URL is the filename of the database.  For a
relative file path, this requires three slashes:

     # sqlite://<nohostname>/<path>
     # where <path> is relative:
     engine = create_engine('sqlite:///foo.db')

And for an absolute file path, the three slashes are followed by the
absolute path:

     # Unix/Mac - 4 initial slashes in total
     engine = create_engine('sqlite:////absolute/path/to/foo.db')

     # Windows
     engine = create_engine('sqlite:///C:\\path\\to\\foo.db')

     # Windows alternative using raw string
     engine = create_engine(r'sqlite:///C:\path\to\foo.db')

To use a SQLite ‘:memory:’ database, specify an empty URL:

     engine = create_engine('sqlite://')

More notes on connecting to SQLite at SQLite.

4.5.1.8 Others
..............

See Dialects, the top-level page for all additional dialect
documentation.

4.5.1.9 Engine Creation API
...........................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See create_engine.(url,Create a new Engine instance.
**kwargs)

See create_mock_engine.(url,Create a “mock” engine used for echoing DDL.
executor,
**kw)

See engine_from_config.(configuration[,Create a new Engine instance using a configuration dictionary.
prefix],
**kwargs)

See make_url.(name_or_url)Given a string or unicode instance, produce a new URL instance.

See URL.Represent the components of a URL used to connect to a database.

 -- Function: sqlalchemy.create_engine (url, **kwargs)

     Create a new Engine instance.

     The standard calling form is to send the URL as the
     first positional argument, usually a string that indicates database
     dialect and connection arguments:

          engine = create_engine("postgresql://scott:tiger@localhost/test")

          Note: Please review Database Urls for general
          guidelines in composing URL strings.  In particular, special
          characters, such as those often part of passwords, must be URL
          encoded to be properly parsed.

     Additional keyword arguments may then follow it which establish
     various options on the resulting Engine and its
     underlying Dialect and Pool constructs:

          engine = create_engine("mysql://scott:tiger@hostname/dbname",
                                      encoding='latin1', echo=True)

     The string form of the URL is
     ‘dialect[+driver]://user:password@host/dbname[?key=value..]’, where
     ‘dialect’ is a database name such as ‘mysql’, ‘oracle’,
     ‘postgresql’, etc., and ‘driver’ the name of a DBAPI, such as
     ‘psycopg2’, ‘pyodbc’, ‘cx_oracle’, etc.  Alternatively, the URL can
     be an instance of ‘URL’.

     ‘**kwargs’ takes a wide variety of options which are routed towards
     their appropriate components.  Arguments may be specific to the
     Engine, the underlying Dialect, as well as
     the Pool.  Specific dialects also accept keyword
     arguments that are unique to that dialect.  Here, we describe the
     parameters that are common to most create_engine()
     usage.

     Once established, the newly resulting Engine will
     request a connection from the underlying Pool once
     Engine.connect() is called, or a method which depends
     on it such as Engine.execute() is invoked.  The
     Pool in turn will establish the first actual DBAPI
     connection when this request is received.  The
     create_engine() call itself does `not' establish any actual
     DBAPI connections directly.

     See also
     ........

     See Engine Configuration.

     See Dialects.

     See Working with Engines and Connections.

     Parameters:

        * ‘case_sensitive’ – if False, result column names will match in
          a case-insensitive fashion, that is, ‘row['SomeColumn']’.

          Deprecated since version 1.4: The
          create_engine.case_sensitive parameter is deprecated
          and will be removed in a future release.  Applications should
          work with result column names in a case sensitive fashion.

        * ‘connect_args’ – a dictionary of options which will be passed
          directly to the DBAPI’s ‘connect()’ method as additional
          keyword arguments.  See the example at Custom DBAPI connect() arguments / on-connect routines.

        * ‘convert_unicode=False’ – if set to True, causes all
          String datatypes to act as though the
          String.convert_unicode flag has been set to ‘True’,
          regardless of a setting of ‘False’ on an individual
          String type.  This has the effect of causing all
          String. -based columns to accommodate Python Unicode
          objects directly as though the datatype were the
          Unicode type.

          Deprecated since version 1.3: The
          create_engine.convert_unicode parameter is deprecated
          and will be removed in a future release.  All modern DBAPIs
          now support Python Unicode directly and this parameter is
          unnecessary.

        * ‘creator’ – a callable which returns a DBAPI connection.  This
          creation function will be passed to the underlying connection
          pool and will be used to create all new database connections.
          Usage of this function causes connection parameters specified
          in the URL argument to be bypassed.

          This hook is not as flexible as the newer
          DialectEvents.do_connect() hook which allows complete
          control over how a connection is made to the database, given
          the full set of URL arguments and state beforehand.

          See also
          ........

          See DialectEvents.do_connect(). - event hook that
          allows full control over DBAPI connection mechanics.

          See Custom DBAPI connect() arguments / on-connect routines.

        * ‘echo=False’ – if True, the Engine will log all statements as
          well as a ‘repr()’ of their parameter lists to the default log
          handler, which defaults to ‘sys.stdout’ for output.  If set to
          the string ‘"debug"’, result rows will be printed to the
          standard output as well.  The ‘echo’ attribute of ‘Engine’ can
          be modified at any time to turn logging on and off; direct
          control of logging is also available using the standard Python
          ‘logging’ module.

          See also
          ........

          See Configuring Logging. - further detail on how to
          configure logging.

        * ‘echo_pool=False’ – if True, the connection pool will log
          informational output such as when connections are invalidated
          as well as when connections are recycled to the default log
          handler, which defaults to ‘sys.stdout’ for output.  If set to
          the string ‘"debug"’, the logging will include pool checkouts
          and checkins.  Direct control of logging is also available
          using the standard Python ‘logging’ module.

          See also
          ........

          See Configuring Logging. - further detail on how to
          configure logging.

        * ‘empty_in_strategy’ – No longer used; SQLAlchemy now uses
          “empty set” behavior for IN in all cases.

          Deprecated since version 1.4: The
          create_engine.empty_in_strategy keyword is deprecated,
          and no longer has any effect.  All IN expressions are now
          rendered using the “expanding parameter” strategy which
          renders a set of boundexpressions, or an “empty set” SELECT,
          at statement executiontime.

        * ‘enable_from_linting’ – defaults to True.  Will emit a warning
          if a given SELECT statement is found to have un-linked FROM
          elements which would cause a cartesian product.

          New in version 1.4.

          See also
          ........

          See Built-in FROM linting will warn for any potential cartesian products in a SELECT statement.

        * ‘encoding’ – Defaults to ‘utf-8’.  This is the string encoding
          used by SQLAlchemy for string encode/decode operations which
          occur within SQLAlchemy, `outside of the DBAPIs own encoding
          facilities.'

               Note: The ‘encoding’ parameter deals only with in-Python
               encoding issues that were prevalent with many DBAPIs
               under Python 2.  Under Python 3 it is mostly unused.  For
               DBAPIs that require client encoding configurations, such
               as those of MySQL and Oracle, please consult specific
               dialect documentation for details.

          All modern DBAPIs that work in Python 3 necessarily feature
          direct support for Python unicode strings.  Under Python 2,
          this was not always the case.  For those scenarios where the
          DBAPI is detected as not supporting a Python ‘unicode’ object
          under Python 2, this encoding is used to determine the
          source/destination encoding.  It is `not used' for those cases
          where the DBAPI handles unicode directly.

          To properly configure a system to accommodate Python ‘unicode’
          objects, the DBAPI should be configured to handle unicode to
          the greatest degree as is appropriate - see the notes on
          unicode pertaining to the specific target database in use at
          Dialects.

          Areas where string encoding may need to be accommodated
          outside of the DBAPI, nearly always under `Python 2 only',
          include zero or more of:

             * the values passed to bound parameters, corresponding to
               the Unicode type or the String
               type when ‘convert_unicode’ is ‘True’;

             * the values returned in result set columns corresponding
               to the Unicode type or the String
               type when ‘convert_unicode’ is ‘True’;

             * the string SQL statement passed to the DBAPI’s
               ‘cursor.execute()’ method;

             * the string names of the keys in the bound parameter
               dictionary passed to the DBAPI’s ‘cursor.execute()’ as
               well as ‘cursor.setinputsizes()’ methods;

             * the string column names retrieved from the DBAPI’s
               ‘cursor.description’ attribute.

          When using Python 3, the DBAPI is required to support all of
          the above values as Python ‘unicode’ objects, which in Python
          3 are just known as ‘str’.  In Python 2, the DBAPI does not
          specify unicode behavior at all, so SQLAlchemy must make
          decisions for each of the above values on a per-DBAPI basis -
          implementations are completely inconsistent in their behavior.

        * ‘execution_options’ – Dictionary execution options which will
          be applied to all connections.  See
          Connection.execution_options().

        * ‘future’ – Use the 2.0 style Engine and
          Connection. API.

          New in version 1.4.

          See also
          ........

          See Migrating to SQLAlchemy 2.0.

        * ‘hide_parameters’ – Boolean, when set to True, SQL statement
          parameters will not be displayed in INFO logging nor will they
          be formatted into the string representation of
          StatementError objects.

          New in version 1.3.8.

          See also
          ........

          See Configuring Logging. - further detail on how to
          configure logging.

        * ‘implicit_returning=True’ – When ‘True’, a RETURNING-
          compatible construct, if available, will be used to fetch
          newly generated primary key values when a single row INSERT
          statement is emitted with no existing returning() clause.
          This applies to those backends which support RETURNING or a
          compatible construct, including PostgreSQL, Firebird, Oracle,
          Microsoft SQL Server.  Set this to ‘False’ to disable the
          automatic usage of RETURNING.

        * ‘isolation_level’ – this string parameter is interpreted by
          various dialects in order to affect the transaction isolation
          level of the database connection.  The parameter essentially
          accepts some subset of these string arguments:
          ‘"SERIALIZABLE"’, ‘"REPEATABLE READ"’, ‘"READ COMMITTED"’,
          ‘"READ UNCOMMITTED"’ and ‘"AUTOCOMMIT"’.  Behavior here varies
          per backend, and individual dialects should be consulted
          directly.

          Note that the isolation level can also be set on a per-see
          Connection basis as well, using the
          Connection.execution_options.isolation_level feature.

          See also
          ........

          See Connection.default_isolation_level. - view default
          level

          See Connection.execution_options.isolation_level. -
          set per Connection isolation level

          See SQLite Transaction Isolation.

          See PostgreSQL Transaction Isolation.

          See MySQL Transaction Isolation.

          See Setting Transaction Isolation Levels / DBAPI AUTOCOMMIT.
          - for the ORM

        * ‘json_deserializer’ – for dialects that support the
          JSON datatype, this is a Python callable that will
          convert a JSON string to a Python object.  By default, the
          Python ‘json.loads’ function is used.

          Changed in version 1.3.7: The SQLite dialect renamed this from
          ‘_json_deserializer’.

        * ‘json_serializer’ – for dialects that support the JSON
          datatype, this is a Python callable that will render a
          given object as JSON. By default, the Python ‘json.dumps’
          function is used.

          Changed in version 1.3.7: The SQLite dialect renamed this from
          ‘_json_serializer’.

        * ‘label_length=None’ – optional integer value which limits the
          size of dynamically generated column labels to that many
          characters.  If less than 6, labels are generated as
          “_(counter)”.  If ‘None’, the value of
          ‘dialect.max_identifier_length’, which may be affected via the
          create_engine.max_identifier_length parameter, is
          used instead.  The value of create_engine.label_length
          may not be larger than that of
          create_engine.max_identfier_length.

          See also
          ........

          See create_engine.max_identifier_length.

        * ‘listeners’ – A list of one or more ‘PoolListener’ objects
          which will receive connection pool events.

        * ‘logging_name’ – String identifier which will be used within
          the “name” field of logging records generated within the
          “sqlalchemy.engine” logger.  Defaults to a hexstring of the
          object’s id.

          See also
          ........

          See Configuring Logging. - further detail on how to
          configure logging.

          See Connection.execution_options.logging_token.

        * ‘max_identifier_length’ – integer; override the
          max_identifier_length determined by the dialect.  if ‘None’ or
          zero, has no effect.  This is the database’s configured
          maximum number of characters that may be used in a SQL
          identifier such as a table name, column name, or label name.
          All dialects determine this value automatically, however in
          the case of a new database version for which this value has
          changed but SQLAlchemy’s dialect has not been adjusted, the
          value may be passed here.

          New in version 1.3.9.

          See also
          ........

          See create_engine.label_length.

        * ‘max_overflow=10’ – the number of connections to allow in
          connection pool “overflow”, that is connections that can be
          opened above and beyond the pool_size setting, which defaults
          to five.  this is only used with QueuePool.

        * ‘module=None’ – reference to a Python module object (the
          module itself, not its string name).  Specifies an alternate
          DBAPI module to be used by the engine’s dialect.  Each
          sub-dialect references a specific DBAPI which will be imported
          before first connect.  This parameter causes the import to be
          bypassed, and the given module to be used instead.  Can be
          used for testing of DBAPIs as well as to inject “mock” DBAPI
          implementations into the Engine.

        * ‘paramstyle=None’ – The paramstyle(1) to use when rendering
          bound parameters.  This style defaults to the one recommended
          by the DBAPI itself, which is retrieved from the ‘.paramstyle’
          attribute of the DBAPI. However, most DBAPIs accept more than
          one paramstyle, and in particular it may be desirable to
          change a “named” paramstyle into a “positional” one, or vice
          versa.  When this attribute is passed, it should be one of the
          values ‘"qmark"’, ‘"numeric"’, ‘"named"’, ‘"format"’ or
          ‘"pyformat"’, and should correspond to a parameter style known
          to be supported by the DBAPI in use.

        * ‘pool=None’ – an already-constructed instance of Pool,
          such as a QueuePool instance.  If non-None,
          this pool will be used directly as the underlying connection
          pool for the engine, bypassing whatever connection parameters
          are present in the URL argument.  For information on
          constructing connection pools manually, see Connection Pooling.

        * ‘poolclass=None’ – a Pool subclass, which will be
          used to create a connection pool instance using the connection
          parameters given in the URL. Note this differs from ‘pool’ in
          that you don’t actually instantiate the pool in this case, you
          just indicate what type of pool to be used.

        * ‘pool_logging_name’ – String identifier which will be used
          within the “name” field of logging records generated within
          the “sqlalchemy.pool” logger.  Defaults to a hexstring of the
          object’s id.

          See also
          ........

          See Configuring Logging. - further detail on how to
          configure logging.

        * ‘pool_pre_ping’ – boolean, if True will enable the connection
          pool “pre-ping” feature that tests connections for liveness
          upon each checkout.

          New in version 1.2.

          See also
          ........

          See Disconnect Handling - Pessimistic.

        * ‘pool_size=5’ – the number of connections to keep open inside
          the connection pool.  This used with QueuePool as
          well as SingletonThreadPool.  With
          QueuePool, a ‘pool_size’ setting of 0 indicates no
          limit; to disable pooling, set ‘poolclass’ to NullPool
          instead.

        * ‘pool_recycle=-1’ – this setting causes the pool to recycle
          connections after the given number of seconds has passed.  It
          defaults to -1, or no timeout.  For example, setting to 3600
          means connections will be recycled after one hour.  Note that
          MySQL in particular will disconnect automatically if no
          activity is detected on a connection for eight hours (although
          this is configurable with the MySQLDB connection itself and
          the server configuration as well).

          See also
          ........

          See Setting Pool Recycle.

        * ‘pool_reset_on_return='rollback'’ – set the
          Pool.reset_on_return parameter of the underlying
          Pool object, which can be set to the values
          ‘"rollback"’, ‘"commit"’, or ‘None’.

          See also
          ........

          See Pool.reset_on_return.

        * ‘pool_timeout=30’ – number of seconds to wait before giving up
          on getting a connection from the pool.  This is only used with
          QueuePool.  This can be a float but is subject to
          the limitations of Python time functions which may not be
          reliable in the tens of milliseconds.

        * ‘pool_use_lifo=False’ – use LIFO (last-in-first-out) when
          retrieving connections from QueuePool instead of
          FIFO (first-in-first-out).  Using LIFO, a server-side timeout
          scheme can reduce the number of connections used during non-
          peak periods of use.  When planning for server-side timeouts,
          ensure that a recycle or pre-ping strategy is in use to
          gracefully handle stale connections.

               New in version 1.3.

               See also
               ........

               See Using FIFO vs. LIFO.

               See Dealing with Disconnects.

        * ‘plugins’ – string list of plugin names to load.  See
          CreateEnginePlugin for background.

          New in version 1.2.3.

        * ‘query_cache_size’ – size of the cache used to cache the SQL
          string form of queries.  Set to zero to disable caching.

          The cache is pruned of its least recently used items when its
          size reaches N * 1.5.  Defaults to 500, meaning the cache will
          always store at least 500 SQL statements when filled, and will
          grow up to 750 items at which point it is pruned back down to
          500 by removing the 250 least recently used items.

          Caching is accomplished on a per-statement basis by generating
          a cache key that represents the statement’s structure, then
          generating string SQL for the current dialect only if that key
          is not present in the cache.  All statements support caching,
          however some features such as an INSERT with a large set of
          parameters will intentionally bypass the cache.  SQL logging
          will indicate statistics for each statement whether or not it
          were pull from the cache.

               Note: some ORM functions related to unit-of-work
               persistence as well as some attribute loading strategies
               will make use of individual per-mapper caches outside of
               the main cache.

          See also
          ........

          See SQL Compilation Caching.

          New in version 1.4.

 -- Function: sqlalchemy.engine_from_config (configuration,
          prefix='sqlalchemy.', **kwargs)

     Create a new Engine instance using a configuration dictionary.

     The dictionary is typically produced from a config file.

     The keys of interest to ‘engine_from_config()’ should be prefixed,
     e.g.  ‘sqlalchemy.url’, ‘sqlalchemy.echo’, etc.  The ‘prefix’
     argument indicates the prefix to be searched for.  Each matching
     key (after the prefix is stripped) is treated as though it were the
     corresponding keyword argument to a create_engine()
     call.

     The only required key is (assuming the default prefix)
     ‘sqlalchemy.url’, which provides the database URL.

     A select set of keyword arguments will be “coerced” to their
     expected type based on string values.  The set of arguments is
     extensible per-dialect using the ‘engine_config_types’ accessor.

     Parameters:

        * ‘configuration’ – A dictionary (typically produced from a
          config file, but this is not a requirement).  Items whose keys
          start with the value of ‘prefix’ will have that prefix
          stripped, and will then be passed to create_engine().

        * ‘prefix’ – Prefix to match and then strip from keys in
          ‘configuration’.

        * ‘kwargs’ – Each keyword argument to ‘engine_from_config()’
          itself overrides the corresponding item taken from the
          ‘configuration’ dictionary.  Keyword arguments should `not' be
          prefixed.

 -- Function: sqlalchemy.create_mock_engine (url, executor, **kw)

     Create a “mock” engine used for echoing DDL.

     This is a utility function used for debugging or storing the output
     of DDL sequences as generated by MetaData.create_all()
     and related methods.

     The function accepts a URL which is used only to determine the kind
     of dialect to be used, as well as an “executor” callable function
     which will receive a SQL expression object and parameters, which
     can then be echoed or otherwise printed.  The executor’s return
     value is not handled, nor does the engine allow regular string
     statements to be invoked, and is therefore only useful for DDL that
     is sent to the database without receiving any results.

     E.g.:

          from sqlalchemy import create_mock_engine

          def dump(sql, *multiparams, **params):
              print(sql.compile(dialect=engine.dialect))

          engine = create_mock_engine('postgresql://', dump)
          metadata.create_all(engine, checkfirst=False)

     Parameters:

        * ‘url’ – A string URL which typically needs to contain only the
          database backend name.

        * ‘executor’ – a callable which receives the arguments ‘sql’,
          ‘*multiparams’ and ‘**params’.  The ‘sql’ parameter is
          typically an instance of DDLElement, which can then
          be compiled into a string using ‘DDLElement.compile()’.

     New in version 1.4: - the create_mock_engine()
     function replaces the previous “mock” engine strategy used with
     create_engine().

     See also
     ........

     See How can I get the CREATE TABLE/ DROP TABLE output as a string?.

 -- Function: sqlalchemy.engine.make_url (name_or_url)

     Given a string or unicode instance, produce a new URL instance.

     The given string is parsed according to the RFC 1738 spec.  If an
     existing URL object is passed, just returns the object.

 -- Class: sqlalchemy.engine.URL (*arg, **kw)

     Represent the components of a URL used to connect to a database.

     This object is suitable to be passed directly to a
     create_engine() call.  The fields of the URL are parsed from a
     string by the make_url() function.  The string format
     of the URL is an RFC-1738-style string.

     To create a new URL object, use the ‘make_url()’
     function.  To construct a URL programmatically, use
     the URL.create() constructor.

     Changed in version 1.4: The URL object is now an
     immutable object.  To create a URL, use the make_url()
     or URL.create() function / method.  To modify a
     URL, use methods like URL.set() and
     URL.update_query_dict() to return a new URL
     object with modifications.  See notes for this change at The URL object is now immutable.

     URL contains the following attributes:

     Variables:

        * ‘driver’ – database backend and driver name, such as
          ‘postgresql+psycopg2’

        * username. – username string

        * password. – password, which is normally a string
          but may also be any object that has a ‘__str__()’ method.

        * host. – string hostname

        * port. – integer port number

        * database. – string database name

        * query. – an immutable mapping representing the
          query string.  contains strings for keys and either strings or
          tuples of strings for values.

     `Class signature'

     class sqlalchemy.engine.URL. (see
     sqlalchemy.engine.URL)

      -- Attribute: sqlalchemy.engine.URL..drivername str

          database backend and driver name, such as
          ‘postgresql+psycopg2’

      -- Attribute: sqlalchemy.engine.URL..username str

          username string

      -- Attribute: sqlalchemy.engine.URL..password str

          password, which is normally a string but may also be any
          object that has a ‘__str__()’ method.

      -- Attribute: sqlalchemy.engine.URL..host str

          string hostname

      -- Attribute: sqlalchemy.engine.URL..port int

          integer port number

      -- Attribute: sqlalchemy.engine.URL..database str

          string database name

      -- Attribute: sqlalchemy.engine.URL..query
               Mapping[str, Union[str, Sequence[str]]]

          an immutable mapping representing the query string.  contains
          strings for keys and either strings or tuples of strings for
          values, e.g.:

                  >>> from sqlalchemy.engine import make_url
                  >>> url = make_url("postgresql://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt")
                  >>> url.query
                  immutabledict({'alt_host': ('host1', 'host2'), 'ssl_cipher': '/path/to/crt'})

               To create a mutable copy of this mapping, use the ``dict`` constructor::

                  mutable_query_opts = dict(url.query)

          See also
          ........

          See URL.normalized_query. - normalizes all values into
          sequences for consistent processing

          Methods for altering the contents of URL.query:

          URL.update_query_dict().

          See URL.update_query_string().

          See URL.update_query_pairs().

          See URL.difference_update_query().

      -- Method: sqlalchemy.engine.URL..classmethod create
               (drivername: str, username: Optional[str] = None,
               password: Optional[Union[str, object]] = None, host:
               Optional[str] = None, port: Optional[int] = None,
               database: Optional[str] = None, query: Mapping[str,
               Union[str, Sequence[str]]] = {}) -> URL

          Create a new URL object.

          Parameters:

             * ‘drivername’ – the name of the database backend.  This
               name will correspond to a module in sqlalchemy/databases
               or a third party plug-in.

             * ‘username’ – The user name.

             * ‘password’ – database password.  May be a string or an
               object that can be stringified with ‘str()’.

             * ‘host’ – The name of the host.

             * ‘port’ – The port number.

             * ‘database’ – The database name.

             * ‘query’ – A dictionary of string keys to string values to
               be passed to the dialect and/or the DBAPI upon connect.
               To specify non-string parameters to a Python DBAPI
               directly, use the create_engine.connect_args
               parameter to create_engine().  See also
               URL.normalized_query for a dictionary that is
               consistently string->list of string.

          Returns: new URL object.

          New in version 1.4: The URL object is now an
          `immutable named tuple'.  In addition, the ‘query’ dictionary
          is also immutable.  To create a URL, use the ‘make_url()’ or
          URL.create() function/ method.  To modify a
          URL, use the URL.set() and
          ‘URL.update_query()’ methods.

      -- Method: sqlalchemy.engine.URL..
               difference_update_query (names: Sequence[str]) ->
               URL

          Remove the given names from the URL.query
          dictionary, returning the new URL.

          E.g.:

               url = url.difference_update_query(['foo', 'bar'])

          Equivalent to using URL.set() as follows:

               url = url.set(
                   query={
                       key: url.query[key]
                       for key in set(url.query).difference(['foo', 'bar'])
                   }
               )

          New in version 1.4.

          See also
          ........

          See URL.query.

          See URL.update_query_dict().

          See URL.set().

      -- Method: sqlalchemy.engine.URL..get_backend_name ()

          Return the backend name.

          This is the name that corresponds to the database backend in
          use, and is the portion of the URL.drivername
          that is to the left of the plus sign.

      -- Method: sqlalchemy.engine.URL..get_dialect ()

          Return the SQLAlchemy Dialect class corresponding
          to this URL’s driver name.

      -- Method: sqlalchemy.engine.URL..get_driver_name ()

          Return the backend name.

          This is the name that corresponds to the DBAPI driver in use,
          and is the portion of the URL.drivername that is
          to the right of the plus sign.

          If the URL.drivername does not include a plus
          sign, then the default Dialect for this
          URL is imported in order to get the driver name.

      -- Attribute: sqlalchemy.engine.URL..normalized_query

          Return the URL.query dictionary with values
          normalized into sequences.

          As the URL.query dictionary may contain either
          string values or sequences of string values to differentiate
          between parameters that are specified multiple times in the
          query string, code that needs to handle multiple parameters
          generically will wish to use this attribute so that all
          parameters present are presented as sequences.  Inspiration is
          from Python’s ‘urllib.parse.parse_qs’ function.  E.g.:

               >>> from sqlalchemy.engine import make_url
               >>> url = make_url("postgresql://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt")
               >>> url.query
               immutabledict({'alt_host': ('host1', 'host2'), 'ssl_cipher': '/path/to/crt'})
               >>> url.normalized_query
               immutabledict({'alt_host': ('host1', 'host2'), 'ssl_cipher': ('/path/to/crt',)})

      -- Method: sqlalchemy.engine.URL..render_as_string
               (hide_password: bool = True) -> str

          Render this URL object as a string.

          This method is used when the ‘__str__()’ or ‘__repr__()’
          methods are used.  The method directly includes additional
          options.

          Parameters: ‘hide_password’ – Defaults to True.  The password
          is not shown in the string unless this is set to False.

      -- Method: sqlalchemy.engine.URL..set (drivername:
               Optional[str] = None, username: Optional[str] = None,
               password: Optional[Union[str, object]] = None, host:
               Optional[str] = None, port: Optional[int] = None,
               database: Optional[str] = None, query:
               Optional[Mapping[str, Union[str, Sequence[str]]]] = None)
               -> URL

          return a new URL object with modifications.

          Values are used if they are non-None.  To set a value to
          ‘None’ explicitly, use the ‘URL._replace()’ method adapted
          from ‘namedtuple’.

          Parameters:

             * ‘drivername’ – new drivername

             * ‘username’ – new username

             * ‘password’ – new password

             * ‘host’ – new hostname

             * ‘port’ – new port

             * ‘query’ – new query parameters, passed a dict of string
               keys referring to string or sequence of string values.
               Fully replaces the previous list of arguments.

          Returns: new URL object.

          New in version 1.4.

          See also
          ........

          See URL.update_query_dict().

      -- Method: sqlalchemy.engine.URL..
               translate_connect_args (names=[], **kw)

          Translate url attributes into a dictionary of connection
          arguments.

          Returns attributes of this url (‘host’, ‘database’,
          ‘username’, ‘password’, ‘port’) as a plain dictionary.  The
          attribute names are used as the keys by default.  Unset or
          false attributes are omitted from the final dictionary.

          Parameters:

             * ‘**kw’ – Optional, alternate key names for url
               attributes.

             * ‘names’ – Deprecated.  Same purpose as the keyword-based
               alternate names, but correlates the name to the original
               positionally.

      -- Method: sqlalchemy.engine.URL..update_query_dict
               (query_parameters: Mapping[str, Union[str,
               Sequence[str]]], append: bool = False) -> URL

          Return a new URL object with the URL.query
          parameter dictionary updated by the given dictionary.

          The dictionary typically contains string keys and string
          values.  In order to represent a query parameter that is
          expressed multiple times, pass a sequence of string values.

          E.g.:

               >>> from sqlalchemy.engine import make_url
               >>> url = make_url("postgresql://user:pass@host/dbname")
               >>> url = url.update_query_dict({"alt_host": ["host1", "host2"], "ssl_cipher": "/path/to/crt"})
               >>> str(url)
               'postgresql://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt'

          Parameters:

             * ‘query_parameters’ – A dictionary with string keys and
               values that are either strings, or sequences of strings.

             * ‘append’ – if True, parameters in the existing query
               string will not be removed; new parameters will be in
               addition to those present.  If left at its default of
               False, keys present in the given query parameters will
               replace those of the existing query string.

          New in version 1.4.

          See also
          ........

          See URL.query.

          See URL.update_query_string().

          See URL.update_query_pairs().

          See URL.difference_update_query().

          See URL.set().

      -- Method: sqlalchemy.engine.URL..update_query_pairs
               (key_value_pairs: Sequence[Tuple[str, str]], append: bool
               = False) -> URL

          Return a new URL object with the URL.query
          parameter dictionary updated by the given sequence of
          key/value pairs

          E.g.:

               >>> from sqlalchemy.engine import make_url
               >>> url = make_url("postgresql://user:pass@host/dbname")
               >>> url = url.update_query_pairs([("alt_host", "host1"), ("alt_host", "host2"), ("ssl_cipher", "/path/to/crt")])
               >>> str(url)
               'postgresql://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt'

          Parameters:

             * ‘key_value_pairs’ – A sequence of tuples containing two
               strings each.

             * ‘append’ – if True, parameters in the existing query
               string will not be removed; new parameters will be in
               addition to those present.  If left at its default of
               False, keys present in the given query parameters will
               replace those of the existing query string.

          New in version 1.4.

          See also
          ........

          See URL.query.

          See URL.difference_update_query().

          See URL.set().

      -- Method: sqlalchemy.engine.URL..update_query_string
               (query_string: str, append: bool = False) ->
               sqlalchemy.engine.URL

          Return a new URL object with the URL.query
          parameter dictionary updated by the given query string.

          E.g.:

               >>> from sqlalchemy.engine import make_url
               >>> url = make_url("postgresql://user:pass@host/dbname")
               >>> url = url.update_query_string("alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt")
               >>> str(url)
               'postgresql://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt'

          Parameters:

             * ‘query_string’ – a URL escaped query string, not
               including the question mark.

             * ‘append’ – if True, parameters in the existing query
               string will not be removed; new parameters will be in
               addition to those present.  If left at its default of
               False, keys present in the given query parameters will
               replace those of the existing query string.

          New in version 1.4.

          See also
          ........

          See URL.query.

          See URL.update_query_dict().

   ---------- Footnotes ----------

   (1) http://legacy.python.org/dev/peps/pep-0249/#paramstyle

4.5.1.10 Pooling
................

The Engine will ask the connection pool for a connection
when the ‘connect()’ or ‘execute()’ methods are called.  The default
connection pool, see QueuePool, will open connections to the
database on an as-needed basis.  As concurrent statements are executed,
see QueuePool will grow its pool of connections to a default
size of five, and will allow a default “overflow” of ten.  Since the
Engine is essentially “home base” for the connection pool,
it follows that you should keep a single Engine per database
established within an application, rather than creating a new one for
each connection.

     Note: QueuePool is not used by default for SQLite
     engines.  See SQLite for details on SQLite connection
     pool usage.

For more information on connection pooling, see Connection Pooling.

4.5.1.11 Custom DBAPI connect() arguments / on-connect routines
...............................................................

For cases where special connection methods are needed, in the vast
majority of cases, it is most appropriate to use one of several hooks at
the create_engine() level in order to customize this process.
These are described in the following sub-sections.

4.5.1.12 Special Keyword Arguments Passed to dbapi.connect()
............................................................

All Python DBAPIs accept additional arguments beyond the basics of
connecting.  Common parameters include those to specify character set
encodings and timeout values; more complex data includes special DBAPI
constants and objects and SSL sub-parameters.  There are two rudimentary
means of passing these arguments without complexity.

4.5.1.13 Add Parameters to the URL Query string
...............................................

Simple string values, as well as some numeric values and boolean flags,
may be often specified in the query string of the URL directly.  A
common example of this is DBAPIs that accept an argument ‘encoding’ for
character encodings, such as most MySQL DBAPIs:

     engine = create_engine(
         "mysql+pymysql://user:pass@host/test?charset=utf8mb4"
     )

The advantage of using the query string is that additional DBAPI options
may be specified in configuration files in a manner that’s portable to
the DBAPI specified in the URL. The specific parameters passed through
at this level vary by SQLAlchemy dialect.  Some dialects pass all
arguments through as strings, while others will parse for specific
datatypes and move parameters to different places, such as into
driver-level DSNs and connect strings.  As per-dialect behavior in this
area currently varies, the dialect documentation should be consulted for
the specific dialect in use to see if particular parameters are
supported at this level.

     Tip: A general technique to display the exact arguments passed to
     the DBAPI for a given URL may be performed using the
     Dialect.create_connect_args() method directly as follows:

          >>> from sqlalchemy import create_engine
          >>> engine = create_engine("mysql+pymysql://some_user:some_pass@some_host/test?charset=utf8mb4")
          >>> args, kwargs = engine.dialect.create_connect_args(engine.url)
          >>> args, kwargs
          ([], {'host': 'some_host', 'database': 'test', 'user': 'some_user', 'password': 'some_pass', 'charset': 'utf8mb4', 'client_flag': 2})

     The above ‘args, kwargs’ pair is normally passed to the DBAPI as
     ‘dbapi.connect(*args, **kwargs)’.

4.5.1.14 Use the connect_args dictionary parameter
..................................................

A more general system of passing any parameter to the ‘dbapi.connect()’
function that is guaranteed to pass all parameters at all times is the
create_engine.connect_args dictionary parameter.  This may
be used for parameters that are otherwise not handled by the dialect
when added to the query string, as well as when special sub-structures
or objects must be passed to the DBAPI. Sometimes it’s just that a
particular flag must be sent as the ‘True’ symbol and the SQLAlchemy
dialect is not aware of this keyword argument to coerce it from its
string form as presented in the URL. Below illustrates the use of a
psycopg2 “connection factory” that replaces the underlying
implementation the connection:

     engine = create_engine(
         "postgresql://user:pass@hostname/dbname",
         connect_args={"connection_factory": MyConnectionFactory}
     )

Another example is the pyodbc “timeout” parameter:

     engine = create_engine(
       "mssql+pyodbc://user:pass@sqlsrvr?driver=ODBC+Driver+13+for+SQL+Server",
       connect_args={"timeout": 30}
     )

The above example also illustrates that both URL “query string”
parameters as well as create_engine.connect_args may be
used at the same time; in the case of pyodbc, the “driver” keyword has
special meaning within the URL.

4.5.1.15 Controlling how parameters are passed to the DBAPI connect() function
..............................................................................

Beyond manipulating the parameters passed to ‘connect()’, we can further
customize how the DBAPI ‘connect()’ function itself is called using the
DialectEvents.do_connect() event hook.  This hook is passed
the full ‘*args, **kwargs’ that the dialect would send to ‘connect()’.
These collections can then be modified in place to alter how they are
used:

     from sqlalchemy import event

     engine = create_engine("postgresql://user:pass@hostname/dbname")

     @event.listens_for(engine, "do_connect")
     def receive_do_connect(dialect, conn_rec, cargs, cparams):
         cparams['connection_factory'] = MyConnectionFactory

4.5.1.16 Generating dynamic authentication tokens
.................................................

DialectEvents.do_connect() is also an ideal way to
dynamically insert an authentication token that might change over the
lifespan of an Engine.  For example, if the token gets
generated by ‘get_authentication_token()’ and passed to the DBAPI in a
‘token’ parameter, this could be implemented as:

     from sqlalchemy import event

     engine = create_engine("postgresql://user@hostname/dbname")

     @event.listens_for(engine, "do_connect")
     def provide_token(dialect, conn_rec, cargs, cparams):
         cparams['token'] = get_authentication_token()

See also
........

See Connecting to databases with access tokens. - a more
concrete example involving SQL Server

4.5.1.17 Modifying the DBAPI connection after connect, or running commands after connect
........................................................................................

For a DBAPI connection that SQLAlchemy creates without issue, but where
we would like to modify the completed connection before it’s actually
used, such as for setting special flags or running certain commands, the
PoolEvents.connect() event hook is the most appropriate
hook.  This hook is called for every new connection created, before it
is used by SQLAlchemy:

     from sqlalchemy import event

     engine = create_engine(
         "postgresql://user:pass@hostname/dbname"
     )

     @event.listens_for(engine, "connect")
     def connect(dbapi_connection, connection_record):
         cursor = dbapi_connection.cursor()
         cursor.execute("SET some session variables")
         cursor.close()

4.5.1.18 Fully Replacing the DBAPI ‘connect()’ function
.......................................................

Finally, the DialectEvents.do_connect() event hook can also
allow us to take over the connection process entirely by establishing
the connection and returning it:

     from sqlalchemy import event

     engine = create_engine(
         "postgresql://user:pass@hostname/dbname"
     )

     @event.listens_for(engine, "do_connect")
     def receive_do_connect(dialect, conn_rec, cargs, cparams):
         # return the new DBAPI connection with whatever we'd like to
         # do
         return psycopg2.connect(*cargs, **cparams)

The DialectEvents.do_connect() hook supersedes the previous
create_engine.creator hook, which remains available.
DialectEvents.do_connect() has the distinct advantage that the
complete arguments parsed from the URL are also passed to the
user-defined function which is not the case with
create_engine.creator.

4.5.1.19 Configuring Logging
............................

Python’s standard logging(1) module is used to implement informational
and debug log output with SQLAlchemy.  This allows SQLAlchemy’s logging
to integrate in a standard way with other applications and libraries.
There are also two parameters create_engine.echo and
create_engine.echo_pool present on create_engine()
which allow immediate logging to ‘sys.stdout’ for the purposes of local
development; these parameters ultimately interact with the regular
Python loggers described below.

This section assumes familiarity with the above linked logging module.
All logging performed by SQLAlchemy exists underneath the ‘sqlalchemy’
namespace, as used by ‘logging.getLogger('sqlalchemy')’.  When logging
has been configured (i.e.  such as via ‘logging.basicConfig()’), the
general namespace of SA loggers that can be turned on is as follows:

   * ‘sqlalchemy.engine’ - controls SQL echoing.  Set to ‘logging.INFO’
     for SQL query output, ‘logging.DEBUG’ for query + result set
     output.  These settings are equivalent to ‘echo=True’ and
     ‘echo="debug"’ on create_engine.echo, respectively.

   * ‘sqlalchemy.pool’ - controls connection pool logging.  Set to
     ‘logging.INFO’ to log connection invalidation and recycle events;
     set to ‘logging.DEBUG’ to additionally log all pool checkins and
     checkouts.  These settings are equivalent to ‘pool_echo=True’ and
     ‘pool_echo="debug"’ on create_engine.echo_pool,
     respectively.

   * ‘sqlalchemy.dialects’ - controls custom logging for SQL dialects,
     to the extend that logging is used within specific dialects, which
     is generally minimal.

   * ‘sqlalchemy.orm’ - controls logging of various ORM functions to the
     extent that logging is used within the ORM, which is generally
     minimal.  Set to ‘logging.INFO’ to log some top-level information
     on mapper configurations.

For example, to log SQL queries using Python logging instead of the
‘echo=True’ flag:

     import logging

     logging.basicConfig()
     logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)

By default, the log level is set to ‘logging.WARN’ within the entire
‘sqlalchemy’ namespace so that no log operations occur, even within an
application that has logging enabled otherwise.

     Note: The SQLAlchemy Engine conserves Python function
     call overhead by only emitting log statements when the current
     logging level is detected as ‘logging.INFO’ or ‘logging.DEBUG’.  It
     only checks this level when a new connection is procured from the
     connection pool.  Therefore when changing the logging configuration
     for an already-running application, any Connection
     that’s currently active, or more commonly a ‘Session’ object that’s
     active in a transaction, won’t log any SQL according to the new
     configuration until a new Connection is procured (in
     the case of ‘Session’, this is after the current transaction ends
     and a new one begins).

   ---------- Footnotes ----------

   (1) http://docs.python.org/library/logging.html

4.5.1.20 More on the Echo Flag
..............................

As mentioned previously, the create_engine.echo and
create_engine.echo_pool parameters are a shortcut to immediate
logging to ‘sys.stdout’:

     >>> from sqlalchemy import create_engine, text
     >>> e = create_engine("sqlite://", echo=True, echo_pool='debug')
     >>> with e.connect() as conn:
     ...    print(conn.scalar(text("select 'hi'")))
     ...
     2020-10-24 12:54:57,701 DEBUG sqlalchemy.pool.impl.SingletonThreadPool Created new connection <sqlite3.Connection object at 0x7f287819ac60>
     2020-10-24 12:54:57,701 DEBUG sqlalchemy.pool.impl.SingletonThreadPool Connection <sqlite3.Connection object at 0x7f287819ac60> checked out from pool
     2020-10-24 12:54:57,702 INFO sqlalchemy.engine.Engine select 'hi'
     2020-10-24 12:54:57,702 INFO sqlalchemy.engine.Engine ()
     hi
     2020-10-24 12:54:57,703 DEBUG sqlalchemy.pool.impl.SingletonThreadPool Connection <sqlite3.Connection object at 0x7f287819ac60> being returned to pool
     2020-10-24 12:54:57,704 DEBUG sqlalchemy.pool.impl.SingletonThreadPool Connection <sqlite3.Connection object at 0x7f287819ac60> rollback-on-return

Use of these flags is roughly equivalent to:

     import logging
     logging.basicConfig()
     logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO)
     logging.getLogger("sqlalchemy.pool").setLevel(logging.DEBUG)

It’s important to note that these two flags work `independently' of any
existing logging configuration, and will make use of
‘logging.basicConfig()’ unconditionally.  This has the effect of being
configured `in addition' to any existing logger configurations.
Therefore, `when configuring logging explicitly, ensure all echo flags
are set to False at all times', to avoid getting duplicate log lines.

4.5.1.21 Setting the Logging Name
.................................

The logger name of instance such as an Engine or Pool
defaults to using a truncated hex identifier string.  To set this
to a specific name, use the create_engine.logging_name and
create_engine.pool_logging_name with
sqlalchemy.create_engine():

     >>> from sqlalchemy import create_engine
     >>> from sqlalchemy import text
     >>> e = create_engine("sqlite://", echo=True, logging_name='myengine')
     >>> with e.connect() as conn:
     ...     conn.execute(text("select 'hi'"))
     ...
     2020-10-24 12:47:04,291 INFO sqlalchemy.engine.Engine.myengine select 'hi'
     2020-10-24 12:47:04,292 INFO sqlalchemy.engine.Engine.myengine ()

4.5.1.22 Setting Per-Connection / Sub-Engine Tokens
...................................................

New in version 1.4.0b2.

While the logging name is appropriate to establish on an Engine
object that is long lived, it’s not flexible enough to accommodate
for an arbitrarily large list of names, for the case of tracking
individual connections and/or transactions in log messages.

For this use case, the log message itself generated by the
Connection and Result objects may be augmented with
additional tokens such as transaction or request identifiers.  The
Connection.execution_options.logging_token parameter accepts a
string argument that may be used to establish per-connection tracking
tokens:

     >>> from sqlalchemy import create_engine
     >>> e = create_engine("sqlite://", echo="debug")
     >>> with e.connect().execution_options(logging_token="track1") as conn:
     ...     conn.execute("select 1").all()
     2021-02-03 11:48:45,754 INFO sqlalchemy.engine.Engine [track1] select 1
     2021-02-03 11:48:45,754 INFO sqlalchemy.engine.Engine [track1] [raw sql] ()
     2021-02-03 11:48:45,754 DEBUG sqlalchemy.engine.Engine [track1] Col ('1',)
     2021-02-03 11:48:45,755 DEBUG sqlalchemy.engine.Engine [track1] Row (1,)

The Connection.execution_options.logging_token parameter
may also be established on engines or sub-engines via
create_engine.execution_options or
Engine.execution_options().  This may be useful to apply different
logging tokens to different components of an application without
creating new engines:

     >>> from sqlalchemy import create_engine
     >>> e = create_engine("sqlite://", echo="debug")
     >>> e1 = e.execution_options(logging_token="track1")
     >>> e2 = e.execution_options(logging_token="track2")
     >>> with e1.connect() as conn:
     ...     conn.execute("select 1").all()
     2021-02-03 11:51:08,960 INFO sqlalchemy.engine.Engine [track1] select 1
     2021-02-03 11:51:08,960 INFO sqlalchemy.engine.Engine [track1] [raw sql] ()
     2021-02-03 11:51:08,960 DEBUG sqlalchemy.engine.Engine [track1] Col ('1',)
     2021-02-03 11:51:08,961 DEBUG sqlalchemy.engine.Engine [track1] Row (1,)

     >>> with e2.connect() as conn:
     ...     conn.execute("select 2").all()
     2021-02-03 11:52:05,518 INFO sqlalchemy.engine.Engine [track2] Select 1
     2021-02-03 11:52:05,519 INFO sqlalchemy.engine.Engine [track2] [raw sql] ()
     2021-02-03 11:52:05,520 DEBUG sqlalchemy.engine.Engine [track2] Col ('1',)
     2021-02-03 11:52:05,520 DEBUG sqlalchemy.engine.Engine [track2] Row (1,)

4.5.1.23 Hiding Parameters
..........................

The logging emitted by Engine also indicates an excerpt of
the SQL parameters that are present for a particular statement.  To
prevent these parameters from being logged for privacy purposes, enable
the create_engine.hide_parameters flag:

     >>> e = create_engine("sqlite://", echo=True, hide_parameters=True)
     >>> with e.connect() as conn:
     ...     conn.execute(text("select :some_private_name"), {"some_private_name": "pii"})
     ...
     2020-10-24 12:48:32,808 INFO sqlalchemy.engine.Engine select ?
     2020-10-24 12:48:32,808 INFO sqlalchemy.engine.Engine [SQL parameters hidden due to hide_parameters=True]

4.5.2 Working with Engines and Connections
------------------------------------------

This section details direct usage of the Engine,
Connection, and related objects.  Its important to note that when
using the SQLAlchemy ORM, these objects are not generally accessed;
instead, the Session object is used as the interface to the
database.  However, for applications that are built around direct usage
of textual SQL statements and/or SQL expression constructs without
involvement by the ORM’s higher level management services, the
Engine and Connection are king (and queen?)  - read
on.

4.5.2.1 Basic Usage
...................

Recall from Engine Configuration that an Engine
is created via the create_engine() call:

     engine = create_engine('mysql://scott:tiger@localhost/test')

The typical usage of create_engine() is once per particular
database URL, held globally for the lifetime of a single application
process.  A single Engine manages many individual DBAPI
connections on behalf of the process and is intended to be called upon
in a concurrent fashion.  The Engine is `not' synonymous to
the DBAPI ‘connect’ function, which represents just one connection
resource - the Engine is most efficient when created just
once at the module level of an application, not per-object or
per-function call.

tip
...

When using an Engine with multiple Python processes, such as
when using ‘os.fork’ or Python ‘multiprocessing’, it’s important that
the engine is initialized per process.  See Using Connection Pools with Multiprocessing or os.fork()
for details.

The most basic function of the Engine is to provide access
to a Connection, which can then invoke SQL statements.  To
emit a textual statement to the database looks like:

     from sqlalchemy import text

     with engine.connect() as connection:
         result = connection.execute(text("select username from users"))
         for row in result:
             print("username:", row['username'])

Above, the Engine.connect() method returns a
Connection object, and by using it in a Python context manager
(e.g.  the ‘with:’ statement) the Connection.close() method
is automatically invoked at the end of the block.  The Connection,
is a `proxy' object for an actual DBAPI connection.  The DBAPI
connection is retrieved from the connection pool at the point at which
Connection is created.

The object returned is known as CursorResult, which
references a DBAPI cursor and provides methods for fetching rows similar
to that of the DBAPI cursor.  The DBAPI cursor will be closed by the
CursorResult when all of its result rows (if any) are
exhausted.  A CursorResult that returns no rows, such as
that of an UPDATE statement (without any returned rows), releases cursor
resources immediately upon construction.

When the Connection is closed at the end of the ‘with:’
block, the referenced DBAPI connection is released to the connection
pool.  From the perspective of the database itself, the connection pool
will not actually “close” the connection assuming the pool has room to
store this connection for the next use.  When the connection is returned
to the pool for re-use, the pooling mechanism issues a ‘rollback()’ call
on the DBAPI connection so that any transactional state or locks are
removed, and the connection is ready for its next use.

Deprecated since version 2.0: The CursorResult object is
replaced in SQLAlchemy 2.0 with a newly refined object known as
‘Result’.

Our example above illustrated the execution of a textual SQL string,
which should be invoked by using the text() construct to
indicate that we’d like to use textual SQL. The
Connection.execute() method can of course accommodate more than
that, including the variety of SQL expression constructs described in
SQL Expression Language Tutorial (1.x API).

4.5.2.2 Using Transactions
..........................

     Note: This section describes how to use transactions when working
     directly with Engine and Connection
     objects.  When using the SQLAlchemy ORM, the public API for
     transaction control is via the Session object, which
     makes usage of the Transaction object internally.  See
     Managing Transactions for further information.

The Connection object provides a Connection.begin()
method which returns a Transaction object.  Like the
Connection itself, this object is usually used within a
Python ‘with:’ block so that its scope is managed:

     with engine.connect() as connection:
         with connection.begin():
             r1 = connection.execute(table1.select())
             connection.execute(table1.insert(), {"col1": 7, "col2": "this is some data"})

The above block can be stated more simply by using the
Engine.begin() method of Engine:

     # runs a transaction
     with engine.begin() as connection:
         r1 = connection.execute(table1.select())
         connection.execute(table1.insert(), {"col1": 7, "col2": "this is some data"})

The block managed by each ‘.begin()’ method has the behavior such that
the transaction is committed when the block completes.  If an exception
is raised, the transaction is instead rolled back, and the exception
propagated outwards.

The underlying object used to represent the transaction is the
Transaction object.  This object is returned by the
Connection.begin() method and includes the methods
Transaction.commit() and Transaction.rollback().  The
context manager calling form, which invokes these methods automatically,
is recommended as a best practice.

4.5.2.3 Nesting of Transaction Blocks
.....................................

Deprecated since version 1.4: The “transaction nesting” feature of
SQLAlchemy is a legacy feature that is deprecated in the 1.4 release and
will be removed in SQLAlchemy 2.0.  The pattern has proven to be a
little too awkward and complicated, unless an application makes more of
a first-class framework around the behavior.  See the following
subsection Arbitrary Transaction Nesting as an Antipattern.

The Transaction object also handles “nested” behavior by
keeping track of the outermost begin/commit pair.  In this example, two
functions both issue a transaction on a Connection, but only
the outermost Transaction object actually takes effect when
it is committed.

     # method_a starts a transaction and calls method_b
     def method_a(connection):
         with connection.begin():  # open a transaction
             method_b(connection)

     # method_b also starts a transaction
     def method_b(connection):
         with connection.begin(): # open a transaction - this runs in the
                                  # context of method_a's transaction
             connection.execute(text("insert into mytable values ('bat', 'lala')"))
             connection.execute(mytable.insert(), {"col1": "bat", "col2": "lala"})

     # open a Connection and call method_a
     with engine.connect() as conn:
         method_a(conn)

Above, ‘method_a’ is called first, which calls ‘connection.begin()’.
Then it calls ‘method_b’.  When ‘method_b’ calls ‘connection.begin()’,
it just increments a counter that is decremented when it calls
‘commit()’.  If either ‘method_a’ or ‘method_b’ calls ‘rollback()’, the
whole transaction is rolled back.  The transaction is not committed
until ‘method_a’ calls the ‘commit()’ method.  This “nesting” behavior
allows the creation of functions which “guarantee” that a transaction
will be used if one was not already available, but will automatically
participate in an enclosing transaction if one exists.

4.5.2.4 Arbitrary Transaction Nesting as an Antipattern
.......................................................

With many years of experience, the above “nesting” pattern has not
proven to be very popular, and where it has been observed in large
projects such as Openstack, it tends to be complicated.

The most ideal way to organize an application would have a single, or at
least very few, points at which the “beginning” and “commit” of all
database transactions is demarcated.  This is also the general idea
discussed in terms of the ORM at When do I construct a Session, when do I commit it, and when do I close it?.
To adapt the example
from the previous section to this practice looks like:

     # method_a calls method_b
     def method_a(connection):
         method_b(connection)

     # method_b uses the connection and assumes the transaction
     # is external
     def method_b(connection):
         connection.execute(text("insert into mytable values ('bat', 'lala')"))
         connection.execute(mytable.insert(), {"col1": "bat", "col2": "lala"})

     # open a Connection inside of a transaction and call method_a
     with engine.begin() as conn:
         method_a(conn)

That is, ‘method_a()’ and ‘method_b()’ do not deal with the details of
the transaction at all; the transactional scope of the connection is
defined `externally' to the functions that have a SQL dialogue with the
connection.

It may be observed that the above code has fewer lines, and less
indentation which tends to correlate with lower cyclomatic complexity.
The above code is organized such that ‘method_a()’ and ‘method_b()’ are
always invoked from a point at which a transaction is begun.  The
previous version of the example features a ‘method_a()’ and a
‘method_b()’ that are trying to be agnostic of this fact, which suggests
they are prepared for at least twice as many potential codepaths through
them.

4.5.2.5 Migrating from the “nesting” pattern
............................................

As SQLAlchemy’s intrinsic-nested pattern is considered legacy, an
application that for either legacy or novel reasons still seeks to have
a context that automatically frames transactions should seek to maintain
this functionality through the use of a custom Python context manager.
A similar example is also provided in terms of the ORM in the “seealso”
section below.

To provide backwards compatibility for applications that make use of
this pattern, the following context manager or a similar implementation
based on a decorator may be used:

     import contextlib

     @contextlib.contextmanager
     def transaction(connection):
         if not connection.in_transaction():
             with connection.begin():
                 yield connection
         else:
             yield connection

The above contextmanager would be used as:

     # method_a starts a transaction and calls method_b
     def method_a(connection):
         with transaction(connection):  # open a transaction
             method_b(connection)

     # method_b either starts a transaction, or uses the one already
     # present
     def method_b(connection):
         with transaction(connection):  # open a transaction
             connection.execute(text("insert into mytable values ('bat', 'lala')"))
             connection.execute(mytable.insert(), {"col1": "bat", "col2": "lala"})

     # open a Connection and call method_a
     with engine.connect() as conn:
         method_a(conn)

A similar approach may be taken such that connectivity is established on
demand as well; the below approach features a single-use context manager
that accesses an enclosing state in order to test if connectivity is
already present:

     import contextlib

     def connectivity(engine):
         connection = None

         @contextlib.contextmanager
         def connect():
             nonlocal connection

             if connection is None:
                 connection = engine.connect()
                 with connection:
                     with connection.begin():
                         yield connection
             else:
                 yield connection

         return connect

Using the above would look like:

     # method_a passes along connectivity context, at the same time
     # it chooses to establish a connection by calling "with"
     def method_a(connectivity):
         with connectivity():
             method_b(connectivity)

     # method_b also wants to use a connection from the context, so it
     # also calls "with:", but also it actually uses the connection.
     def method_b(connectivity):
         with connectivity() as connection:
             connection.execute(text("insert into mytable values ('bat', 'lala')"))
             connection.execute(mytable.insert(), {"col1": "bat", "col2": "lala"})

     # create a new connection/transaction context object and call
     # method_a
     method_a(connectivity(engine))

The above context manager acts not only as a “transaction” context but
also as a context that manages having an open connection against a
particular Engine.  When using the ORM Session,
this connectivty management is provided by the Session
itself.  An overview of ORM connectivity patterns is at Managing Transactions.

See also
........

See Migrating from the “subtransaction” pattern. - ORM version

4.5.2.6 Library Level (e.g. emulated) Autocommit
................................................

Deprecated since version 1.4: The “autocommit” feature of SQLAlchemy
Core is deprecated and will not be present in version 2.0 of SQLAlchemy.
DBAPI-level AUTOCOMMIT is now widely available which offers superior
performance and occurs transparently.  See Library-level (but not driver level) “Autocommit” removed from both Core and ORM
for
background.

     Note: This section discusses the feature within SQLAlchemy that
     automatically invokes the ‘.commit()’ method on a DBAPI connection,
     however this is against a DBAPI connection that `is itself
     transactional'.  For true AUTOCOMMIT, see the next section
     Setting Transaction Isolation Levels including DBAPI Autocommit.

The previous transaction example illustrates how to use
Transaction so that several executions can take part in the same
transaction.  What happens when we issue an INSERT, UPDATE or DELETE
call without using Transaction.?  While some DBAPI
implementations provide various special “non-transactional” modes, the
core behavior of DBAPI per PEP-0249 is that a `transaction is always in
progress', providing only ‘rollback()’ and ‘commit()’ methods but no
‘begin()’.  SQLAlchemy assumes this is the case for any given DBAPI.

Given this requirement, SQLAlchemy implements its own “autocommit”
feature which works completely consistently across all backends.  This
is achieved by detecting statements which represent data-changing
operations, i.e.  INSERT, UPDATE, DELETE, as well as data definition
language (DDL) statements such as CREATE TABLE, ALTER TABLE, and then
issuing a COMMIT automatically if no transaction is in progress.  The
detection is based on the presence of the ‘autocommit=True’ execution
option on the statement.  If the statement is a text-only statement and
the flag is not set, a regular expression is used to detect INSERT,
UPDATE, DELETE, as well as a variety of other commands for a particular
backend:

     conn = engine.connect()
     conn.execute(text("INSERT INTO users VALUES (1, 'john')"))  # autocommits

The “autocommit” feature is only in effect when no Transaction
has otherwise been declared.  This means the feature is not
generally used with the ORM, as the Session object by default
always maintains an ongoing Transaction.

Full control of the “autocommit” behavior is available using the
generative Connection.execution_options() method provided on
Connection and Engine, using the “autocommit”
flag which will turn on or off the autocommit for the selected scope.
For example, a text() construct representing a stored
procedure that commits might use it so that a SELECT statement will
issue a COMMIT:

     with engine.connect().execution_options(autocommit=True) as conn:
         conn.execute(text("SELECT my_mutating_procedure()"))

4.5.2.7 Setting Transaction Isolation Levels including DBAPI Autocommit
.......................................................................

Most DBAPIs support the concept of configurable transaction isolation
levels.  These are traditionally the four levels “READ UNCOMMITTED”,
“READ COMMITTED”, “REPEATABLE READ” and “SERIALIZABLE”.  These are
usually applied to a DBAPI connection before it begins a new
transaction, noting that most DBAPIs will begin this transaction
implicitly when SQL statements are first emitted.

DBAPIs that support isolation levels also usually support the concept of
true “autocommit”, which means that the DBAPI connection itself will be
placed into a non-transactional autocommit mode.  This usually means
that the typical DBAPI behavior of emitting “BEGIN” to the database
automatically no longer occurs, but it may also include other
directives.  When using this mode, `the DBAPI does not use a transaction
under any circumstances'.  SQLAlchemy methods like ‘.begin()’,
‘.commit()’ and ‘.rollback()’ pass silently and have no effect.

Instead, each statement invoked upon the connection will commit any
changes automatically; it sometimes also means that the connection
itself will use fewer server-side database resources.  For this reason
and others, “autocommit” mode is often desirable for non-transactional
applications that need to read individual tables or rows outside the
scope of a true ACID transaction.

SQLAlchemy dialects should support these isolation levels as well as
autocommit to as great a degree as possible.  The levels are set via
family of “execution_options” parameters and methods that are throughout
the Core, such as the Connection.execution_options() method.
The parameter is known as
Connection.execution_options.isolation_level and the values are
strings which are typically a subset of the following names:

     # possible values for Connection.execution_options(isolation_level="<value>")

     "AUTOCOMMIT"
     "READ COMMITTED"
     "READ UNCOMMITTED"
     "REPEATABLE READ"
     "SERIALIZABLE"

Not every DBAPI supports every value; if an unsupported value is used
for a certain backend, an error is raised.

For example, to force REPEATABLE READ on a specific connection, then
begin a transaction:

     with engine.connect().execution_options(isolation_level="REPEATABLE READ") as connection:
         with connection.begin():
             connection.execute(<statement>)

The Connection.execution_options.isolation_level option may
also be set engine wide, as is often preferable.  This is achieved by
passing it within the create_engine.execution_options
parameter to create_engine():

     from sqlalchemy import create_engine

     eng = create_engine(
         "postgresql://scott:tiger@localhost/test",
         execution_options={
             "isolation_level": "REPEATABLE READ"
         }
     )

With the above setting, the DBAPI connection will be set to use a
‘"REPEATABLE READ"’ isolation level setting for each new transaction
begun.

An application that frequently chooses to run operations within
different isolation levels may wish to create multiple “sub-engines” of
a lead Engine, each of which will be configured to a
different isolation level.  One such use case is an application that has
operations that break into “transactional” and “read-only” operations, a
separate Engine that makes use of ‘"AUTOCOMMIT"’ may be
separated off from the main engine:

     from sqlalchemy import create_engine

     eng = create_engine("postgresql://scott:tiger@localhost/test")

     autocommit_engine = eng.execution_options(isolation_level="AUTOCOMMIT")

Above, the Engine.execution_options() method creates a
shallow copy of the original Engine.  Both ‘eng’ and
‘autocommit_engine’ share the same dialect and connection pool.
However, the “AUTOCOMMIT” mode will be set upon connections when they
are acquired from the ‘autocommit_engine’.

The isolation level setting, regardless of which one it is, is
unconditionally reverted when a connection is returned to the connection
pool.

     Note: The Connection.execution_options.isolation_level
     parameter necessarily does not apply to statement level options,
     such as that of Executable.execution_options().  This
     because the option must be set on a DBAPI connection on a
     per-transaction basis.

See also
........

See SQLite Transaction Isolation.

See PostgreSQL Transaction Isolation.

See MySQL Transaction Isolation.

See SQL Server Transaction Isolation.

See Setting Transaction Isolation Levels / DBAPI AUTOCOMMIT. -
for the ORM

See Using DBAPI Autocommit Allows for a Readonly Version of Transparent Reconnect.
- a recipe that uses DBAPI autocommit to
transparently reconnect to the database for read-only operations

4.5.2.8 Using Server Side Cursors (a.k.a. stream results)
.........................................................

A limited number of dialects have explicit support for the concept of
“server side cursors” vs.  “buffered cursors”.  While a server side
cursor implies a variety of different capabilities, within SQLAlchemy’s
engine and dialect implementation, it refers only to whether or not a
particular set of results is fully buffered in memory before they are
fetched from the cursor, using a method such as ‘cursor.fetchall()’.
SQLAlchemy has no direct support for cursor behaviors such as scrolling;
to make use of these features for a particular DBAPI, use the cursor
directly as documented at Working with Driver SQL and Raw DBAPI Connections.

Some DBAPIs, such as the cx_Oracle DBAPI, exclusively use server side
cursors internally.  All result sets are essentially unbuffered across
the total span of a result set, utilizing only a smaller buffer that is
of a fixed size such as 100 rows at a time.

For those dialects that have conditional support for buffered or
unbuffered results, there are usually caveats to the use of the
“unbuffered”, or server side cursor mode.  When using the psycopg2
dialect for example, an error is raised if a server side cursor is used
with any kind of DML or DDL statement.  When using MySQL drivers with a
server side cursor, the DBAPI connection is in a more fragile state and
does not recover as gracefully from error conditions nor will it allow a
rollback to proceed until the cursor is fully closed.

For this reason, SQLAlchemy’s dialects will always default to the less
error prone version of a cursor, which means for PostgreSQL and MySQL
dialects it defaults to a buffered, “client side” cursor where the full
set of results is pulled into memory before any fetch methods are called
from the cursor.  This mode of operation is appropriate in the `vast
majority' of cases; unbuffered cursors are not generally useful except
in the uncommon case of an application fetching a very large number of
rows in chunks, where the processing of these rows can be complete
before more rows are fetched.

To make use of a server side cursor for a particular execution, the
Connection.execution_options.stream_results option is used,
which may be called on the Connection object, on the
statement object, or in the ORM-level contexts mentioned below.

When using this option for a statement, it’s usually appropriate to use
a method like Result.partitions() to work on small sections
of the result set at a time, while also fetching enough rows for each
pull so that the operation is efficient:

     with engine.connect() as conn:
         result = conn.execution_options(stream_results=True).execute(text("select * from table"))

         for partition in result.partitions(100):
             _process_rows(partition)

If the Result is iterated directly, rows are fetched
internally using a default buffering scheme that buffers first a small
set of rows, then a larger and larger buffer on each fetch up to a
pre-configured limit of 1000 rows.  This can be affected using the
‘max_row_buffer’ execution option:

     with engine.connect() as conn:
         conn = conn.execution_options(stream_results=True, max_row_buffer=100)
         result = conn.execute(text("select * from table"))

         for row in result:
             _process_row(row)

The size of the buffer may also be set to a fixed size using the
Result.yield_per() method.  Calling this method with a number of
rows will cause all result-fetching methods to work from buffers of the
given size, only fetching new rows when the buffer is empty:

     with engine.connect() as conn:
         result = conn.execution_options(stream_results=True).execute(text("select * from table"))

         for row in result.yield_per(100):
             _process_row(row)

The ‘stream_results’ option is also available with the ORM. When using
the ORM, either the Result.yield_per() or
Result.partitions() methods should be used to set the number of
ORM rows to be buffered each time while yielding:

     with orm.Session(engine) as session:
         result = session.execute(
             select(User).order_by(User_id).execution_options(stream_results=True),
         )
         for partition in result.partitions(100):
             _process_rows(partition)

     Note: ORM result sets currently must make use of
     Result.yield_per() or Result.partitions() in
     order to achieve streaming ORM results.  If either of these methods
     are not used to set the number of rows to fetch before yielding,
     the entire result is fetched before rows are yielded.  This may
     change in a future release so that the automatic buffer size used
     by Connection takes place for ORM results as well.

When using a 1.x style ORM query with Query, yield_per is
available via Query.yield_per(). - this also sets the
‘stream_results’ execution option:

     for row in session.query(User).yield_per(100):
         # process row

4.5.2.9 Connectionless Execution, Implicit Execution
....................................................

Deprecated since version 2.0: The features of “connectionless” and
“implicit” execution in SQLAlchemy are deprecated and will be removed in
version 2.0.  See “Implicit” and “Connectionless” execution, “bound metadata” removed
for background.

Recall from the first section we mentioned executing with and without
explicit usage of Connection.  “Connectionless” execution
refers to the usage of the ‘execute()’ method on an object which is not
a Connection.  This was illustrated using the
Engine.execute() method of Engine:

     result = engine.execute(text("select username from users"))
     for row in result:
         print("username:", row['username'])

In addition to “connectionless” execution, it is also possible to use
the Executable.execute() method of any Executable
construct, which is a marker for SQL expression objects that
support execution.  The SQL expression object itself references an
Engine or Connection known as the `bind', which it
uses in order to provide so-called “implicit” execution services.

Given a table as below:

     from sqlalchemy import MetaData, Table, Column, Integer

     meta = MetaData()
     users_table = Table('users', meta,
         Column('id', Integer, primary_key=True),
         Column('name', String(50))
     )

Explicit execution delivers the SQL text or constructed SQL expression
to the Connection.execute() method of Connection:

     engine = create_engine('sqlite:///file.db')
     with engine.connect() as connection:
         result = connection.execute(users_table.select())
         for row in result:
             # ....

Explicit, connectionless execution delivers the expression to the
Engine.execute() method of Engine:

     engine = create_engine('sqlite:///file.db')
     result = engine.execute(users_table.select())
     for row in result:
         # ....
     result.close()

Implicit execution is also connectionless, and makes usage of the
Executable.execute() method on the expression itself.  This method
is provided as part of the Executable class, which refers to
a SQL statement that is sufficient for being invoked against the
database.  The method makes usage of the assumption that either an
Engine or Connection has been `bound' to the
expression object.  By “bound” we mean that the special attribute
MetaData.bind has been used to associate a series of Table
objects and all SQL constructs derived from them with a specific
engine:

     engine = create_engine('sqlite:///file.db')
     meta.bind = engine
     result = users_table.select().execute()
     for row in result:
         # ....
     result.close()

Above, we associate an Engine with a MetaData
object using the special attribute MetaData.bind.  The
select() construct produced from the Table object has a
method Executable.execute(), which will search for an
Engine that’s “bound” to the Table.

Overall, the usage of “bound metadata” has three general effects:

   * SQL statement objects gain an Executable.execute().
     method which automatically locates a “bind” with which to execute
     themselves.

   * The ORM Session object supports using “bound metadata”
     in order to establish which Engine should be used to
     invoke SQL statements on behalf of a particular mapped class,
     though the Session also features its own explicit system
     of establishing complex Engine./ mapped class
     configurations.

   * The MetaData.create_all(), MetaData.drop_all(),
     Table.create(), Table.drop(), and
     “autoload” features all make usage of the bound Engine
     automatically without the need to pass it explicitly.

     Note: The concepts of “bound metadata” and “implicit execution” are
     not emphasized in modern SQLAlchemy.  While they offer some
     convenience, they are no longer required by any API and are never
     necessary.

     In applications where multiple Engine objects are
     present, each one logically associated with a certain set of tables
     (i.e.  `vertical sharding'), the “bound metadata” technique can be
     used so that individual Table can refer to the
     appropriate Engine automatically; in particular this is
     supported within the ORM via the Session object as a
     means to associate Table objects with an appropriate
     Engine, as an alternative to using the bind arguments
     accepted directly by the Session.

     However, the “implicit execution” technique is not at all
     appropriate for use with the ORM, as it bypasses the transactional
     context maintained by the Session.

     Overall, in the `vast majority' of cases, “bound metadata” and
     “implicit execution” are `not useful'.  While “bound metadata” has
     a marginal level of usefulness with regards to ORM configuration,
     “implicit execution” is a very old usage pattern that in most cases
     is more confusing than it is helpful, and its usage is discouraged.
     Both patterns seem to encourage the overuse of expedient “short
     cuts” in application design which lead to problems later on.

     Modern SQLAlchemy usage, especially the ORM, places a heavy stress
     on working within the context of a transaction at all times; the
     “implicit execution” concept makes the job of associating statement
     execution with a particular transaction much more difficult.  The
     Executable.execute() method on a particular SQL
     statement usually implies that the execution is not part of any
     particular transaction, which is usually not the desired effect.

In both “connectionless” examples, the Connection is created
behind the scenes; the CursorResult returned by the
‘execute()’ call references the Connection used to issue the
SQL statement.  When the CursorResult is closed, the
underlying Connection is closed for us, resulting in the
DBAPI connection being returned to the pool with transactional resources
removed.

4.5.2.10 Translation of Schema Names
....................................

To support multi-tenancy applications that distribute common sets of
tables into multiple schemas, the
Connection.execution_options.schema_translate_map execution
option may be used to repurpose a set of Table objects to
render under different schema names without any changes.

Given a table:

     user_table = Table(
         'user', metadata,
         Column('id', Integer, primary_key=True),
         Column('name', String(50))
     )

The “schema” of this Table as defined by the
Table.schema attribute is ‘None’.  The
Connection.execution_options.schema_translate_map can specify
that all Table objects with a schema of ‘None’ would instead
render the schema as ‘user_schema_one’:

     connection = engine.connect().execution_options(
         schema_translate_map={None: "user_schema_one"})

     result = connection.execute(user_table.select())

The above code will invoke SQL on the database of the form:

     SELECT user_schema_one.user.id, user_schema_one.user.name FROM
     user_schema_one.user

That is, the schema name is substituted with our translated name.  The
map can specify any number of target->destination schemas:

     connection = engine.connect().execution_options(
         schema_translate_map={
             None: "user_schema_one",     # no schema name -> "user_schema_one"
             "special": "special_schema", # schema="special" becomes "special_schema"
             "public": None               # Table objects with schema="public" will render with no schema
         })

The Connection.execution_options.schema_translate_map
parameter affects all DDL and SQL constructs generated from the SQL
expression language, as derived from the Table or
Sequence objects.  It does `not' impact literal string SQL used
via the text() construct nor via plain strings passed to
Connection.execute().

The feature takes effect `only' in those cases where the name of the
schema is derived directly from that of a Table or
Sequence; it does not impact methods where a string schema name is
passed directly.  By this pattern, it takes effect within the “can
create” / “can drop” checks performed by methods such as
MetaData.create_all() or MetaData.drop_all() are called,
and it takes effect when using table reflection given a Table
object.  However it does `not' affect the operations present on the
Inspector object, as the schema name is passed to these
methods explicitly.

     Tip: To use the schema translation feature with the ORM
     Session, set this option at the level of the Engine,
     then pass that engine to the Session.  The Session
     uses a new Connection for each transaction:

          schema_engine = engine.execution_options(schema_translate_map = { ... } )

          session = Session(schema_engine)

          ...

New in version 1.1.

4.5.2.11 SQL Compilation Caching
................................

New in version 1.4: SQLAlchemy now has a transparent query caching
system that substantially lowers the Python computational overhead
involved in converting SQL statement constructs into SQL strings across
both Core and ORM. See the introduction at Transparent SQL Compilation Caching added to All DQL, DML Statements in Core, ORM.

SQLAlchemy includes a comprehensive caching system for the SQL compiler
as well as its ORM variants.  This caching system is transparent within
the Engine and provides that the SQL compilation process for
a given Core or ORM SQL statement, as well as related computations which
assemble result-fetching mechanics for that statement, will only occur
once for that statement object and all others with the identical
structure, for the duration that the particular structure remains within
the engine’s “compiled cache”.  By “statement objects that have the
identical structure”, this generally corresponds to a SQL statement that
is constructed within a function and is built each time that function
runs:

     def run_my_statement(connection, parameter):
         stmt = select(table)
         stmt = stmt.where(table.c.col == parameter)
         stmt = stmt.order_by(table.c.id)
         return connection.execute(stmt)

The above statement will generate SQL resembling ‘SELECT id, col FROM
table WHERE col = :col ORDER BY id’, noting that while the value of
‘parameter’ is a plain Python object such as a string or an integer, the
string SQL form of the statement does not include this value as it uses
bound parameters.  Subsequent invocations of the above
‘run_my_statement()’ function will use a cached compilation construct
within the scope of the ‘connection.execute()’ call for enhanced
performance.

     Note: it is important to note that the SQL compilation cache is
     caching the `SQL string that is passed to the database only', and
     `not the data' returned by a query.  It is in no way a data cache
     and does not impact the results returned for a particular SQL
     statement nor does it imply any memory use linked to fetching of
     result rows.

While SQLAlchemy has had a rudimentary statement cache since the early
1.x series, and additionally has featured the “Baked Query” extension
for the ORM, both of these systems required a high degree of special API
use in order for the cache to be effective.  The new cache as of 1.4 is
instead completely automatic and requires no change in programming style
to be effective.

The cache is automatically used without any configurational changes and
no special steps are needed in order to enable it.  The following
sections detail the configuration and advanced usage patterns for the
cache.

4.5.2.12 Configuration
......................

The cache itself is a dictionary-like object called an ‘LRUCache’, which
is an internal SQLAlchemy dictionary subclass that tracks the usage of
particular keys and features a periodic “pruning” step which removes the
least recently used items when the size of the cache reaches a certain
threshold.  The size of this cache defaults to 500 and may be configured
using the create_engine.query_cache_size parameter:

     engine = create_engine("postgresql://scott:tiger@localhost/test", query_cache_size=1200)

The size of the cache can grow to be a factor of 150% of the size given,
before it’s pruned back down to the target size.  A cache of size 1200
above can therefore grow to be 1800 elements in size at which point it
will be pruned to 1200.

The sizing of the cache is based on a single entry per unique SQL
statement rendered, per engine.  SQL statements generated from both the
Core and the ORM are treated equally.  DDL statements will usually not
be cached.  In order to determine what the cache is doing, engine
logging will include details about the cache’s behavior, described in
the next section.

4.5.2.13 Estimating Cache Performance Using Logging
...................................................

The above cache size of 1200 is actually fairly large.  For small
applications, a size of 100 is likely sufficient.  To estimate the
optimal size of the cache, assuming enough memory is present on the
target host, the size of the cache should be based on the number of
unique SQL strings that may be rendered for the target engine in use.
The most expedient way to see this is to use SQL echoing, which is most
directly enabled by using the create_engine.echo flag, or by
using Python logging; see the section Configuring Logging for
background on logging configuration.

As an example, we will examine the logging produced by the following
program:

     from sqlalchemy import Column
     from sqlalchemy import create_engine
     from sqlalchemy import ForeignKey
     from sqlalchemy import Integer
     from sqlalchemy import String
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.orm import relationship
     from sqlalchemy.orm import Session

     Base = declarative_base()

     class A(Base):
         __tablename__ = "a"

         id = Column(Integer, primary_key=True)
         data = Column(String)
         bs = relationship("B")

     class B(Base):
         __tablename__ = "b"
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey("a.id"))
         data = Column(String)

     e = create_engine("sqlite://", echo=True)
     Base.metadata.create_all(e)

     s = Session(e)

     s.add_all(
         [A(bs=[B(), B(), B()]), A(bs=[B(), B(), B()]), A(bs=[B(), B(), B()])]
     )
     s.commit()

     for a_rec in s.query(A):
         print(a_rec.bs)

When run, each SQL statement that’s logged will include a bracketed
cache statistics badge to the left of the parameters passed.  The four
types of message we may see are summarized as follows:

   * ‘[raw sql]’ - the driver or the end-user emitted raw SQL using
     Connection.exec_driver_sql(). - caching does not apply

   * ‘[no key]’ - the statement object is a DDL statement that is not
     cached, or the statement object contains uncacheable elements such
     as user-defined constructs or arbitrarily large VALUES clauses.

   * ‘[generated in Xs]’ - the statement was a `cache miss' and had to
     be compiled, then stored in the cache.  it took X seconds to
     produce the compiled construct.  The number X will be in the small
     fractional seconds.

   * ‘[cached since Xs ago]’ - the statement was a `cache hit' and did
     not have to be recompiled.  The statement has been stored in the
     cache since X seconds ago.  The number X will be proportional to
     how long the application has been running and how long the
     statement has been cached, so for example would be 86400 for a 24
     hour period.

Each badge is described in more detail below.

The first statements we see for the above program will be the SQLite
dialect checking for the existence of the “a” and “b” tables:

     INFO sqlalchemy.engine.Engine PRAGMA temp.table_info("a")
     INFO sqlalchemy.engine.Engine [raw sql] ()
     INFO sqlalchemy.engine.Engine PRAGMA main.table_info("b")
     INFO sqlalchemy.engine.Engine [raw sql] ()

For the above two SQLite PRAGMA statements, the badge reads ‘[raw sql]’,
which indicates the driver is sending a Python string directly to the
database using Connection.exec_driver_sql().  Caching does
not apply to such statements because they already exist in string form,
and there is nothing known about what kinds of result rows will be
returned since SQLAlchemy does not parse SQL strings ahead of time.

The next statements we see are the CREATE TABLE statements:

     INFO sqlalchemy.engine.Engine
     CREATE TABLE a (
       id INTEGER NOT NULL,
       data VARCHAR,
       PRIMARY KEY (id)
     )

     INFO sqlalchemy.engine.Engine [no key 0.00007s] ()
     INFO sqlalchemy.engine.Engine
     CREATE TABLE b (
       id INTEGER NOT NULL,
       a_id INTEGER,
       data VARCHAR,
       PRIMARY KEY (id),
       FOREIGN KEY(a_id) REFERENCES a (id)
     )

     INFO sqlalchemy.engine.Engine [no key 0.00006s] ()

For each of these statements, the badge reads ‘[no key 0.00006s]’.  This
indicates that these two particular statements, caching did not occur
because the DDL-oriented CreateTable construct did not
produce a cache key.  DDL constructs generally do not participate in
caching because they are not typically subject to being repeated a
second time and DDL is also a database configurational step where
performance is not as critical.

The ‘[no key]’ badge is important for one other reason, as it can be
produced for SQL statements that are cacheable except for some
particular sub-construct that is not currently cacheable.  Examples of
this include custom user-defined SQL elements that don’t define caching
parameters, as well as some constructs that generate arbitrarily long
and non-reproducible SQL strings, the main examples being the
Values construct as well as when using “multivalued inserts” with
the Insert.values() method.

So far our cache is still empty.  The next statements will be cached
however, a segment looks like:

     INFO sqlalchemy.engine.Engine INSERT INTO a (data) VALUES (?)
     INFO sqlalchemy.engine.Engine [generated in 0.00011s] (None,)
     INFO sqlalchemy.engine.Engine INSERT INTO a (data) VALUES (?)
     INFO sqlalchemy.engine.Engine [cached since 0.0003533s ago] (None,)
     INFO sqlalchemy.engine.Engine INSERT INTO a (data) VALUES (?)
     INFO sqlalchemy.engine.Engine [cached since 0.0005326s ago] (None,)
     INFO sqlalchemy.engine.Engine INSERT INTO b (a_id, data) VALUES (?, ?)
     INFO sqlalchemy.engine.Engine [generated in 0.00010s] (1, None)
     INFO sqlalchemy.engine.Engine INSERT INTO b (a_id, data) VALUES (?, ?)
     INFO sqlalchemy.engine.Engine [cached since 0.0003232s ago] (1, None)
     INFO sqlalchemy.engine.Engine INSERT INTO b (a_id, data) VALUES (?, ?)
     INFO sqlalchemy.engine.Engine [cached since 0.0004887s ago] (1, None)

Above, we see essentially two unique SQL strings; ‘"INSERT INTO a (data)
VALUES (?)"’ and ‘"INSERT INTO b (a_id, data) VALUES (?, ?)"’.  Since
SQLAlchemy uses bound parameters for all literal values, even though
these statements are repeated many times for different objects, because
the parameters are separate, the actual SQL string stays the same.

     Note: the above two statements are generated by the ORM unit of
     work process, and in fact will be caching these in a separate cache
     that is local to each mapper.  However the mechanics and
     terminology are the same.  The section Disabling or using an alternate dictionary to cache some (or all) statements
     below
     will describe how user-facing code can also use an alternate
     caching container on a per-statement basis.

The caching badge we see for the first occurrence of each of these two
statements is ‘[generated in 0.00011s]’.  This indicates that the
statement was `not in the cache, was compiled into a String in .00011s
and was then cached'.  When we see the ‘[generated]’ badge, we know that
this means there was a `cache miss'.  This is to be expected for the
first occurrence of a particular statement.  However, if lots of new
‘[generated]’ badges are observed for a long-running application that is
generally using the same series of SQL statements over and over, this
may be a sign that the create_engine.query_cache_size
parameter is too small.  When a statement that was cached is then
evicted from the cache due to the LRU cache pruning lesser used items,
it will display the ‘[generated]’ badge when it is next used.

The caching badge that we then see for the subsequent occurrences of
each of these two statements looks like ‘[cached since 0.0003533s ago]’.
This indicates that the statement `was found in the cache, and was
originally placed into the cache .0003533 seconds ago'.  It is important
to note that while the ‘[generated]’ and ‘[cached since]’ badges refer
to a number of seconds, they mean different things; in the case of
‘[generated]’, the number is a rough timing of how long it took to
compile the statement, and will be an extremely small amount of time.
In the case of ‘[cached since]’, this is the total time that a statement
has been present in the cache.  For an application that’s been running
for six hours, this number may read ‘[cached since 21600 seconds ago]’,
and that’s a good thing.  Seeing high numbers for “cached since” is an
indication that these statements have not been subject to cache misses
for a long time.  Statements that frequently have a low number of
“cached since” even if the application has been running a long time may
indicate these statements are too frequently subject to cache misses,
and that the create_engine.query_cache_size may need to be
increased.

Our example program then performs some SELECTs where we can see the same
pattern of “generated” then “cached”, for the SELECT of the “a” table as
well as for subsequent lazy loads of the “b” table:

     INFO sqlalchemy.engine.Engine SELECT a.id AS a_id, a.data AS a_data
     FROM a
     INFO sqlalchemy.engine.Engine [generated in 0.00009s] ()
     INFO sqlalchemy.engine.Engine SELECT b.id AS b_id, b.a_id AS b_a_id, b.data AS b_data
     FROM b
     WHERE ? = b.a_id
     INFO sqlalchemy.engine.Engine [generated in 0.00010s] (1,)
     INFO sqlalchemy.engine.Engine SELECT b.id AS b_id, b.a_id AS b_a_id, b.data AS b_data
     FROM b
     WHERE ? = b.a_id
     INFO sqlalchemy.engine.Engine [cached since 0.0005922s ago] (2,)
     INFO sqlalchemy.engine.Engine SELECT b.id AS b_id, b.a_id AS b_a_id, b.data AS b_data
     FROM b
     WHERE ? = b.a_id

From our above program, a full run shows a total of four distinct SQL
strings being cached.  Which indicates a cache size of `four' would be
sufficient.  This is obviously an extremely small size, and the default
size of 500 is fine to be left at its default.

4.5.2.14 How much memory does the cache use?
............................................

The previous section detailed some techniques to check if the
create_engine.query_cache_size needs to be bigger.  How do we
know if the cache is not too large?  The reason we may want to set
create_engine.query_cache_size to not be higher than a certain
number would be because we have an application that may make use of a
very large number of different statements, such as an application that
is building queries on the fly from a search UX, and we don’t want our
host to run out of memory if for example, a hundred thousand different
queries were run in the past 24 hours and they were all cached.

It is extremely difficult to measure how much memory is occupied by
Python data structures, however using a process to measure growth in
memory via ‘top’ as a successive series of 250 new statements are added
to the cache suggest a moderate Core statement takes up about 12K while
a small ORM statement takes about 20K, including result-fetching
structures which for the ORM will be much greater.

4.5.2.15 Disabling or using an alternate dictionary to cache some (or all) statements
.....................................................................................

The internal cache used is known as ‘LRUCache’, but this is mostly just
a dictionary.  Any dictionary may be used as a cache for any series of
statements by using the
Connection.execution_options.compiled_cache option as an
execution option.  Execution options may be set on a statement, on an
Engine or Connection, as well as when using the
ORM Session.execute() method for SQLAlchemy-2.0 style
invocations.  For example, to run a series of SQL statements and have
them cached in a particular dictionary:

     my_cache = {}
     with engine.connect().execution_options(compiled_cache=my_cache) as conn:
         conn.execute(table.select())

The SQLAlchemy ORM uses the above technique to hold onto per-mapper
caches within the unit of work “flush” process that are separate from
the default cache configured on the Engine, as well as for
some relationship loader queries.

The cache can also be disabled with this argument by sending a value of
‘None’:

     # disable caching for this connection
     with engine.connect().execution_options(compiled_cache=None) as conn:
         conn.execute(table.select())

4.5.2.16 Using Lambdas to add significant speed gains to statement production
.............................................................................

     deepalchemy: This technique is generally non-essential except in
     very performance intensive scenarios, and intended for experienced
     Python programmers.  While fairly straightforward, it involves
     metaprogramming concepts that are not appropriate for novice Python
     developers.  The lambda approach can be applied to at a later time
     to existing code with a minimal amount of effort.

Python functions, typically expressed as lambdas, may be used to
generate SQL expressions which are cacheable based on the Python code
location of the lambda function itself as well as the closure variables
within the lambda.  The rationale is to allow caching of not only the
SQL string-compiled form of a SQL expression construct as is
SQLAlchemy’s normal behavior when the lambda system isn’t used, but also
the in-Python composition of the SQL expression construct itself, which
also has some degree of Python overhead.

The lambda SQL expression feature is available as a performance
enhancing feature, and is also optionally used in the
with_loader_criteria(). ORM option in order to provide a generic
SQL fragment.

4.5.2.17 Synopsis
.................

Lambda statements are constructed using the lambda_stmt()
function, which returns an instance of StatementLambdaElement,
which is itself an executable statement construct.  Additional
modifiers and criteria are added to the object using the Python addition
operator ‘+’, or alternatively the
StatementLambdaElement.add_criteria() method which allows for more
options.

It is assumed that the lambda_stmt() construct is being
invoked within an enclosing function or method that expects to be used
many times within an application, so that subsequent executions beyond
the first one can take advantage of the compiled SQL being cached.  When
the lambda is constructed inside of an enclosing function in Python it
is then subject to also having closure variables, which are significant
to the whole approach:

     from sqlalchemy import lambda_stmt

     def run_my_statement(connection, parameter):
         stmt = lambda_stmt(lambda: select(table))
         stmt += lambda s: s.where(table.c.col == parameter)
         stmt += lambda s: s.order_by(table.c.id)

         return connection.execute(stmt)

     with engine.connect() as conn:
         result = run_my_statement(some_connection, "some parameter")

Above, the three ‘lambda’ callables that are used to define the
structure of a SELECT statement are invoked exactly once, and the
resulting SQL string cached in the compilation cache of the engine.
From that point forward, the ‘run_my_statement()’ function may be
invoked any number of times and the ‘lambda’ callables within it will
not be called, only used as cache keys to retrieve the already-compiled
SQL.

     Note: It is important to note that there is already SQL caching in
     place when the lambda system is not used.  The lambda system only
     adds an additional layer of work reduction per SQL statement
     invoked by caching the building up of the SQL construct itself and
     also using a simpler cache key.

4.5.2.18 Quick Guidelines for Lambdas
.....................................

Above all, the emphasis within the lambda SQL system is ensuring that
there is never a mismatch between the cache key generated for a lambda
and the SQL string it will produce.  The ‘LamdaElement’ and related
objects will run and analyze the given lambda in order to calculate how
it should be cached on each run, trying to detect any potential
problems.  Basic guidelines include:

   * `Any kind of statement is supported' - while it’s expected that
     select() constructs are the prime use case for
     lambda_stmt(), DML statements such as insert() and
     update() are equally usable:

          def upd(id_, newname):
              stmt = lambda_stmt(lambda: users.update())
              stmt += lambda s: s.values(name=newname)
              stmt += lambda s: s.where(users.c.id==id_)
              return stmt

          with engine.begin() as conn:
              conn.execute(upd(7, "foo"))

   * `ORM use cases directly supported as well' - the
     lambda_stmt() can accommodate ORM functionality completely
     and used directly with Session.execute():

          def select_user(session, name):
              stmt = lambda_stmt(lambda: select(User))
              stmt += lambda s: s.where(User.name == name)

              row = session.execute(stmt).first()
              return row

   * `Bound parameters are automatically accommodated' - in contrast to
     SQLAlchemy’s previous “baked query” system, the lambda SQL system
     accommodates for Python literal values which become SQL bound
     parameters automatically.  This means that even though a given
     lambda runs only once, the values that become bound parameters are
     extracted from the `closure' of the lambda on every run:

          >>> def my_stmt(x, y):
          ...     stmt = lambda_stmt(lambda: select(func.max(x, y)))
          ...     return stmt
          ...
          >>> engine = create_engine("sqlite://", echo=True)
          >>> with engine.connect() as conn:
          ...     print(conn.scalar(my_stmt(5, 10)))
          ...     print(conn.scalar(my_stmt(12, 8)))
          ...
          {opensql}SELECT max(?, ?) AS max_1
          [generated in 0.00057s] (5, 10){stop}
          10
          {opensql}SELECT max(?, ?) AS max_1
          [cached since 0.002059s ago] (12, 8){stop}
          12

     Above, see StatementLambdaElement extracted the values of
     ‘x’ and ‘y’ from the `closure' of the lambda that is generated each
     time ‘my_stmt()’ is invoked; these were substituted into the cached
     SQL construct as the values of the parameters.

   * `The lambda should ideally produce an identical SQL structure in
     all cases' - Avoid using conditionals or custom callables inside of
     lambdas that might make it produce different SQL based on inputs;
     if a function might conditionally use two different SQL fragments,
     use two separate lambdas:

          # **Don't** do this:

          def my_stmt(parameter, thing=False):
              stmt = lambda_stmt(lambda: select(table))
              stmt += (
                  lambda s: s.where(table.c.x > parameter) if thing
                  else s.where(table.c.y == parameter)
              return stmt

          # **Do** do this:

          def my_stmt(parameter, thing=False):
              stmt = lambda_stmt(lambda: select(table))
              if thing:
                  stmt += s.where(table.c.x > parameter)
              else:
                  stmt += s.where(table.c.y == parameter)
              return stmt

     There are a variety of failures which can occur if the lambda does
     not produce a consistent SQL construct and some are not trivially
     detectable right now.

   * `Don’t use functions inside the lambda to produce bound values' -
     the bound value tracking approach requires that the actual value to
     be used in the SQL statement be locally present in the closure of
     the lambda.  This is not possible if values are generated from
     other functions, and the LambdaElement should normally
     raise an error if this is attempted:

          >>> def my_stmt(x, y):
          ...     def get_x():
          ...         return x
          ...     def get_y():
          ...         return y
          ...
          ...     stmt = lambda_stmt(lambda: select(func.max(get_x(), get_y())))
          ...     return stmt
          ...
          >>> with engine.connect() as conn:
          ...     print(conn.scalar(my_stmt(5, 10)))
          ...
          Traceback (most recent call last):
            # ...
          sqlalchemy.exc.InvalidRequestError: Can't invoke Python callable get_x()
          inside of lambda expression argument at
          <code object <lambda> at 0x7fed15f350e0, file "<stdin>", line 6>;
          lambda SQL constructs should not invoke functions from closure variables
          to produce literal values since the lambda SQL system normally extracts
          bound values without actually invoking the lambda or any functions within it.

     Above, the use of ‘get_x()’ and ‘get_y()’, if they are necessary,
     should occur `outside' of the lambda and assigned to a local
     closure variable:

          >>> def my_stmt(x, y):
          ...     def get_x():
          ...         return x
          ...     def get_y():
          ...         return y
          ...
          ...     x_param, y_param = get_x(), get_y()
          ...     stmt = lambda_stmt(lambda: select(func.max(x_param, y_param)))
          ...     return stmt

   * `Avoid referring to non-SQL constructs inside of lambdas as they
     are not cacheable by default' - this issue refers to how the
     LambdaElement creates a cache key from other closure
     variables within the statement.  In order to provide the best
     guarantee of an accurate cache key, all objects located in the
     closure of the lambda are considered to be significant, and none
     will be assumed to be appropriate for a cache key by default.  So
     the following example will also raise a rather detailed error
     message:

          >>> class Foo:
          ...     def __init__(self, x, y):
          ...         self.x = x
          ...         self.y = y
          ...
          >>> def my_stmt(foo):
          ...     stmt = lambda_stmt(lambda: select(func.max(foo.x, foo.y)))
          ...     return stmt
          ...
          >>> with engine.connect() as conn:
          ...    print(conn.scalar(my_stmt(Foo(5, 10))))
          ...
          Traceback (most recent call last):
            # ...
          sqlalchemy.exc.InvalidRequestError: Closure variable named 'foo' inside of
          lambda callable <code object <lambda> at 0x7fed15f35450, file
          "<stdin>", line 2> does not refer to a cachable SQL element, and also
          does not appear to be serving as a SQL literal bound value based on the
          default SQL expression returned by the function.  This variable needs to
          remain outside the scope of a SQL-generating lambda so that a proper cache
          key may be generated from the lambda's state.  Evaluate this variable
          outside of the lambda, set track_on=[<elements>] to explicitly select
          closure elements to track, or set track_closure_variables=False to exclude
          closure variables from being part of the cache key.

     The above error indicates that LambdaElement will not
     assume that the ‘Foo’ object passed in will contine to behave the
     same in all cases.  It also won’t assume it can use ‘Foo’ as part
     of the cache key by default; if it were to use the ‘Foo’ object as
     part of the cache key, if there were many different ‘Foo’ objects
     this would fill up the cache with duplicate information, and would
     also hold long-lasting references to all of these objects.

     The best way to resolve the above situation is to not refer to
     ‘foo’ inside of the lambda, and refer to it `outside' instead:

          >>> def my_stmt(foo):
          ...     x_param, y_param = foo.x, foo.y
          ...     stmt = lambda_stmt(lambda: select(func.max(x_param, y_param)))
          ...     return stmt

     In some situations, if the SQL structure of the lambda is
     guaranteed to never change based on input, to pass
     ‘track_closure_variables=False’ which will disable any tracking of
     closure variables other than those used for bound parameters:

          >>> def my_stmt(foo):
          ...     stmt = lambda_stmt(
          ...         lambda: select(func.max(foo.x, foo.y)),
          ...         track_closure_variables=False
          ...     )
          ...     return stmt

     There is also the option to add objects to the element to
     explicitly form part of the cache key, using the ‘track_on’
     parameter; using this parameter allows specific values to serve as
     the cache key and will also prevent other closure variables from
     being considered.  This is useful for cases where part of the SQL
     being constructed originates from a contextual object of some sort
     that may have many different values.  In the example below, the
     first segment of the SELECT statement will disable tracking of the
     ‘foo’ variable, whereas the second segment will explicitly track
     ‘self’ as part of the cache key:

          >>> def my_stmt(self, foo):
          ...     stmt = lambda_stmt(
          ...         lambda: select(*self.column_expressions),
          ...         track_closure_variables=False
          ...     )
          ...     stmt = stmt.add_criteria(
          ...         lambda: self.where_criteria,
          ...         track_on=[self]
          ...     )
          ...     return stmt

     Using ‘track_on’ means the given objects will be stored long term
     in the lambda’s internal cache and will have strong references for
     as long as the cache doesn’t clear out those objects (an LRU scheme
     of 1000 entries is used by default).

4.5.2.19 Cache Key Generation
.............................

In order to understand some of the options and behaviors which occur
with lambda SQL constructs, an understanding of the caching system is
helpful.

SQLAlchemy’s caching system normally generates a cache key from a given
SQL expression construct by producing a structure that represents all
the state within the construct:

     >>> from sqlalchemy import select, column
     >>> stmt = select(column('q'))
     >>> cache_key = stmt._generate_cache_key()
     >>> print(cache_key)  # somewhat paraphrased
     CacheKey(key=(
       '0',
       <class 'sqlalchemy.sql.selectable.Select'>,
       '_raw_columns',
       (
         (
           '1',
           <class 'sqlalchemy.sql.elements.ColumnClause'>,
           'name',
           'q',
           'type',
           (
             <class 'sqlalchemy.sql.sqltypes.NullType'>,
           ),
         ),
       ),
       # a few more elements are here, and many more for a more
       # complicated SELECT statement
     ),)

The above key is stored in the cache which is essentially a dictionary,
and the value is a construct that among other things stores the string
form of the SQL statement, in this case the phrase “SELECT q”.  We can
observe that even for an extremely short query the cache key is pretty
verbose as it has to represent everything that may vary about what’s
being rendered and potentially executed.

The lambda construction system by contrast creates a different kind of
cache key:

     >>> from sqlalchemy import lambda_stmt
     >>> stmt = lambda_stmt(lambda: select(column("q")))
     >>> cache_key = stmt._generate_cache_key()
     >>> print(cache_key)
     CacheKey(key=(
       <code object <lambda> at 0x7fed1617c710, file "<stdin>", line 1>,
       <class 'sqlalchemy.sql.lambdas.StatementLambdaElement'>,
     ),)

Above, we see a cache key that is vastly shorter than that of the
non-lambda statement, and additionally that production of the
‘select(column("q"))’ construct itself was not even necessary; the
Python lambda itself contains an attribute called ‘__code__’ which
refers to a Python code object that within the runtime of the
application is immutable and permanent.

When the lambda also includes closure variables, in the normal case that
these variables refer to SQL constructs such as column objects, they
become part of the cache key, or if they refer to literal values that
will be bound parameters, they are placed in a separate element of the
cache key:

     >>> def my_stmt(parameter):
     ...     col = column("q")
     ...     stmt = lambda_stmt(lambda: select(col))
     ...     stmt += lambda s: s.where(col == parameter)
     ...     return stmt

The above StatementLambdaElement includes two lambdas, both
of which refer to the ‘col’ closure variable, so the cache key will
represent both of these segments as well as the ‘column()’ object:

     >>> stmt = my_stmt(5)
     >>> key = stmt._generate_cache_key()
     >>> print(key)
     CacheKey(key=(
       <code object <lambda> at 0x7f07323c50e0, file "<stdin>", line 3>,
       (
         '0',
         <class 'sqlalchemy.sql.elements.ColumnClause'>,
         'name',
         'q',
         'type',
         (
           <class 'sqlalchemy.sql.sqltypes.NullType'>,
         ),
       ),
       <code object <lambda> at 0x7f07323c5190, file "<stdin>", line 4>,
       <class 'sqlalchemy.sql.lambdas.LinkedLambdaElement'>,
       (
         '0',
         <class 'sqlalchemy.sql.elements.ColumnClause'>,
         'name',
         'q',
         'type',
         (
           <class 'sqlalchemy.sql.sqltypes.NullType'>,
         ),
       ),
       (
         '0',
         <class 'sqlalchemy.sql.elements.ColumnClause'>,
         'name',
         'q',
         'type',
         (
           <class 'sqlalchemy.sql.sqltypes.NullType'>,
         ),
       ),
     ),)

The second part of the cache key has retrieved the bound parameters that
will be used when the statement is invoked:

     >>> key.bindparams
     [BindParameter('%(139668884281280 parameter)s', 5, type_=Integer())]

For a series of examples of “lambda” caching with performance
comparisons, see the “short_selects” test suite within the
Performance performance example.

4.5.2.20 Engine Disposal
........................

The Engine refers to a connection pool, which means under
normal circumstances, there are open database connections present while
the Engine object is still resident in memory.  When an
Engine is garbage collected, its connection pool is no
longer referred to by that Engine, and assuming none of its
connections are still checked out, the pool and its connections will
also be garbage collected, which has the effect of closing out the
actual database connections as well.  But otherwise, the Engine
will hold onto open database connections assuming it uses the
normally default pool implementation of QueuePool.

The Engine is intended to normally be a permanent fixture
established up-front and maintained throughout the lifespan of an
application.  It is `not' intended to be created and disposed on a
per-connection basis; it is instead a registry that maintains both a
pool of connections as well as configurational information about the
database and DBAPI in use, as well as some degree of internal caching of
per-database resources.

However, there are many cases where it is desirable that all connection
resources referred to by the Engine be completely closed
out.  It’s generally not a good idea to rely on Python garbage
collection for this to occur for these cases; instead, the Engine
can be explicitly disposed using the Engine.dispose()
method.  This disposes of the engine’s underlying connection pool and
replaces it with a new one that’s empty.  Provided that the
Engine is discarded at this point and no longer used, all
`checked-in' connections which it refers to will also be fully closed.

Valid use cases for calling Engine.dispose() include:

   * When a program wants to release any remaining checked-in
     connections held by the connection pool and expects to no longer be
     connected to that database at all for any future operations.

   * When a program uses multiprocessing or ‘fork()’, and an
     Engine object is copied to the child process, see
     Engine.dispose() should be called so that the engine creates
     brand new database connections local to that fork.  Database
     connections generally do `not' travel across process boundaries.

   * Within test suites or multitenancy scenarios where many ad-hoc,
     short-lived Engine objects may be created and disposed.

Connections that are `checked out' are `not' discarded when the engine
is disposed or garbage collected, as these connections are still
strongly referenced elsewhere by the application.  However, after
Engine.dispose() is called, those connections are no longer
associated with that Engine; when they are closed, they will
be returned to their now-orphaned connection pool which will ultimately
be garbage collected, once all connections which refer to it are also no
longer referenced anywhere.  Since this process is not easy to control,
it is strongly recommended that Engine.dispose() is called
only after all checked out connections are checked in or otherwise
de-associated from their pool.

An alternative for applications that are negatively impacted by the
Engine object’s use of connection pooling is to disable
pooling entirely.  This typically incurs only a modest performance
impact upon the use of new connections, and means that when a connection
is checked in, it is entirely closed out and is not held in memory.  See
Switching Pool Implementations for guidelines on how to
disable pooling.

4.5.2.21 Working with Driver SQL and Raw DBAPI Connections
..........................................................

The introduction on using Connection.execute() made use of
the text() construct in order to illustrate how textual SQL
statements may be invoked.  When working with SQLAlchemy, textual SQL is
actually more of the exception rather than the norm, as the Core
expression language and the ORM both abstract away the textual
representation of SQL. However, the text() construct itself
also provides some abstraction of textual SQL in that it normalizes how
bound parameters are passed, as well as that it supports datatyping
behavior for parameters and result set rows.

4.5.2.22 Invoking SQL strings directly to the driver
....................................................

For the use case where one wants to invoke textual SQL directly passed
to the underlying driver (known as the DBAPI) without any intervention
from the text() construct, the
Connection.exec_driver_sql() method may be used:

     with engine.connect() as conn:
         conn.exec_driver_sql("SET param='bar'")

New in version 1.4: Added the Connection.exec_driver_sql()
method.

4.5.2.23 Working with the DBAPI cursor directly
...............................................

There are some cases where SQLAlchemy does not provide a genericized way
at accessing some DBAPI functions, such as calling stored procedures as
well as dealing with multiple result sets.  In these cases, it’s just as
expedient to deal with the raw DBAPI connection directly.

The most common way to access the raw DBAPI connection is to get it from
an already present Connection object directly.  It is
present using the Connection.connection attribute:

     connection = engine.connect()
     dbapi_conn = connection.connection

The DBAPI connection here is actually a “proxied” in terms of the
originating connection pool, however this is an implementation detail
that in most cases can be ignored.  As this DBAPI connection is still
contained within the scope of an owning Connection object,
it is best to make use of the Connection object for most
features such as transaction control as well as calling the
Connection.close() method; if these operations are performed on
the DBAPI connection directly, the owning Connection will
not be aware of these changes in state.

To overcome the limitations imposed by the DBAPI connection that is
maintained by an owning Connection, a DBAPI connection is
also available without the need to procure a Connection
first, using the Engine.raw_connection() method of
Engine:

     dbapi_conn = engine.raw_connection()

This DBAPI connection is again a “proxied” form as was the case before.
The purpose of this proxying is now apparent, as when we call the
‘.close()’ method of this connection, the DBAPI connection is typically
not actually closed, but instead released back to the engine’s
connection pool:

     dbapi_conn.close()

While SQLAlchemy may in the future add built-in patterns for more DBAPI
use cases, there are diminishing returns as these cases tend to be
rarely needed and they also vary highly dependent on the type of DBAPI
in use, so in any case the direct DBAPI calling pattern is always there
for those cases where it is needed.

Some recipes for DBAPI connection use follow.

4.5.2.24 Calling Stored Procedures
..................................

For stored procedures with special syntactical or parameter concerns,
DBAPI-level callproc(1) may be used:

     connection = engine.raw_connection()
     try:
         cursor = connection.cursor()
         cursor.callproc("my_procedure", ['x', 'y', 'z'])
         results = list(cursor.fetchall())
         cursor.close()
         connection.commit()
     finally:
         connection.close()

   ---------- Footnotes ----------

   (1) http://legacy.python.org/dev/peps/pep-0249/#callproc

4.5.2.25 Multiple Result Sets
.............................

Multiple result set support is available from a raw DBAPI cursor using
the nextset(1) method:

     connection = engine.raw_connection()
     try:
         cursor = connection.cursor()
         cursor.execute("select * from table1; select * from table2")
         results_one = cursor.fetchall()
         cursor.nextset()
         results_two = cursor.fetchall()
         cursor.close()
     finally:
         connection.close()

   ---------- Footnotes ----------

   (1) http://legacy.python.org/dev/peps/pep-0249/#nextset

4.5.2.26 Registering New Dialects
.................................

The create_engine() function call locates the given dialect
using setuptools entrypoints.  These entry points can be established for
third party dialects within the setup.py script.  For example, to create
a new dialect “foodialect://”, the steps are as follows:

  1. Create a package called ‘foodialect’.

  2. The package should have a module containing the dialect class,
     which is typically a subclass of
     sqlalchemy.engine.default.DefaultDialect.  In this example
     let’s say it’s called ‘FooDialect’ and its module is accessed via
     ‘foodialect.dialect’.

  3. The entry point can be established in setup.py as follows:

          entry_points="""
          [sqlalchemy.dialects]
          foodialect = foodialect.dialect:FooDialect
          """

If the dialect is providing support for a particular DBAPI on top of an
existing SQLAlchemy-supported database, the name can be given including
a database-qualification.  For example, if ‘FooDialect’ were in fact a
MySQL dialect, the entry point could be established like this:

     entry_points="""
     [sqlalchemy.dialects]
     mysql.foodialect = foodialect.dialect:FooDialect
     """

The above entrypoint would then be accessed as
‘create_engine("mysql+foodialect://")’.

4.5.2.27 Registering Dialects In-Process
........................................

SQLAlchemy also allows a dialect to be registered within the current
process, bypassing the need for separate installation.  Use the
‘register()’ function as follows:

     from sqlalchemy.dialects import registry
     registry.register("mysql.foodialect", "myapp.dialect", "MyMySQLDialect")

The above will respond to ‘create_engine("mysql+foodialect://")’ and
load the ‘MyMySQLDialect’ class from the ‘myapp.dialect’ module.

4.5.2.28 Connection / Engine API
................................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See Connection.Provides high-level functionality for a wrapped DB-API connection.

See CreateEnginePlugin.A set of hooks intended to augment the construction of an Engine object based on
               entrypoint names in a URL.

See Engine.Connects a Pool and ‘Dialect’ together to provide a source of database
               connectivity and behavior.

See ExceptionContext.Encapsulate information about an error condition in progress.

See NestedTransaction.Represent a ‘nested’, or SAVEPOINT transaction.

See RootTransaction.Represent the “root” transaction on a Connection.

See Transaction.Represent a database transaction in progress.

See TwoPhaseTransaction.Represent a two-phase transaction.

 -- Class: sqlalchemy.engine.Connection (engine, connection=None,
          close_with_result=False, _branch_from=None,
          _execution_options=None, _dispatch=None, _has_events=None)

     Provides high-level functionality for a wrapped DB-API connection.

     `This is the SQLAlchemy 1.x.x version' of the Connection
     class.  For the 2.0 style version, which features some API
     differences, see Connection.

     The Connection object is procured by calling the
     Engine.connect() method of the Engine object, and
     provides services for execution of SQL statements as well as
     transaction control.

     The Connection object is `not' thread-safe.  While a Connection can
     be shared among threads using properly synchronized access, it is
     still possible that the underlying DBAPI connection may not support
     shared access between threads.  Check the DBAPI documentation for
     details.

     The Connection object represents a single DBAPI connection checked
     out from the connection pool.  In this state, the connection pool
     has no affect upon the connection, including its expiration or
     timeout state.  For the connection pool to properly manage
     connections, connections should be returned to the connection pool
     (i.e.  ‘connection.close()’) whenever the connection is not in use.

     `Class signature'

     class sqlalchemy.engine.Connection.
     (‘sqlalchemy.engine.Connectable’)

      -- Method: sqlalchemy.engine.Connection..__init__
               (engine, connection=None, close_with_result=False,
               _branch_from=None, _execution_options=None,
               _dispatch=None, _has_events=None)

          Construct a new Connection.

      -- Method: sqlalchemy.engine.Connection..begin ()

          Begin a transaction and return a transaction handle.

          The returned object is an instance of Transaction.
          This object represents the “scope” of the transaction, which
          completes when either the Transaction.rollback()
          or Transaction.commit() method is called.

          Nested calls to begin() on the same
          Connection will return new Transaction
          objects that represent an emulated transaction within the
          scope of the enclosing transaction, that is:

               trans = conn.begin()   # outermost transaction
               trans2 = conn.begin()  # "nested"
               trans2.commit()        # does nothing
               trans.commit()         # actually commits

          Calls to Transaction.commit() only have an effect
          when invoked via the outermost Transaction object,
          though the Transaction.rollback() method of any
          of the Transaction objects will roll back the
          transaction.

          See also
          ........

          See Connection.begin_nested(). - use a SAVEPOINT

          See Connection.begin_twophase(). - use a two phase
          /XID transaction

          See Engine.begin(). - context manager available from
          Engine.

      -- Method: sqlalchemy.engine.Connection..begin_nested
               ()

          Begin a nested transaction and return a transaction handle.

          The returned object is an instance of NestedTransaction.

          Nested transactions require SAVEPOINT support in the
          underlying database.  Any transaction in the hierarchy may
          ‘commit’ and ‘rollback’, however the outermost transaction
          still controls the overall ‘commit’ or ‘rollback’ of the
          transaction of a whole.

          See also
          ........

          See Connection.begin().

          See Connection.begin_twophase().

      -- Method: sqlalchemy.engine.Connection..begin_twophase
               (xid=None)

          Begin a two-phase or XA transaction and return a transaction
          handle.

          The returned object is an instance of
          TwoPhaseTransaction, which in addition to the methods
          provided by Transaction, also provides a
          TwoPhaseTransaction.prepare() method.

          Parameters: ‘xid’ – the two phase transaction id.  If not
          supplied, a random id will be generated.

          See also
          ........

          See Connection.begin().

          See Connection.begin_twophase().

      -- Method: sqlalchemy.engine.Connection..close ()

          Close this Connection.

          This results in a release of the underlying database
          resources, that is, the DBAPI connection referenced
          internally.  The DBAPI connection is typically restored back
          to the connection-holding Pool referenced by the
          Engine that produced this Connection.
          Any transactional state present on the DBAPI connection is
          also unconditionally released via the DBAPI connection’s
          ‘rollback()’ method, regardless of any Transaction
          object that may be outstanding with regards to this
          Connection.

          After Connection.close() is called, the
          Connection is permanently in a closed state, and will
          allow no further operations.

      -- Attribute: sqlalchemy.engine.Connection..closed

          Return True if this connection is closed.

      -- Method: sqlalchemy.engine.Connection..connect
               (close_with_result=False)

          Returns a branched version of this Connection.

          Deprecated since version 1.4: The Connection.connect()
          method is considered legacy as of the 1.x series of
          SQLAlchemy and will be removed in 2.0.  (Background on
          SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

          The Connection.close() method on the returned
          Connection can be called and this
          Connection will remain open.

          This method provides usage symmetry with
          Engine.connect(), including for usage with context
          managers.

      -- Attribute: sqlalchemy.engine.Connection..connection

          The underlying DB-API connection managed by this Connection.

          See also
          ........

          See Working with Driver SQL and Raw DBAPI Connections.

      -- Attribute: sqlalchemy.engine.Connection..
               default_isolation_level

          The default isolation level assigned to this Connection.

          This is the isolation level setting that the Connection
          has when first procured via the Engine.connect()
          method.  This level stays in place until the
          Connection.execution_options.isolation_level is used to
          change the setting on a per-see Connection basis.

          Unlike Connection.get_isolation_level(), this
          attribute is set ahead of time from the first connection
          procured by the dialect, so SQL query is not invoked when this
          accessor is called.

          New in version 0.9.9.

          See also
          ........

          See Connection.get_isolation_level(). - view current
          level

          See create_engine.isolation_level. - set per
          Engine isolation level

          See Connection.execution_options.isolation_level. -
          set per Connection isolation level

      -- Method: sqlalchemy.engine.Connection..detach ()

          Detach the underlying DB-API connection from its connection
          pool.

          E.g.:

               with engine.connect() as conn:
                   conn.detach()
                   conn.execute(text("SET search_path TO schema1, schema2"))

                   # work with connection

               # connection is fully closed (since we used "with:", can
               # also call .close())

          This Connection instance will remain usable.  When
          closed (or exited from a context manager context as above),
          the DB-API connection will be literally closed and not
          returned to its originating pool.

          This method can be used to insulate the rest of an application
          from a modified state on a connection (such as a transaction
          isolation level or similar).

      -- Method: sqlalchemy.engine.Connection..
               exec_driver_sql (statement, parameters=None,
               execution_options=None)

          Executes a SQL statement construct and returns a
          CursorResult.

          Parameters:

             * ‘statement’ – The statement str to be executed.  Bound
               parameters must use the underlying DBAPI’s paramstyle,
               such as “qmark”, “pyformat”, “format”, etc.

             * ‘parameters’ – represent bound parameter values to be
               used in the execution.  The format is one of: a
               dictionary of named parameters, a tuple of positional
               parameters, or a list containing either dictionaries or
               tuples for multiple-execute support.

               E.g.  multiple dictionaries:

                    conn.exec_driver_sql(
                        "INSERT INTO table (id, value) VALUES (%(id)s, %(value)s)",
                        [{"id":1, "value":"v1"}, {"id":2, "value":"v2"}]
                    )

               Single dictionary:

                    conn.exec_driver_sql(
                        "INSERT INTO table (id, value) VALUES (%(id)s, %(value)s)",
                        dict(id=1, value="v1")
                    )

               Single tuple:

                    conn.exec_driver_sql(
                        "INSERT INTO table (id, value) VALUES (?, ?)",
                        (1, 'v1')
                    )

                    Note: The Connection.exec_driver_sql()
                    method does not participate in the
                    ConnectionEvents.before_execute() and
                    ConnectionEvents.after_execute() events.  To
                    intercept calls to
                    Connection.exec_driver_sql(), use
                    ConnectionEvents.before_cursor_execute() and
                    ConnectionEvents.after_cursor_execute().

               See also
               ........

               PEP 249(1)

      -- Method: sqlalchemy.engine.Connection..execute
               (statement, *multiparams, **params)

          Executes a SQL statement construct and returns a
          CursorResult.

          Parameters:

             * ‘statement’ – The statement to be executed.  May be one
               of:

                  * a plain string (deprecated)

                  * any ClauseElement construct that is also
                    a subclass of Executable, such as a
                    select() construct

                  * a FunctionElement, such as that generated
                    by func, will be automatically wrapped in
                    a SELECT statement, which is then executed.

                  * a DDLElement object

                  * a DefaultGenerator object

                  * a Compiled object

               Deprecated since version 2.0: passing a string to
               Connection.execute() is deprecated and will be
               removed in version 2.0.  Use the text()
               construct with Connection.execute(), or the
               Connection.exec_driver_sql() method to
               invoke a driver-level SQL string.

             * ‘*multiparams/**params’ – represent bound parameter
               values to be used in the execution.  Typically, the
               format is either a collection of one or more dictionaries
               passed to *multiparams:

                    conn.execute(
                        table.insert(),
                        {"id":1, "value":"v1"},
                        {"id":2, "value":"v2"}
                    )

               …or individual key/values interpreted by **params:

                    conn.execute(
                        table.insert(), id=1, value="v1"
                    )

               In the case that a plain SQL string is passed, and the
               underlying DBAPI accepts positional bind parameters, a
               collection of tuples or individual values in *multiparams
               may be passed:

                    conn.execute(
                        "INSERT INTO table (id, value) VALUES (?, ?)",
                        (1, "v1"), (2, "v2")
                    )

                    conn.execute(
                        "INSERT INTO table (id, value) VALUES (?, ?)",
                        1, "v1"
                    )

               Note above, the usage of a question mark “?” or other
               symbol is contingent upon the “paramstyle” accepted by
               the DBAPI in use, which may be any of “qmark”, “named”,
               “pyformat”, “format”, “numeric”.  See pep-249(2) for
               details on paramstyle.

               To execute a textual SQL statement which uses bound
               parameters in a DBAPI-agnostic way, use the text()
               construct.

               Deprecated since version 2.0: use of tuple or scalar
               positional parameters is deprecated.  All params should
               be dicts or sequences of dicts.  Use
               exec_driver_sql() to execute a plain string with
               tuple or scalar positional parameters.

      -- Method: sqlalchemy.engine.Connection..
               execution_options (**opt)

          Set non-SQL options for the connection which take effect
          during execution.

          For a “future” style connection, this method returns this same
          Connection object with the new options added.

          For a legacy connection, this method returns a copy of this
          Connection which references the same underlying
          DBAPI connection, but also defines the given execution options
          which will take effect for a call to execute().  As
          the new Connection references the same underlying
          resource, it’s usually a good idea to ensure that the copies
          will be discarded immediately, which is implicit if used as
          in:

               result = connection.execution_options(stream_results=True).\
                                   execute(stmt)

          Note that any key/value can be passed to
          Connection.execution_options(), and it will be stored in
          the ‘_execution_options’ dictionary of the Connection.
          It is suitable for usage by end-user schemes to
          communicate with event listeners, for example.

          The keywords that are currently recognized by SQLAlchemy
          itself include all those listed under
          Executable.execution_options(), as well as others that
          are specific to Connection.

          Parameters:

             * ‘autocommit’ – Available on: Connection, statement.  When
               True, a COMMIT will be invoked after execution when
               executed in ‘autocommit’ mode, i.e.  when an explicit
               transaction is not begun on the connection.  Note that
               this is `library level, not DBAPI level autocommit'.  The
               DBAPI connection will remain in a real transaction unless
               the “AUTOCOMMIT” isolation level is used.

               Deprecated since version 1.4: The “autocommit” execution
               option is deprecated and will be removed in SQLAlchemy
               2.0.  See Library-level (but not driver level) “Autocommit” removed from both Core and ORM
               for
               discussion.

             * ‘compiled_cache’ – Available on: Connection.  A
               dictionary where Compiled objects will be
               cached when the Connection compiles a clause
               expression into a Compiled object.  This
               dictionary will supersede the statement cache that may be
               configured on the Engine itself.  If set to
               None, caching is disabled, even if the engine has a
               configured cache size.

               Note that the ORM makes use of its own “compiled” caches
               for some operations, including flush operations.  The
               caching used by the ORM internally supersedes a cache
               dictionary specified here.

             * ‘logging_token’ – Available on: Connection,
               Engine.

               Adds the specified string token surrounded by brackets in
               log messages logged by the connection, i.e.  the logging
               that’s enabled either via the create_engine.echo
               flag or via the
               ‘logging.getLogger("sqlalchemy.engine")’ logger.  This
               allows a per-connection or per-sub-engine token to be
               available which is useful for debugging concurrent
               connection scenarios.

               New in version 1.4.0b2.

               See also
               ........

               See Setting Per-Connection / Sub-Engine Tokens. -
               usage example

               See create_engine.logging_name. - adds a name to
               the name used by the Python logger object itself.

             * ‘isolation_level’ – Available on: Connection.

               Set the transaction isolation level for the lifespan of
               this Connection object.  Valid values include
               those string values accepted by the
               create_engine.isolation_level parameter passed to
               create_engine().  These levels are
               semi-database specific; see individual dialect
               documentation for valid levels.

               The isolation level option applies the isolation level by
               emitting statements on the DBAPI connection, and
               `necessarily affects the original Connection object
               overall', not just the copy that is returned by the call
               to Connection.execution_options() method.
               The isolation level will remain at the given setting
               until the DBAPI connection itself is returned to the
               connection pool, i.e.  the Connection.close()
               method on the original Connection is
               called, where an event handler will emit additional
               statements on the DBAPI connection in order to revert the
               isolation level change.

                    Warning: The ‘isolation_level’ execution option
                    should `not' be used when a transaction is already
                    established, that is, the Connection.begin()
                    method or similar has been called.  A database
                    cannot change the isolation level on a transaction
                    in progress, and different DBAPIs and/or SQLAlchemy
                    dialects may implicitly roll back or commit the
                    transaction, or not affect the connection at all.

                    Note: The ‘isolation_level’ execution option is
                    implicitly reset if the Connection is
                    invalidated, e.g.  via the
                    Connection.invalidate() method, or if a
                    disconnection error occurs.  The new connection
                    produced after the invalidation will not have the
                    isolation level re-applied to it automatically.

               See also
               ........

               See create_engine.isolation_level. - set per
               Engine isolation level

               See Connection.get_isolation_level(). - view
               current level

               See SQLite Transaction Isolation.

               See PostgreSQL Transaction Isolation.

               See MySQL Transaction Isolation.

               See SQL Server Transaction Isolation.

               See Setting Transaction Isolation Levels / DBAPI AUTOCOMMIT.
               - for the ORM

             * ‘no_parameters’ – When ‘True’, if the final parameter
               list or dictionary is totally empty, will invoke the
               statement on the cursor as ‘cursor.execute(statement)’,
               not passing the parameter collection at all.  Some DBAPIs
               such as psycopg2 and mysql-python consider percent signs
               as significant only when parameters are present; this
               option allows code to generate SQL containing percent
               signs (and possibly other characters) that is neutral
               regarding whether it’s executed by the DBAPI or piped
               into a script that’s later invoked by command line tools.

             * ‘stream_results’ – Available on: Connection, statement.
               Indicate to the dialect that results should be “streamed”
               and not pre-buffered, if possible.  This is a limitation
               of many DBAPIs.  The flag is currently understood within
               a subset of dialects within the PostgreSQL and MySQL
               categories, and may be supported by other third party
               dialects as well.

               See also
               ........

               See Using Server Side Cursors (a.k.a. stream results).

             * ‘schema_translate_map’ – Available on: Connection,
               Engine.  A dictionary mapping schema names to schema
               names, that will be applied to the Table.schema
               element of each Table encountered when
               SQL or DDL expression elements are compiled into strings;
               the resulting schema name will be converted based on
               presence in the map of the original name.

               New in version 1.1.

               See also
               ........

               See Translation of Schema Names.

          See also
          ........

          See Engine.execution_options().

          See Executable.execution_options().

          See Connection.get_execution_options().

      -- Method: sqlalchemy.engine.Connection..
               get_execution_options ()

          Get the non-SQL options which will take effect during
          execution.

          New in version 1.3.

          See also
          ........

          See Connection.execution_options().

      -- Method: sqlalchemy.engine.Connection..
               get_isolation_level ()

          Return the current isolation level assigned to this
          Connection.

          This will typically be the default isolation level as
          determined by the dialect, unless if the
          Connection.execution_options.isolation_level feature
          has been used to alter the isolation level on a per-see
          Connection basis.

          This attribute will typically perform a live SQL operation in
          order to procure the current isolation level, so the value
          returned is the actual level on the underlying DBAPI
          connection regardless of how this state was set.  Compare to
          the Connection.default_isolation_level accessor
          which returns the dialect-level setting without performing a
          SQL query.

          New in version 0.9.9.

          See also
          ........

          See Connection.default_isolation_level. - view default
          level

          See create_engine.isolation_level. - set per
          Engine isolation level

          See Connection.execution_options.isolation_level. -
          set per Connection isolation level

      -- Method: sqlalchemy.engine.Connection..
               get_nested_transaction ()

          Return the current nested transaction in progress, if any.

          New in version 1.4.

      -- Method: sqlalchemy.engine.Connection..
               get_transaction ()

          Return the current root transaction in progress, if any.

          New in version 1.4.

      -- Method: sqlalchemy.engine.Connection..
               in_nested_transaction ()

          Return True if a transaction is in progress.

      -- Method: sqlalchemy.engine.Connection..in_transaction
               ()

          Return True if a transaction is in progress.

      -- Attribute: sqlalchemy.engine.Connection..info

          Info dictionary associated with the underlying DBAPI
          connection referred to by this Connection, allowing
          user-defined data to be associated with the connection.

          The data here will follow along with the DBAPI connection
          including after it is returned to the connection pool and used
          again in subsequent instances of Connection.

      -- Method: sqlalchemy.engine.Connection..invalidate
               (exception=None)

          Invalidate the underlying DBAPI connection associated with
          this Connection.

          An attempt will be made to close the underlying DBAPI
          connection immediately; however if this operation fails, the
          error is logged but not raised.  The connection is then
          discarded whether or not close() succeeded.

          Upon the next use (where “use” typically means using the
          Connection.execute() method or similar), this
          Connection will attempt to procure a new DBAPI
          connection using the services of the Pool as a
          source of connectivity (e.g.  a “reconnection”).

          If a transaction was in progress (e.g.  the
          Connection.begin() method has been called) when
          Connection.invalidate() method is called, at the DBAPI
          level all state associated with this transaction is lost, as
          the DBAPI connection is closed.  The Connection
          will not allow a reconnection to proceed until the
          Transaction object is ended, by calling the
          Transaction.rollback() method; until that point, any
          attempt at continuing to use the Connection will
          raise an InvalidRequestError.  This is to prevent
          applications from accidentally continuing an ongoing
          transactional operations despite the fact that the transaction
          has been lost due to an invalidation.

          The Connection.invalidate() method, just like
          auto-invalidation, will at the connection pool level invoke
          the PoolEvents.invalidate() event.

          Parameters: ‘exception’ – an optional ‘Exception’ instance
          that’s the reason for the invalidation.  is passed along to
          event handlers and logging functions.

          See also
          ........

          See More on Invalidation.

      -- Attribute: sqlalchemy.engine.Connection..invalidated

          Return True if this connection was invalidated.

      -- Method: sqlalchemy.engine.Connection..run_callable
               (callable_, *args, **kwargs)

          Given a callable object or function, execute it, passing a
          Connection as the first argument.

          Deprecated since version 1.4: The
          Connection.run_callable() method is deprecated and will
          be removed in a future release.  Invoke the callable function
          directly, passing the Connection.

          The given *args and **kwargs are passed subsequent to the
          Connection argument.

          This function, along with Engine.run_callable(),
          allows a function to be run with a Connection or
          Engine object without the need to know which one
          is being dealt with.

      -- Method: sqlalchemy.engine.Connection..scalar
               (object_, *multiparams, **params)

          Executes and returns the first column of the first row.

          The underlying result/cursor is closed after execution.

      -- Method: sqlalchemy.engine.Connection..
               schema_for_object (obj)

          Return the schema name for the given schema item taking into
          account current schema translate map.

      -- Method: sqlalchemy.engine.Connection..transaction
               (callable_, *args, **kwargs)

          Execute the given function within a transaction boundary.

          Deprecated since version 1.4: The
          Connection.transaction() method is deprecated and will
          be removed in a future release.  Use the Engine.begin()
          context manager instead.

          The function is passed this Connection as the
          first argument, followed by the given *args and **kwargs,
          e.g.:

               def do_something(conn, x, y):
                   conn.execute(text("some statement"), {'x':x, 'y':y})

               conn.transaction(do_something, 5, 10)

          The operations inside the function are all invoked within the
          context of a single Transaction.  Upon success, the
          transaction is committed.  If an exception is raised, the
          transaction is rolled back before propagating the exception.

               Note: The transaction() method is superseded
               by the usage of the Python ‘with:’ statement, which can
               be used with Connection.begin():

                    with conn.begin():
                        conn.execute(text("some statement"), {'x':5, 'y':10})

               As well as with Engine.begin():

                    with engine.begin() as conn:
                        conn.execute(text("some statement"), {'x':5, 'y':10})

          See also
          ........

          See Engine.begin(). - engine-level transactional
          context

          See Engine.transaction(). - engine-level version of
          Connection.transaction().

 -- Class: sqlalchemy.engine.CreateEnginePlugin (url: URL, kwargs:
          dict[str, Any])

     A set of hooks intended to augment the construction of an
     Engine object based on entrypoint names in a URL.

     The purpose of CreateEnginePlugin is to allow
     third-party systems to apply engine, pool and dialect level event
     listeners without the need for the target application to be
     modified; instead, the plugin names can be added to the database
     URL. Target applications for CreateEnginePlugin
     include:

        * connection and SQL performance tools, e.g.  which use events
          to track number of checkouts and/or time spent with statements

        * connectivity plugins such as proxies

     A rudimentary CreateEnginePlugin that attaches a
     logger to an Engine object might look like:

          import logging

          from sqlalchemy.engine import CreateEnginePlugin
          from sqlalchemy import event

          class LogCursorEventsPlugin(CreateEnginePlugin):
              def __init__(self, url, kwargs):
                  # consume the parameter "log_cursor_logging_name" from the
                  # URL query
                  logging_name = url.query.get("log_cursor_logging_name", "log_cursor")

                  self.log = logging.getLogger(logging_name)

              def update_url(self, url):
                  "update the URL to one that no longer includes our parameters"
                  return url.difference_update_query(["log_cursor_logging_name"])

              def engine_created(self, engine):
                  "attach an event listener after the new Engine is constructed"
                  event.listen(engine, "before_cursor_execute", self._log_event)

              def _log_event(
                  self,
                  conn,
                  cursor,
                  statement,
                  parameters,
                  context,
                  executemany):

                  self.log.info("Plugin logged cursor event: %s", statement)

     Plugins are registered using entry points in a similar way as that
     of dialects:

          entry_points={
              'sqlalchemy.plugins': [
                  'log_cursor_plugin = myapp.plugins:LogCursorEventsPlugin'
              ]

     A plugin that uses the above names would be invoked from a database
     URL as in:

          from sqlalchemy import create_engine

          engine = create_engine(
              "mysql+pymysql://scott:tiger@localhost/test?"
              "plugin=log_cursor_plugin&log_cursor_logging_name=mylogger"
          )

     The ‘plugin’ URL parameter supports multiple instances, so that a
     URL may specify multiple plugins; they are loaded in the order
     stated in the URL:

          engine = create_engine(
            "mysql+pymysql://scott:tiger@localhost/test?"
            "plugin=plugin_one&plugin=plugin_twp&plugin=plugin_three")

     The plugin names may also be passed directly to
     create_engine() using the create_engine.plugins
     argument:

          engine = create_engine(
            "mysql+pymysql://scott:tiger@localhost/test",
            plugins=["myplugin"])

     New in version 1.2.3: plugin names can also be specified to
     create_engine() as a list

     A plugin may consume plugin-specific arguments from the URL
     object as well as the ‘kwargs’ dictionary, which is the
     dictionary of arguments passed to the create_engine()
     call.  “Consuming” these arguments includes that they must be
     removed when the plugin initializes, so that the arguments are not
     passed along to the Dialect constructor, where they
     will raise an ArgumentError because they are not known
     by the dialect.

     As of version 1.4 of SQLAlchemy, arguments should continue to be
     consumed from the ‘kwargs’ dictionary directly, by removing the
     values with a method such as ‘dict.pop’.  Arguments from the
     URL object should be consumed by implementing the
     CreateEnginePlugin.update_url() method, returning a new copy
     of the URL with plugin-specific parameters removed:

          class MyPlugin(CreateEnginePlugin):
              def __init__(self, url, kwargs):
                  self.my_argument_one = url.query['my_argument_one']
                  self.my_argument_two = url.query['my_argument_two']
                  self.my_argument_three = kwargs.pop('my_argument_three', None)

              def update_url(self, url):
                  return url.difference_update_query(
                      ["my_argument_one", "my_argument_two"]
                  )

     Arguments like those illustrated above would be consumed from a
     create_engine() call such as:

          from sqlalchemy import create_engine

          engine = create_engine(
            "mysql+pymysql://scott:tiger@localhost/test?"
            "plugin=myplugin&my_argument_one=foo&my_argument_two=bar",
            my_argument_three='bat'
          )

     Changed in version 1.4: The URL object is now
     immutable; a CreateEnginePlugin that needs to alter
     the URL should implement the newly added
     CreateEnginePlugin.update_url() method, which is invoked
     after the plugin is constructed.

     For migration, construct the plugin in the following way, checking
     for the existence of the CreateEnginePlugin.update_url()
     method to detect which version is running:

          class MyPlugin(CreateEnginePlugin):
              def __init__(self, url, kwargs):
                  if hasattr(CreateEnginePlugin, "update_url"):
                      # detect the 1.4 API
                      self.my_argument_one = url.query['my_argument_one']
                      self.my_argument_two = url.query['my_argument_two']
                  else:
                      # detect the 1.3 and earlier API - mutate the
                      # URL directly
                      self.my_argument_one = url.query.pop('my_argument_one')
                      self.my_argument_two = url.query.pop('my_argument_two')

                  self.my_argument_three = kwargs.pop('my_argument_three', None)

              def update_url(self, url):
                  # this method is only called in the 1.4 version
                  return url.difference_update_query(
                      ["my_argument_one", "my_argument_two"]
                  )

     See also
     ........

     See The URL object is now immutable. - overview of the
     URL change which also includes notes regarding
     CreateEnginePlugin.

     When the engine creation process completes and produces the
     Engine object, it is again passed to the plugin via the
     CreateEnginePlugin.engine_created() hook.  In this hook,
     additional changes can be made to the engine, most typically
     involving setup of events (e.g.  those defined in Core Events).

     New in version 1.1.

      -- Method: sqlalchemy.engine.CreateEnginePlugin..
               __init__ (url: URL, kwargs: dict[str, Any]) -> None

          Construct a new CreateEnginePlugin.

          The plugin object is instantiated individually for each call
          to create_engine().  A single ‘ Engine’ will be
          passed to the CreateEnginePlugin.engine_created()
          method corresponding to this URL.

          Parameters:

             * ‘url’ – the URL object.  The plugin may
               inspect the URL for arguments.  Arguments
               used by the plugin should be removed, by returning an
               updated URL from the
               CreateEnginePlugin.update_url() method.

               Changed in version 1.4: The URL object is
               now immutable, so a CreateEnginePlugin that
               needs to alter the URL object should
               implement the CreateEnginePlugin.update_url()
               method.

             * ‘kwargs’ – The keyword arguments passed to
               create_engine().

      -- Method: sqlalchemy.engine.CreateEnginePlugin..
               engine_created (engine)

          Receive the Engine object when it is fully
          constructed.

          The plugin may make additional changes to the engine, such as
          registering engine or connection pool events.

      -- Method: sqlalchemy.engine.CreateEnginePlugin..
               handle_dialect_kwargs (dialect_cls, dialect_args)

          parse and modify dialect kwargs

      -- Method: sqlalchemy.engine.CreateEnginePlugin..
               handle_pool_kwargs (pool_cls, pool_args)

          parse and modify pool kwargs

      -- Method: sqlalchemy.engine.CreateEnginePlugin..
               update_url (url)

          Update the URL.

          A new URL should be returned.  This method is
          typically used to consume configuration arguments from the
          URL which must be removed, as they will not be
          recognized by the dialect.  The
          URL.difference_update_query() method is available to
          remove these arguments.  See the docstring at
          CreateEnginePlugin for an example.

          New in version 1.4.

 -- Class: sqlalchemy.engine.Engine (pool, dialect, url,
          logging_name=None, echo=None, query_cache_size=500,
          execution_options=None, hide_parameters=False)

     Connects a Pool and ‘Dialect’ together to provide a
     source of database connectivity and behavior.

     This is the `SQLAlchemy 1.x version' of Engine.  For the
     2.0 style version, which includes some API differences, see
     Engine.

     An Engine object is instantiated publicly using the
     create_engine() function.

     See also
     ........

     See Engine Configuration.

     See Working with Engines and Connections.

     `Class signature'

     class sqlalchemy.engine.Engine.
     (‘sqlalchemy.engine.Connectable’, see sqlalchemy.log.Identified)

      -- Method: sqlalchemy.engine.Engine..begin
               (close_with_result=False)

          Return a context manager delivering a Connection
          with a Transaction established.

          E.g.:

               with engine.begin() as conn:
                   conn.execute(
                       text("insert into table (x, y, z) values (1, 2, 3)")
                   )
                   conn.execute(text("my_special_procedure(5)"))

          Upon successful operation, the Transaction is
          committed.  If an error is raised, the Transaction
          is rolled back.

          The ‘close_with_result’ flag is normally ‘False’, and
          indicates that the Connection will be closed when
          the operation is complete.  When set to ‘True’, it indicates
          the Connection is in “single use” mode, where the
          CursorResult returned by the first call to
          Connection.execute() will close the Connection
          when that CursorResult has exhausted all
          result rows.

          See also
          ........

          See Engine.connect(). - procure a Connection
          from an Engine.

          See Connection.begin(). - start a Transaction
          for a particular Connection.

      -- Method: sqlalchemy.engine.Engine..
               clear_compiled_cache ()

          Clear the compiled cache associated with the dialect.

          This applies `only' to the built-in cache that is established
          via the ‘create_engine.query_cache_size’ parameter.  It will
          not impact any dictionary caches that were passed via the
          Connection.execution_options.query_cache
          parameter.

          New in version 1.4.

      -- Method: sqlalchemy.engine.Engine..connect
               (close_with_result=False)

          Return a new Connection object.

          The Connection object is a facade that uses a
          DBAPI connection internally in order to communicate with the
          database.  This connection is procured from the
          connection-holding Pool referenced by this
          Engine.  When the Connection.close() method
          of the Connection object is called, the underlying
          DBAPI connection is then returned to the connection pool,
          where it may be used again in a subsequent call to
          Engine.connect().

      -- Method: sqlalchemy.engine.Engine..dispose ()

          Dispose of the connection pool used by this Engine.

          This has the effect of fully closing all `currently checked
          in' database connections.  Connections that are still checked
          out will `not' be closed, however they will no longer be
          associated with this Engine, so when they are
          closed individually, eventually the Pool which
          they are associated with will be garbage collected and they
          will be closed out fully, if not already closed on checkin.

          A new connection pool is created immediately after the old one
          has been disposed.  This new pool, like all SQLAlchemy
          connection pools, does not make any actual connections to the
          database until one is first requested, so as long as the
          Engine isn’t used again, no new connections will be
          made.

          See also
          ........

          See Engine Disposal.

      -- Attribute: sqlalchemy.engine.Engine..driver

          Driver name of the ‘Dialect’ in use by this Engine.

      -- Method: sqlalchemy.engine.Engine..execute
               (statement, *multiparams, **params)

          Executes the given construct and returns a CursorResult.

          Deprecated since version 1.4: The Engine.execute()
          method is considered legacy as of the 1.x series of SQLAlchemy
          and will be removed in 2.0.  All statement execution in
          SQLAlchemy 2.0 is performed by the Connection.execute()
          method of Connection, or in the ORM by the
          Session.execute() method of Session.
          (Background on SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

          The arguments are the same as those used by
          Connection.execute().

          Here, a Connection is acquired using the
          Engine.connect() method, and the statement executed with
          that connection.  The returned CursorResult is
          flagged such that when the CursorResult is
          exhausted and its underlying cursor is closed, the
          Connection created here will also be closed, which
          allows its associated DBAPI connection resource to be returned
          to the connection pool.

      -- Method: sqlalchemy.engine.Engine..execution_options
               (**opt)

          Return a new Engine that will provide
          Connection objects with the given execution options.

          The returned Engine remains related to the
          original Engine in that it shares the same
          connection pool and other state:

             * The Pool used by the new Engine.
               is the same instance.  The Engine.dispose()
               method will replace the connection pool instance for the
               parent engine as well as this one.

             * Event listeners are “cascaded” - meaning, the new
               Engine inherits the events of the parent, and new
               events can be associated with the new Engine
               individually.

             * The logging configuration and logging_name is copied from
               the parent Engine.

          The intent of the Engine.execution_options()
          method is to implement “sharding” schemes where multiple
          Engine objects refer to the same connection pool, but
          are differentiated by options that would be consumed by a
          custom event:

               primary_engine = create_engine("mysql://")
               shard1 = primary_engine.execution_options(shard_id="shard1")
               shard2 = primary_engine.execution_options(shard_id="shard2")

          Above, the ‘shard1’ engine serves as a factory for
          Connection objects that will contain the execution
          option ‘shard_id=shard1’, and ‘shard2’ will produce
          Connection objects that contain the execution option
          ‘shard_id=shard2’.

          An event handler can consume the above execution option to
          perform a schema switch or other operation, given a
          connection.  Below we emit a MySQL ‘use’ statement to switch
          databases, at the same time keeping track of which database
          we’ve established using the Connection.info
          dictionary, which gives us a persistent storage space that
          follows the DBAPI connection:

               from sqlalchemy import event
               from sqlalchemy.engine import Engine

               shards = {"default": "base", shard_1: "db1", "shard_2": "db2"}

               @event.listens_for(Engine, "before_cursor_execute")
               def _switch_shard(conn, cursor, stmt,
                       params, context, executemany):
                   shard_id = conn._execution_options.get('shard_id', "default")
                   current_shard = conn.info.get("current_shard", None)

                   if current_shard != shard_id:
                       cursor.execute("use %s" % shards[shard_id])
                       conn.info["current_shard"] = shard_id

          See also
          ........

          See Connection.execution_options(). - update execution
          options on a Connection object.

          See Engine.update_execution_options(). - update the
          execution options for a given Engine in place.

          See Engine.get_execution_options().

      -- Method: sqlalchemy.engine.Engine..
               get_execution_options ()

          Get the non-SQL options which will take effect during
          execution.

          See also
          ........

          See Engine.execution_options().

      -- Method: sqlalchemy.engine.Engine..has_table
               (table_name, schema=None)

          Return True if the given backend has a table of the given
          name.

          Deprecated since version 1.4: The Engine.has_table()
          method is deprecated and will be removed in a future
          release.  Please refer to Inspector.has_table().

          See also
          ........

          See Fine Grained Reflection with Inspector. - detailed
          schema inspection using the Inspector interface.

          See quoted_name. - used to pass quoting information
          along with a schema identifier.

      -- Attribute: sqlalchemy.engine.Engine..name

          String name of the ‘Dialect’ in use by this Engine.

      -- Method: sqlalchemy.engine.Engine..raw_connection
               (_connection=None)

          Return a “raw” DBAPI connection from the connection pool.

          The returned object is a proxied version of the DBAPI
          connection object used by the underlying driver in use.  The
          object will have all the same behavior as the real DBAPI
          connection, except that its ‘close()’ method will result in
          the connection being returned to the pool, rather than being
          closed for real.

          This method provides direct DBAPI connection access for
          special situations when the API provided by Connection
          is not needed.  When a Connection object is
          already present, the DBAPI connection is available using the
          Connection.connection accessor.

          See also
          ........

          See Working with Driver SQL and Raw DBAPI Connections.

      -- Method: sqlalchemy.engine.Engine..run_callable
               (callable_, *args, **kwargs)

          Given a callable object or function, execute it, passing a
          Connection as the first argument.

          Deprecated since version 1.4: The Engine.run_callable()
          method is deprecated and will be removed in a future
          release.  Use the Engine.connect() context manager
          instead.

          The given *args and **kwargs are passed subsequent to the
          Connection argument.

          This function, along with Connection.run_callable(),
          allows a function to be run with a Connection
          or Engine object without the need to know
          which one is being dealt with.

      -- Method: sqlalchemy.engine.Engine..scalar (statement,
               *multiparams, **params)

          Executes and returns the first column of the first row.

          Deprecated since version 1.4: The Engine.scalar()
          method is considered legacy as of the 1.x series of SQLAlchemy
          and will be removed in 2.0.  All statement execution in
          SQLAlchemy 2.0 is performed by the Connection.execute()
          method of Connection, or in the ORM by the
          Session.execute() method of Session; the
          ‘Result.scalar()’ method can then be used to return a scalar
          result.  (Background on SQLAlchemy 2.0 at: Migrating to SQLAlchemy 2.0)

          The underlying result/cursor is closed after execution.

      -- Method: sqlalchemy.engine.Engine..table_names
               (schema=None, connection=None)

          Return a list of all table names available in the database.

          Deprecated since version 1.4: The Engine.table_names()
          method is deprecated and will be removed in a future
          release.  Please refer to Inspector.get_table_names().

          Parameters:

             * ‘schema’ – Optional, retrieve names from a non-default
               schema.

             * ‘connection’ – Optional, use a specified connection.

      -- Method: sqlalchemy.engine.Engine..transaction
               (callable_, *args, **kwargs)

          Execute the given function within a transaction boundary.

          Deprecated since version 1.4: The Engine.transaction()
          method is deprecated and will be removed in a future
          release.  Use the Engine.begin() context manager
          instead.

          The function is passed a Connection newly procured
          from Engine.connect() as the first argument,
          followed by the given *args and **kwargs.

          e.g.:

               def do_something(conn, x, y):
                   conn.execute(text("some statement"), {'x':x, 'y':y})

               engine.transaction(do_something, 5, 10)

          The operations inside the function are all invoked within the
          context of a single Transaction.  Upon success, the
          transaction is committed.  If an exception is raised, the
          transaction is rolled back before propagating the exception.

               Note: The transaction() method is superseded
               by the usage of the Python ‘with:’ statement, which can
               be used with Engine.begin():

                    with engine.begin() as conn:
                        conn.execute(text("some statement"), {'x':5, 'y':10})

          See also
          ........

          See Engine.begin(). - engine-level transactional
          context

          See Connection.transaction(). - connection-level
          version of Engine.transaction().

      -- Method: sqlalchemy.engine.Engine..
               update_execution_options (**opt)

          Update the default execution_options dictionary of this
          Engine.

          The given keys/values in **opt are added to the default
          execution options that will be used for all connections.  The
          initial contents of this dictionary can be sent via the
          ‘execution_options’ parameter to create_engine().

          See also
          ........

          See Connection.execution_options().

          See Engine.execution_options().

 -- Class: sqlalchemy.engine.ExceptionContext

     Encapsulate information about an error condition in progress.

     This object exists solely to be passed to the
     ConnectionEvents.handle_error() event, supporting an
     interface that can be extended without backwards-incompatibility.

     New in version 0.9.7.

      -- Attribute: sqlalchemy.engine.ExceptionContext..
               chained_exception = None

          The exception that was returned by the previous handler in the
          exception chain, if any.

          If present, this exception will be the one ultimately raised
          by SQLAlchemy unless a subsequent handler replaces it.

          May be None.

      -- Attribute: sqlalchemy.engine.ExceptionContext..
               connection = None

          The Connection in use during the exception.

          This member is present, except in the case of a failure when
          first connecting.

          See also
          ........

          See ExceptionContext.engine.

      -- Attribute: sqlalchemy.engine.ExceptionContext..
               cursor = None

          The DBAPI cursor object.

          May be None.

      -- Attribute: sqlalchemy.engine.ExceptionContext..
               engine = None

          The Engine in use during the exception.

          This member should always be present, even in the case of a
          failure when first connecting.

          New in version 1.0.0.

      -- Attribute: sqlalchemy.engine.ExceptionContext..
               execution_context = None

          The ExecutionContext corresponding to the
          execution operation in progress.

          This is present for statement execution operations, but not
          for operations such as transaction begin/end.  It also is not
          present when the exception was raised before the
          ExecutionContext could be constructed.

          Note that the ExceptionContext.statement and
          ExceptionContext.parameters members may represent
          a different value than that of the ExecutionContext,
          potentially in the case where a
          ConnectionEvents.before_cursor_execute() event or
          similar modified the statement/parameters to be sent.

          May be None.

      -- Attribute: sqlalchemy.engine.ExceptionContext..
               invalidate_pool_on_disconnect = True

          Represent whether all connections in the pool should be
          invalidated when a “disconnect” condition is in effect.

          Setting this flag to False within the scope of the
          ConnectionEvents.handle_error() event will have the
          effect such that the full collection of connections in the
          pool will not be invalidated during a disconnect; only the
          current connection that is the subject of the error will
          actually be invalidated.

          The purpose of this flag is for custom disconnect-handling
          schemes where the invalidation of other connections in the
          pool is to be performed based on other conditions, or even on
          a per-connection basis.

          New in version 1.0.3.

      -- Attribute: sqlalchemy.engine.ExceptionContext..
               is_disconnect = None

          Represent whether the exception as occurred represents a
          “disconnect” condition.

          This flag will always be True or False within the scope of the
          ConnectionEvents.handle_error() handler.

          SQLAlchemy will defer to this flag in order to determine
          whether or not the connection should be invalidated
          subsequently.  That is, by assigning to this flag, a
          “disconnect” event which then results in a connection and pool
          invalidation can be invoked or prevented by changing this
          flag.

               Note: The pool “pre_ping” handler enabled using the
               create_engine.pool_pre_ping parameter does `not'
               consult this event before deciding if the “ping” returned
               false, as opposed to receiving an unhandled error.  For
               this use case, the legacy recipe based on engine_connect() may be used.
               A future API allow
               more comprehensive customization of the “disconnect”
               detection mechanism across all functions.

      -- Attribute: sqlalchemy.engine.ExceptionContext..
               original_exception = None

          The exception object which was caught.

          This member is always present.

      -- Attribute: sqlalchemy.engine.ExceptionContext..
               parameters = None

          Parameter collection that was emitted directly to the DBAPI.

          May be None.

      -- Attribute: sqlalchemy.engine.ExceptionContext..
               sqlalchemy_exception = None

          The sqlalchemy.exc.StatementError which wraps the
          original, and will be raised if exception handling is not
          circumvented by the event.

          May be None, as not all exception types are wrapped by
          SQLAlchemy.  For DBAPI-level exceptions that subclass the
          dbapi’s Error class, this field will always be present.

      -- Attribute: sqlalchemy.engine.ExceptionContext..
               statement = None

          String SQL statement that was emitted directly to the DBAPI.

          May be None.

 -- Class: sqlalchemy.engine.NestedTransaction (connection)

     Represent a ‘nested’, or SAVEPOINT transaction.

     The NestedTransaction object is created by calling the
     Connection.begin_nested() method of Connection.

     When using NestedTransaction, the semantics of “begin” /
     “commit” / “rollback” are as follows:

        * the “begin” operation corresponds to the “BEGIN SAVEPOINT”
          command, where the savepoint is given an explicit name that is
          part of the state of this object.

        * The NestedTransaction.commit() method corresponds
          to a “RELEASE SAVEPOINT” operation, using the savepoint
          identifier associated with this NestedTransaction.

        * The NestedTransaction.rollback() method
          corresponds to a “ROLLBACK TO SAVEPOINT” operation, using the
          savepoint identifier associated with this
          NestedTransaction.

     The rationale for mimicking the semantics of an outer transaction
     in terms of savepoints so that code may deal with a “savepoint”
     transaction and an “outer” transaction in an agnostic way.

     See also
     ........

     See Using SAVEPOINT. - ORM version of the SAVEPOINT API.

     `Class signature'

     class sqlalchemy.engine.NestedTransaction. (see
     sqlalchemy.engine.Transaction)

      -- Method: sqlalchemy.engine.NestedTransaction..close
               ()

          `inherited from the' Transaction.close(). `method
          of' Transaction.

          Close this Transaction.

          If this transaction is the base transaction in a begin/commit
          nesting, the transaction will rollback().  Otherwise, the
          method returns.

          This is used to cancel a Transaction without affecting the
          scope of an enclosing transaction.

      -- Method: sqlalchemy.engine.NestedTransaction..commit
               ()

          `inherited from the' Transaction.commit(). `method
          of' Transaction.

          Commit this Transaction.

          The implementation of this may vary based on the type of
          transaction in use:

             * For a simple database transaction (e.g.  see
               RootTransaction), it corresponds to a COMMIT.

             * For a NestedTransaction, it corresponds to a
               “RELEASE SAVEPOINT” operation.

             * For a TwoPhaseTransaction, DBAPI-specific
               methods for two phase transactions may be used.

      -- Method: sqlalchemy.engine.NestedTransaction..
               rollback ()

          `inherited from the' Transaction.rollback().
          `method of' Transaction.

          Roll back this Transaction.

          The implementation of this may vary based on the type of
          transaction in use:

             * For a simple database transaction (e.g.  see
               RootTransaction), it corresponds to a ROLLBACK.

             * For a NestedTransaction, it corresponds to a
               “ROLLBACK TO SAVEPOINT” operation.

             * For a TwoPhaseTransaction, DBAPI-specific
               methods for two phase transactions may be used.

 -- Class: sqlalchemy.engine.RootTransaction (connection)

     Represent the “root” transaction on a Connection.

     This corresponds to the current “BEGIN/COMMIT/ROLLBACK” that’s
     occurring for the Connection.

     The RootTransaction object is accessible via the
     Connection.get_transaction method of Connection.

     `Class signature'

     class sqlalchemy.engine.RootTransaction. (see
     sqlalchemy.engine.Transaction)

      -- Method: sqlalchemy.engine.RootTransaction..close ()

          `inherited from the' Transaction.close(). `method
          of' Transaction.

          Close this Transaction.

          If this transaction is the base transaction in a begin/commit
          nesting, the transaction will rollback().  Otherwise, the
          method returns.

          This is used to cancel a Transaction without affecting the
          scope of an enclosing transaction.

      -- Method: sqlalchemy.engine.RootTransaction..commit
               ()

          `inherited from the' Transaction.commit(). `method
          of' Transaction.

          Commit this Transaction.

          The implementation of this may vary based on the type of
          transaction in use:

             * For a simple database transaction (e.g.  see
               RootTransaction), it corresponds to a COMMIT.

             * For a NestedTransaction, it corresponds to a
               “RELEASE SAVEPOINT” operation.

             * For a TwoPhaseTransaction, DBAPI-specific
               methods for two phase transactions may be used.

      -- Method: sqlalchemy.engine.RootTransaction..rollback
               ()

          `inherited from the' Transaction.rollback().
          `method of' Transaction.

          Roll back this Transaction.

          The implementation of this may vary based on the type of
          transaction in use:

             * For a simple database transaction (e.g.  see
               RootTransaction), it corresponds to a ROLLBACK.

             * For a NestedTransaction, it corresponds to a
               “ROLLBACK TO SAVEPOINT” operation.

             * For a TwoPhaseTransaction, DBAPI-specific
               methods for two phase transactions may be used.

 -- Class: sqlalchemy.engine.Transaction (connection)

     Represent a database transaction in progress.

     The Transaction object is procured by calling the
     Connection.begin() method of Connection:

          from sqlalchemy import create_engine
          engine = create_engine("postgresql://scott:tiger@localhost/test")
          connection = engine.connect()
          trans = connection.begin()
          connection.execute(text("insert into x (a, b) values (1, 2)"))
          trans.commit()

     The object provides rollback() and commit()
     methods in order to control transaction boundaries.  It also
     implements a context manager interface so that the Python ‘with’
     statement can be used with the Connection.begin()
     method:

          with connection.begin():
              connection.execute(text("insert into x (a, b) values (1, 2)"))

     The Transaction object is `not' threadsafe.

     See also
     ........

     See Connection.begin().

     See Connection.begin_twophase().

     See Connection.begin_nested().

      -- Method: sqlalchemy.engine.Transaction..close ()

          Close this Transaction.

          If this transaction is the base transaction in a begin/commit
          nesting, the transaction will rollback().  Otherwise, the
          method returns.

          This is used to cancel a Transaction without affecting the
          scope of an enclosing transaction.

      -- Method: sqlalchemy.engine.Transaction..commit ()

          Commit this Transaction.

          The implementation of this may vary based on the type of
          transaction in use:

             * For a simple database transaction (e.g.  see
               RootTransaction), it corresponds to a COMMIT.

             * For a NestedTransaction, it corresponds to a
               “RELEASE SAVEPOINT” operation.

             * For a TwoPhaseTransaction, DBAPI-specific
               methods for two phase transactions may be used.

      -- Method: sqlalchemy.engine.Transaction..rollback ()

          Roll back this Transaction.

          The implementation of this may vary based on the type of
          transaction in use:

             * For a simple database transaction (e.g.  see
               RootTransaction), it corresponds to a ROLLBACK.

             * For a NestedTransaction, it corresponds to a
               “ROLLBACK TO SAVEPOINT” operation.

             * For a TwoPhaseTransaction, DBAPI-specific
               methods for two phase transactions may be used.

 -- Class: sqlalchemy.engine.TwoPhaseTransaction (connection, xid)

     Represent a two-phase transaction.

     A new TwoPhaseTransaction object may be procured using
     the Connection.begin_twophase() method.

     The interface is the same as that of Transaction with
     the addition of the prepare() method.

     `Class signature'

     class sqlalchemy.engine.TwoPhaseTransaction. (see
     sqlalchemy.engine.RootTransaction)

      -- Method: sqlalchemy.engine.TwoPhaseTransaction..close
               ()

          `inherited from the' Transaction.close(). `method
          of' Transaction.

          Close this Transaction.

          If this transaction is the base transaction in a begin/commit
          nesting, the transaction will rollback().  Otherwise, the
          method returns.

          This is used to cancel a Transaction without affecting the
          scope of an enclosing transaction.

      -- Method: sqlalchemy.engine.TwoPhaseTransaction..
               commit ()

          `inherited from the' Transaction.commit(). `method
          of' Transaction.

          Commit this Transaction.

          The implementation of this may vary based on the type of
          transaction in use:

             * For a simple database transaction (e.g.  see
               RootTransaction), it corresponds to a COMMIT.

             * For a NestedTransaction, it corresponds to a
               “RELEASE SAVEPOINT” operation.

             * For a TwoPhaseTransaction, DBAPI-specific
               methods for two phase transactions may be used.

      -- Method: sqlalchemy.engine.TwoPhaseTransaction..
               prepare ()

          Prepare this TwoPhaseTransaction.

          After a PREPARE, the transaction can be committed.

      -- Method: sqlalchemy.engine.TwoPhaseTransaction..
               rollback ()

          `inherited from the' Transaction.rollback().
          `method of' Transaction.

          Roll back this Transaction.

          The implementation of this may vary based on the type of
          transaction in use:

             * For a simple database transaction (e.g.  see
               RootTransaction), it corresponds to a ROLLBACK.

             * For a NestedTransaction, it corresponds to a
               “ROLLBACK TO SAVEPOINT” operation.

             * For a TwoPhaseTransaction, DBAPI-specific
               methods for two phase transactions may be used.

   ---------- Footnotes ----------

   (1) https://www.python.org/dev/peps/pep-0249

   (2) http://www.python.org/dev/peps/pep-0249/

4.5.2.29 Result Set API
.......................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See BaseCursorResult.Base class for database result objects.

See ChunkedIteratorResult.An IteratorResult that works from an iterator-producing callable.

See CursorResult.A Result that is representing state from a DBAPI cursor.

See FrozenResult.Represents a Result object in a “frozen” state suitable for caching.

See IteratorResult.A Result that gets data from a Python iterator of Row objects.

See LegacyCursorResult.Legacy version of CursorResult.

See LegacyRow.A subclass of Row that delivers 1.x SQLAlchemy behaviors for Core.

See MappingResult.A wrapper for a Result that returns dictionary values rather than Row.
               values.

See MergedResult.A Result that is merged from any number of Result objects.

See Result.Represent a set of database results.

See Row. Represent a single result row.

See RowMapping.A ‘Mapping’ that maps column names and objects to Row values.

See ScalarResult.A wrapper for a Result that returns scalar values rather than Row.
               values.

 -- Class: sqlalchemy.engine.BaseCursorResult (context, cursor_strategy,
          cursor_description)

     Base class for database result objects.

      -- Attribute: sqlalchemy.engine.BaseCursorResult..
               inserted_primary_key

          Return the primary key for the row just inserted.

          The return value is a list of scalar values corresponding to
          the list of primary key columns in the target table.

          This only applies to single row insert() constructs
          which did not explicitly specify Insert.returning().

          Note that primary key columns which specify a server_default
          clause, or otherwise do not qualify as “autoincrement” columns
          (see the notes at Column), and were generated using
          the database-side default, will appear in this list as ‘None’
          unless the backend supports “returning” and the insert
          statement executed with the “implicit returning” enabled.

          Raises InvalidRequestError if the executed
          statement is not a compiled expression construct or is not an
          insert() construct.

      -- Attribute: sqlalchemy.engine.BaseCursorResult..
               inserted_primary_key_rows

          Return a list of tuples, each containing the primary key for
          each row just inserted.

          Usually, this method will return at most a list with a single
          entry which is the same row one would get back from
          CursorResult.inserted_primary_key.  To support
          “executemany with INSERT” mode, multiple rows can be part of
          the list returned.

          New in version 1.4.

      -- Attribute: sqlalchemy.engine.BaseCursorResult..
               is_insert

          True if this CursorResult is the result of a
          executing an expression language compiled insert()
          construct.

          When True, this implies that the inserted_primary_key
          attribute is accessible, assuming the statement did not
          include a user defined “returning” construct.

      -- Method: sqlalchemy.engine.BaseCursorResult..
               last_inserted_params ()

          Return the collection of inserted parameters from this
          execution.

          Raises InvalidRequestError if the executed
          statement is not a compiled expression construct or is not an
          insert() construct.

      -- Method: sqlalchemy.engine.BaseCursorResult..
               last_updated_params ()

          Return the collection of updated parameters from this
          execution.

          Raises InvalidRequestError if the executed
          statement is not a compiled expression construct or is not an
          update() construct.

      -- Method: sqlalchemy.engine.BaseCursorResult..
               lastrow_has_defaults ()

          Return ‘lastrow_has_defaults()’ from the underlying
          ExecutionContext.

          See ExecutionContext for details.

      -- Attribute: sqlalchemy.engine.BaseCursorResult..
               lastrowid

          Return the ‘lastrowid’ accessor on the DBAPI cursor.

          This is a DBAPI specific method and is only functional for
          those backends which support it, for statements where it is
          appropriate.  It’s behavior is not consistent across backends.

          Usage of this method is normally unnecessary when using
          insert() expression constructs; the
          CursorResult.inserted_primary_key attribute provides a
          tuple of primary key values for a newly inserted row,
          regardless of database backend.

      -- Method: sqlalchemy.engine.BaseCursorResult..
               postfetch_cols ()

          Return ‘postfetch_cols()’ from the underlying
          ExecutionContext.

          See ExecutionContext for details.

          Raises InvalidRequestError if the executed
          statement is not a compiled expression construct or is not an
          insert() or update() construct.

      -- Method: sqlalchemy.engine.BaseCursorResult..
               prefetch_cols ()

          Return ‘prefetch_cols()’ from the underlying
          ExecutionContext.

          See ExecutionContext for details.

          Raises InvalidRequestError if the executed
          statement is not a compiled expression construct or is not an
          insert() or update() construct.

      -- Attribute: sqlalchemy.engine.BaseCursorResult..
               returned_defaults

          Return the values of default columns that were fetched using
          the ValuesBase.return_defaults() feature.

          The value is an instance of Row, or ‘None’ if
          ValuesBase.return_defaults() was not used or if the
          backend does not support RETURNING.

          New in version 0.9.0.

          See also
          ........

          See ValuesBase.return_defaults().

      -- Attribute: sqlalchemy.engine.BaseCursorResult..
               returned_defaults_rows

          Return a list of rows each containing the values of default
          columns that were fetched using the
          ValuesBase.return_defaults() feature.

          The return value is a list of Row objects.

          New in version 1.4.

      -- Attribute: sqlalchemy.engine.BaseCursorResult..
               returns_rows

          True if this CursorResult returns zero or more
          rows.

          I.e.  if it is legal to call the methods
          CursorResult.fetchone(), CursorResult.fetchmany().
          See CursorResult.fetchall().

          Overall, the value of CursorResult.returns_rows
          should always be synonymous with whether or not the DBAPI
          cursor had a ‘.description’ attribute, indicating the presence
          of result columns, noting that a cursor that returns zero rows
          still has a ‘.description’ if a row-returning statement was
          emitted.

          This attribute should be True for all results that are against
          SELECT statements, as well as for DML statements
          INSERT/UPDATE/DELETE that use RETURNING. For
          INSERT/UPDATE/DELETE statements that were not using RETURNING,
          the value will usually be False, however there are some
          dialect-specific exceptions to this, such as when using the
          MSSQL / pyodbc dialect a SELECT is emitted inline in order to
          retrieve an inserted primary key value.

      -- Attribute: sqlalchemy.engine.BaseCursorResult..
               rowcount

          Return the ‘rowcount’ for this result.

          The ‘rowcount’ reports the number of rows `matched' by the
          WHERE criterion of an UPDATE or DELETE statement.

               Note: Notes regarding CursorResult.rowcount:

                  * This attribute returns the number of rows `matched',
                    which is not necessarily the same as the number of
                    rows that were actually `modified' - an UPDATE
                    statement, for example, may have no net change on a
                    given row if the SET values given are the same as
                    those present in the row already.  Such a row would
                    be matched but not modified.  On backends that
                    feature both styles, such as MySQL, rowcount is
                    configured by default to return the match count in
                    all cases.

                  * CursorResult.rowcount is `only' useful
                    in conjunction with an UPDATE or DELETE statement.
                    Contrary to what the Python DBAPI says, it does
                    `not' return the number of rows available from the
                    results of a SELECT statement as DBAPIs cannot
                    support this functionality when rows are unbuffered.

                  * CursorResult.rowcount may not be fully
                    implemented by all dialects.  In particular, most
                    DBAPIs do not support an aggregate rowcount result
                    from an executemany call.  The
                    CursorResult.supports_sane_rowcount() and
                    CursorResult.supports_sane_multi_rowcount()
                    methods will report from the dialect if each
                    usage is known to be supported.

                  * Statements that use RETURNING may not return a
                    correct rowcount.

      -- Method: sqlalchemy.engine.BaseCursorResult..
               supports_sane_multi_rowcount ()

          Return ‘supports_sane_multi_rowcount’ from the dialect.

          See CursorResult.rowcount for background.

      -- Method: sqlalchemy.engine.BaseCursorResult..
               supports_sane_rowcount ()

          Return ‘supports_sane_rowcount’ from the dialect.

          See CursorResult.rowcount for background.

 -- Class: sqlalchemy.engine.ChunkedIteratorResult (cursor_metadata,
          chunks, source_supports_scalars=False, raw=None,
          dynamic_yield_per=False)

     An IteratorResult that works from an
     iterator-producing callable.

     The given ‘chunks’ argument is a function that is given a number of
     rows to return in each chunk, or ‘None’ for all rows.  The function
     should then return an un-consumed iterator of lists, each list of
     the requested size.

     The function can be called at any time again, in which case it
     should continue from the same result set but adjust the chunk size
     as given.

     New in version 1.4.

     `Class signature'

     class sqlalchemy.engine.ChunkedIteratorResult. (see
     sqlalchemy.engine.IteratorResult)

      -- Method: sqlalchemy.engine.ChunkedIteratorResult..
               yield_per (num)

          Configure the row-fetching strategy to fetch num rows at a
          time.

          This impacts the underlying behavior of the result when
          iterating over the result object, or otherwise making use of
          methods such as Result.fetchone() that return one
          row at a time.  Data from the underlying cursor or other data
          source will be buffered up to this many rows in memory, and
          the buffered collection will then be yielded out one row at at
          time or as many rows are requested.  Each time the buffer
          clears, it will be refreshed to this many rows or as many rows
          remain if fewer remain.

          The Result.yield_per() method is generally used
          in conjunction with the
          Connection.execution_options.stream_results execution
          option, which will allow the database dialect in use to make
          use of a server side cursor, if the DBAPI supports it.

          Most DBAPIs do not use server side cursors by default, which
          means all rows will be fetched upfront from the database
          regardless of the Result.yield_per() setting.
          However, see Result.yield_per() may still be useful
          in that it batches the SQLAlchemy-side processing of the raw
          data from the database, and additionally when used for ORM
          scenarios will batch the conversion of database rows into ORM
          entity rows.

          New in version 1.4.

          Parameters: ‘num’ – number of rows to fetch each time the
          buffer is refilled.  If set to a value below 1, fetches all
          rows for the next buffer.

 -- Class: sqlalchemy.engine.FrozenResult (result)

     Represents a Result object in a “frozen” state suitable
     for caching.

     The FrozenResult object is returned from the
     Result.freeze() method of any Result object.

     A new iterable Result object is generated from a fixed
     set of data each time the FrozenResult is invoked as a
     callable:

          result = connection.execute(query)

          frozen = result.freeze()

          unfrozen_result_one = frozen()

          for row in unfrozen_result_one:
              print(row)

          unfrozen_result_two = frozen()
          rows = unfrozen_result_two.all()

          # ... etc

     New in version 1.4.

     See also
     ........

     See Re-Executing Statements. - example usage within the ORM
     to implement a result-set cache.

     ‘merge_frozen_result()’ - ORM function to merge a frozen result
     back into a Session.

 -- Class: sqlalchemy.engine.IteratorResult (cursor_metadata, iterator,
          raw=None)

     A Result that gets data from a Python iterator of
     Row objects.

     New in version 1.4.

     `Class signature'

     class sqlalchemy.engine.IteratorResult. (see
     sqlalchemy.engine.Result)

 -- Class: sqlalchemy.engine.LegacyRow (parent, processors, keymap,
          key_style, data)

     A subclass of Row that delivers 1.x SQLAlchemy behaviors
     for Core.

     The LegacyRow class is where most of the Python mapping
     (i.e.  dictionary-like) behaviors are implemented for the row
     object.  The mapping behavior of Row going forward is
     accessible via the ‘_mapping’ attribute.

     New in version 1.4: - added LegacyRow which
     encapsulates most of the deprecated behaviors of Row.

     `Class signature'

     class sqlalchemy.engine.LegacyRow. (see
     sqlalchemy.engine.Row)

      -- Method: sqlalchemy.engine.LegacyRow..has_key (key)

          Return True if this LegacyRow contains the given
          key.

          Deprecated since version 1.4: The LegacyRow.has_key()
          method is deprecated and will be removed in a future
          release.  To test for key membership, use the
          Row._mapping attribute, i.e.  ‘key in row._mapping‘.

          Through the SQLAlchemy 1.x series, the ‘__contains__()’ method
          of Row. (or LegacyRow as of SQLAlchemy
          1.4) also links to ‘Row.has_key()’, in that an expression such
          as

               "some_col" in row

          Will return True if the row contains a column named
          ‘"some_col"’, in the way that a Python mapping works.

          However, it is planned that the 2.0 series of SQLAlchemy will
          reverse this behavior so that ‘__contains__()’ will refer to a
          value being present in the row, in the way that a Python tuple
          works.

          See also
          ........

          See RowProxy is no longer a “proxy”; is now called Row and behaves like an enhanced named tuple.

      -- Method: sqlalchemy.engine.LegacyRow..items ()

          Return a list of tuples, each tuple containing a key/value
          pair.

          Deprecated since version 1.4: The LegacyRow.items()
          method is deprecated and will be removed in a future
          release.  Use the Row._mapping attribute, i.e.,
          ‘row._mapping.items()’.

          This method is analogous to the Python dictionary ‘.items()’
          method, except that it returns a list, not an iterator.

      -- Method: sqlalchemy.engine.LegacyRow..iterkeys ()

          Return a an iterator against the Row.keys()
          method.

          Deprecated since version 1.4: The LegacyRow.iterkeys()
          method is deprecated and will be removed in a future
          release.  Use the Row._mapping attribute, i.e.,
          ‘row._mapping.keys()’.

          This method is analogous to the Python-2-only dictionary
          ‘.iterkeys()’ method.

      -- Method: sqlalchemy.engine.LegacyRow..itervalues ()

          Return a an iterator against the ‘Row.values()’ method.

          Deprecated since version 1.4: The
          LegacyRow.itervalues() method is deprecated and will be
          removed in a future release.  Use the Row._mapping
          attribute, i.e., ‘row._mapping.values()’.

          This method is analogous to the Python-2-only dictionary
          ‘.itervalues()’ method.

      -- Method: sqlalchemy.engine.LegacyRow..values ()

          Return the values represented by this Row as a
          list.

          Deprecated since version 1.4: The LegacyRow.values()
          method is deprecated and will be removed in a future
          release.  Use the Row._mapping attribute, i.e.,
          ‘row._mapping.values()’.

          This method is analogous to the Python dictionary ‘.values()’
          method, except that it returns a list, not an iterator.

 -- Class: sqlalchemy.engine.MergedResult (cursor_metadata, results)

     A Result that is merged from any number of Result
     objects.

     Returned by the Result.merge() method.

     New in version 1.4.

     `Class signature'

     class sqlalchemy.engine.MergedResult. (see
     sqlalchemy.engine.IteratorResult)

 -- Class: sqlalchemy.engine.Result (cursor_metadata)

     Represent a set of database results.

     New in version 1.4: The Result object provides a
     completely updated usage model and calling facade for SQLAlchemy
     Core and SQLAlchemy ORM. In Core, it forms the basis of the
     CursorResult object which replaces the previous ‘ResultProxy’
     interface.  When using the ORM, a higher level object called
     ChunkedIteratorResult is normally used.

     See also
     ........

     See Fetching Rows. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

     `Class signature'

     class sqlalchemy.engine.Result.
     (‘sqlalchemy.engine._WithKeys’, ‘sqlalchemy.engine.ResultInternal’)

      -- Method: sqlalchemy.engine.Result..all () -> List[Row]

          Return all rows in a list.

          Closes the result set after invocation.  Subsequent
          invocations will return an empty list.

          New in version 1.4.

          Returns: a list of Row objects.

      -- Method: sqlalchemy.engine.Result..columns
               (*col_expressions: object) -> sqlalchemy.engine.Result

          Establish the columns that should be returned in each row.

          This method may be used to limit the columns returned as well
          as to reorder them.  The given list of expressions are
          normally a series of integers or string key names.  They may
          also be appropriate ColumnElement objects which
          correspond to a given statement construct.

          E.g.:

               statement = select(table.c.x, table.c.y, table.c.z)
               result = connection.execute(statement)

               for z, y in result.columns('z', 'y'):
                   # ...

          Example of using the column objects from the statement itself:

               for z, y in result.columns(
                       statement.selected_columns.c.z,
                       statement.selected_columns.c.y
               ):
                   # ...

          New in version 1.4.

          Parameters: ‘*col_expressions’ – indicates columns to be
          returned.  Elements may be integer row indexes, string column
          names, or appropriate ColumnElement objects
          corresponding to a select construct.

          Returns: this Result object with the modifications
          given.

      -- Method: sqlalchemy.engine.Result..fetchall () ->
               List[Row]

          A synonym for the Result.all() method.

      -- Method: sqlalchemy.engine.Result..fetchmany (size:
               Optional[Int] = None) -> List[Row]

          Fetch many rows.

          When all rows are exhausted, returns an empty list.

          This method is provided for backwards compatibility with
          SQLAlchemy 1.x.x.

          To fetch rows in groups, use the Result.partitions()
          method.

          Returns: a list of Row objects.

      -- Method: sqlalchemy.engine.Result..fetchone () ->
               sqlalchemy.engine.Row

          Fetch one row.

          When all rows are exhausted, returns None.

          This method is provided for backwards compatibility with
          SQLAlchemy 1.x.x.

          To fetch the first row of a result only, use the
          Result.first() method.  To iterate through all rows,
          iterate the Result object directly.

          Returns: a Row object if no filters are applied, or
          None if no rows remain.

      -- Method: sqlalchemy.engine.Result..first () ->
               sqlalchemy.engine.Row

          Fetch the first row or None if no row is present.

          Closes the result set and discards remaining rows.

               Note: This method returns one `row', e.g.  tuple, by
               default.  To return exactly one single scalar value, that
               is, the first column of the first row, use the
               Result.scalar() method, or combine
               Result.scalars() and Result.first().

          Returns: a Row object, or None if no rows remain.

          See also
          ........

          See Result.scalar().

          See Result.one().

      -- Method: sqlalchemy.engine.Result..freeze ()

          Return a callable object that will produce copies of this
          Result when invoked.

          The callable object returned is an instance of
          FrozenResult.

          This is used for result set caching.  The method must be
          called on the result when it has been unconsumed, and calling
          the method will consume the result fully.  When the
          FrozenResult is retrieved from a cache, it can be called
          any number of times where it will produce a new Result
          object each time against its stored set of rows.

          See also
          ........

          See Re-Executing Statements. - example usage within the
          ORM to implement a result-set cache.

      -- Method: sqlalchemy.engine.Result..keys ()

          `inherited from the' ‘sqlalchemy.engine._WithKeys.keys’
          `method of' ‘sqlalchemy.engine._WithKeys’

          Return an iterable view which yields the string keys that
          would be represented by each Row.

          The keys can represent the labels of the columns returned by a
          core statement or the names of the orm classes returned by an
          orm execution.

          The view also can be tested for key containment using the
          Python ‘in’ operator, which will test both for the string keys
          represented in the view, as well as for alternate keys such as
          column objects.

          Changed in version 1.4: a key view object is returned rather
          than a plain list.

      -- Method: sqlalchemy.engine.Result..mappings ()

          Apply a mappings filter to returned rows, returning an
          instance of MappingResult.

          When this filter is applied, fetching rows will return
          RowMapping objects instead of Row objects.

          New in version 1.4.

          Returns: a new MappingResult filtering object
          referring to this Result object.

      -- Method: sqlalchemy.engine.Result..merge (*others)

          Merge this Result with other compatible result
          objects.

          The object returned is an instance of MergedResult,
          which will be composed of iterators from the given result
          objects.

          The new result will use the metadata from this result object.
          The subsequent result objects must be against an identical set
          of result / cursor metadata, otherwise the behavior is
          undefined.

      -- Method: sqlalchemy.engine.Result..one () ->
               sqlalchemy.engine.Row

          Return exactly one row or raise an exception.

          Raises NoResultFound if the result returns no
          rows, or MultipleResultsFound if multiple rows
          would be returned.

               Note: This method returns one `row', e.g.  tuple, by
               default.  To return exactly one single scalar value, that
               is, the first column of the first row, use the
               Result.scalar_one() method, or combine
               Result.scalars() and Result.one().

          New in version 1.4.

          Returns: The first Row.

          Raises: MultipleResultsFound, NoResultFound.

          See also
          ........

          See Result.first().

          See Result.one_or_none().

          See Result.scalar_one().

      -- Method: sqlalchemy.engine.Result..one_or_none () ->
               Optional[Row]

          Return at most one result or raise an exception.

          Returns ‘None’ if the result has no rows.  Raises
          MultipleResultsFound if multiple rows are returned.

          New in version 1.4.

          Returns: The first Row or None if no row is
          available.

          Raises: MultipleResultsFound.

          See also
          ........

          See Result.first().

          See Result.one().

      -- Method: sqlalchemy.engine.Result..partitions (size:
               Optional[Int] = None) -> Iterator[List[Row]]

          Iterate through sub-lists of rows of the size given.

          Each list will be of the size given, excluding the last list
          to be yielded, which may have a small number of rows.  No
          empty lists will be yielded.

          The result object is automatically closed when the iterator is
          fully consumed.

          Note that the backend driver will usually buffer the entire
          result ahead of time unless the
          Connection.execution_options.stream_results execution
          option is used indicating that the driver should not
          pre-buffer results, if possible.  Not all drivers support this
          option and the option is silently ignored for those who do
          not.

          New in version 1.4.

          Parameters: ‘size’ – indicate the maximum number of rows to be
          present in each list yielded.  If None, makes use of the value
          set by Result.yield_per(), if present, otherwise
          uses the Result.fetchmany() default which may be
          backend specific.

          Returns: iterator of lists

      -- Method: sqlalchemy.engine.Result..scalar () ->
               Optional[Any]

          Fetch the first column of the first row, and close the result
          set.

          Returns None if there are no rows to fetch.

          No validation is performed to test if additional rows remain.

          After calling this method, the object is fully closed, e.g.
          the CursorResult.close() method will have been
          called.

          Returns: a Python scalar value , or None if no rows remain.

      -- Method: sqlalchemy.engine.Result..scalar_one () ->
               Any

          Return exactly one scalar result or raise an exception.

          This is equivalent to calling Result.scalars() and
          then Result.one().

          See also
          ........

          See Result.one().

          See Result.scalars().

      -- Method: sqlalchemy.engine.Result..scalar_one_or_none
               () -> Optional[Any]

          Return exactly one or no scalar result.

          This is equivalent to calling Result.scalars() and
          then Result.one_or_none().

          See also
          ........

          See Result.one_or_none().

          See Result.scalars().

      -- Method: sqlalchemy.engine.Result..scalars (index: Int
               = 0) -> ScalarResult

          Return a ScalarResult filtering object which will
          return single elements rather than Row objects.

          E.g.:

               >>> result = conn.execute(text("select int_id from table"))
               >>> result.scalars().all()
               [1, 2, 3]

          When results are fetched from the ScalarResult
          filtering object, the single column-row that would be returned
          by the Result is instead returned as the column’s
          value.

          New in version 1.4.

          Parameters: ‘index’ – integer or row key indicating the column
          to be fetched from each row, defaults to ‘0’ indicating the
          first column.

          Returns: a new ScalarResult filtering object
          referring to this Result object.

      -- Method: sqlalchemy.engine.Result..unique (strategy:
               Optional[object] = None) -> Result

          Apply unique filtering to the objects returned by this
          Result.

          When this filter is applied with no arguments, the rows or
          objects returned will filtered such that each row is returned
          uniquely.  The algorithm used to determine this uniqueness is
          by default the Python hashing identity of the whole tuple.  In
          some cases a specialized per-entity hashing scheme may be
          used, such as when using the ORM, a scheme is applied which
          works against the primary key identity of returned objects.

          The unique filter is applied `after all other filters', which
          means if the columns returned have been refined using a method
          such as the Result.columns() or
          Result.scalars() method, the uniquing is applied to
          `only the column or columns returned'.  This occurs regardless
          of the order in which these methods have been called upon the
          Result object.

          The unique filter also changes the calculus used for methods
          like Result.fetchmany() and
          Result.partitions().  When using Result.unique(),
          these methods will continue to yield the number of rows
          or objects requested, after uniquing has been applied.
          However, this necessarily impacts the buffering behavior of
          the underlying cursor or datasource, such that multiple
          underlying calls to ‘cursor.fetchmany()’ may be necessary in
          order to accumulate enough objects in order to provide a
          unique collection of the requested size.

          Parameters: ‘strategy’ – a callable that will be applied to
          rows or objects being iterated, which should return an object
          that represents the unique value of the row.  A Python ‘set()’
          is used to store these identities.  If not passed, a default
          uniqueness strategy is used which may have been assembled by
          the source of this Result object.

      -- Method: sqlalchemy.engine.Result..yield_per (num)

          Configure the row-fetching strategy to fetch num rows at a
          time.

          This impacts the underlying behavior of the result when
          iterating over the result object, or otherwise making use of
          methods such as Result.fetchone() that return one
          row at a time.  Data from the underlying cursor or other data
          source will be buffered up to this many rows in memory, and
          the buffered collection will then be yielded out one row at at
          time or as many rows are requested.  Each time the buffer
          clears, it will be refreshed to this many rows or as many rows
          remain if fewer remain.

          The Result.yield_per() method is generally used
          in conjunction with the
          Connection.execution_options.stream_results execution
          option, which will allow the database dialect in use to make
          use of a server side cursor, if the DBAPI supports it.

          Most DBAPIs do not use server side cursors by default, which
          means all rows will be fetched upfront from the database
          regardless of the Result.yield_per() setting.
          However, see Result.yield_per() may still be useful
          in that it batches the SQLAlchemy-side processing of the raw
          data from the database, and additionally when used for ORM
          scenarios will batch the conversion of database rows into ORM
          entity rows.

          New in version 1.4.

          Parameters: ‘num’ – number of rows to fetch each time the
          buffer is refilled.  If set to a value below 1, fetches all
          rows for the next buffer.

 -- Class: sqlalchemy.engine.ScalarResult (real_result, index)

     A wrapper for a Result that returns scalar values rather
     than Row values.

     The ScalarResult object is acquired by calling the
     Result.scalars() method.

     A special limitation of ScalarResult is that it has no
     ‘fetchone()’ method; since the semantics of ‘fetchone()’ are that
     the ‘None’ value indicates no more results, this is not compatible
     with ScalarResult since there is no way to distinguish
     between ‘None’ as a row value versus ‘None’ as an indicator.  Use
     ‘next(result)’ to receive values individually.

     `Class signature'

     class sqlalchemy.engine.ScalarResult.
     (‘sqlalchemy.engine.FilterResult’)

      -- Method: sqlalchemy.engine.ScalarResult..all () ->
               List[Any]

          Return all scalar values in a list.

          Equivalent to Result.all() except that scalar
          values, rather than Row objects, are returned.

      -- Method: sqlalchemy.engine.ScalarResult..fetchall ()
               -> List[Any]

          A synonym for the ScalarResult.all() method.

      -- Method: sqlalchemy.engine.ScalarResult..fetchmany
               (size: Optional[Int] = None) -> List[Any]

          Fetch many objects.

          Equivalent to Result.fetchmany() except that
          scalar values, rather than Row objects, are
          returned.

      -- Method: sqlalchemy.engine.ScalarResult..first () ->
               Optional[Any]

          Fetch the first object or None if no object is present.

          Equivalent to Result.first() except that scalar
          values, rather than Row objects, are returned.

      -- Method: sqlalchemy.engine.ScalarResult..one () ->
               Any

          Return exactly one object or raise an exception.

          Equivalent to Result.one() except that scalar
          values, rather than Row objects, are returned.

      -- Method: sqlalchemy.engine.ScalarResult..one_or_none
               () -> Optional[Any]

          Return at most one object or raise an exception.

          Equivalent to Result.one_or_none() except that
          scalar values, rather than Row objects, are
          returned.

      -- Method: sqlalchemy.engine.ScalarResult..partitions
               (size: Optional[Int] = None) -> Iterator[List[Any]]

          Iterate through sub-lists of elements of the size given.

          Equivalent to Result.partitions() except that
          scalar values, rather than Row objects, are
          returned.

      -- Method: sqlalchemy.engine.ScalarResult..unique
               (strategy=None) -> sqlalchemy.engine.ScalarResult

          Apply unique filtering to the objects returned by this
          ScalarResult.

          See Result.unique() for usage details.

 -- Class: sqlalchemy.engine.MappingResult (result)

     A wrapper for a Result that returns dictionary values
     rather than Row values.

     The MappingResult object is acquired by calling the
     Result.mappings() method.

     `Class signature'

     class sqlalchemy.engine.MappingResult.
     (‘sqlalchemy.engine._WithKeys’, ‘sqlalchemy.engine.FilterResult’)

      -- Method: sqlalchemy.engine.MappingResult..all () ->
               List[Mapping]

          Return all scalar values in a list.

          Equivalent to Result.all() except that mapping
          values, rather than Row objects, are returned.

      -- Method: sqlalchemy.engine.MappingResult..columns
               (*col_expressions: object) ->
               sqlalchemy.engine.MappingResult

          Establish the columns that should be returned in each row.

      -- Method: sqlalchemy.engine.MappingResult..fetchall ()
               -> List[Mapping]

          A synonym for the MappingResult.all() method.

      -- Method: sqlalchemy.engine.MappingResult..fetchmany
               (size: Optional[Int] = None) -> List[Mapping]

          Fetch many objects.

          Equivalent to Result.fetchmany() except that
          mapping values, rather than Row objects, are
          returned.

      -- Method: sqlalchemy.engine.MappingResult..fetchone ()
               -> Mapping

          Fetch one object.

          Equivalent to Result.fetchone() except that
          mapping values, rather than Row objects, are
          returned.

      -- Method: sqlalchemy.engine.MappingResult..first () ->
               Optional[Mapping]

          Fetch the first object or None if no object is present.

          Equivalent to Result.first() except that mapping
          values, rather than Row objects, are returned.

      -- Method: sqlalchemy.engine.MappingResult..keys ()

          `inherited from the' ‘sqlalchemy.engine._WithKeys.keys’
          `method of' ‘sqlalchemy.engine._WithKeys’

          Return an iterable view which yields the string keys that
          would be represented by each Row.

          The keys can represent the labels of the columns returned by a
          core statement or the names of the orm classes returned by an
          orm execution.

          The view also can be tested for key containment using the
          Python ‘in’ operator, which will test both for the string keys
          represented in the view, as well as for alternate keys such as
          column objects.

          Changed in version 1.4: a key view object is returned rather
          than a plain list.

      -- Method: sqlalchemy.engine.MappingResult..one () ->
               Mapping

          Return exactly one object or raise an exception.

          Equivalent to Result.one() except that mapping
          values, rather than Row objects, are returned.

      -- Method: sqlalchemy.engine.MappingResult..one_or_none
               () -> Optional[Mapping]

          Return at most one object or raise an exception.

          Equivalent to Result.one_or_none() except that
          mapping values, rather than Row objects, are
          returned.

      -- Method: sqlalchemy.engine.MappingResult..partitions
               (size: Optional[Int] = None) -> Iterator[List[Mapping]]

          Iterate through sub-lists of elements of the size given.

          Equivalent to Result.partitions() except that
          mapping values, rather than Row objects, are
          returned.

      -- Method: sqlalchemy.engine.MappingResult..unique
               (strategy=None) -> sqlalchemy.engine.MappingResult

          Apply unique filtering to the objects returned by this
          MappingResult.

          See Result.unique() for usage details.

 -- Class: sqlalchemy.engine.CursorResult (context, cursor_strategy,
          cursor_description)

     A Result that is representing state from a DBAPI cursor.

     Changed in version 1.4: The CursorResult and
     LegacyCursorResult classes replace the previous
     ‘ResultProxy’ interface.  These classes are based on the
     Result calling API which provides an updated usage model and
     calling facade for SQLAlchemy Core and SQLAlchemy ORM.

     Returns database rows via the Row class, which provides
     additional API features and behaviors on top of the raw data
     returned by the DBAPI. Through the use of filters such as the
     Result.scalars() method, other kinds of objects may also be
     returned.

     Within the scope of the 1.x series of SQLAlchemy, Core SQL results
     in version 1.4 return an instance of LegacyCursorResult
     which takes the place of the ‘CursorResult’ class used for
     the 1.3 series and previously.  This object returns rows as
     LegacyRow objects, which maintains Python mapping (i.e.
     dictionary) like behaviors upon the object itself.  Going forward,
     the Row._mapping attribute should be used for
     dictionary behaviors.

     See also
     ........

     See Selecting. - introductory material for accessing
     CursorResult and Row objects.

     `Class signature'

     class sqlalchemy.engine.CursorResult. (see
     sqlalchemy.engine.BaseCursorResult,
     sqlalchemy.engine.Result)

      -- Method: sqlalchemy.engine.CursorResult..all () ->
               List[Row]

          `inherited from the' Result.all(). `method of'
          Result.

          Return all rows in a list.

          Closes the result set after invocation.  Subsequent
          invocations will return an empty list.

          New in version 1.4.

          Returns: a list of Row objects.

      -- Method: sqlalchemy.engine.CursorResult..close ()

          Close this CursorResult.

          This closes out the underlying DBAPI cursor corresponding to
          the statement execution, if one is still present.  Note that
          the DBAPI cursor is automatically released when the
          CursorResult exhausts all available rows.
          CursorResult.close() is generally an optional method
          except in the case when discarding a CursorResult
          that still has additional rows pending for fetch.

          After this method is called, it is no longer valid to call
          upon the fetch methods, which will raise a
          ResourceClosedError on subsequent use.

          See also
          ........

          See Working with Engines and Connections.

      -- Method: sqlalchemy.engine.CursorResult..columns
               (*col_expressions: object) -> sqlalchemy.engine.Result

          `inherited from the' Result.columns(). `method of'
          Result.

          Establish the columns that should be returned in each row.

          This method may be used to limit the columns returned as well
          as to reorder them.  The given list of expressions are
          normally a series of integers or string key names.  They may
          also be appropriate ColumnElement objects which
          correspond to a given statement construct.

          E.g.:

               statement = select(table.c.x, table.c.y, table.c.z)
               result = connection.execute(statement)

               for z, y in result.columns('z', 'y'):
                   # ...

          Example of using the column objects from the statement itself:

               for z, y in result.columns(
                       statement.selected_columns.c.z,
                       statement.selected_columns.c.y
               ):
                   # ...

          New in version 1.4.

          Parameters: ‘*col_expressions’ – indicates columns to be
          returned.  Elements may be integer row indexes, string column
          names, or appropriate ColumnElement objects
          corresponding to a select construct.

          Returns: this Result object with the modifications
          given.

      -- Method: sqlalchemy.engine.CursorResult..fetchall ()
               -> List[Row]

          `inherited from the' Result.fetchall(). `method
          of' Result.

          A synonym for the Result.all() method.

      -- Method: sqlalchemy.engine.CursorResult..fetchmany
               (size: Optional[Int] = None) -> List[Row]

          `inherited from the' Result.fetchmany(). `method
          of' Result.

          Fetch many rows.

          When all rows are exhausted, returns an empty list.

          This method is provided for backwards compatibility with
          SQLAlchemy 1.x.x.

          To fetch rows in groups, use the Result.partitions()
          method.

          Returns: a list of Row objects.

      -- Method: sqlalchemy.engine.CursorResult..fetchone ()
               -> sqlalchemy.engine.Row

          `inherited from the' Result.fetchone(). `method
          of' Result.

          Fetch one row.

          When all rows are exhausted, returns None.

          This method is provided for backwards compatibility with
          SQLAlchemy 1.x.x.

          To fetch the first row of a result only, use the
          Result.first() method.  To iterate through all rows,
          iterate the Result object directly.

          Returns: a Row object if no filters are applied, or
          None if no rows remain.

      -- Method: sqlalchemy.engine.CursorResult..first () ->
               sqlalchemy.engine.Row

          `inherited from the' Result.first(). `method of'
          Result.

          Fetch the first row or None if no row is present.

          Closes the result set and discards remaining rows.

               Note: This method returns one `row', e.g.  tuple, by
               default.  To return exactly one single scalar value, that
               is, the first column of the first row, use the
               Result.scalar() method, or combine
               Result.scalars() and Result.first().

          Returns: a Row object, or None if no rows remain.

          See also
          ........

          See Result.scalar().

          See Result.one().

      -- Method: sqlalchemy.engine.CursorResult..freeze ()

          `inherited from the' Result.freeze(). `method of'
          Result.

          Return a callable object that will produce copies of this
          Result when invoked.

          The callable object returned is an instance of
          FrozenResult.

          This is used for result set caching.  The method must be
          called on the result when it has been unconsumed, and calling
          the method will consume the result fully.  When the
          FrozenResult is retrieved from a cache, it can be called
          any number of times where it will produce a new Result
          object each time against its stored set of rows.

          See also
          ........

          See Re-Executing Statements. - example usage within the
          ORM to implement a result-set cache.

      -- Attribute: sqlalchemy.engine.CursorResult..
               inserted_primary_key

          `inherited from the'
          BaseCursorResult.inserted_primary_key. `attribute of'
          BaseCursorResult.

          Return the primary key for the row just inserted.

          The return value is a list of scalar values corresponding to
          the list of primary key columns in the target table.

          This only applies to single row insert() constructs
          which did not explicitly specify Insert.returning().

          Note that primary key columns which specify a server_default
          clause, or otherwise do not qualify as “autoincrement” columns
          (see the notes at Column), and were generated using
          the database-side default, will appear in this list as ‘None’
          unless the backend supports “returning” and the insert
          statement executed with the “implicit returning” enabled.

          Raises InvalidRequestError if the executed
          statement is not a compiled expression construct or is not an
          insert() construct.

      -- Attribute: sqlalchemy.engine.CursorResult..
               inserted_primary_key_rows

          `inherited from the'
          BaseCursorResult.inserted_primary_key_rows. `attribute
          of' BaseCursorResult.

          Return a list of tuples, each containing the primary key for
          each row just inserted.

          Usually, this method will return at most a list with a single
          entry which is the same row one would get back from
          CursorResult.inserted_primary_key.  To support
          “executemany with INSERT” mode, multiple rows can be part of
          the list returned.

          New in version 1.4.

      -- Attribute: sqlalchemy.engine.CursorResult..is_insert

          `inherited from the' BaseCursorResult.is_insert.
          `attribute of' BaseCursorResult.

          True if this CursorResult is the result of a
          executing an expression language compiled insert()
          construct.

          When True, this implies that the inserted_primary_key
          attribute is accessible, assuming the statement did not
          include a user defined “returning” construct.

      -- Method: sqlalchemy.engine.CursorResult..keys ()

          `inherited from the' ‘sqlalchemy.engine._WithKeys.keys’
          `method of' ‘sqlalchemy.engine._WithKeys’

          Return an iterable view which yields the string keys that
          would be represented by each Row.

          The keys can represent the labels of the columns returned by a
          core statement or the names of the orm classes returned by an
          orm execution.

          The view also can be tested for key containment using the
          Python ‘in’ operator, which will test both for the string keys
          represented in the view, as well as for alternate keys such as
          column objects.

          Changed in version 1.4: a key view object is returned rather
          than a plain list.

      -- Method: sqlalchemy.engine.CursorResult..
               last_inserted_params ()

          `inherited from the'
          BaseCursorResult.last_inserted_params(). `method of'
          BaseCursorResult.

          Return the collection of inserted parameters from this
          execution.

          Raises InvalidRequestError if the executed
          statement is not a compiled expression construct or is not an
          insert() construct.

      -- Method: sqlalchemy.engine.CursorResult..
               last_updated_params ()

          `inherited from the'
          BaseCursorResult.last_updated_params(). `method of'
          BaseCursorResult.

          Return the collection of updated parameters from this
          execution.

          Raises InvalidRequestError if the executed
          statement is not a compiled expression construct or is not an
          update() construct.

      -- Method: sqlalchemy.engine.CursorResult..
               lastrow_has_defaults ()

          `inherited from the'
          BaseCursorResult.lastrow_has_defaults(). `method of'
          BaseCursorResult.

          Return ‘lastrow_has_defaults()’ from the underlying
          ExecutionContext.

          See ExecutionContext for details.

      -- Attribute: sqlalchemy.engine.CursorResult..lastrowid

          `inherited from the' BaseCursorResult.lastrowid.
          `attribute of' BaseCursorResult.

          Return the ‘lastrowid’ accessor on the DBAPI cursor.

          This is a DBAPI specific method and is only functional for
          those backends which support it, for statements where it is
          appropriate.  It’s behavior is not consistent across backends.

          Usage of this method is normally unnecessary when using
          insert() expression constructs; the
          CursorResult.inserted_primary_key attribute provides a
          tuple of primary key values for a newly inserted row,
          regardless of database backend.

      -- Method: sqlalchemy.engine.CursorResult..mappings ()

          `inherited from the' Result.mappings(). `method of'
          Result.

          Apply a mappings filter to returned rows, returning an
          instance of MappingResult.

          When this filter is applied, fetching rows will return
          RowMapping objects instead of Row objects.

          New in version 1.4.

          Returns: a new MappingResult filtering object
          referring to this Result object.

      -- Method: sqlalchemy.engine.CursorResult..merge
               (*others)

          Merge this Result with other compatible result
          objects.

          The object returned is an instance of MergedResult,
          which will be composed of iterators from the given result
          objects.

          The new result will use the metadata from this result object.
          The subsequent result objects must be against an identical set
          of result / cursor metadata, otherwise the behavior is
          undefined.

      -- Method: sqlalchemy.engine.CursorResult..one () ->
               sqlalchemy.engine.Row

          `inherited from the' Result.one(). `method of'
          Result.

          Return exactly one row or raise an exception.

          Raises NoResultFound if the result returns no
          rows, or MultipleResultsFound if multiple rows
          would be returned.

               Note: This method returns one `row', e.g.  tuple, by
               default.  To return exactly one single scalar value, that
               is, the first column of the first row, use the
               Result.scalar_one() method, or combine
               Result.scalars() and Result.one().

          New in version 1.4.

          Returns: The first Row.

          Raises: MultipleResultsFound, NoResultFound.

          See also
          ........

          See Result.first().

          See Result.one_or_none().

          See Result.scalar_one().

      -- Method: sqlalchemy.engine.CursorResult..one_or_none
               () -> Optional[Row]

          `inherited from the' Result.one_or_none(). `method
          of' Result.

          Return at most one result or raise an exception.

          Returns ‘None’ if the result has no rows.  Raises
          MultipleResultsFound if multiple rows are returned.

          New in version 1.4.

          Returns: The first Row or None if no row is
          available.

          Raises: MultipleResultsFound.

          See also
          ........

          See Result.first().

          See Result.one().

      -- Method: sqlalchemy.engine.CursorResult..partitions
               (size: Optional[Int] = None) -> Iterator[List[Row]]

          `inherited from the' Result.partitions(). `method
          of' Result.

          Iterate through sub-lists of rows of the size given.

          Each list will be of the size given, excluding the last list
          to be yielded, which may have a small number of rows.  No
          empty lists will be yielded.

          The result object is automatically closed when the iterator is
          fully consumed.

          Note that the backend driver will usually buffer the entire
          result ahead of time unless the
          Connection.execution_options.stream_results execution
          option is used indicating that the driver should not
          pre-buffer results, if possible.  Not all drivers support this
          option and the option is silently ignored for those who do
          not.

          New in version 1.4.

          Parameters: ‘size’ – indicate the maximum number of rows to be
          present in each list yielded.  If None, makes use of the value
          set by Result.yield_per(), if present, otherwise
          uses the Result.fetchmany() default which may be
          backend specific.

          Returns: iterator of lists

      -- Method: sqlalchemy.engine.CursorResult..
               postfetch_cols ()

          `inherited from the' BaseCursorResult.postfetch_cols().
          `method of' BaseCursorResult.

          Return ‘postfetch_cols()’ from the underlying
          ExecutionContext.

          See ExecutionContext for details.

          Raises InvalidRequestError if the executed
          statement is not a compiled expression construct or is not an
          insert() or update() construct.

      -- Method: sqlalchemy.engine.CursorResult..
               prefetch_cols ()

          `inherited from the' BaseCursorResult.prefetch_cols().
          `method of' BaseCursorResult.

          Return ‘prefetch_cols()’ from the underlying
          ExecutionContext.

          See ExecutionContext for details.

          Raises InvalidRequestError if the executed
          statement is not a compiled expression construct or is not an
          insert() or update() construct.

      -- Attribute: sqlalchemy.engine.CursorResult..
               returned_defaults

          `inherited from the' BaseCursorResult.returned_defaults.
          `attribute of' BaseCursorResult.

          Return the values of default columns that were fetched using
          the ValuesBase.return_defaults() feature.

          The value is an instance of Row, or ‘None’ if
          ValuesBase.return_defaults() was not used or if the
          backend does not support RETURNING.

          New in version 0.9.0.

          See also
          ........

          See ValuesBase.return_defaults().

      -- Attribute: sqlalchemy.engine.CursorResult..
               returned_defaults_rows

          `inherited from the'
          BaseCursorResult.returned_defaults_rows. `attribute of'
          BaseCursorResult.

          Return a list of rows each containing the values of default
          columns that were fetched using the
          ValuesBase.return_defaults() feature.

          The return value is a list of Row objects.

          New in version 1.4.

      -- Attribute: sqlalchemy.engine.CursorResult..
               returns_rows

          `inherited from the' BaseCursorResult.returns_rows.
          `attribute of' BaseCursorResult.

          True if this CursorResult returns zero or more
          rows.

          I.e.  if it is legal to call the methods
          CursorResult.fetchone(), CursorResult.fetchmany().
          See CursorResult.fetchall().

          Overall, the value of CursorResult.returns_rows
          should always be synonymous with whether or not the DBAPI
          cursor had a ‘.description’ attribute, indicating the presence
          of result columns, noting that a cursor that returns zero rows
          still has a ‘.description’ if a row-returning statement was
          emitted.

          This attribute should be True for all results that are against
          SELECT statements, as well as for DML statements
          INSERT/UPDATE/DELETE that use RETURNING. For
          INSERT/UPDATE/DELETE statements that were not using RETURNING,
          the value will usually be False, however there are some
          dialect-specific exceptions to this, such as when using the
          MSSQL / pyodbc dialect a SELECT is emitted inline in order to
          retrieve an inserted primary key value.

      -- Attribute: sqlalchemy.engine.CursorResult..rowcount

          `inherited from the' BaseCursorResult.rowcount.
          `attribute of' BaseCursorResult.

          Return the ‘rowcount’ for this result.

          The ‘rowcount’ reports the number of rows `matched' by the
          WHERE criterion of an UPDATE or DELETE statement.

               Note: Notes regarding CursorResult.rowcount:

                  * This attribute returns the number of rows `matched',
                    which is not necessarily the same as the number of
                    rows that were actually `modified' - an UPDATE
                    statement, for example, may have no net change on a
                    given row if the SET values given are the same as
                    those present in the row already.  Such a row would
                    be matched but not modified.  On backends that
                    feature both styles, such as MySQL, rowcount is
                    configured by default to return the match count in
                    all cases.

                  * CursorResult.rowcount is `only' useful
                    in conjunction with an UPDATE or DELETE statement.
                    Contrary to what the Python DBAPI says, it does
                    `not' return the number of rows available from the
                    results of a SELECT statement as DBAPIs cannot
                    support this functionality when rows are unbuffered.

                  * CursorResult.rowcount may not be fully
                    implemented by all dialects.  In particular, most
                    DBAPIs do not support an aggregate rowcount result
                    from an executemany call.  The
                    CursorResult.supports_sane_rowcount() and
                    CursorResult.supports_sane_multi_rowcount()
                    methods will report from the dialect if each
                    usage is known to be supported.

                  * Statements that use RETURNING may not return a
                    correct rowcount.

      -- Method: sqlalchemy.engine.CursorResult..scalar () ->
               Optional[Any]

          `inherited from the' Result.scalar(). `method of'
          Result.

          Fetch the first column of the first row, and close the result
          set.

          Returns None if there are no rows to fetch.

          No validation is performed to test if additional rows remain.

          After calling this method, the object is fully closed, e.g.
          the CursorResult.close() method will have been
          called.

          Returns: a Python scalar value , or None if no rows remain.

      -- Method: sqlalchemy.engine.CursorResult..scalar_one
               () -> Any

          `inherited from the' Result.scalar_one(). `method
          of' Result.

          Return exactly one scalar result or raise an exception.

          This is equivalent to calling Result.scalars() and
          then Result.one().

          See also
          ........

          See Result.one().

          See Result.scalars().

      -- Method: sqlalchemy.engine.CursorResult..
               scalar_one_or_none () -> Optional[Any]

          `inherited from the' Result.scalar_one_or_none().
          `method of' Result.

          Return exactly one or no scalar result.

          This is equivalent to calling Result.scalars() and
          then Result.one_or_none().

          See also
          ........

          See Result.one_or_none().

          See Result.scalars().

      -- Method: sqlalchemy.engine.CursorResult..scalars
               (index: Int = 0) -> ScalarResult

          `inherited from the' Result.scalars(). `method of'
          Result.

          Return a ScalarResult filtering object which will
          return single elements rather than Row objects.

          E.g.:

               >>> result = conn.execute(text("select int_id from table"))
               >>> result.scalars().all()
               [1, 2, 3]

          When results are fetched from the ScalarResult
          filtering object, the single column-row that would be returned
          by the Result is instead returned as the column’s
          value.

          New in version 1.4.

          Parameters: ‘index’ – integer or row key indicating the column
          to be fetched from each row, defaults to ‘0’ indicating the
          first column.

          Returns: a new ScalarResult filtering object
          referring to this Result object.

      -- Method: sqlalchemy.engine.CursorResult..
               supports_sane_multi_rowcount ()

          `inherited from the'
          BaseCursorResult.supports_sane_multi_rowcount(). `method
          of' BaseCursorResult.

          Return ‘supports_sane_multi_rowcount’ from the dialect.

          See CursorResult.rowcount for background.

      -- Method: sqlalchemy.engine.CursorResult..
               supports_sane_rowcount ()

          `inherited from the'
          BaseCursorResult.supports_sane_rowcount(). `method of'
          BaseCursorResult.

          Return ‘supports_sane_rowcount’ from the dialect.

          See CursorResult.rowcount for background.

      -- Method: sqlalchemy.engine.CursorResult..unique
               (strategy: Optional[object] = None) -> Result

          `inherited from the' Result.unique(). `method of'
          Result.

          Apply unique filtering to the objects returned by this
          Result.

          When this filter is applied with no arguments, the rows or
          objects returned will filtered such that each row is returned
          uniquely.  The algorithm used to determine this uniqueness is
          by default the Python hashing identity of the whole tuple.  In
          some cases a specialized per-entity hashing scheme may be
          used, such as when using the ORM, a scheme is applied which
          works against the primary key identity of returned objects.

          The unique filter is applied `after all other filters', which
          means if the columns returned have been refined using a method
          such as the Result.columns() or
          Result.scalars() method, the uniquing is applied to
          `only the column or columns returned'.  This occurs regardless
          of the order in which these methods have been called upon the
          Result object.

          The unique filter also changes the calculus used for methods
          like Result.fetchmany() and
          Result.partitions().  When using Result.unique(),
          these methods will continue to yield the number of rows
          or objects requested, after uniquing has been applied.
          However, this necessarily impacts the buffering behavior of
          the underlying cursor or datasource, such that multiple
          underlying calls to ‘cursor.fetchmany()’ may be necessary in
          order to accumulate enough objects in order to provide a
          unique collection of the requested size.

          Parameters: ‘strategy’ – a callable that will be applied to
          rows or objects being iterated, which should return an object
          that represents the unique value of the row.  A Python ‘set()’
          is used to store these identities.  If not passed, a default
          uniqueness strategy is used which may have been assembled by
          the source of this Result object.

      -- Method: sqlalchemy.engine.CursorResult..yield_per
               (num)

          Configure the row-fetching strategy to fetch num rows at a
          time.

          This impacts the underlying behavior of the result when
          iterating over the result object, or otherwise making use of
          methods such as Result.fetchone() that return one
          row at a time.  Data from the underlying cursor or other data
          source will be buffered up to this many rows in memory, and
          the buffered collection will then be yielded out one row at at
          time or as many rows are requested.  Each time the buffer
          clears, it will be refreshed to this many rows or as many rows
          remain if fewer remain.

          The Result.yield_per() method is generally used
          in conjunction with the
          Connection.execution_options.stream_results execution
          option, which will allow the database dialect in use to make
          use of a server side cursor, if the DBAPI supports it.

          Most DBAPIs do not use server side cursors by default, which
          means all rows will be fetched upfront from the database
          regardless of the Result.yield_per() setting.
          However, see Result.yield_per() may still be useful
          in that it batches the SQLAlchemy-side processing of the raw
          data from the database, and additionally when used for ORM
          scenarios will batch the conversion of database rows into ORM
          entity rows.

          New in version 1.4.

          Parameters: ‘num’ – number of rows to fetch each time the
          buffer is refilled.  If set to a value below 1, fetches all
          rows for the next buffer.

 -- Class: sqlalchemy.engine.LegacyCursorResult (context,
          cursor_strategy, cursor_description)

     Legacy version of CursorResult.

     This class includes connection “connection autoclose” behavior for
     use with “connectionless” execution, as well as delivers rows using
     the LegacyRow row implementation.

     New in version 1.4.

     `Class signature'

     class sqlalchemy.engine.LegacyCursorResult. (see
     sqlalchemy.engine.CursorResult)

      -- Method: sqlalchemy.engine.LegacyCursorResult..close
               ()

          Close this LegacyCursorResult.

          This method has the same behavior as that of
          ‘sqlalchemy.engine.CursorResult()’, but it also may close the
          underlying Connection for the case of
          “connectionless” execution.

          Deprecated since version 2.0: “connectionless” execution is
          deprecated and will be removed in version 2.0.  Version 2.0
          will feature the ‘Result’ object that will no longer affect
          the status of the originating connection in any case.

          After this method is called, it is no longer valid to call
          upon the fetch methods, which will raise a
          ResourceClosedError on subsequent use.

          See also
          ........

          See Working with Engines and Connections.

          See Connectionless Execution, Implicit Execution.

 -- Class: sqlalchemy.engine.Row (parent, processors, keymap, key_style,
          data)

     Represent a single result row.

     The Row object represents a row of a database result.
     It is typically associated in the 1.x series of SQLAlchemy with the
     CursorResult object, however is also used by the ORM
     for tuple-like results as of SQLAlchemy 1.4.

     The Row object seeks to act as much like a Python named
     tuple as possible.  For mapping (i.e.  dictionary) behavior on a
     row, such as testing for containment of keys, refer to the
     Row._mapping attribute.

     See also
     ........

     See Selecting. - includes examples of selecting rows from
     SELECT statements.

     See LegacyRow. - Compatibility interface introduced in
     SQLAlchemy 1.4.

     Changed in version 1.4: Renamed ‘RowProxy’ to Row.
     Row is no longer a “proxy” object in that it contains the
     final form of data within it, and now acts mostly like a named
     tuple.  Mapping-like functionality is moved to the
     Row._mapping attribute, but will remain available in
     SQLAlchemy 1.x series via the LegacyRow class that is
     used by LegacyCursorResult.  See *note RowProxy is no
     longer a “proxy”; is now called Row and behaves like an enhanced
     named tuple: c98. for background on this change.

     `Class signature'

     class sqlalchemy.engine.Row.
     (‘sqlalchemy.engine.BaseRow’, ‘collections.abc.Sequence’)

      -- Attribute: sqlalchemy.engine.Row.._fields

          Return a tuple of string keys as represented by this
          Row.

          The keys can represent the labels of the columns returned by a
          core statement or the names of the orm classes returned by an
          orm execution.

          This attribute is analogous to the Python named tuple
          ‘._fields’ attribute.

          New in version 1.4.

          See also
          ........

          See Row._mapping.

      -- Attribute: sqlalchemy.engine.Row.._mapping

          Return a RowMapping for this Row.

          This object provides a consistent Python mapping (i.e.
          dictionary) interface for the data contained within the row.
          The Row by itself behaves like a named tuple,
          however in the 1.4 series of SQLAlchemy, the LegacyRow
          class is still used by Core which continues to have
          mapping-like behaviors against the row object itself.

          See also
          ........

          See Row._fields.

          New in version 1.4.

      -- Method: sqlalchemy.engine.Row..keys ()

          Return the list of keys as strings represented by this
          Row.

          Deprecated since version 1.4: The Row.keys()
          method is considered legacy as of the 1.x series of SQLAlchemy
          and will be removed in 2.0.  Use the namedtuple standard
          accessor Row._fields, or for full mapping behavior
          use row._mapping.keys() (Background on SQLAlchemy 2.0 at:
          Migrating to SQLAlchemy 2.0)

          The keys can represent the labels of the columns returned by a
          core statement or the names of the orm classes returned by an
          orm execution.

          This method is analogous to the Python dictionary ‘.keys()’
          method, except that it returns a list, not an iterator.

          See also
          ........

          See Row._fields.

          See Row._mapping.

 -- Class: sqlalchemy.engine.RowMapping (parent, processors, keymap,
          key_style, data)

     A ‘Mapping’ that maps column names and objects to Row
     values.

     The RowMapping is available from a Row via
     the Row._mapping attribute, as well as from the
     iterable interface provided by the MappingResult object
     returned by the Result.mappings() method.

     RowMapping supplies Python mapping (i.e.  dictionary)
     access to the contents of the row.  This includes support for
     testing of containment of specific keys (string column names or
     objects), as well as iteration of keys, values, and items:

          for row in result:
              if 'a' in row._mapping:
                  print("Column 'a': %s" % row._mapping['a'])

              print("Column b: %s" % row._mapping[table.c.b])

     New in version 1.4: The RowMapping object replaces the
     mapping-like access previously provided by a database result row,
     which now seeks to behave mostly like a named tuple.

     `Class signature'

     class sqlalchemy.engine.RowMapping.
     (‘sqlalchemy.engine.BaseRow’, ‘collections.abc.Mapping’)

      -- Method: sqlalchemy.engine.RowMapping..items ()

          Return a view of key/value tuples for the elements in the
          underlying Row.

      -- Method: sqlalchemy.engine.RowMapping..keys ()

          Return a view of ‘keys’ for string column names represented by
          the underlying Row.

      -- Method: sqlalchemy.engine.RowMapping..values ()

          Return a view of values for the values represented in the
          underlying Row.

4.5.3 Connection Pooling
------------------------

A connection pool is a standard technique used to maintain long running
connections in memory for efficient re-use, as well as to provide
management for the total number of connections an application might use
simultaneously.

Particularly for server-side web applications, a connection pool is the
standard way to maintain a “pool” of active database connections in
memory which are reused across requests.

SQLAlchemy includes several connection pool implementations which
integrate with the Engine.  They can also be used directly
for applications that want to add pooling to an otherwise plain DBAPI
approach.

4.5.3.1 Connection Pool Configuration
.....................................

The Engine returned by the create_engine()
function in most cases has a QueuePool integrated,
pre-configured with reasonable pooling defaults.  If you’re reading this
section only to learn how to enable pooling - congratulations!  You’re
already done.

The most common QueuePool tuning parameters can be passed
directly to create_engine() as keyword arguments:
‘pool_size’, ‘max_overflow’, ‘pool_recycle’ and ‘pool_timeout’.  For
example:

     engine = create_engine('postgresql://me@localhost/mydb',
                            pool_size=20, max_overflow=0)

In the case of SQLite, the SingletonThreadPool or
NullPool are selected by the dialect to provide greater
compatibility with SQLite’s threading and locking model, as well as to
provide a reasonable default behavior to SQLite “memory” databases,
which maintain their entire dataset within the scope of a single
connection.

All SQLAlchemy pool implementations have in common that none of them
“pre create” connections - all implementations wait until first use
before creating a connection.  At that point, if no additional
concurrent checkout requests for more connections are made, no
additional connections are created.  This is why it’s perfectly fine for
create_engine() to default to using a QueuePool
of size five without regard to whether or not the application really
needs five connections queued up - the pool would only grow to that size
if the application actually used five connections concurrently, in which
case the usage of a small pool is an entirely appropriate default
behavior.

4.5.3.2 Switching Pool Implementations
......................................

The usual way to use a different kind of pool with
create_engine() is to use the ‘poolclass’ argument.  This argument
accepts a class imported from the ‘sqlalchemy.pool’ module, and handles
the details of building the pool for you.  Common options include
specifying QueuePool with SQLite:

     from sqlalchemy.pool import QueuePool
     engine = create_engine('sqlite:///file.db', poolclass=QueuePool)

Disabling pooling using NullPool:

     from sqlalchemy.pool import NullPool
     engine = create_engine(
               'postgresql+psycopg2://scott:tiger@localhost/test',
               poolclass=NullPool)

4.5.3.3 Using a Custom Connection Function
..........................................

See the section Custom DBAPI connect() arguments / on-connect routines
for a rundown of the various connection customization
routines.

4.5.3.4 Constructing a Pool
...........................

To use a Pool by itself, the ‘creator’ function is the only
argument that’s required and is passed first, followed by any additional
options:

     import sqlalchemy.pool as pool
     import psycopg2

     def getconn():
         c = psycopg2.connect(user='ed', host='127.0.0.1', dbname='test')
         return c

     mypool = pool.QueuePool(getconn, max_overflow=10, pool_size=5)

DBAPI connections can then be procured from the pool using the
Pool.connect() function.  The return value of this method is a
DBAPI connection that’s contained within a transparent proxy:

     # get a connection
     conn = mypool.connect()

     # use it
     cursor = conn.cursor()
     cursor.execute("select foo")

The purpose of the transparent proxy is to intercept the ‘close()’ call,
such that instead of the DBAPI connection being closed, it is returned
to the pool:

     # "close" the connection.  Returns
     # it to the pool.
     conn.close()

The proxy also returns its contained DBAPI connection to the pool when
it is garbage collected, though it’s not deterministic in Python that
this occurs immediately (though it is typical with cPython).  This usage
is not recommended however and in particular is not supported with
asyncio DBAPI drivers.

4.5.3.5 Reset On Return
.......................

The pool also includes the a “reset on return” feature which will call
the ‘rollback()’ method of the DBAPI connection when the connection is
returned to the pool.  This is so that any existing transaction on the
connection is removed, not only ensuring that no existing state remains
on next usage, but also so that table and row locks are released as well
as that any isolated data snapshots are removed.  This ‘rollback()’
occurs in most cases even when using an Engine object,
except in the case when the Connection can guarantee that a
‘rollback()’ has been called immediately before the connection is
returned to the pool.

For most DBAPIs, the call to ‘rollback()’ is very inexpensive and if the
DBAPI has already completed a transaction, the method should be a no-op.
However, for DBAPIs that incur performance issues with ‘rollback()’ even
if there’s no state on the connection, this behavior can be disabled
using the ‘reset_on_return’ option of Pool.  The behavior is
safe to disable under the following conditions:

   * If the database does not support transactions at all, such as using
     MySQL with the MyISAM engine, or the DBAPI is used in autocommit
     mode only, the behavior can be disabled.

   * If the pool itself doesn’t maintain a connection after it’s checked
     in, such as when using NullPool, the behavior can be
     disabled.

   * Otherwise, it must be ensured that: * the application ensures that
     all Connection.

          objects are explicitly closed out using a context manager
          (i.e.  ‘with’ block) or a ‘try/finally’ style block

        * connections are never allowed to be garbage collected before
          being explicitly closed.

        * the DBAPI connection itself, e.g.  ‘connection.connection’, is
          not used directly, or the application ensures that
          ‘.rollback()’ is called on this connection before releasing it
          back to the connection pool.

The “reset on return” step may be logged using the ‘logging.DEBUG’ log
level along with the ‘sqlalchemy.pool’ logger, or by setting
‘echo_pool='debug'’ with create_engine().

4.5.3.6 Pool Events
...................

Connection pools support an event interface that allows hooks to execute
upon first connect, upon each new connection, and upon checkout and
checkin of connections.  See PoolEvents for details.

4.5.3.7 Dealing with Disconnects
................................

The connection pool has the ability to refresh individual connections as
well as its entire set of connections, setting the previously pooled
connections as “invalid”.  A common use case is allow the connection
pool to gracefully recover when the database server has been restarted,
and all previously established connections are no longer functional.
There are two approaches to this.

4.5.3.8 Disconnect Handling - Pessimistic
.........................................

The pessimistic approach refers to emitting a test statement on the SQL
connection at the start of each connection pool checkout, to test that
the database connection is still viable.  Typically, this is a simple
statement like “SELECT 1”, but may also make use of some DBAPI-specific
method to test the connection for liveness.

The approach adds a small bit of overhead to the connection checkout
process, however is otherwise the most simple and reliable approach to
completely eliminating database errors due to stale pooled connections.
The calling application does not need to be concerned about organizing
operations to be able to recover from stale connections checked out from
the pool.

It is critical to note that the pre-ping approach `does not accommodate
for connections dropped in the middle of transactions or other SQL
operations'.  If the database becomes unavailable while a transaction is
in progress, the transaction will be lost and the database error will be
raised.  While the Connection object will detect a
“disconnect” situation and recycle the connection as well as invalidate
the rest of the connection pool when this condition occurs, the
individual operation where the exception was raised will be lost, and
it’s up to the application to either abandon the operation, or retry the
whole transaction again.  If the engine is configured using DBAPI-level
autocommit connections, as described at Setting Transaction Isolation Levels including DBAPI Autocommit,
a connection `may' be
reconnected transparently mid-operation using events.  See the section
How Do I “Retry” a Statement Execution Automatically? for
an example.

Pessimistic testing of connections upon checkout is achievable by using
the Pool.pre_ping argument, available from
create_engine() via the create_engine.pool_pre_ping
argument:

     engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True)

The “pre ping” feature will normally emit SQL equivalent to “SELECT 1”
each time a connection is checked out from the pool; if an error is
raised that is detected as a “disconnect” situation, the connection will
be immediately recycled, and all other pooled connections older than the
current time are invalidated, so that the next time they are checked
out, they will also be recycled before use.

If the database is still not available when “pre ping” runs, then the
initial connect will fail and the error for failure to connect will be
propagated normally.  In the uncommon situation that the database is
available for connections, but is not able to respond to a “ping”, the
“pre_ping” will try up to three times before giving up, propagating the
database error last received.

     Note: the “SELECT 1” emitted by “pre-ping” is invoked within the
     scope of the connection pool / dialect, using a very short codepath
     for minimal Python latency.  As such, this statement is `not logged
     in the SQL echo output', and will not show up in SQLAlchemy’s
     engine logging.

New in version 1.2: Added “pre-ping” capability to the Pool
class.

4.5.3.9 Custom / Legacy Pessimistic Ping
........................................

Before create_engine.pool_pre_ping was added, the
“pre-ping” approach historically has been performed manually using the
ConnectionEvents.engine_connect() engine event.  The most
common recipe for this is below, for reference purposes in case an
application is already using such a recipe, or special behaviors are
needed:

     from sqlalchemy import exc
     from sqlalchemy import event
     from sqlalchemy import select

     some_engine = create_engine(...)

     @event.listens_for(some_engine, "engine_connect")
     def ping_connection(connection, branch):
         if branch:
             # "branch" refers to a sub-connection of a connection,
             # we don't want to bother pinging on these.
             return

         # turn off "close with result".  This flag is only used with
         # "connectionless" execution, otherwise will be False in any case
         save_should_close_with_result = connection.should_close_with_result
         connection.should_close_with_result = False

         try:
             # run a SELECT 1.   use a core select() so that
             # the SELECT of a scalar value without a table is
             # appropriately formatted for the backend
             connection.scalar(select(1))
         except exc.DBAPIError as err:
             # catch SQLAlchemy's DBAPIError, which is a wrapper
             # for the DBAPI's exception.  It includes a .connection_invalidated
             # attribute which specifies if this connection is a "disconnect"
             # condition, which is based on inspection of the original exception
             # by the dialect in use.
             if err.connection_invalidated:
                 # run the same SELECT again - the connection will re-validate
                 # itself and establish a new connection.  The disconnect detection
                 # here also causes the whole connection pool to be invalidated
                 # so that all stale connections are discarded.
                 connection.scalar(select(1))
             else:
                 raise
         finally:
             # restore "close with result"
             connection.should_close_with_result = save_should_close_with_result

The above recipe has the advantage that we are making use of
SQLAlchemy’s facilities for detecting those DBAPI exceptions that are
known to indicate a “disconnect” situation, as well as the Engine
object’s ability to correctly invalidate the current connection
pool when this condition occurs and allowing the current
Connection to re-validate onto a new DBAPI connection.

4.5.3.10 Disconnect Handling - Optimistic
.........................................

When pessimistic handling is not employed, as well as when the database
is shutdown and/or restarted in the middle of a connection’s period of
use within a transaction, the other approach to dealing with stale /
closed connections is to let SQLAlchemy handle disconnects as they
occur, at which point all connections in the pool are invalidated,
meaning they are assumed to be stale and will be refreshed upon next
checkout.  This behavior assumes the Pool is used in
conjunction with a Engine.  The Engine has logic
which can detect disconnection events and refresh the pool
automatically.

When the Connection attempts to use a DBAPI connection, and
an exception is raised that corresponds to a “disconnect” event, the
connection is invalidated.  The Connection then calls the
Pool.recreate() method, effectively invalidating all
connections not currently checked out so that they are replaced with new
ones upon next checkout.  This flow is illustrated by the code example
below:

     from sqlalchemy import create_engine, exc
     e = create_engine(...)
     c = e.connect()

     try:
         # suppose the database has been restarted.
         c.execute(text("SELECT * FROM table"))
         c.close()
     except exc.DBAPIError, e:
         # an exception is raised, Connection is invalidated.
         if e.connection_invalidated:
             print("Connection was invalidated!")

     # after the invalidate event, a new connection
     # starts with a new Pool
     c = e.connect()
     c.execute(text("SELECT * FROM table"))

The above example illustrates that no special intervention is needed to
refresh the pool, which continues normally after a disconnection event
is detected.  However, one database exception is raised, per each
connection that is in use while the database unavailability event
occurred.  In a typical web application using an ORM Session, the above
condition would correspond to a single request failing with a 500 error,
then the web application continuing normally beyond that.  Hence the
approach is “optimistic” in that frequent database restarts are not
anticipated.

4.5.3.11 Setting Pool Recycle
.............................

An additional setting that can augment the “optimistic” approach is to
set the pool recycle parameter.  This parameter prevents the pool from
using a particular connection that has passed a certain age, and is
appropriate for database backends such as MySQL that automatically close
connections that have been stale after a particular period of time:

     from sqlalchemy import create_engine
     e = create_engine("mysql://scott:tiger@localhost/test", pool_recycle=3600)

Above, any DBAPI connection that has been open for more than one hour
will be invalidated and replaced, upon next checkout.  Note that the
invalidation `only' occurs during checkout - not on any connections that
are held in a checked out state.  ‘pool_recycle’ is a function of the
Pool itself, independent of whether or not an Engine
is in use.

4.5.3.12 More on Invalidation
.............................

The Pool provides “connection invalidation” services which
allow both explicit invalidation of a connection as well as automatic
invalidation in response to conditions that are determined to render a
connection unusable.

“Invalidation” means that a particular DBAPI connection is removed from
the pool and discarded.  The ‘.close()’ method is called on this
connection if it is not clear that the connection itself might not be
closed, however if this method fails, the exception is logged but the
operation still proceeds.

When using a Engine, the Connection.invalidate()
method is the usual entrypoint to explicit invalidation.  Other
conditions by which a DBAPI connection might be invalidated include:

   * a DBAPI exception such as OperationalError, raised when
     a method like ‘connection.execute()’ is called, is detected as
     indicating a so-called “disconnect” condition.  As the Python DBAPI
     provides no standard system for determining the nature of an
     exception, all SQLAlchemy dialects include a system called
     ‘is_disconnect()’ which will examine the contents of an exception
     object, including the string message and any potential error codes
     included with it, in order to determine if this exception indicates
     that the connection is no longer usable.  If this is the case, the
     _ConnectionFairy.invalidate() method is called and the
     DBAPI connection is then discarded.

   * When the connection is returned to the pool, and calling the
     ‘connection.rollback()’ or ‘connection.commit()’ methods, as
     dictated by the pool’s “reset on return” behavior, throws an
     exception.  A final attempt at calling ‘.close()’ on the connection
     will be made, and it is then discarded.

   * When a listener implementing PoolEvents.checkout().
     raises the DisconnectionError exception, indicating
     that the connection won’t be usable and a new connection attempt
     needs to be made.

All invalidations which occur will invoke the
PoolEvents.invalidate() event.

4.5.3.13 Using FIFO vs. LIFO
............................

The QueuePool class features a flag called
QueuePool.use_lifo, which can also be accessed from
create_engine() via the flag create_engine.pool_use_lifo.
Setting this flag to ‘True’ causes the pool’s “queue” behavior to
instead be that of a “stack”, e.g.  the last connection to be returned
to the pool is the first one to be used on the next request.  In
contrast to the pool’s long- standing behavior of first-in-first-out,
which produces a round-robin effect of using each connection in the pool
in series, lifo mode allows excess connections to remain idle in the
pool, allowing server-side timeout schemes to close these connections
out.  The difference between FIFO and LIFO is basically whether or not
its desirable for the pool to keep a full set of connections ready to go
even during idle periods:

     engine = create_engine(
         "postgreql://", pool_use_lifo=True, pool_pre_ping=True)

Above, we also make use of the create_engine.pool_pre_ping
flag so that connections which are closed from the server side are
gracefully handled by the connection pool and replaced with a new
connection.

Note that the flag only applies to QueuePool use.

New in version 1.3.

See also
........

See Dealing with Disconnects.

4.5.3.14 Using Connection Pools with Multiprocessing or os.fork()
.................................................................

It’s critical that when using a connection pool, and by extension when
using an Engine created via create_engine(), that
the pooled connections `are not shared to a forked process'.  TCP
connections are represented as file descriptors, which usually work
across process boundaries, meaning this will cause concurrent access to
the file descriptor on behalf of two or more entirely independent Python
interpreter states.

Depending on specifics of the driver and OS, the issues that arise here
range from non-working connections to socket connections that are used
by multiple processes concurrently, leading to broken messaging (the
latter case is typically the most common).

The SQLAlchemy Engine object refers to a connection pool of
existing database connections.  So when this object is replicated to a
child process, the goal is to ensure that no database connections are
carried over.  There are three general approaches to this:

  1. Disable pooling using NullPool.  This is the most
     simplistic, one shot system that prevents the Engine
     from using any connection more than once:

          from sqlalchemy.pool import NullPool
          engine = create_engine("mysql://user:pass@host/dbname", poolclass=NullPool)

  2. Call Engine.dispose() on any given Engine.
     as soon one is within the new process.  In Python multiprocessing,
     constructs such as ‘multiprocessing.Pool’ include “initializer”
     hooks which are a place that this can be performed; otherwise at
     the top of where ‘os.fork()’ or where the ‘Process’ object begins
     the child fork, a single call to Engine.dispose() will
     ensure any remaining connections are flushed.  `This is the
     recommended approach':

          engine = create_engine("mysql://user:pass@host/dbname")

          def run_in_process():
              # process starts.  ensure engine.dispose() is called just once
              # at the beginning
              engine.dispose()

              with engine.connect() as conn:
                  conn.execute(text("..."))

          p = Process(target=run_in_process)
          p.start()

  3. An event handler can be applied to the connection pool that tests
     for connections being shared across process boundaries, and
     invalidates them.  This approach, `when combined with an explicit
     call to dispose() as mentioned above', should cover all cases:

          from sqlalchemy import event
          from sqlalchemy import exc
          import os

          engine = create_engine("...")

          @event.listens_for(engine, "connect")
          def connect(dbapi_connection, connection_record):
              connection_record.info['pid'] = os.getpid()

          @event.listens_for(engine, "checkout")
          def checkout(dbapi_connection, connection_record, connection_proxy):
              pid = os.getpid()
              if connection_record.info['pid'] != pid:
                  connection_record.connection = connection_proxy.connection = None
                  raise exc.DisconnectionError(
                          "Connection record belongs to pid %s, "
                          "attempting to check out in pid %s" %
                          (connection_record.info['pid'], pid)
                  )

     Above, we use an approach similar to that described in
     Disconnect Handling - Pessimistic to treat a DBAPI
     connection that originated in a different parent process as an
     “invalid” connection, coercing the pool to recycle the connection
     record to make a new connection.

     When using the above recipe, `ensure the dispose approach from #2
     is also used', as if the connection pool is exhausted in the parent
     process when the fork occurs, an empty pool will be copied into the
     child process which will then hang because it has no connections.

The above strategies will accommodate the case of an Engine
being shared among processes.  However, for the case of a
transaction-active Session or Connection being
shared, there’s no automatic fix for this; an application needs to
ensure a new child process only initiate new Connection
objects and transactions, as well as ORM Session objects.
For a Session object, technically this is only needed if the
session is currently transaction-bound, however the scope of a single
Session is in any case intended to be kept within a single
call stack in any case (e.g.  not a global object, not shared between
processes or threads).

4.5.3.15 API Documentation - Available Pool Implementations
...........................................................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See _ConnectionFairy.Proxies a DBAPI connection and provides return-on-dereference support.

See _ConnectionRecord.Internal object which maintains an individual DBAPI connection referenced by a
               Pool.

See AssertionPool.A Pool that allows at most one checked out connection at any given time.

See NullPool.A Pool which does not pool connections.

See Pool.Abstract base class for connection pools.

See QueuePool.A Pool that imposes a limit on the number of open connections.

See SingletonThreadPool.A Pool that maintains one connection per thread.

See StaticPool.A Pool of exactly one connection, used for all requests.

 -- Class: sqlalchemy.pool.Pool (creator, recycle=- 1, echo=None,
          logging_name=None, reset_on_return=True, events=None,
          dialect=None, pre_ping=False, _dispatch=None)

     Abstract base class for connection pools.

     `Class signature'

     class sqlalchemy.pool.Pool. (see
     sqlalchemy.log.Identified)

      -- Method: sqlalchemy.pool.Pool..__init__ (creator,
               recycle=- 1, echo=None, logging_name=None,
               reset_on_return=True, events=None, dialect=None,
               pre_ping=False, _dispatch=None)

          Construct a Pool.

          Parameters:

             * ‘creator’ – a callable function that returns a DB-API
               connection object.  The function will be called with
               parameters.

             * ‘recycle’ – If set to a value other than -1, number of
               seconds between connection recycling, which means upon
               checkout, if this timeout is surpassed the connection
               will be closed and replaced with a newly opened
               connection.  Defaults to -1.

             * ‘logging_name’ – String identifier which will be used
               within the “name” field of logging records generated
               within the “sqlalchemy.pool” logger.  Defaults to a
               hexstring of the object’s id.

             * ‘echo’ – if True, the connection pool will log
               informational output such as when connections are
               invalidated as well as when connections are recycled to
               the default log handler, which defaults to ‘sys.stdout’
               for output..  If set to the string ‘"debug"’, the logging
               will include pool checkouts and checkins.

               The Pool.echo parameter can also be set from
               the create_engine() call by using the
               create_engine.echo_pool parameter.

               See also
               ........

               See Configuring Logging. - further detail on how to
               configure logging.

             * ‘reset_on_return’ –

               Determine steps to take on

                    connections as they are returned to the pool, which
                    were not otherwise handled by a Connection.

                    reset_on_return can have any of these values:

                       * ‘"rollback"’ - call rollback() on the
                         connection, to release locks and transaction
                         resources.  This is the default value.  The
                         vast majority of use cases should leave this
                         value set.

                       * ‘True’ - same as ‘rollback’, this is here for
                         backwards compatibility.

                       * ‘"commit"’ - call commit() on the connection,
                         to release locks and transaction resources.  A
                         commit here may be desirable for databases that
                         cache query plans if a commit is emitted, such
                         as Microsoft SQL Server.  However, this value
                         is more dangerous than ‘rollback’ because any
                         data changes present on the transaction are
                         committed unconditionally.

                       * ‘None’ - don’t do anything on the connection.
                         This setting is only appropriate if the
                         database / DBAPI works in pure “autocommit”
                         mode at all times, or if the application uses
                         the Engine with consistent
                         connectivity patterns.  See the section
                         Reset On Return for more details.

                       * ‘False’ - same as None, this is here for
                         backwards compatibility.

               See also
               ........

               See Reset On Return.

             * ‘events’ – a list of 2-tuples, each of the form
               ‘(callable, target)’ which will be passed to
               listen() upon construction.  Provided here so that
               event listeners can be assigned via
               create_engine() before dialect-level listeners are
               applied.

             * ‘dialect’ – a Dialect that will handle the
               job of calling rollback(), close(), or commit() on DBAPI
               connections.  If omitted, a built-in “stub” dialect is
               used.  Applications that make use of
               create_engine() should not use this parameter as it
               is handled by the engine creation strategy.

               New in version 1.1: - ‘dialect’ is now a public parameter
               to the Pool.

             * ‘pre_ping’ – if True, the pool will emit a “ping”
               (typically “SELECT 1”, but is dialect-specific) on the
               connection upon checkout, to test if the connection is
               alive or not.  If not, the connection is transparently
               re-connected and upon success, all other pooled
               connections established prior to that timestamp are
               invalidated.  Requires that a dialect is passed as well
               to interpret the disconnection error.

               New in version 1.2.

      -- Method: sqlalchemy.pool.Pool..connect ()

          Return a DBAPI connection from the pool.

          The connection is instrumented such that when its ‘close()’
          method is called, the connection will be returned to the pool.

      -- Method: sqlalchemy.pool.Pool..dispose ()

          Dispose of this pool.

          This method leaves the possibility of checked-out connections
          remaining open, as it only affects connections that are idle
          in the pool.

          See also
          ........

          See Pool.recreate().

      -- Method: sqlalchemy.pool.Pool..recreate ()

          Return a new Pool, of the same class as this one
          and configured with identical creation arguments.

          This method is used in conjunction with dispose()
          to close out an entire Pool and create a new one
          in its place.

 -- Class: sqlalchemy.pool.QueuePool (creator, pool_size=5,
          max_overflow=10, timeout=30.0, use_lifo=False, **kw)

     A Pool that imposes a limit on the number of open
     connections.

     QueuePool is the default pooling implementation used
     for all Engine objects, unless the SQLite dialect is in
     use.

     `Class signature'

     class sqlalchemy.pool.QueuePool.
     (‘sqlalchemy.pool.base.Pool’)

      -- Method: sqlalchemy.pool.QueuePool..__init__
               (creator, pool_size=5, max_overflow=10, timeout=30.0,
               use_lifo=False, **kw)

          Construct a QueuePool.

          Parameters:

             * ‘creator’ – a callable function that returns a DB-API
               connection object, same as that of Pool.creator.

             * ‘pool_size’ – The size of the pool to be maintained,
               defaults to 5.  This is the largest number of connections
               that will be kept persistently in the pool.  Note that
               the pool begins with no connections; once this number of
               connections is requested, that number of connections will
               remain.  ‘pool_size’ can be set to 0 to indicate no size
               limit; to disable pooling, use a NullPool
               instead.

             * ‘max_overflow’ – The maximum overflow size of the pool.
               When the number of checked-out connections reaches the
               size set in pool_size, additional connections will be
               returned up to this limit.  When those additional
               connections are returned to the pool, they are
               disconnected and discarded.  It follows then that the
               total number of simultaneous connections the pool will
               allow is pool_size + ‘max_overflow’, and the total number
               of “sleeping” connections the pool will allow is
               pool_size.  ‘max_overflow’ can be set to -1 to indicate
               no overflow limit; no limit will be placed on the total
               number of concurrent connections.  Defaults to 10.

             * ‘timeout’ – The number of seconds to wait before giving
               up on returning a connection.  Defaults to 30.0.  This
               can be a float but is subject to the limitations of
               Python time functions which may not be reliable in the
               tens of milliseconds.

             * ‘use_lifo’ – use LIFO (last-in-first-out) when retrieving
               connections instead of FIFO (first-in-first-out).  Using
               LIFO, a server-side timeout scheme can reduce the number
               of connections used during non-peak periods of use.  When
               planning for server-side timeouts, ensure that a recycle
               or pre-ping strategy is in use to gracefully handle stale
               connections.

               New in version 1.3.

               See also
               ........

               See Using FIFO vs. LIFO.

               See Dealing with Disconnects.

             * ‘**kw’ – Other keyword arguments including
               Pool.recycle, Pool.echo,
               Pool.reset_on_return and others are passed to the
               Pool constructor.

      -- Method: sqlalchemy.pool.QueuePool..connect ()

          `inherited from the' ‘Pool.connect()’ `method of' ‘Pool’

          Return a DBAPI connection from the pool.

          The connection is instrumented such that when its ‘close()’
          method is called, the connection will be returned to the pool.

 -- Class: sqlalchemy.pool.SingletonThreadPool (creator, pool_size=5,
          **kw)

     A Pool that maintains one connection per thread.

     Maintains one connection per each thread, never moving a connection
     to a thread other than the one which it was created in.

          Warning: the SingletonThreadPool will call
          ‘.close()’ on arbitrary connections that exist beyond the size
          setting of ‘pool_size’, e.g.  if more unique `thread
          identities' than what ‘pool_size’ states are used.  This
          cleanup is non-deterministic and not sensitive to whether or
          not the connections linked to those thread identities are
          currently in use.

          SingletonThreadPool may be improved in a future
          release, however in its current status it is generally used
          only for test scenarios using a SQLite ‘:memory:’ database and
          is not recommended for production use.

     Options are the same as those of Pool, as well as:

     Parameters: ‘pool_size’ – The number of threads in which to
     maintain connections at once.  Defaults to five.

     SingletonThreadPool is used by the SQLite dialect
     automatically when a memory-based database is used.  See
     SQLite.

     `Class signature'

     class sqlalchemy.pool.SingletonThreadPool.
     (‘sqlalchemy.pool.base.Pool’)

      -- Method: sqlalchemy.pool.SingletonThreadPool..
               __init__ (creator, pool_size=5, **kw)

          Construct a Pool.

          Parameters:

             * ‘creator’ – a callable function that returns a DB-API
               connection object.  The function will be called with
               parameters.

             * ‘recycle’ – If set to a value other than -1, number of
               seconds between connection recycling, which means upon
               checkout, if this timeout is surpassed the connection
               will be closed and replaced with a newly opened
               connection.  Defaults to -1.

             * ‘logging_name’ – String identifier which will be used
               within the “name” field of logging records generated
               within the “sqlalchemy.pool” logger.  Defaults to a
               hexstring of the object’s id.

             * ‘echo’ – if True, the connection pool will log
               informational output such as when connections are
               invalidated as well as when connections are recycled to
               the default log handler, which defaults to ‘sys.stdout’
               for output..  If set to the string ‘"debug"’, the logging
               will include pool checkouts and checkins.

               The Pool.echo parameter can also be set from
               the create_engine() call by using the
               create_engine.echo_pool parameter.

               See also
               ........

               See Configuring Logging. - further detail on how to
               configure logging.

             * ‘reset_on_return’ –

               Determine steps to take on

                    connections as they are returned to the pool, which
                    were not otherwise handled by a Connection.

                    reset_on_return can have any of these values:

                       * ‘"rollback"’ - call rollback() on the
                         connection, to release locks and transaction
                         resources.  This is the default value.  The
                         vast majority of use cases should leave this
                         value set.

                       * ‘True’ - same as ‘rollback’, this is here for
                         backwards compatibility.

                       * ‘"commit"’ - call commit() on the connection,
                         to release locks and transaction resources.  A
                         commit here may be desirable for databases that
                         cache query plans if a commit is emitted, such
                         as Microsoft SQL Server.  However, this value
                         is more dangerous than ‘rollback’ because any
                         data changes present on the transaction are
                         committed unconditionally.

                       * ‘None’ - don’t do anything on the connection.
                         This setting is only appropriate if the
                         database / DBAPI works in pure “autocommit”
                         mode at all times, or if the application uses
                         the Engine with consistent
                         connectivity patterns.  See the section
                         Reset On Return for more details.

                       * ‘False’ - same as None, this is here for
                         backwards compatibility.

               See also
               ........

               See Reset On Return.

             * ‘events’ – a list of 2-tuples, each of the form
               ‘(callable, target)’ which will be passed to
               listen() upon construction.  Provided here so that
               event listeners can be assigned via
               create_engine() before dialect-level listeners are
               applied.

             * ‘dialect’ – a Dialect that will handle the
               job of calling rollback(), close(), or commit() on DBAPI
               connections.  If omitted, a built-in “stub” dialect is
               used.  Applications that make use of
               create_engine() should not use this parameter as it
               is handled by the engine creation strategy.

               New in version 1.1: - ‘dialect’ is now a public parameter
               to the Pool.

             * ‘pre_ping’ – if True, the pool will emit a “ping”
               (typically “SELECT 1”, but is dialect-specific) on the
               connection upon checkout, to test if the connection is
               alive or not.  If not, the connection is transparently
               re-connected and upon success, all other pooled
               connections established prior to that timestamp are
               invalidated.  Requires that a dialect is passed as well
               to interpret the disconnection error.

               New in version 1.2.

 -- Class: sqlalchemy.pool.AssertionPool (*args, **kw)

     A Pool that allows at most one checked out connection
     at any given time.

     This will raise an exception if more than one connection is checked
     out at a time.  Useful for debugging code that is using more
     connections than desired.

     `Class signature'

     class sqlalchemy.pool.AssertionPool.
     (‘sqlalchemy.pool.base.Pool’)

 -- Class: sqlalchemy.pool.NullPool (creator, recycle=- 1, echo=None,
          logging_name=None, reset_on_return=True, events=None,
          dialect=None, pre_ping=False, _dispatch=None)

     A Pool which does not pool connections.

     Instead it literally opens and closes the underlying DB-API
     connection per each connection open/close.

     Reconnect-related functions such as ‘recycle’ and connection
     invalidation are not supported by this Pool implementation, since
     no connections are held persistently.

     `Class signature'

     class sqlalchemy.pool.NullPool.
     (‘sqlalchemy.pool.base.Pool’)

 -- Class: sqlalchemy.pool.StaticPool (creator, recycle=- 1, echo=None,
          logging_name=None, reset_on_return=True, events=None,
          dialect=None, pre_ping=False, _dispatch=None)

     A Pool of exactly one connection, used for all requests.

     Reconnect-related functions such as ‘recycle’ and connection
     invalidation (which is also used to support auto-reconnect) are not
     currently supported by this Pool implementation but may be
     implemented in a future release.

     `Class signature'

     class sqlalchemy.pool.StaticPool.
     (‘sqlalchemy.pool.base.Pool’)

 -- Class: sqlalchemy.pool._ConnectionFairy (dbapi_connection,
          connection_record, echo)

     Proxies a DBAPI connection and provides return-on-dereference
     support.

     This is an internal object used by the Pool
     implementation to provide context management to a DBAPI connection
     delivered by that Pool.

     The name “fairy” is inspired by the fact that the
     _ConnectionFairy object’s lifespan is transitory, as it
     lasts only for the length of a specific DBAPI connection being
     checked out from the pool, and additionally that as a transparent
     proxy, it is mostly invisible.

     See also
     ........

     See _ConnectionRecord.

      -- Attribute: sqlalchemy.pool._ConnectionFairy..
               _connection_record = None

          A reference to the _ConnectionRecord object
          associated with the DBAPI connection.

          This is currently an internal accessor which is subject to
          change.

      -- Attribute: sqlalchemy.pool._ConnectionFairy..
               connection = None

          A reference to the actual DBAPI connection being tracked.

      -- Method: sqlalchemy.pool._ConnectionFairy..cursor
               (*args, **kwargs)

          Return a new DBAPI cursor for the underlying connection.

          This method is a proxy for the ‘connection.cursor()’ DBAPI
          method.

      -- Method: sqlalchemy.pool._ConnectionFairy..detach ()

          Separate this connection from its Pool.

          This means that the connection will no longer be returned to
          the pool when closed, and will instead be literally closed.
          The containing ConnectionRecord is separated from the DB-API
          connection, and will create a new connection when next used.

          Note that any overall connection limiting constraints imposed
          by a Pool implementation may be violated after a detach, as
          the detached connection is removed from the pool’s knowledge
          and control.

      -- Attribute: sqlalchemy.pool._ConnectionFairy..info

          Info dictionary associated with the underlying DBAPI
          connection referred to by this ‘ConnectionFairy’, allowing
          user-defined data to be associated with the connection.

          The data here will follow along with the DBAPI connection
          including after it is returned to the connection pool and used
          again in subsequent instances of _ConnectionFairy.
          It is shared with the _ConnectionRecord.info and
          Connection.info accessors.

          The dictionary associated with a particular DBAPI connection
          is discarded when the connection itself is discarded.

      -- Method: sqlalchemy.pool._ConnectionFairy..
               invalidate (e=None, soft=False)

          Mark this connection as invalidated.

          This method can be called directly, and is also called as a
          result of the Connection.invalidate() method.
          When invoked, the DBAPI connection is immediately closed and
          discarded from further use by the pool.  The invalidation
          mechanism proceeds via the
          _ConnectionRecord.invalidate() internal method.

          Parameters:

             * ‘e’ – an exception object indicating a reason for the
               invalidation.

             * ‘soft’ – if True, the connection isn’t closed; instead,
               this connection will be recycled on next checkout.

               New in version 1.0.3.

          See also
          ........

          See More on Invalidation.

      -- Attribute: sqlalchemy.pool._ConnectionFairy..
               is_valid

          Return True if this _ConnectionFairy still refers
          to an active DBAPI connection.

      -- Attribute: sqlalchemy.pool._ConnectionFairy..
               record_info

          Info dictionary associated with the ‘_ConnectionRecord
          container referred to by this :class:’.ConnectionFairy‘.

          Unlike the _ConnectionFairy.info dictionary, the
          lifespan of this dictionary is persistent across connections
          that are disconnected and/or invalidated within the lifespan
          of a _ConnectionRecord.

          New in version 1.1.

 -- Class: sqlalchemy.pool._ConnectionRecord (pool, connect=True)

     Internal object which maintains an individual DBAPI connection
     referenced by a Pool.

     The _ConnectionRecord object always exists for any
     particular DBAPI connection whether or not that DBAPI connection
     has been “checked out”.  This is in contrast to the
     _ConnectionFairy which is only a public facade to the DBAPI
     connection while it is checked out.

     A _ConnectionRecord may exist for a span longer than
     that of a single DBAPI connection.  For example, if the
     _ConnectionRecord.invalidate() method is called, the DBAPI
     connection associated with this _ConnectionRecord will
     be discarded, but the _ConnectionRecord may be used
     again, in which case a new DBAPI connection is produced when the
     Pool next uses this record.

     The _ConnectionRecord is delivered along with
     connection pool events, including PoolEvents.connect()
     and PoolEvents.checkout(), however
     _ConnectionRecord still remains an internal object whose API
     and internals may change.

     See also
     ........

     See _ConnectionFairy.

      -- Attribute: sqlalchemy.pool._ConnectionRecord..
               connection = None

          A reference to the actual DBAPI connection being tracked.

          May be ‘None’ if this _ConnectionRecord has been
          marked as invalidated; a new DBAPI connection may replace it
          if the owning pool calls upon this _ConnectionRecord
          to reconnect.

      -- Attribute: sqlalchemy.pool._ConnectionRecord..info

          The ‘.info’ dictionary associated with the DBAPI connection.

          This dictionary is shared among the
          _ConnectionFairy.info and Connection.info
          accessors.

               Note: The lifespan of this dictionary is linked to the
               DBAPI connection itself, meaning that it is `discarded'
               each time the DBAPI connection is closed and/or
               invalidated.  The _ConnectionRecord.record_info
               dictionary remains persistent throughout the
               lifespan of the _ConnectionRecord container.

      -- Method: sqlalchemy.pool._ConnectionRecord..
               invalidate (e=None, soft=False)

          Invalidate the DBAPI connection held by this
          _ConnectionRecord.

          This method is called for all connection invalidations,
          including when the _ConnectionFairy.invalidate()
          or Connection.invalidate() methods are called, as
          well as when any so-called “automatic invalidation” condition
          occurs.

          Parameters:

             * ‘e’ – an exception object indicating a reason for the
               invalidation.

             * ‘soft’ – if True, the connection isn’t closed; instead,
               this connection will be recycled on next checkout.

               New in version 1.0.3.

          See also
          ........

          See More on Invalidation.

      -- Attribute: sqlalchemy.pool._ConnectionRecord..
               record_info

          An “info’ dictionary associated with the connection record
          itself.

          Unlike the _ConnectionRecord.info dictionary,
          which is linked to the lifespan of the DBAPI connection, this
          dictionary is linked to the lifespan of the
          _ConnectionRecord container itself and will remain
          persistent throughout the life of the _ConnectionRecord.

          New in version 1.1.

4.5.4 Core Events
-----------------

This section describes the event interfaces provided in SQLAlchemy Core.
For an introduction to the event listening API, see Events.
ORM events are described in ORM Events.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See Events.Define event listening functions for a particular target type.

 -- Class: sqlalchemy.event.base.Events

     Define event listening functions for a particular target type.

4.5.4.1 Connection Pool Events
..............................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See PoolEvents.Available events for Pool.

 -- Class: sqlalchemy.events.PoolEvents

     Available events for Pool.

     The methods here define the name of an event as well as the names
     of members that are passed to listener functions.

     e.g.:

          from sqlalchemy import event

          def my_on_checkout(dbapi_conn, connection_rec, connection_proxy):
              "handle an on checkout event"

          event.listen(Pool, 'checkout', my_on_checkout)

     In addition to accepting the Pool class and
     Pool instances, see PoolEvents also accepts
     Engine objects and the Engine class as targets,
     which will be resolved to the ‘.pool’ attribute of the given engine
     or the Pool class:

          engine = create_engine("postgresql://scott:tiger@localhost/test")

          # will associate with engine.pool
          event.listen(engine, 'checkout', my_on_checkout)

     `Class signature'

     class sqlalchemy.events.PoolEvents.
     (‘sqlalchemy.event.Events’)

      -- Method: sqlalchemy.events.PoolEvents..checkin
               (dbapi_connection, connection_record)

          Called when a connection returns to the pool.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngineOrPool, 'checkin')
               def receive_checkin(dbapi_connection, connection_record):
                   "listen for the 'checkin' event"

                   # ... (event handling logic) ...

          Note that the connection may be closed, and may be None if the
          connection has been invalidated.  ‘checkin’ will not be called
          for detached connections.  (They do not return to the pool.)

          Parameters:

             * ‘dbapi_connection’ – a DBAPI connection.

             * ‘connection_record’ – the _ConnectionRecord.
               managing the DBAPI connection.

      -- Method: sqlalchemy.events.PoolEvents..checkout
               (dbapi_connection, connection_record, connection_proxy)

          Called when a connection is retrieved from the Pool.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngineOrPool, 'checkout')
               def receive_checkout(dbapi_connection, connection_record, connection_proxy):
                   "listen for the 'checkout' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘dbapi_connection’ – a DBAPI connection.

             * ‘connection_record’ – the _ConnectionRecord.
               managing the DBAPI connection.

             * ‘connection_proxy’ – the _ConnectionFairy.
               object which will proxy the public interface of the DBAPI
               connection for the lifespan of the checkout.

          If you raise a DisconnectionError, the current
          connection will be disposed and a fresh connection retrieved.
          Processing of all checkout listeners will abort and restart
          using the new connection.

          See also
          ........

          See ConnectionEvents.engine_connect(). - a similar
          event which occurs upon creation of a new Connection.

      -- Method: sqlalchemy.events.PoolEvents..close
               (dbapi_connection, connection_record)

          Called when a DBAPI connection is closed.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngineOrPool, 'close')
               def receive_close(dbapi_connection, connection_record):
                   "listen for the 'close' event"

                   # ... (event handling logic) ...

          The event is emitted before the close occurs.

          The close of a connection can fail; typically this is because
          the connection is already closed.  If the close operation
          fails, the connection is discarded.

          The close() event corresponds to a connection
          that’s still associated with the pool.  To intercept close
          events for detached connections use close_detached().

          New in version 1.1.

      -- Method: sqlalchemy.events.PoolEvents..
               close_detached (dbapi_connection)

          Called when a detached DBAPI connection is closed.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngineOrPool, 'close_detached')
               def receive_close_detached(dbapi_connection):
                   "listen for the 'close_detached' event"

                   # ... (event handling logic) ...

          The event is emitted before the close occurs.

          The close of a connection can fail; typically this is because
          the connection is already closed.  If the close operation
          fails, the connection is discarded.

          New in version 1.1.

      -- Method: sqlalchemy.events.PoolEvents..connect
               (dbapi_connection, connection_record)

          Called at the moment a particular DBAPI connection is first
          created for a given Pool.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngineOrPool, 'connect')
               def receive_connect(dbapi_connection, connection_record):
                   "listen for the 'connect' event"

                   # ... (event handling logic) ...

          This event allows one to capture the point directly after
          which the DBAPI module-level ‘.connect()’ method has been used
          in order to produce a new DBAPI connection.

          Parameters:

             * ‘dbapi_connection’ – a DBAPI connection.

             * ‘connection_record’ – the _ConnectionRecord.
               managing the DBAPI connection.

      -- Method: sqlalchemy.events.PoolEvents..detach
               (dbapi_connection, connection_record)

          Called when a DBAPI connection is “detached” from a pool.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngineOrPool, 'detach')
               def receive_detach(dbapi_connection, connection_record):
                   "listen for the 'detach' event"

                   # ... (event handling logic) ...

          This event is emitted after the detach occurs.  The connection
          is no longer associated with the given connection record.

          New in version 1.1.

      -- Method: sqlalchemy.events.PoolEvents..first_connect
               (dbapi_connection, connection_record)

          Called exactly once for the first time a DBAPI connection is
          checked out from a particular Pool.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngineOrPool, 'first_connect')
               def receive_first_connect(dbapi_connection, connection_record):
                   "listen for the 'first_connect' event"

                   # ... (event handling logic) ...

          The rationale for PoolEvents.first_connect() is
          to determine information about a particular series of database
          connections based on the settings used for all connections.
          Since a particular Pool refers to a single
          “creator” function (which in terms of a Engine
          refers to the URL and connection options used), it is
          typically valid to make observations about a single connection
          that can be safely assumed to be valid about all subsequent
          connections, such as the database version, the server and
          client encoding settings, collation settings, and many others.

          Parameters:

             * ‘dbapi_connection’ – a DBAPI connection.

             * ‘connection_record’ – the _ConnectionRecord.
               managing the DBAPI connection.

      -- Method: sqlalchemy.events.PoolEvents..invalidate
               (dbapi_connection, connection_record, exception)

          Called when a DBAPI connection is to be “invalidated”.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngineOrPool, 'invalidate')
               def receive_invalidate(dbapi_connection, connection_record, exception):
                   "listen for the 'invalidate' event"

                   # ... (event handling logic) ...

          This event is called any time the
          _ConnectionRecord.invalidate() method is invoked,
          either from API usage or via “auto-invalidation”, without the
          ‘soft’ flag.

          The event occurs before a final attempt to call ‘.close()’ on
          the connection occurs.

          Parameters:

             * ‘dbapi_connection’ – a DBAPI connection.

             * ‘connection_record’ – the _ConnectionRecord.
               managing the DBAPI connection.

             * ‘exception’ – the exception object corresponding to the
               reason for this invalidation, if any.  May be ‘None’.

          New in version 0.9.2: Added support for connection
          invalidation listening.

          See also
          ........

          See More on Invalidation.

      -- Method: sqlalchemy.events.PoolEvents..reset
               (dbapi_connection, connection_record)

          Called before the “reset” action occurs for a pooled
          connection.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngineOrPool, 'reset')
               def receive_reset(dbapi_connection, connection_record):
                   "listen for the 'reset' event"

                   # ... (event handling logic) ...

          This event represents when the ‘rollback()’ method is called
          on the DBAPI connection before it is returned to the pool.
          The behavior of “reset” can be controlled, including disabled,
          using the ‘reset_on_return’ pool argument.

          The PoolEvents.reset() event is usually followed
          by the PoolEvents.checkin() event is called,
          except in those cases where the connection is discarded
          immediately after reset.

          Parameters:

             * ‘dbapi_connection’ – a DBAPI connection.

             * ‘connection_record’ – the _ConnectionRecord.
               managing the DBAPI connection.

          See also
          ........

          See ConnectionEvents.rollback().

          See ConnectionEvents.commit().

      -- Method: sqlalchemy.events.PoolEvents..
               soft_invalidate (dbapi_connection,
               connection_record, exception)

          Called when a DBAPI connection is to be “soft invalidated”.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngineOrPool, 'soft_invalidate')
               def receive_soft_invalidate(dbapi_connection, connection_record, exception):
                   "listen for the 'soft_invalidate' event"

                   # ... (event handling logic) ...

          This event is called any time the
          _ConnectionRecord.invalidate() method is invoked with
          the ‘soft’ flag.

          Soft invalidation refers to when the connection record that
          tracks this connection will force a reconnect after the
          current connection is checked in.  It does not actively close
          the dbapi_connection at the point at which it is called.

          New in version 1.0.3.

4.5.4.2 SQL Execution and Connection Events
...........................................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See ConnectionEvents.Available events for ‘Connectable’, which includes Connection and
               Engine.

See DialectEvents.event interface for execution-replacement functions.

 -- Class: sqlalchemy.events.ConnectionEvents

     Available events for ‘Connectable’, which includes
     Connection and Engine.

     The methods here define the name of an event as well as the names
     of members that are passed to listener functions.

     An event listener can be associated with any ‘Connectable’ class or
     instance, such as an Engine, e.g.:

          from sqlalchemy import event, create_engine

          def before_cursor_execute(conn, cursor, statement, parameters, context,
                                                          executemany):
              log.info("Received statement: %s", statement)

          engine = create_engine('postgresql://scott:tiger@localhost/test')
          event.listen(engine, "before_cursor_execute", before_cursor_execute)

     or with a specific Connection:

          with engine.begin() as conn:
              @event.listens_for(conn, 'before_cursor_execute')
              def before_cursor_execute(conn, cursor, statement, parameters,
                                              context, executemany):
                  log.info("Received statement: %s", statement)

     When the methods are called with a ‘statement’ parameter, such as
     in after_cursor_execute() or
     before_cursor_execute(), the statement is the exact SQL
     string that was prepared for transmission to the DBAPI ‘cursor’ in
     the connection’s Dialect.

     The before_execute() and
     before_cursor_execute() events can also be established with
     the ‘retval=True’ flag, which allows modification of the statement
     and parameters to be sent to the database.  The
     before_cursor_execute() event is particularly useful here to
     add ad-hoc string transformations, such as comments, to all
     executions:

          from sqlalchemy.engine import Engine
          from sqlalchemy import event

          @event.listens_for(Engine, "before_cursor_execute", retval=True)
          def comment_sql_calls(conn, cursor, statement, parameters,
                                              context, executemany):
              statement = statement + " -- some comment"
              return statement, parameters

          Note: ConnectionEvents can be established on any
          combination of Engine, Connection, as
          well as instances of each of those classes.  Events across all
          four scopes will fire off for a given instance of
          Connection.  However, for performance reasons, the
          Connection object determines at instantiation time
          whether or not its parent Engine has event
          listeners established.  Event listeners added to the
          Engine class or to an instance of Engine.
          `after' the instantiation of a dependent Connection
          instance will usually `not' be available on that
          Connection instance.  The newly added listeners will
          instead take effect for Connection instances
          created subsequent to those event listeners being established
          on the parent Engine class or instance.

     Parameters: ‘retval=False’ – Applies to the before_execute()
     and before_cursor_execute() events only.  When
     True, the user-defined event function must have a return value,
     which is a tuple of parameters that replace the given statement and
     parameters.  See those methods for a description of specific return
     arguments.

     `Class signature'

     class sqlalchemy.events.ConnectionEvents.
     (‘sqlalchemy.event.Events’)

      -- Method: sqlalchemy.events.ConnectionEvents..
               after_cursor_execute (conn, cursor, statement,
               parameters, context, executemany)

          Intercept low-level cursor execute() events after execution.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'after_cursor_execute')
               def receive_after_cursor_execute(conn, cursor, statement, parameters, context, executemany):
                   "listen for the 'after_cursor_execute' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘conn’ – see Connection object

             * ‘cursor’ – DBAPI cursor object.  Will have results
               pending if the statement was a SELECT, but these should
               not be consumed as they will be needed by the
               CursorResult.

             * ‘statement’ – string SQL statement, as passed to the
               DBAPI

             * ‘parameters’ – Dictionary, tuple, or list of parameters
               being passed to the ‘execute()’ or ‘executemany()’ method
               of the DBAPI ‘cursor’.  In some cases may be ‘None’.

             * ‘context’ – see ExecutionContext object in use.
               May be ‘None’.

             * ‘executemany’ – boolean, if ‘True’, this is an
               ‘executemany()’ call, if ‘False’, this is an ‘execute()’
               call.

      -- Method: sqlalchemy.events.ConnectionEvents..
               after_execute (conn, clauseelement, multiparams,
               params, execution_options, result)

          Intercept high level execute() events after execute.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'after_execute')
               def receive_after_execute(conn, clauseelement, multiparams, params, execution_options, result):
                   "listen for the 'after_execute' event"

                   # ... (event handling logic) ...

               # DEPRECATED calling style (pre-1.4, will be removed in a future release)
               @event.listens_for(SomeEngine, 'after_execute')
               def receive_after_execute(conn, clauseelement, multiparams, params, result):
                   "listen for the 'after_execute' event"

                   # ... (event handling logic) ...

          Deprecated since version 1.4: The ‘after_execute’ event now
          accepts the arguments ‘conn, clauseelement, multiparams,
          params, execution_options, result’.  Support for listener
          functions which accept the previous argument signature(s)
          listed above as “deprecated” will be removed in a future
          release.

          Parameters:

             * ‘conn’ – see Connection object

             * ‘clauseelement’ – SQL expression construct, see
               Compiled instance, or string statement passed to
               Connection.execute().

             * ‘multiparams’ – Multiple parameter sets, a list of
               dictionaries.

             * ‘params’ – Single parameter set, a single dictionary.

             * ‘execution_options’ – dictionary of execution options
               passed along with the statement, if any.  This is a merge
               of all options that will be used, including those of the
               statement, the connection, and those passed in to the
               method itself for the 2.0 style of execution.

             * ‘result’ – see CursorResult generated by the
               execution.

      -- Method: sqlalchemy.events.ConnectionEvents..
               before_cursor_execute (conn, cursor, statement,
               parameters, context, executemany)

          Intercept low-level cursor execute() events before execution,
          receiving the string SQL statement and DBAPI-specific
          parameter list to be invoked against a cursor.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'before_cursor_execute')
               def receive_before_cursor_execute(conn, cursor, statement, parameters, context, executemany):
                   "listen for the 'before_cursor_execute' event"

                   # ... (event handling logic) ...

          This event is a good choice for logging as well as late
          modifications to the SQL string.  It’s less ideal for
          parameter modifications except for those which are specific to
          a target backend.

          This event can be optionally established with the
          ‘retval=True’ flag.  The ‘statement’ and ‘parameters’
          arguments should be returned as a two-tuple in this case:

               @event.listens_for(Engine, "before_cursor_execute", retval=True)
               def before_cursor_execute(conn, cursor, statement,
                               parameters, context, executemany):
                   # do something with statement, parameters
                   return statement, parameters

          See the example at ConnectionEvents.

          Parameters:

             * ‘conn’ – see Connection object

             * ‘cursor’ – DBAPI cursor object

             * ‘statement’ – string SQL statement, as to be passed to
               the DBAPI

             * ‘parameters’ – Dictionary, tuple, or list of parameters
               being passed to the ‘execute()’ or ‘executemany()’ method
               of the DBAPI ‘cursor’.  In some cases may be ‘None’.

             * ‘context’ – see ExecutionContext object in use.
               May be ‘None’.

             * ‘executemany’ – boolean, if ‘True’, this is an
               ‘executemany()’ call, if ‘False’, this is an ‘execute()’
               call.

          See also
          ........

          See before_execute().

          See after_cursor_execute().

      -- Method: sqlalchemy.events.ConnectionEvents..
               before_execute (conn, clauseelement, multiparams,
               params, execution_options)

          Intercept high level execute() events, receiving uncompiled
          SQL constructs and other objects prior to rendering into SQL.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'before_execute')
               def receive_before_execute(conn, clauseelement, multiparams, params, execution_options):
                   "listen for the 'before_execute' event"

                   # ... (event handling logic) ...

               # DEPRECATED calling style (pre-1.4, will be removed in a future release)
               @event.listens_for(SomeEngine, 'before_execute')
               def receive_before_execute(conn, clauseelement, multiparams, params):
                   "listen for the 'before_execute' event"

                   # ... (event handling logic) ...

          Deprecated since version 1.4: The ‘before_execute’ event now
          accepts the arguments ‘conn, clauseelement, multiparams,
          params, execution_options’.  Support for listener functions
          which accept the previous argument signature(s) listed above
          as “deprecated” will be removed in a future release.

          This event is good for debugging SQL compilation issues as
          well as early manipulation of the parameters being sent to the
          database, as the parameter lists will be in a consistent
          format here.

          This event can be optionally established with the
          ‘retval=True’ flag.  The ‘clauseelement’, ‘multiparams’, and
          ‘params’ arguments should be returned as a three-tuple in this
          case:

               @event.listens_for(Engine, "before_execute", retval=True)
               def before_execute(conn, clauseelement, multiparams, params):
                   # do something with clauseelement, multiparams, params
                   return clauseelement, multiparams, params

          Parameters:

             * ‘conn’ – see Connection object

             * ‘clauseelement’ – SQL expression construct, see
               Compiled instance, or string statement passed to
               Connection.execute().

             * ‘multiparams’ – Multiple parameter sets, a list of
               dictionaries.

             * ‘params’ – Single parameter set, a single dictionary.

             * ‘execution_options’ – dictionary of execution options
               passed along with the statement, if any.  This is a merge
               of all options that will be used, including those of the
               statement, the connection, and those passed in to the
               method itself for the 2.0 style of execution.

          See also
          ........

          See before_cursor_execute().

      -- Method: sqlalchemy.events.ConnectionEvents..begin
               (conn)

          Intercept begin() events.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'begin')
               def receive_begin(conn):
                   "listen for the 'begin' event"

                   # ... (event handling logic) ...

          Parameters: ‘conn’ – see Connection object

      -- Method: sqlalchemy.events.ConnectionEvents..
               begin_twophase (conn, xid)

          Intercept begin_twophase() events.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'begin_twophase')
               def receive_begin_twophase(conn, xid):
                   "listen for the 'begin_twophase' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘conn’ – see Connection object

             * ‘xid’ – two-phase XID identifier

      -- Method: sqlalchemy.events.ConnectionEvents..commit
               (conn)

          Intercept commit() events, as initiated by a
          Transaction.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'commit')
               def receive_commit(conn):
                   "listen for the 'commit' event"

                   # ... (event handling logic) ...

          Note that the Pool may also “auto-commit” a DBAPI
          connection upon checkin, if the ‘reset_on_return’ flag is set
          to the value ‘'commit'’.  To intercept this commit, use the
          PoolEvents.reset() hook.

          Parameters: ‘conn’ – see Connection object

      -- Method: sqlalchemy.events.ConnectionEvents..
               commit_twophase (conn, xid, is_prepared)

          Intercept commit_twophase() events.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'commit_twophase')
               def receive_commit_twophase(conn, xid, is_prepared):
                   "listen for the 'commit_twophase' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘conn’ – see Connection object

             * ‘xid’ – two-phase XID identifier

             * ‘is_prepared’ – boolean, indicates if
               TwoPhaseTransaction.prepare() was called.

      -- Method: sqlalchemy.events.ConnectionEvents..
               engine_connect (conn, branch)

          Intercept the creation of a new Connection.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'engine_connect')
               def receive_engine_connect(conn, branch):
                   "listen for the 'engine_connect' event"

                   # ... (event handling logic) ...

          This event is called typically as the direct result of calling
          the Engine.connect() method.

          It differs from the PoolEvents.connect() method,
          which refers to the actual connection to a database at the
          DBAPI level; a DBAPI connection may be pooled and reused for
          many operations.  In contrast, this event refers only to the
          production of a higher level Connection wrapper
          around such a DBAPI connection.

          It also differs from the PoolEvents.checkout()
          event in that it is specific to the Connection
          object, not the DBAPI connection that
          PoolEvents.checkout() deals with, although this DBAPI
          connection is available here via the
          Connection.connection attribute.  But note there can in
          fact be multiple PoolEvents.checkout() events
          within the lifespan of a single Connection object,
          if that Connection is invalidated and
          re-established.  There can also be multiple Connection
          objects generated for the same already-checked-out DBAPI
          connection, in the case that a “branch” of a Connection
          is produced.

          Parameters:

             * ‘conn’ – see Connection object.

             * ‘branch’ – if True, this is a “branch” of an existing
               Connection.  A branch is generated within the
               course of a statement execution to invoke supplemental
               statements, most typically to pre-execute a SELECT of a
               default value for the purposes of an INSERT statement.

          See also
          ........

          PoolEvents.checkout() the lower-level pool
          checkout event for an individual DBAPI connection

      -- Method: sqlalchemy.events.ConnectionEvents..
               engine_disposed (engine)

          Intercept when the Engine.dispose() method is
          called.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'engine_disposed')
               def receive_engine_disposed(engine):
                   "listen for the 'engine_disposed' event"

                   # ... (event handling logic) ...

          The Engine.dispose() method instructs the engine
          to “dispose” of it’s connection pool (e.g.  see Pool),
          and replaces it with a new one.  Disposing of the old
          pool has the effect that existing checked-in connections are
          closed.  The new pool does not establish any new connections
          until it is first used.

          This event can be used to indicate that resources related to
          the Engine should also be cleaned up, keeping in
          mind that the Engine can still be used for new
          requests in which case it re-acquires connection resources.

          New in version 1.0.5.

      -- Method: sqlalchemy.events.ConnectionEvents..
               handle_error (exception_context)

          Intercept all exceptions processed by the Connection.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'handle_error')
               def receive_handle_error(exception_context):
                   "listen for the 'handle_error' event"

                   # ... (event handling logic) ...

          This includes all exceptions emitted by the DBAPI as well as
          within SQLAlchemy’s statement invocation process, including
          encoding errors and other statement validation errors.  Other
          areas in which the event is invoked include transaction begin
          and end, result row fetching, cursor creation.

          Note that handle_error() may support new kinds of
          exceptions and new calling scenarios at `any time'.  Code
          which uses this event must expect new calling patterns to be
          present in minor releases.

          To support the wide variety of members that correspond to an
          exception, as well as to allow extensibility of the event
          without backwards incompatibility, the sole argument received
          is an instance of ExceptionContext.  This object
          contains data members representing detail about the exception.

          Use cases supported by this hook include:

             * read-only, low-level exception handling for logging and
               debugging purposes

             * exception re-writing

             * Establishing or disabling whether a connection or the
               owning connection pool is invalidated or expired in
               response to a specific exception (1).

          The hook is called while the cursor from the failed operation
          (if any) is still open and accessible.  Special cleanup
          operations can be called on this cursor; SQLAlchemy will
          attempt to close this cursor subsequent to this hook being
          invoked.  If the connection is in “autocommit” mode, the
          transaction also remains open within the scope of this hook;
          the rollback of the per-statement transaction also occurs
          after the hook is called.

               Note:
          A handler function has two options for replacing the
          SQLAlchemy-constructed exception into one that is user
          defined.  It can either raise this new exception directly, in
          which case all further event listeners are bypassed and the
          exception will be raised, after appropriate cleanup as taken
          place:

               @event.listens_for(Engine, "handle_error")
               def handle_exception(context):
                   if isinstance(context.original_exception,
                       psycopg2.OperationalError) and \
                       "failed" in str(context.original_exception):
                       raise MySpecialException("failed operation")

               Warning: Because the
               ConnectionEvents.handle_error() event specifically
               provides for exceptions to be re-thrown as the ultimate
               exception raised by the failed statement, `stack traces
               will be misleading' if the user-defined event handler
               itself fails and throws an unexpected exception; the
               stack trace may not illustrate the actual code line that
               failed!  It is advised to code carefully here and use
               logging and/or inline debugging if unexpected exceptions
               are occurring.

          Alternatively, a “chained” style of event handling can be
          used, by configuring the handler with the ‘retval=True’
          modifier and returning the new exception instance from the
          function.  In this case, event handling will continue onto the
          next handler.  The “chained” exception is available using
          ExceptionContext.chained_exception:

               @event.listens_for(Engine, "handle_error", retval=True)
               def handle_exception(context):
                   if context.chained_exception is not None and \
                       "special" in context.chained_exception.message:
                       return MySpecialException("failed",
                           cause=context.chained_exception)

          Handlers that return ‘None’ may be used within the chain; when
          a handler returns ‘None’, the previous exception instance, if
          any, is maintained as the current exception that is passed
          onto the next handler.

          When a custom exception is raised or returned, SQLAlchemy
          raises this new exception as-is, it is not wrapped by any
          SQLAlchemy object.  If the exception is not a subclass of
          sqlalchemy.exc.StatementError, certain features
          may not be available; currently this includes the ORM’s
          feature of adding a detail hint about “autoflush” to
          exceptions raised within the autoflush process.

          Parameters: ‘context’ – an ExceptionContext
          object.  See this class for details on all available members.

          New in version 0.9.7: Added the
          ConnectionEvents.handle_error() hook.

          Changed in version 1.1: The handle_error() event
          will now receive all exceptions that inherit from
          ‘BaseException’, including ‘SystemExit’ and
          ‘KeyboardInterrupt’.  The setting for
          ExceptionContext.is_disconnect is ‘True’ in this case
          and the default for
          ExceptionContext.invalidate_pool_on_disconnect is
          ‘False’.

          Changed in version 1.0.0: The handle_error()
          event is now invoked when an Engine fails during
          the initial call to Engine.connect(), as well as
          when a Connection object encounters an error
          during a reconnect operation.

          Changed in version 1.0.0: The handle_error()
          event is not fired off when a dialect makes use of the
          ‘skip_user_error_events’ execution option.  This is used by
          dialects which intend to catch SQLAlchemy-specific exceptions
          within specific operations, such as when the MySQL dialect
          detects a table not present within the ‘has_table()’ dialect
          method.  Prior to 1.0.0, code which implements
          handle_error() needs to ensure that exceptions thrown
          in these scenarios are re-raised without modification.

      -- Method: sqlalchemy.events.ConnectionEvents..
               prepare_twophase (conn, xid)

          Intercept prepare_twophase() events.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'prepare_twophase')
               def receive_prepare_twophase(conn, xid):
                   "listen for the 'prepare_twophase' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘conn’ – see Connection object

             * ‘xid’ – two-phase XID identifier

      -- Method: sqlalchemy.events.ConnectionEvents..
               release_savepoint (conn, name, context)

          Intercept release_savepoint() events.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'release_savepoint')
               def receive_release_savepoint(conn, name, context):
                   "listen for the 'release_savepoint' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘conn’ – see Connection object

             * ‘name’ – specified name used for the savepoint.

             * ‘context’ – not used

      -- Method: sqlalchemy.events.ConnectionEvents..
               rollback (conn)

          Intercept rollback() events, as initiated by a
          Transaction.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'rollback')
               def receive_rollback(conn):
                   "listen for the 'rollback' event"

                   # ... (event handling logic) ...

          Note that the Pool also “auto-rolls back” a DBAPI
          connection upon checkin, if the ‘reset_on_return’ flag is set
          to its default value of ‘'rollback'’.  To intercept this
          rollback, use the PoolEvents.reset() hook.

          Parameters: ‘conn’ – see Connection object

          See also
          ........

          See PoolEvents.reset().

      -- Method: sqlalchemy.events.ConnectionEvents..
               rollback_savepoint (conn, name, context)

          Intercept rollback_savepoint() events.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'rollback_savepoint')
               def receive_rollback_savepoint(conn, name, context):
                   "listen for the 'rollback_savepoint' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘conn’ – see Connection object

             * ‘name’ – specified name used for the savepoint.

             * ‘context’ – not used

      -- Method: sqlalchemy.events.ConnectionEvents..
               rollback_twophase (conn, xid, is_prepared)

          Intercept rollback_twophase() events.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'rollback_twophase')
               def receive_rollback_twophase(conn, xid, is_prepared):
                   "listen for the 'rollback_twophase' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘conn’ – see Connection object

             * ‘xid’ – two-phase XID identifier

             * ‘is_prepared’ – boolean, indicates if
               TwoPhaseTransaction.prepare() was called.

      -- Method: sqlalchemy.events.ConnectionEvents..
               savepoint (conn, name)

          Intercept savepoint() events.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'savepoint')
               def receive_savepoint(conn, name):
                   "listen for the 'savepoint' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘conn’ – see Connection object

             * ‘name’ – specified name used for the savepoint.

      -- Method: sqlalchemy.events.ConnectionEvents..
               set_connection_execution_options (conn, opts)

          Intercept when the Connection.execution_options()
          method is called.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'set_connection_execution_options')
               def receive_set_connection_execution_options(conn, opts):
                   "listen for the 'set_connection_execution_options' event"

                   # ... (event handling logic) ...

          This method is called after the new Connection has
          been produced, with the newly updated execution options
          collection, but before the Dialect has acted upon
          any of those new options.

          Note that this method is not called when a new
          Connection is produced which is inheriting execution
          options from its parent Engine; to intercept this
          condition, use the ConnectionEvents.engine_connect()
          event.

          Parameters:

             * ‘conn’ – The newly copied Connection object

             * ‘opts’ – dictionary of options that were passed to the
               Connection.execution_options() method.

          New in version 0.9.0.

          See also
          ........

          See ConnectionEvents.set_engine_execution_options(). -
          event which is called when Engine.execution_options()
          is called.

      -- Method: sqlalchemy.events.ConnectionEvents..
               set_engine_execution_options (engine, opts)

          Intercept when the Engine.execution_options()
          method is called.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'set_engine_execution_options')
               def receive_set_engine_execution_options(engine, opts):
                   "listen for the 'set_engine_execution_options' event"

                   # ... (event handling logic) ...

          The Engine.execution_options() method produces a
          shallow copy of the Engine which stores the new
          options.  That new Engine is passed here.  A
          particular application of this method is to add a
          ConnectionEvents.engine_connect() event handler to the
          given Engine which will perform some per- see
          Connection task specific to these execution options.

          Parameters:

             * ‘conn’ – The newly copied Engine object

             * ‘opts’ – dictionary of options that were passed to the
               Connection.execution_options() method.

          New in version 0.9.0.

          See also
          ........

          See ConnectionEvents.set_connection_execution_options().
          - event which is called when
          Connection.execution_options() is called.

 -- Class: sqlalchemy.events.DialectEvents

     event interface for execution-replacement functions.

     These events allow direct instrumentation and replacement of key
     dialect functions which interact with the DBAPI.

          Note: DialectEvents hooks should be considered
          `semi-public' and experimental.  These hooks are not for
          general use and are only for those situations where intricate
          re-statement of DBAPI mechanics must be injected onto an
          existing dialect.  For general-use statement-interception
          events, please use the ConnectionEvents
          interface.

     See also
     ........

     See ConnectionEvents.before_cursor_execute().

     See ConnectionEvents.before_execute().

     See ConnectionEvents.after_cursor_execute().

     See ConnectionEvents.after_execute().

     New in version 0.9.4.

     `Class signature'

     class sqlalchemy.events.DialectEvents.
     (‘sqlalchemy.event.Events’)

      -- Method: sqlalchemy.events.DialectEvents..do_connect
               (dialect, conn_rec, cargs, cparams)

          Receive connection arguments before a connection is made.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'do_connect')
               def receive_do_connect(dialect, conn_rec, cargs, cparams):
                   "listen for the 'do_connect' event"

                   # ... (event handling logic) ...

          Return a DBAPI connection to halt further events from
          invoking; the returned connection will be used.

          Alternatively, the event can manipulate the cargs and/or
          cparams collections; cargs will always be a Python list that
          can be mutated in-place and cparams a Python dictionary.
          Return None to allow control to pass to the next event handler
          and ultimately to allow the dialect to connect normally, given
          the updated arguments.

          New in version 1.0.3.

          See also
          ........

          See Custom DBAPI connect() arguments / on-connect routines.

      -- Method: sqlalchemy.events.DialectEvents..do_execute
               (cursor, statement, parameters, context)

          Receive a cursor to have execute() called.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'do_execute')
               def receive_do_execute(cursor, statement, parameters, context):
                   "listen for the 'do_execute' event"

                   # ... (event handling logic) ...

          Return the value True to halt further events from invoking,
          and to indicate that the cursor execution has already taken
          place within the event handler.

      -- Method: sqlalchemy.events.DialectEvents..
               do_execute_no_params (cursor, statement, context)

          Receive a cursor to have execute() with no parameters called.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'do_execute_no_params')
               def receive_do_execute_no_params(cursor, statement, context):
                   "listen for the 'do_execute_no_params' event"

                   # ... (event handling logic) ...

          Return the value True to halt further events from invoking,
          and to indicate that the cursor execution has already taken
          place within the event handler.

      -- Method: sqlalchemy.events.DialectEvents..
               do_executemany (cursor, statement, parameters,
               context)

          Receive a cursor to have executemany() called.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'do_executemany')
               def receive_do_executemany(cursor, statement, parameters, context):
                   "listen for the 'do_executemany' event"

                   # ... (event handling logic) ...

          Return the value True to halt further events from invoking,
          and to indicate that the cursor execution has already taken
          place within the event handler.

      -- Method: sqlalchemy.events.DialectEvents..
               do_setinputsizes (inputsizes, cursor, statement,
               parameters, context)

          Receive the setinputsizes dictionary for possible
          modification.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeEngine, 'do_setinputsizes')
               def receive_do_setinputsizes(inputsizes, cursor, statement, parameters, context):
                   "listen for the 'do_setinputsizes' event"

                   # ... (event handling logic) ...

          This event is emitted in the case where the dialect makes use
          of the DBAPI ‘cursor.setinputsizes()’ method which passes
          information about parameter binding for a particular
          statement.  The given ‘inputsizes’ dictionary will contain
          BindParameter objects as keys, linked to
          DBAPI-specific type objects as values; for parameters that are
          not bound, they are added to the dictionary with ‘None’ as the
          value, which means the parameter will not be included in the
          ultimate setinputsizes call.  The event may be used to inspect
          and/or log the datatypes that are being bound, as well as to
          modify the dictionary in place.  Parameters can be added,
          modified, or removed from this dictionary.  Callers will
          typically want to inspect the ‘BindParameter.type’ attribute
          of the given bind objects in order to make decisions about the
          DBAPI object.

          After the event, the ‘inputsizes’ dictionary is converted into
          an appropriate datastructure to be passed to
          ‘cursor.setinputsizes’; either a list for a positional bound
          parameter execution style, or a dictionary of string parameter
          keys to DBAPI type objects for a named bound parameter
          execution style.

          The setinputsizes hook overall is only used for dialects which
          include the flag ‘use_setinputsizes=True’.  Dialects which use
          this include cx_Oracle, pg8000, asyncpg, and pyodbc dialects.

               Note: For use with pyodbc, the ‘use_setinputsizes’ flag
               must be passed to the dialect, e.g.:

                    create_engine("mssql+pyodbc://...", use_setinputsizes=True)

               See also
               ........

               See Setinputsizes Support.

          New in version 1.2.9.

          See also
          ........

          See Fine grained control over cx_Oracle data binding performance with setinputsizes.

   ---------- Footnotes ----------

   (1) (1) The pool “pre_ping” handler enabled using the
create_engine.pool_pre_ping parameter does `not' consult this
event before deciding if the “ping” returned false, as opposed to
receiving an unhandled error.  For this use case, the legacy recipe based on engine_connect() may be used.
A future API allow
more comprehensive customization of the “disconnect” detection mechanism
across all functions.

4.5.4.3 Schema Events
.....................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See DDLEvents.Define event listeners for schema objects, that is, see SchemaItem and other
               SchemaEventTarget subclasses, including MetaData, Table,
               Column.

See SchemaEventTarget.Base class for elements that are the targets of DDLEvents events.

 -- Class: sqlalchemy.events.DDLEvents

     Define event listeners for schema objects, that is, see
     SchemaItem and other SchemaEventTarget
     subclasses, including MetaData, Table,
     Column.

     MetaData and Table support events
     specifically regarding when CREATE and DROP DDL is emitted to the
     database.

     Attachment events are also provided to customize behavior whenever
     a child schema element is associated with a parent, such as, when a
     Column is associated with its Table, when a
     ForeignKeyConstraint is associated with a Table,
     etc.

     Example using the ‘after_create’ event:

          from sqlalchemy import event
          from sqlalchemy import Table, Column, Metadata, Integer

          m = MetaData()
          some_table = Table('some_table', m, Column('data', Integer))

          def after_create(target, connection, **kw):
              connection.execute(text(
                  "ALTER TABLE %s SET name=foo_%s" % (target.name, target.name)
              ))

          event.listen(some_table, "after_create", after_create)

     DDL events integrate closely with the DDL class and the
     DDLElement hierarchy of DDL clause constructs, which
     are themselves appropriate as listener callables:

          from sqlalchemy import DDL
          event.listen(
              some_table,
              "after_create",
              DDL("ALTER TABLE %(table)s SET name=foo_%(table)s")
          )

     The methods here define the name of an event as well as the names
     of members that are passed to listener functions.

     For all ‘DDLEvent’ events, the ‘propagate=True’ keyword argument
     will ensure that a given event handler is propagated to copies of
     the object, which are made when using the
     Table.to_metadata() method:

          from sqlalchemy import DDL
          event.listen(
              some_table,
              "after_create",
              DDL("ALTER TABLE %(table)s SET name=foo_%(table)s"),
              propagate=True
          )

          new_table = some_table.to_metadata(new_metadata)

     The above DDL object will also be associated with the
     Table object represented by ‘new_table’.

     See also
     ........

     See Events.

     See DDLElement.

     See DDL.

     See Controlling DDL Sequences.

     `Class signature'

     class sqlalchemy.events.DDLEvents.
     (‘sqlalchemy.event.Events’)

      -- Method: sqlalchemy.events.DDLEvents..after_create
               (target, connection, **kw)

          Called after CREATE statements are emitted.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSchemaClassOrObject, 'after_create')
               def receive_after_create(target, connection, **kw):
                   "listen for the 'after_create' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘target’ – the MetaData or Table.
               object which is the target of the event.

             * ‘connection’ – the Connection where the
               CREATE statement or statements have been emitted.

             * ‘**kw’ – additional keyword arguments relevant to the
               event.  The contents of this dictionary may vary across
               releases, and include the list of tables being generated
               for a metadata-level event, the checkfirst flag, and
               other elements used by internal events.

          listen() also accepts the ‘propagate=True’
          modifier for this event; when True, the listener function will
          be established for any copies made of the target object, i.e.
          those copies that are generated when
          Table.to_metadata() is used.

      -- Method: sqlalchemy.events.DDLEvents..after_drop
               (target, connection, **kw)

          Called after DROP statements are emitted.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSchemaClassOrObject, 'after_drop')
               def receive_after_drop(target, connection, **kw):
                   "listen for the 'after_drop' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘target’ – the MetaData or Table.
               object which is the target of the event.

             * ‘connection’ – the Connection where the DROP
               statement or statements have been emitted.

             * ‘**kw’ – additional keyword arguments relevant to the
               event.  The contents of this dictionary may vary across
               releases, and include the list of tables being generated
               for a metadata-level event, the checkfirst flag, and
               other elements used by internal events.

          listen() also accepts the ‘propagate=True’
          modifier for this event; when True, the listener function will
          be established for any copies made of the target object, i.e.
          those copies that are generated when
          Table.to_metadata() is used.

      -- Method: sqlalchemy.events.DDLEvents..
               after_parent_attach (target, parent)

          Called after a SchemaItem is associated with a
          parent SchemaItem.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSchemaClassOrObject, 'after_parent_attach')
               def receive_after_parent_attach(target, parent):
                   "listen for the 'after_parent_attach' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘target’ – the target object

             * ‘parent’ – the parent to which the target is being
               attached.

          listen() also accepts the ‘propagate=True’
          modifier for this event; when True, the listener function will
          be established for any copies made of the target object, i.e.
          those copies that are generated when
          Table.to_metadata() is used.

      -- Method: sqlalchemy.events.DDLEvents..before_create
               (target, connection, **kw)

          Called before CREATE statements are emitted.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSchemaClassOrObject, 'before_create')
               def receive_before_create(target, connection, **kw):
                   "listen for the 'before_create' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘target’ – the MetaData or Table.
               object which is the target of the event.

             * ‘connection’ – the Connection where the
               CREATE statement or statements will be emitted.

             * ‘**kw’ – additional keyword arguments relevant to the
               event.  The contents of this dictionary may vary across
               releases, and include the list of tables being generated
               for a metadata-level event, the checkfirst flag, and
               other elements used by internal events.

          listen() also accepts the ‘propagate=True’
          modifier for this event; when True, the listener function will
          be established for any copies made of the target object, i.e.
          those copies that are generated when
          Table.to_metadata() is used.

      -- Method: sqlalchemy.events.DDLEvents..before_drop
               (target, connection, **kw)

          Called before DROP statements are emitted.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSchemaClassOrObject, 'before_drop')
               def receive_before_drop(target, connection, **kw):
                   "listen for the 'before_drop' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘target’ – the MetaData or Table.
               object which is the target of the event.

             * ‘connection’ – the Connection where the DROP
               statement or statements will be emitted.

             * ‘**kw’ – additional keyword arguments relevant to the
               event.  The contents of this dictionary may vary across
               releases, and include the list of tables being generated
               for a metadata-level event, the checkfirst flag, and
               other elements used by internal events.

          listen() also accepts the ‘propagate=True’
          modifier for this event; when True, the listener function will
          be established for any copies made of the target object, i.e.
          those copies that are generated when
          Table.to_metadata() is used.

      -- Method: sqlalchemy.events.DDLEvents..
               before_parent_attach (target, parent)

          Called before a SchemaItem is associated with a
          parent SchemaItem.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSchemaClassOrObject, 'before_parent_attach')
               def receive_before_parent_attach(target, parent):
                   "listen for the 'before_parent_attach' event"

                   # ... (event handling logic) ...

          Parameters:

             * ‘target’ – the target object

             * ‘parent’ – the parent to which the target is being
               attached.

          listen() also accepts the ‘propagate=True’
          modifier for this event; when True, the listener function will
          be established for any copies made of the target object, i.e.
          those copies that are generated when
          Table.to_metadata() is used.

      -- Method: sqlalchemy.events.DDLEvents..column_reflect
               (inspector, table, column_info)

          Called for each unit of ‘column info’ retrieved when a
          Table is being reflected.

          Example argument forms:

               from sqlalchemy import event

               @event.listens_for(SomeSchemaClassOrObject, 'column_reflect')
               def receive_column_reflect(inspector, table, column_info):
                   "listen for the 'column_reflect' event"

                   # ... (event handling logic) ...

          This event is most easily used by applying it to a specific
          MetaData instance, where it will take effect for
          all Table objects within that MetaData
          that undergo reflection:

               metadata = MetaData()

               @event.listens_for(metadata, 'column_reflect')
               def receive_column_reflect(inspector, table, column_info):
                   # receives for all Table objects that are reflected
                   # under this MetaData

               # will use the above event hook
               my_table = Table("my_table", metadata, autoload_with=some_engine)

          New in version 1.4.0b2: The DDLEvents.column_reflect()
          hook may now be applied to a MetaData object
          as well as the MetaData class itself where it will
          take place for all Table objects associated with
          the targeted MetaData.

          It may also be applied to the Table class across
          the board:

               from sqlalchemy import Table

               @event.listens_for(Table, 'column_reflect')
               def receive_column_reflect(inspector, table, column_info):
                   # receives for all Table objects that are reflected

          It can also be applied to a specific Table at the
          point that one is being reflected using the
          Table.listeners parameter:

               t1 = Table(
                   "my_table",
                   autoload_with=some_engine,
                   listeners=[
                       ('column_reflect', receive_column_reflect)
                   ]
               )

          A future release will allow it to be associated with a
          specific MetaData object as well.

          The dictionary of column information as returned by the
          dialect is passed, and can be modified.  The dictionary is
          that returned in each element of the list returned by
          Inspector.get_columns():

                  * ‘name’ - the column’s name, is applied to the
                    Column.name parameter

                  * ‘type’ - the type of this column, which should be an
                    instance of TypeEngine, is applied to the
                    Column.type parameter

                  * ‘nullable’ - boolean flag if the column is NULL or
                    NOT NULL, is applied to the Column.nullable
                    parameter

                  * ‘default’ - the column’s server default value.  This
                    is normally specified as a plain string SQL
                    expression, however the event can pass a
                    FetchedValue, DefaultClause, or
                    text() object as well.  Is applied to the
                    Column.server_default parameter

          The event is called before any action is taken against this
          dictionary, and the contents can be modified; the following
          additional keys may be added to the dictionary to further
          modify how the Column is constructed:

                  * ‘key’ - the string key that will be used to access
                    this Column in the ‘.c’ collection; will
                    be applied to the Column.key parameter.
                    Is also used for ORM mapping.  See the section
                    Automating Column Naming Schemes from Reflected Tables
                    for an example.

                  * ‘quote’ - force or un-force quoting on the column
                    name; is applied to the Column.quote
                    parameter.

                  * ‘info’ - a dictionary of arbitrary data to follow
                    along with the Column, is applied to the
                    Column.info parameter.

          listen() also accepts the ‘propagate=True’
          modifier for this event; when True, the listener function will
          be established for any copies made of the target object, i.e.
          those copies that are generated when
          Table.to_metadata() is used.

          See also
          ........

          See Automating Column Naming Schemes from Reflected Tables.
          - in the ORM mapping documentation

          See Intercepting Column Definitions. - in the
          Automap documentation

          See Reflecting with Database-Agnostic Types. - in the
          Reflecting Database Objects documentation

 -- Class: sqlalchemy.events.SchemaEventTarget

     Base class for elements that are the targets of DDLEvents
     events.

     This includes SchemaItem as well as SchemaType.

4.6 Core API Basics
===================

4.6.1 Events
------------

SQLAlchemy includes an event API which publishes a wide variety of hooks
into the internals of both SQLAlchemy Core and ORM.

4.6.1.1 Event Registration
..........................

Subscribing to an event occurs through a single API point, the
listen() function, or alternatively the listens_for()
decorator.  These functions accept a target, a string identifier which
identifies the event to be intercepted, and a user-defined listening
function.  Additional positional and keyword arguments to these two
functions may be supported by specific types of events, which may
specify alternate interfaces for the given event function, or provide
instructions regarding secondary event targets based on the given
target.

The name of an event and the argument signature of a corresponding
listener function is derived from a class bound specification method,
which exists bound to a marker class that’s described in the
documentation.  For example, the documentation for
PoolEvents.connect() indicates that the event name is ‘"connect"’
and that a user-defined listener function should receive two positional
arguments:

     from sqlalchemy.event import listen
     from sqlalchemy.pool import Pool

     def my_on_connect(dbapi_con, connection_record):
         print("New DBAPI connection:", dbapi_con)

     listen(Pool, 'connect', my_on_connect)

To listen with the listens_for() decorator looks like:

     from sqlalchemy.event import listens_for
     from sqlalchemy.pool import Pool

     @listens_for(Pool, "connect")
     def my_on_connect(dbapi_con, connection_record):
         print("New DBAPI connection:", dbapi_con)

4.6.1.2 Named Argument Styles
.............................

There are some varieties of argument styles which can be accepted by
listener functions.  Taking the example of PoolEvents.connect(),
this function is documented as receiving ‘dbapi_connection’ and
‘connection_record’ arguments.  We can opt to receive these arguments by
name, by establishing a listener function that accepts ‘**keyword’
arguments, by passing ‘named=True’ to either listen() or
listens_for():

     from sqlalchemy.event import listens_for
     from sqlalchemy.pool import Pool

     @listens_for(Pool, "connect", named=True)
     def my_on_connect(**kw):
         print("New DBAPI connection:", kw['dbapi_connection'])

When using named argument passing, the names listed in the function
argument specification will be used as keys in the dictionary.

Named style passes all arguments by name regardless of the function
signature, so specific arguments may be listed as well, in any order, as
long as the names match up:

     from sqlalchemy.event import listens_for
     from sqlalchemy.pool import Pool

     @listens_for(Pool, "connect", named=True)
     def my_on_connect(dbapi_connection, **kw):
         print("New DBAPI connection:", dbapi_connection)
         print("Connection record:", kw['connection_record'])

Above, the presence of ‘**kw’ tells listens_for() that
arguments should be passed to the function by name, rather than
positionally.

New in version 0.9.0: Added optional ‘named’ argument dispatch to event
calling.

4.6.1.3 Targets
...............

The listen() function is very flexible regarding targets.
It generally accepts classes, instances of those classes, and related
classes or objects from which the appropriate target can be derived.
For example, the above mentioned ‘"connect"’ event accepts Engine
classes and objects as well as Pool classes and
objects:

     from sqlalchemy.event import listen
     from sqlalchemy.pool import Pool, QueuePool
     from sqlalchemy import create_engine
     from sqlalchemy.engine import Engine
     import psycopg2

     def connect():
         return psycopg2.connect(user='ed', host='127.0.0.1', dbname='test')

     my_pool = QueuePool(connect)
     my_engine = create_engine('postgresql://ed@localhost/test')

     # associate listener with all instances of Pool
     listen(Pool, 'connect', my_on_connect)

     # associate listener with all instances of Pool
     # via the Engine class
     listen(Engine, 'connect', my_on_connect)

     # associate listener with my_pool
     listen(my_pool, 'connect', my_on_connect)

     # associate listener with my_engine.pool
     listen(my_engine, 'connect', my_on_connect)

4.6.1.4 Modifiers
.................

Some listeners allow modifiers to be passed to listen().
These modifiers sometimes provide alternate calling signatures for
listeners.  Such as with ORM events, some event listeners can have a
return value which modifies the subsequent handling.  By default, no
listener ever requires a return value, but by passing ‘retval=True’ this
value can be supported:

     def validate_phone(target, value, oldvalue, initiator):
         """Strip non-numeric characters from a phone number"""

         return re.sub(r'\D', '', value)

     # setup listener on UserContact.phone attribute, instructing
     # it to use the return value
     listen(UserContact.phone, 'set', validate_phone, retval=True)

4.6.1.5 Event Reference
.......................

Both SQLAlchemy Core and SQLAlchemy ORM feature a wide variety of event
hooks:

   * `Core Events' - these are described in Core Events and
     include event hooks specific to connection pool lifecycle, SQL
     statement execution, transaction lifecycle, and schema creation and
     teardown.

   * `ORM Events' - these are described in ORM Events, and
     include event hooks specific to class and attribute
     instrumentation, object initialization hooks, attribute on-change
     hooks, session state, flush, and commit hooks, mapper
     initialization, object/result population, and per-instance
     persistence hooks.

4.6.1.6 API Reference
.....................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See contains.(target,Return True if the given target/ident/fn is set up to listen.
identifier,
fn)

See listen.(target,Register a listener function for the given target.
identifier,
fn, *args,
**kw)

See listens_for.(target,Decorate a function as a listener for the given target + identifier.
identifier,
*args, **kw)

See remove.(target,Remove an event listener.
identifier,
fn)

 -- Function: sqlalchemy.event.listen (target, identifier, fn, *args,
          **kw)

     Register a listener function for the given target.

     The listen() function is part of the primary interface
     for the SQLAlchemy event system, documented at Events.

     e.g.:

          from sqlalchemy import event
          from sqlalchemy.schema import UniqueConstraint

          def unique_constraint_name(const, table):
              const.name = "uq_%s_%s" % (
                  table.name,
                  list(const.columns)[0].name
              )
          event.listen(
                  UniqueConstraint,
                  "after_parent_attach",
                  unique_constraint_name)

     A given function can also be invoked for only the first invocation
     of the event using the ‘once’ argument:

          def on_config():
              do_config()

          event.listen(Mapper, "before_configure", on_config, once=True)

          Warning: The ‘once’ argument does not imply automatic
          de-registration of the listener function after it has been
          invoked a first time; a listener entry will remain associated
          with the target object.  Associating an arbitrarily high
          number of listeners without explicitly removing them will
          cause memory to grow unbounded even if ‘once=True’ is
          specified.

          Note: The listen() function cannot be called at
          the same time that the target event is being run.  This has
          implications for thread safety, and also means an event cannot
          be added from inside the listener function for itself.  The
          list of events to be run are present inside of a mutable
          collection that can’t be changed during iteration.

          Event registration and removal is not intended to be a “high
          velocity” operation; it is a configurational operation.  For
          systems that need to quickly associate and deassociate with
          events at high scale, use a mutable structure that is handled
          from inside of a single listener.

          Changed in version 1.0.0: - a ‘collections.deque()’ object is
          now used as the container for the list of events, which
          explicitly disallows collection mutation while the collection
          is being iterated.

     See also
     ........

     See listens_for().

     See remove().

 -- Function: sqlalchemy.event.listens_for (target, identifier, *args,
          **kw)

     Decorate a function as a listener for the given target +
     identifier.

     The listens_for() decorator is part of the primary
     interface for the SQLAlchemy event system, documented at
     Events.

     e.g.:

          from sqlalchemy import event
          from sqlalchemy.schema import UniqueConstraint

          @event.listens_for(UniqueConstraint, "after_parent_attach")
          def unique_constraint_name(const, table):
              const.name = "uq_%s_%s" % (
                  table.name,
                  list(const.columns)[0].name
              )

     A given function can also be invoked for only the first invocation
     of the event using the ‘once’ argument:

          @event.listens_for(Mapper, "before_configure", once=True)
          def on_config():
              do_config()

          Warning: The ‘once’ argument does not imply automatic
          de-registration of the listener function after it has been
          invoked a first time; a listener entry will remain associated
          with the target object.  Associating an arbitrarily high
          number of listeners without explicitly removing them will
          cause memory to grow unbounded even if ‘once=True’ is
          specified.

     See also
     ........

     See listen(). - general description of event listening

 -- Function: sqlalchemy.event.remove (target, identifier, fn)

     Remove an event listener.

     The arguments here should match exactly those which were sent to
     listen(); all the event registration which proceeded as
     a result of this call will be reverted by calling remove()
     with the same arguments.

     e.g.:

          # if a function was registered like this...
          @event.listens_for(SomeMappedClass, "before_insert", propagate=True)
          def my_listener_function(*arg):
              pass

          # ... it's removed like this
          event.remove(SomeMappedClass, "before_insert", my_listener_function)

     Above, the listener function associated with ‘SomeMappedClass’ was
     also propagated to subclasses of ‘SomeMappedClass’; the
     remove() function will revert all of these operations.

          Note: The remove() function cannot be called at
          the same time that the target event is being run.  This has
          implications for thread safety, and also means an event cannot
          be removed from inside the listener function for itself.  The
          list of events to be run are present inside of a mutable
          collection that can’t be changed during iteration.

          Event registration and removal is not intended to be a “high
          velocity” operation; it is a configurational operation.  For
          systems that need to quickly associate and deassociate with
          events at high scale, use a mutable structure that is handled
          from inside of a single listener.

          Changed in version 1.0.0: - a ‘collections.deque()’ object is
          now used as the container for the list of events, which
          explicitly disallows collection mutation while the collection
          is being iterated.

     See also
     ........

     See listen().

 -- Function: sqlalchemy.event.contains (target, identifier, fn)

     Return True if the given target/ident/fn is set up to listen.

4.6.2 Runtime Inspection API
----------------------------

The inspection module provides the inspect() function, which
delivers runtime information about a wide variety of SQLAlchemy objects,
both within the Core as well as the ORM.

The inspect() function is the entry point to SQLAlchemy’s
public API for viewing the configuration and construction of in-memory
objects.  Depending on the type of object passed to inspect(),
the return value will either be a related object which provides a
known interface, or in many cases it will return the object itself.

The rationale for inspect() is twofold.  One is that it
replaces the need to be aware of a large variety of “information
getting” functions in SQLAlchemy, such as Inspector.from_engine().
(deprecated in 1.4), see instance_state(),
class_mapper(), and others.  The other is that the return value of
inspect() is guaranteed to obey a documented API, thus
allowing third party tools which build on top of SQLAlchemy
configurations to be constructed in a forwards-compatible way.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See inspect.(subject[,Produce an inspection object for the given target.
raiseerr])

 -- Function: sqlalchemy.inspect (subject, raiseerr=True)

     Produce an inspection object for the given target.

     The returned value in some cases may be the same object as the one
     given, such as if a Mapper object is passed.  In other
     cases, it will be an instance of the registered inspection type for
     the given object, such as if an Engine is passed, an
     Inspector object is returned.

     Parameters:

        * ‘subject’ – the subject to be inspected.

        * ‘raiseerr’ – When ‘True’, if the given subject does not
          correspond to a known SQLAlchemy inspected type, see
          sqlalchemy.exc.NoInspectionAvailable is raised.  If
          ‘False’, ‘None’ is returned.

4.6.2.1 Available Inspection Targets
....................................

Below is a listing of many of the most common inspection targets.

   * ‘Connectable’ (i.e.  see Engine, Connection) -
     returns an Inspector object.

   * ClauseElement. - all SQL expression components,
     including Table, Column, serve as their own
     inspection objects, meaning any of these objects passed to
     inspect() return themselves.

   * ‘object’ - an object given will be checked by the ORM for a mapping
     - if so, an InstanceState is returned representing the
     mapped state of the object.  The InstanceState also
     provides access to per attribute state via the
     AttributeState interface as well as the per-flush “history”
     of any attribute via the History object.

   * ‘type’ (i.e.  a class) - a class given will be checked by the ORM
     for a mapping - if so, a Mapper for that class is
     returned.

   * mapped attribute - passing a mapped attribute to inspect(),
     such as ‘inspect(MyClass.some_attribute)’, returns a
     QueryableAttribute object, which is the descriptor associated
     with a mapped class.  This descriptor refers to a
     MapperProperty, which is usually an instance of
     ColumnProperty or RelationshipProperty, via its
     QueryableAttribute.property attribute.

   * AliasedClass. - returns an AliasedInsp.
     object.

4.6.3 Core Exceptions
---------------------

Exceptions used with SQLAlchemy.

The base exception class is SQLAlchemyError.  Exceptions
which are raised as a result of DBAPI exceptions are all subclasses of
DBAPIError.

 -- Exception: sqlalchemy.exc.AmbiguousForeignKeysError (*arg, **kw)

     Raised when more than one foreign key matching can be located
     between two selectables during a join.

 -- Exception: sqlalchemy.exc.ArgumentError (*arg, **kw)

     Raised when an invalid or conflicting function argument is
     supplied.

     This error generally corresponds to construction time state errors.

 -- Exception: sqlalchemy.exc.AwaitRequired (*arg, **kw)

     Error raised by the async greenlet spawn if no async operation was
     awaited when it required one.

 -- Exception: sqlalchemy.exc.CircularDependencyError (message, cycles,
          edges, msg=None, code=None)

     Raised by topological sorts when a circular dependency is detected.

     There are two scenarios where this error occurs:

        * In a Session flush operation, if two objects are mutually
          dependent on each other, they can not be inserted or deleted
          via INSERT or DELETE statements alone; an UPDATE will be
          needed to post-associate or pre-deassociate one of the foreign
          key constrained values.  The ‘post_update’ flag described at
          Rows that point to themselves / Mutually Dependent Rows
          can resolve this cycle.

        * In a MetaData.sorted_tables operation, two
          ForeignKey or ForeignKeyConstraint objects
          mutually refer to each other.  Apply the ‘use_alter=True’ flag
          to one or both, see Creating/Dropping Foreign Key Constraints via ALTER.

 -- Exception: sqlalchemy.exc.CompileError (*arg, **kw)

     Raised when an error occurs during SQL compilation

 -- Exception: sqlalchemy.exc.DBAPIError (statement, params, orig,
          hide_parameters=False, connection_invalidated=False,
          code=None, ismulti=None)

     Raised when the execution of a database operation fails.

     Wraps exceptions raised by the DB-API underlying the database
     operation.  Driver-specific implementations of the standard DB-API
     exception types are wrapped by matching sub-types of SQLAlchemy’s
     DBAPIError when possible.  DB-API’s ‘Error’ type maps
     to DBAPIError in SQLAlchemy, otherwise the names are
     identical.  Note that there is no guarantee that different DB-API
     implementations will raise the same exception type for any given
     error condition.

     DBAPIError features StatementError.statement
     and StatementError.params attributes which
     supply context regarding the specifics of the statement which had
     an issue, for the typical case when the error was raised within the
     context of emitting a SQL statement.

     The wrapped exception object is available in the
     StatementError.orig attribute.  Its type and properties are
     DB-API implementation specific.

 -- Exception: sqlalchemy.exc.DataError (statement, params, orig,
          hide_parameters=False, connection_invalidated=False,
          code=None, ismulti=None)

     Wraps a DB-API DataError.

 -- Exception: sqlalchemy.exc.DatabaseError (statement, params, orig,
          hide_parameters=False, connection_invalidated=False,
          code=None, ismulti=None)

     Wraps a DB-API DatabaseError.

 -- Exception: sqlalchemy.exc.DisconnectionError (*arg, **kw)

     A disconnect is detected on a raw DB-API connection.

     This error is raised and consumed internally by a connection pool.
     It can be raised by the PoolEvents.checkout() event so
     that the host pool forces a retry; the exception will be caught
     three times in a row before the pool gives up and raises
     InvalidRequestError regarding the connection attempt.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See DontWrapMixin.A mixin class which, when applied to a user-defined Exception class, will not be wrapped
               inside of StatementError if the error is emitted within the process of
               executing a statement.

 -- Class: sqlalchemy.exc.DontWrapMixin

     A mixin class which, when applied to a user-defined Exception
     class, will not be wrapped inside of StatementError if
     the error is emitted within the process of executing a statement.

     E.g.:

          from sqlalchemy.exc import DontWrapMixin

          class MyCustomException(Exception, DontWrapMixin):
              pass

          class MySpecialType(TypeDecorator):
              impl = String

              def process_bind_param(self, value, dialect):
                  if value == 'invalid':
                      raise MyCustomException("invalid!")

 -- Exception: sqlalchemy.exc.IdentifierError (*arg, **kw)

     Raised when a schema name is beyond the max character limit

 -- Exception: sqlalchemy.exc.IntegrityError (statement, params, orig,
          hide_parameters=False, connection_invalidated=False,
          code=None, ismulti=None)

     Wraps a DB-API IntegrityError.

 -- Exception: sqlalchemy.exc.InterfaceError (statement, params, orig,
          hide_parameters=False, connection_invalidated=False,
          code=None, ismulti=None)

     Wraps a DB-API InterfaceError.

 -- Exception: sqlalchemy.exc.InternalError (statement, params, orig,
          hide_parameters=False, connection_invalidated=False,
          code=None, ismulti=None)

     Wraps a DB-API InternalError.

 -- Exception: sqlalchemy.exc.InvalidRequestError (*arg, **kw)

     SQLAlchemy was asked to do something it can’t do.

     This error generally corresponds to runtime state errors.

 -- Exception: sqlalchemy.exc.InvalidatePoolError (*arg, **kw)

     Raised when the connection pool should invalidate all stale
     connections.

     A subclass of DisconnectionError that indicates that
     the disconnect situation encountered on the connection probably
     means the entire pool should be invalidated, as the database has
     been restarted.

     This exception will be handled otherwise the same way as
     DisconnectionError, allowing three attempts to reconnect
     before giving up.

     New in version 1.2.

 -- Exception: sqlalchemy.exc.MissingGreenlet (*arg, **kw)

     Error raised by the async greenlet await_ if called while not
     inside the greenlet spawn context.

 -- Exception: sqlalchemy.exc.MovedIn20Warning

     Subtype of RemovedIn20Warning to indicate an API that moved only.

 -- Exception: sqlalchemy.exc.MultipleResultsFound (*arg, **kw)

     A single database result was required but more than one were found.

     Changed in version 1.4: This exception is now part of the
     ‘sqlalchemy.exc’ module in Core, moved from the ORM. The symbol
     remains importable from ‘sqlalchemy.orm.exc’.

 -- Exception: sqlalchemy.exc.NoForeignKeysError (*arg, **kw)

     Raised when no foreign keys can be located between two selectables
     during a join.

 -- Exception: sqlalchemy.exc.NoInspectionAvailable (*arg, **kw)

     A subject passed to ‘sqlalchemy.inspection.inspect()’ produced no
     context for inspection.

 -- Exception: sqlalchemy.exc.NoReferenceError (*arg, **kw)

     Raised by ‘ForeignKey’ to indicate a reference cannot be resolved.

 -- Exception: sqlalchemy.exc.NoReferencedColumnError (message, tname,
          cname)

     Raised by ‘ForeignKey’ when the referred ‘Column’ cannot be
     located.

 -- Exception: sqlalchemy.exc.NoReferencedTableError (message, tname)

     Raised by ‘ForeignKey’ when the referred ‘Table’ cannot be located.

 -- Exception: sqlalchemy.exc.NoResultFound (*arg, **kw)

     A database result was required but none was found.

     Changed in version 1.4: This exception is now part of the
     ‘sqlalchemy.exc’ module in Core, moved from the ORM. The symbol
     remains importable from ‘sqlalchemy.orm.exc’.

 -- Exception: sqlalchemy.exc.NoSuchColumnError

     A nonexistent column is requested from a ‘Row’.

 -- Exception: sqlalchemy.exc.NoSuchModuleError (*arg, **kw)

     Raised when a dynamically-loaded module (usually a database
     dialect) of a particular name cannot be located.

 -- Exception: sqlalchemy.exc.NoSuchTableError (*arg, **kw)

     Table does not exist or is not visible to a connection.

 -- Exception: sqlalchemy.exc.NotSupportedError (statement, params,
          orig, hide_parameters=False, connection_invalidated=False,
          code=None, ismulti=None)

     Wraps a DB-API NotSupportedError.

 -- Exception: sqlalchemy.exc.ObjectNotExecutableError (target)

     Raised when an object is passed to .execute() that can’t be
     executed as SQL.

     New in version 1.1.

 -- Exception: sqlalchemy.exc.OperationalError (statement, params, orig,
          hide_parameters=False, connection_invalidated=False,
          code=None, ismulti=None)

     Wraps a DB-API OperationalError.

 -- Exception: sqlalchemy.exc.PendingRollbackError (*arg, **kw)

     A transaction has failed and needs to be rolled back before
     continuing.

     New in version 1.4.

 -- Exception: sqlalchemy.exc.ProgrammingError (statement, params, orig,
          hide_parameters=False, connection_invalidated=False,
          code=None, ismulti=None)

     Wraps a DB-API ProgrammingError.

 -- Exception: sqlalchemy.exc.RemovedIn20Warning

     Issued for usage of APIs specifically deprecated in SQLAlchemy 2.0.

     See also
     ........

     See The <some function> in SQLAlchemy 2.0 will no longer <something>.

     See SQLAlchemy 2.0 Deprecations Mode.

      -- Attribute: sqlalchemy.exc.RemovedIn20Warning..
               deprecated_since = '1.4'

          Indicates the version that started raising this deprecation
          warning

 -- Exception: sqlalchemy.exc.ResourceClosedError (*arg, **kw)

     An operation was requested from a connection, cursor, or other
     object that’s in a closed state.

 -- Exception: sqlalchemy.exc.SADeprecationWarning

     Issued for usage of deprecated APIs.

      -- Attribute: sqlalchemy.exc.SADeprecationWarning..
               deprecated_since = None

          Indicates the version that started raising this deprecation
          warning

 -- Exception: sqlalchemy.exc.SAPendingDeprecationWarning

     A similar warning as SADeprecationWarning, this warning
     is not used in modern versions of SQLAlchemy.

      -- Attribute: sqlalchemy.exc.SAPendingDeprecationWarning..
               deprecated_since = None

          Indicates the version that started raising this deprecation
          warning

 -- Exception: sqlalchemy.exc.SAWarning

     Issued at runtime.

 -- Exception: sqlalchemy.exc.SQLAlchemyError (*arg, **kw)

     Generic error class.

 -- Exception: sqlalchemy.exc.StatementError (message, statement,
          params, orig, hide_parameters=False, code=None, ismulti=None)

     An error occurred during execution of a SQL statement.

     StatementError wraps the exception raised during
     execution, and features statement and params
     attributes which supply context regarding the specifics of
     the statement which had an issue.

     The wrapped exception object is available in the orig
     attribute.

      -- Attribute: sqlalchemy.exc.StatementError..orig =
               None

          The DBAPI exception object.

      -- Attribute: sqlalchemy.exc.StatementError..params =
               None

          The parameter list being used when this exception occurred.

      -- Attribute: sqlalchemy.exc.StatementError..statement
               = None

          The string SQL statement being invoked when this exception
          occurred.

 -- Exception: sqlalchemy.exc.TimeoutError (*arg, **kw)

     Raised when a connection pool times out on getting a connection.

 -- Exception: sqlalchemy.exc.UnboundExecutionError (*arg, **kw)

     SQL was attempted without a database connection to execute it on.

 -- Exception: sqlalchemy.exc.UnreflectableTableError (*arg, **kw)

     Table exists but can’t be reflected for some reason.

     New in version 1.2.

 -- Exception: sqlalchemy.exc.UnsupportedCompilationError (compiler,
          element_type, message=None)

     Raised when an operation is not supported by the given compiler.

     See also
     ........

     See How do I render SQL expressions as strings, possibly with bound parameters inlined?.

     See Compiler StrSQLCompiler can’t render element of type <element type>.

4.6.4 Core Internals
--------------------

Some key internal constructs are listed here.

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See Compiled.Represent a compiled SQL or DDL expression.

See DDLCompiler.

See DefaultDialect.Default implementation of Dialect

See DefaultExecutionContext.

See Dialect.Define the behavior of a specific database and DB-API combination.

See ExecutionContext.A messenger object for a Dialect that corresponds to a single execution.

See GenericTypeCompiler.

See Identified.

See IdentifierPreparer.Handle quoting and case-folding of identifiers based on options.

See SQLCompiler.Default implementation of Compiled.

See StrSQLCompiler.A SQLCompiler subclass which allows a small selection of non-standard SQL
               features to render into a string value.

 -- Class: sqlalchemy.engine.Compiled (dialect, statement,
          schema_translate_map=None, render_schema_translate=False,
          compile_kwargs={})

     Represent a compiled SQL or DDL expression.

     The ‘__str__’ method of the ‘Compiled’ object should produce the
     actual text of the statement.  ‘Compiled’ objects are specific to
     their underlying database dialect, and also may or may not be
     specific to the columns referenced within a particular set of bind
     parameters.  In no case should the ‘Compiled’ object be dependent
     on the actual values of those bind parameters, even though it may
     reference those values as defaults.

      -- Method: sqlalchemy.engine.Compiled..__init__
               (dialect, statement, schema_translate_map=None,
               render_schema_translate=False, compile_kwargs={})

          Construct a new Compiled object.

          Parameters:

             * ‘dialect’ – see Dialect to compile against.

             * ‘statement’ – see ClauseElement to be compiled.

             * ‘schema_translate_map’ – dictionary of schema names to be
               translated when forming the resultant SQL

               New in version 1.1.

               See also
               ........

               See Translation of Schema Names.

             * ‘compile_kwargs’ – additional kwargs that will be passed
               to the initial call to ‘Compiled.process()’.

      -- Attribute: sqlalchemy.engine.Compiled..compile_state
               = None

          Optional ‘CompileState’ object that maintains additional state
          used by the compiler.

          Major executable objects such as Insert,
          Update, Delete, Select will generate
          this state when compiled in order to calculate additional
          information about the object.  For the top level object that
          is to be executed, the state can be stored here where it can
          also have applicability towards result set processing.

          New in version 1.4.

      -- Method: sqlalchemy.engine.Compiled..construct_params
               (params=None, extracted_parameters=None)

          Return the bind params for this compiled object.

          Parameters: ‘params’ – a dict of string/object pairs whose
          values will override bind values compiled in to the statement.

      -- Attribute: sqlalchemy.engine.Compiled..
               execution_options = {}

          Execution options propagated from the statement.  In some
          cases, sub-elements of the statement can modify these.

      -- Attribute: sqlalchemy.engine.Compiled..params

          Return the bind params for this compiled object.

      -- Attribute: sqlalchemy.engine.Compiled..sql_compiler

          Return a Compiled that is capable of processing SQL
          expressions.

          If this compiler is one, it would likely just return ‘self’.

 -- Class: sqlalchemy.sql.compiler.DDLCompiler (dialect, statement,
          schema_translate_map=None, render_schema_translate=False,
          compile_kwargs={})

     `Class signature'

     class sqlalchemy.sql.compiler.DDLCompiler.
     (‘sqlalchemy.sql.compiler.Compiled’)

      -- Method: sqlalchemy.sql.compiler.DDLCompiler..
               __init__ (dialect, statement,
               schema_translate_map=None, render_schema_translate=False,
               compile_kwargs={})

          `inherited from the'
          ‘sqlalchemy.sql.compiler.Compiled.__init__’ `method of'
          ‘Compiled’

          Construct a new Compiled object.

          Parameters:

             * ‘dialect’ – see Dialect to compile against.

             * ‘statement’ – see ClauseElement to be compiled.

             * ‘schema_translate_map’ – dictionary of schema names to be
               translated when forming the resultant SQL

               New in version 1.1.

               See also
               ........

               See Translation of Schema Names.

             * ‘compile_kwargs’ – additional kwargs that will be passed
               to the initial call to ‘Compiled.process()’.

      -- Method: sqlalchemy.sql.compiler.DDLCompiler..
               construct_params (params=None,
               extracted_parameters=None)

          Return the bind params for this compiled object.

          Parameters: ‘params’ – a dict of string/object pairs whose
          values will override bind values compiled in to the statement.

      -- Method: sqlalchemy.sql.compiler.DDLCompiler..
               define_constraint_remote_table (constraint, table,
               preparer)

          Format the remote table clause of a CREATE CONSTRAINT clause.

      -- Attribute: sqlalchemy.sql.compiler.DDLCompiler..
               params

          `inherited from the' ‘Compiled.params’ `attribute of'
          ‘Compiled’

          Return the bind params for this compiled object.

 -- Class: sqlalchemy.engine.default.DefaultDialect
          (convert_unicode=False, encoding='utf-8', paramstyle=None,
          dbapi=None, implicit_returning=None, case_sensitive=True,
          supports_native_boolean=None, max_identifier_length=None,
          label_length=None, compiler_linting=0,
          server_side_cursors=False, **kwargs)

     Default implementation of Dialect

     `Class signature'

     class sqlalchemy.engine.default.DefaultDialect.
     (‘sqlalchemy.engine.interfaces.Dialect’)

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               connect (*cargs, **cparams)

          Establish a connection using this dialect’s DBAPI.

          The default implementation of this method is:

               def connect(self, *cargs, **cparams):
                   return self.dbapi.connect(*cargs, **cparams)

          The ‘*cargs, **cparams’ parameters are generated directly from
          this dialect’s Dialect.create_connect_args()
          method.

          This method may be used for dialects that need to perform
          programmatic per-connection steps when a new connection is
          procured from the DBAPI.

          Parameters:

             * ‘*cargs’ – positional parameters returned from the
               Dialect.create_connect_args() method

             * ‘**cparams’ – keyword parameters returned from the
               Dialect.create_connect_args() method.

          Returns: a DBAPI connection, typically from the PEP 249(1)
          module level ‘.connect()’ function.

          See also
          ........

          See Dialect.create_connect_args().

          See Dialect.on_connect().

      -- Attribute: sqlalchemy.engine.default.DefaultDialect..
               construct_arguments = None

          Optional set of argument specifiers for various SQLAlchemy
          constructs, typically schema items.

          To implement, establish as a series of tuples, as in:

               construct_arguments = [
                   (schema.Index, {
                       "using": False,
                       "where": None,
                       "ops": None
                   })
               ]

          If the above construct is established on the PostgreSQL
          dialect, the Index construct will now accept the
          keyword arguments ‘postgresql_using’, ‘postgresql_where’, nad
          ‘postgresql_ops’.  Any other argument specified to the
          constructor of Index which is prefixed with
          ‘postgresql_’ will raise ArgumentError.

          A dialect which does not include a ‘construct_arguments’
          member will not participate in the argument validation system.
          For such a dialect, any argument name is accepted by all
          participating constructs, within the namespace of arguments
          prefixed with that dialect name.  The rationale here is so
          that third-party dialects that haven’t yet implemented this
          feature continue to function in the old way.

          New in version 0.9.2.

          See also
          ........

          See DialectKWArgs. - implementing base class which
          consumes DefaultDialect.construct_arguments.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               create_connect_args (url)

          Build DB-API compatible connection arguments.

          Given a URL object, returns a tuple consisting of
          a ‘(*args, **kwargs)’ suitable to send directly to the dbapi’s
          connect function.  The arguments are sent to the
          Dialect.connect() method which then runs the
          DBAPI-level ‘connect()’ function.

          The method typically makes use of the
          URL.translate_connect_args() method in order to
          generate a dictionary of options.

          The default implementation is:

               def create_connect_args(self, url):
                   opts = url.translate_connect_args()
                   opts.update(url.query)
                   return [[], opts]

          Parameters: ‘url’ – a URL object

          Returns: a tuple of ‘(*args, **kwargs)’ which will be passed
          to the Dialect.connect() method.

          See also
          ........

          See URL.translate_connect_args().

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               create_xid ()

          Create a random two-phase transaction ID.

          This id will be passed to do_begin_twophase(),
          do_rollback_twophase(), do_commit_twophase().  Its format is
          unspecified.

      -- Attribute: sqlalchemy.engine.default.DefaultDialect..
               dbapi_exception_translation_map = {}

          mapping used in the extremely unusual case that a DBAPI’s
          published exceptions don’t actually have the __name__ that
          they are linked towards.

          New in version 1.0.5.

      -- Attribute: sqlalchemy.engine.default.DefaultDialect..
               ddl_compiler

          alias of sqlalchemy.sql.compiler.DDLCompiler.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               denormalize_name (name)

          convert the given name to a case insensitive identifier for
          the backend if it is an all-lowercase name.

          This method is only used if the dialect defines
          requires_name_normalize=True.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               do_begin (dbapi_connection)

          Provide an implementation of ‘connection.begin()’, given a
          DB-API connection.

          The DBAPI has no dedicated “begin” method and it is expected
          that transactions are implicit.  This hook is provided for
          those DBAPIs that might need additional help in this area.

          Note that Dialect.do_begin() is not called unless
          a Transaction object is in use.  The
          ‘Dialect.do_autocommit()’ hook is provided for DBAPIs that
          need some extra commands emitted after a commit in order to
          enter the next transaction, when the SQLAlchemy
          Connection is used in its default “autocommit” mode.

          Parameters: ‘dbapi_connection’ – a DBAPI connection, typically
          proxied within a ‘ConnectionFairy’.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               do_begin_twophase (connection, xid)

          `inherited from the' ‘Dialect.do_begin_twophase()’ `method of'
          ‘Dialect’

          Begin a two phase transaction on the given connection.

          Parameters:

             * ‘connection’ – a Connection.

             * ‘xid’ – xid

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               do_close (dbapi_connection)

          Provide an implementation of ‘connection.close()’, given a
          DBAPI connection.

          This hook is called by the Pool when a connection
          has been detached from the pool, or is being returned beyond
          the normal capacity of the pool.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               do_commit (dbapi_connection)

          Provide an implementation of ‘connection.commit()’, given a
          DB-API connection.

          Parameters: ‘dbapi_connection’ – a DBAPI connection, typically
          proxied within a ‘ConnectionFairy’.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               do_commit_twophase (connection, xid,
               is_prepared=True, recover=False)

          `inherited from the' ‘Dialect.do_commit_twophase()’ `method
          of' ‘Dialect’

          Commit a two phase transaction on the given connection.

          Parameters:

             * ‘connection’ – a Connection.

             * ‘xid’ – xid

             * ‘is_prepared’ – whether or not
               TwoPhaseTransaction.prepare() was called.

             * ‘recover’ – if the recover flag was passed.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               do_execute (cursor, statement, parameters,
               context=None)

          Provide an implementation of ‘cursor.execute(statement,
          parameters)’.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               do_execute_no_params (cursor, statement,
               context=None)

          Provide an implementation of ‘cursor.execute(statement)’.

          The parameter collection should not be sent.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               do_executemany (cursor, statement, parameters,
               context=None)

          Provide an implementation of ‘cursor.executemany(statement,
          parameters)’.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               do_prepare_twophase (connection, xid)

          `inherited from the' ‘Dialect.do_prepare_twophase()’ `method
          of' ‘Dialect’

          Prepare a two phase transaction on the given connection.

          Parameters:

             * ‘connection’ – a Connection.

             * ‘xid’ – xid

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               do_recover_twophase (connection)

          `inherited from the' ‘Dialect.do_recover_twophase()’ `method
          of' ‘Dialect’

          Recover list of uncommitted prepared two phase transaction
          identifiers on the given connection.

          Parameters: ‘connection’ – a Connection.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               do_release_savepoint (connection, name)

          Release the named savepoint on a connection.

          Parameters:

             * ‘connection’ – a Connection.

             * ‘name’ – savepoint name.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               do_rollback (dbapi_connection)

          Provide an implementation of ‘connection.rollback()’, given a
          DB-API connection.

          Parameters: ‘dbapi_connection’ – a DBAPI connection, typically
          proxied within a ‘ConnectionFairy’.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               do_rollback_to_savepoint (connection, name)

          Rollback a connection to the named savepoint.

          Parameters:

             * ‘connection’ – a Connection.

             * ‘name’ – savepoint name.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               do_rollback_twophase (connection, xid,
               is_prepared=True, recover=False)

          `inherited from the' ‘Dialect.do_rollback_twophase()’ `method
          of' ‘Dialect’

          Rollback a two phase transaction on the given connection.

          Parameters:

             * ‘connection’ – a Connection.

             * ‘xid’ – xid

             * ‘is_prepared’ – whether or not
               TwoPhaseTransaction.prepare() was called.

             * ‘recover’ – if the recover flag was passed.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               do_savepoint (connection, name)

          Create a savepoint with the given name.

          Parameters:

             * ‘connection’ – a Connection.

             * ‘name’ – savepoint name.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               do_set_input_sizes (cursor, list_of_tuples, context)

          `inherited from the' ‘Dialect.do_set_input_sizes()’ `method
          of' ‘Dialect’

          invoke the cursor.setinputsizes() method with appropriate
          arguments

          This hook is called if the dialect.use_inputsizes flag is set
          to True.  Parameter data is passed in a list of tuples
          (paramname, dbtype, sqltype), where ‘paramname’ is the key of
          the parameter in the statement, ‘dbtype’ is the DBAPI datatype
          and ‘sqltype’ is the SQLAlchemy type.  The order of tuples is
          in the correct parameter order.

          New in version 1.4.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               classmethod engine_created (engine)

          `inherited from the' ‘Dialect.engine_created()’ `method of'
          ‘Dialect’

          A convenience hook called before returning the final
          Engine.

          If the dialect returned a different class from the
          get_dialect_cls() method, then the hook is called on
          both classes, first on the dialect class returned by the
          get_dialect_cls() method and then on the class on which
          the method was called.

          The hook should be used by dialects and/or wrappers to apply
          special events to the engine or its components.  In
          particular, it allows a dialect-wrapping class to apply
          dialect-level events.

          New in version 1.0.3.

      -- Attribute: sqlalchemy.engine.default.DefaultDialect..
               execute_sequence_format

          alias of ‘tuple’

      -- Attribute: sqlalchemy.engine.default.DefaultDialect..
               execution_ctx_cls

          alias of
          sqlalchemy.engine.default.DefaultExecutionContext.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               get_check_constraints (connection, table_name,
               schema=None, **kw)

          `inherited from the' ‘Dialect.get_check_constraints()’ `method
          of' ‘Dialect’

          Return information about check constraints in ‘table_name’.

          Given a string ‘table_name’ and an optional string ‘schema’,
          return check constraint information as a list of dicts with
          these keys:

             * ‘name’ - the check constraint’s name

             * ‘sqltext’ - the check constraint’s SQL expression

             * ‘**kw’ - other options passed to the dialect’s
               get_check_constraints() method.

          New in version 1.1.0.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               get_columns (connection, table_name, schema=None,
               **kw)

          `inherited from the' ‘Dialect.get_columns()’ `method of'
          ‘Dialect’

          Return information about columns in ‘table_name’.

          Given a Connection, a string ‘table_name’, and an
          optional string ‘schema’, return column information as a list
          of dictionaries with these keys:

          name

               the column’s name

          type

               [sqlalchemy.types#TypeEngine]

          nullable

               boolean

          default

               the column’s default value

          autoincrement

               boolean

          sequence

               a dictionary of the form

                    {‘name’ : str, ‘start’ :int, ‘increment’: int, ‘minvalue’: int,

                         ‘maxvalue’: int, ‘nominvalue’: bool,
                         ‘nomaxvalue’: bool, ‘cycle’: bool, ‘cache’:
                         int, ‘order’: bool}

          Additional column attributes may be present.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               get_default_isolation_level (dbapi_conn)

          Given a DBAPI connection, return its isolation level, or a
          default isolation level if one cannot be retrieved.

          May be overridden by subclasses in order to provide a
          “fallback” isolation level for databases that cannot reliably
          retrieve the actual isolation level.

          By default, calls the ‘Interfaces.get_isolation_level()’
          method, propagating any exceptions raised.

          New in version 1.3.22.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               classmethod get_dialect_cls (url)

          `inherited from the' ‘Dialect.get_dialect_cls()’ `method of'
          ‘Dialect’

          Given a URL, return the Dialect that will be
          used.

          This is a hook that allows an external plugin to provide
          functionality around an existing dialect, by allowing the
          plugin to be loaded from the url based on an entrypoint, and
          then the plugin returns the actual dialect to be used.

          By default this just returns the cls.

          New in version 1.0.3.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               get_foreign_keys (connection, table_name,
               schema=None, **kw)

          `inherited from the' ‘Dialect.get_foreign_keys()’ `method of'
          ‘Dialect’

          Return information about foreign_keys in ‘table_name’.

          Given a Connection, a string ‘table_name’, and an
          optional string ‘schema’, return foreign key information as a
          list of dicts with these keys:

          name

               the constraint’s name

          constrained_columns

               a list of column names that make up the foreign key

          referred_schema

               the name of the referred schema

          referred_table

               the name of the referred table

          referred_columns

               a list of column names in the referred table that
               correspond to constrained_columns

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               get_indexes (connection, table_name, schema=None,
               **kw)

          `inherited from the' ‘Dialect.get_indexes()’ `method of'
          ‘Dialect’

          Return information about indexes in ‘table_name’.

          Given a Connection, a string ‘table_name’ and an
          optional string ‘schema’, return index information as a list
          of dictionaries with these keys:

          name

               the index’s name

          column_names

               list of column names in order

          unique

               boolean

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               get_isolation_level (dbapi_conn)

          `inherited from the' ‘Dialect.get_isolation_level()’ `method
          of' ‘Dialect’

          Given a DBAPI connection, return its isolation level.

          When working with a Connection object, the
          corresponding DBAPI connection may be procured using the
          Connection.connection accessor.

          Note that this is a dialect-level method which is used as part
          of the implementation of the Connection and
          Engine isolation level facilities; these APIs should be
          preferred for most typical use cases.

          See also
          ........

          See Connection.get_isolation_level(). - view current
          level

          See Connection.default_isolation_level. - view default
          level

          See Connection.execution_options.isolation_level. -
          set per Connection isolation level

          See create_engine.isolation_level. - set per
          Engine isolation level

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               get_pk_constraint (connection, table_name,
               schema=None, **kw)

          `inherited from the' ‘Dialect.get_pk_constraint()’ `method of'
          ‘Dialect’

          Return information about the primary key constraint on
          table_name‘.

          Given a Connection, a string ‘table_name’, and an
          optional string ‘schema’, return primary key information as a
          dictionary with these keys:

          constrained_columns

               a list of column names that make up the primary key

          name

               optional name of the primary key constraint.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               get_sequence_names (connection, schema=None, **kw)

          `inherited from the' ‘Dialect.get_sequence_names()’ `method
          of' ‘Dialect’

          Return a list of all sequence names available in the database.

          Parameters: ‘schema’ – schema name to query, if not the
          default schema.

          New in version 1.4.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               get_table_comment (connection, table_name,
               schema=None, **kw)

          `inherited from the' ‘Dialect.get_table_comment()’ `method of'
          ‘Dialect’

          Return the “comment” for the table identified by ‘table_name’.

          Given a string ‘table_name’ and an optional string ‘schema’,
          return table comment information as a dictionary with this
          key:

          text

               text of the comment

          Raises ‘NotImplementedError’ for dialects that don’t support
          comments.

          New in version 1.2.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               get_table_names (connection, schema=None, **kw)

          `inherited from the' ‘Dialect.get_table_names()’ `method of'
          ‘Dialect’

          Return a list of table names for ‘schema’.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               get_temp_table_names (connection, schema=None, **kw)

          `inherited from the' ‘Dialect.get_temp_table_names()’ `method
          of' ‘Dialect’

          Return a list of temporary table names on the given
          connection, if supported by the underlying backend.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               get_temp_view_names (connection, schema=None, **kw)

          `inherited from the' ‘Dialect.get_temp_view_names()’ `method
          of' ‘Dialect’

          Return a list of temporary view names on the given connection,
          if supported by the underlying backend.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               get_unique_constraints (connection, table_name,
               schema=None, **kw)

          `inherited from the' ‘Dialect.get_unique_constraints()’
          `method of' ‘Dialect’

          Return information about unique constraints in ‘table_name’.

          Given a string ‘table_name’ and an optional string ‘schema’,
          return unique constraint information as a list of dicts with
          these keys:

          name

               the unique constraint’s name

          column_names

               list of column names in order

          **kw

               other options passed to the dialect’s
               get_unique_constraints() method.

          New in version 0.9.0.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               get_view_definition (connection, view_name,
               schema=None, **kw)

          `inherited from the' ‘Dialect.get_view_definition()’ `method
          of' ‘Dialect’

          Return view definition.

          Given a Connection, a string ‘view_name’, and an
          optional string ‘schema’, return the view definition.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               get_view_names (connection, schema=None, **kw)

          `inherited from the' ‘Dialect.get_view_names()’ `method of'
          ‘Dialect’

          Return a list of all view names available in the database.

          Parameters: ‘schema’ – schema name to query, if not the
          default schema.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               has_index (connection, table_name, index_name,
               schema=None)

          Check the existence of a particular index name in the
          database.

          Given a Connection object, a string ‘table_name’
          and string index name, return True if an index of the given
          name on the given table exists, false otherwise.

          The DefaultDialect implements this in terms of
          the Dialect.has_table() and
          Dialect.get_indexes() methods, however dialects can
          implement a more performant version.

          New in version 1.4.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               has_sequence (connection, sequence_name,
               schema=None, **kw)

          `inherited from the' ‘Dialect.has_sequence()’ `method of'
          ‘Dialect’

          Check the existence of a particular sequence in the database.

          Given a Connection object and a string
          ‘sequence_name’, return True if the given sequence exists in
          the database, False otherwise.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               has_table (connection, table_name, schema=None,
               **kw)

          `inherited from the' ‘Dialect.has_table()’ `method of'
          ‘Dialect’

          Check the existence of a particular table in the database.

          Given a Connection object and a string
          ‘table_name’, return True if the given table (possibly within
          the specified ‘schema’) exists in the database, False
          otherwise.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               initialize (connection)

          Called during strategized creation of the dialect with a
          connection.

          Allows dialects to configure options based on server version
          info or other properties.

          The connection passed here is a SQLAlchemy Connection object,
          with full capabilities.

          The initialize() method of the base dialect should be called
          via super().

               Note: as of SQLAlchemy 1.4, this method is called
               `before' any Dialect.on_connect() hooks are
               called.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               is_disconnect (e, connection, cursor)

          Return True if the given DB-API error indicates an invalid
          connection

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               classmethod load_provisioning ()

          set up the provision.py module for this dialect.

          For dialects that include a provision.py module that sets up
          provisioning followers, this method should initiate that
          process.

          A typical implementation would be:

               @classmethod
               def load_provisioning(cls):
                   __import__("mydialect.provision")

          The default method assumes a module named ‘provision.py’
          inside the owning package of the current dialect, based on the
          ‘__module__’ attribute:

               @classmethod
               def load_provisioning(cls):
                   package = ".".join(cls.__module__.split(".")[0:-1])
                   try:
                       __import__(package + ".provision")
                   except ImportError:
                       pass

          New in version 1.3.14.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               normalize_name (name)

          convert the given name to lowercase if it is detected as case
          insensitive.

          This method is only used if the dialect defines
          requires_name_normalize=True.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               on_connect ()

          return a callable which sets up a newly created DBAPI
          connection.

          The callable should accept a single argument “conn” which is
          the DBAPI connection itself.  The inner callable has no return
          value.

          E.g.:

               class MyDialect(default.DefaultDialect):
                   # ...

                   def on_connect(self):
                       def do_on_connect(connection):
                           connection.execute("SET SPECIAL FLAGS etc")

                       return do_on_connect

          This is used to set dialect-wide per-connection options such
          as isolation modes, Unicode modes, etc.

          The “do_on_connect” callable is invoked by using the
          PoolEvents.connect() event hook, then unwrapping the
          DBAPI connection and passing it into the callable.

          Changed in version 1.4: the on_connect hook is no longer
          called twice for the first connection of a dialect.  The
          on_connect hook is still called before the
          Dialect.initialize() method however.

          If None is returned, no event listener is generated.

          Returns: a callable that accepts a single DBAPI connection as
          an argument, or None.

          See also
          ........

          See Dialect.connect(). - allows the DBAPI ‘connect()’
          sequence itself to be controlled.

      -- Attribute: sqlalchemy.engine.default.DefaultDialect..
               preparer

          alias of sqlalchemy.sql.compiler.IdentifierPreparer.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               reset_isolation_level (dbapi_conn)

          Given a DBAPI connection, revert its isolation to the default.

          Note that this is a dialect-level method which is used as part
          of the implementation of the Connection and
          Engine isolation level facilities; these APIs should be
          preferred for most typical use cases.

          See also
          ........

          See Connection.get_isolation_level(). - view current
          level

          See Connection.default_isolation_level. - view default
          level

          See Connection.execution_options.isolation_level. -
          set per Connection isolation level

          See create_engine.isolation_level. - set per
          Engine isolation level

      -- Attribute: sqlalchemy.engine.default.DefaultDialect..
               returns_unicode_strings = symbol('RETURNS_UNICODE')

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               set_isolation_level (dbapi_conn, level)

          `inherited from the' ‘Dialect.set_isolation_level()’ `method
          of' ‘Dialect’

          Given a DBAPI connection, set its isolation level.

          Note that this is a dialect-level method which is used as part
          of the implementation of the Connection and
          Engine isolation level facilities; these APIs should be
          preferred for most typical use cases.

          See also
          ........

          See Connection.get_isolation_level(). - view current
          level

          See Connection.default_isolation_level. - view default
          level

          See Connection.execution_options.isolation_level. -
          set per Connection isolation level

          See create_engine.isolation_level. - set per
          Engine isolation level

      -- Attribute: sqlalchemy.engine.default.DefaultDialect..
               statement_compiler

          alias of sqlalchemy.sql.compiler.SQLCompiler.

      -- Attribute: sqlalchemy.engine.default.DefaultDialect..
               supports_sane_rowcount_returning

          True if this dialect supports sane rowcount even if RETURNING
          is in use.

          For dialects that don’t support RETURNING, this is synonymous
          with ‘supports_sane_rowcount’.

      -- Attribute: sqlalchemy.engine.default.DefaultDialect..
               type_compiler

          alias of sqlalchemy.sql.compiler.GenericTypeCompiler.

      -- Method: sqlalchemy.engine.default.DefaultDialect..
               type_descriptor (typeobj)

          Provide a database-specific TypeEngine object,
          given the generic object which comes from the types module.

          This method looks for a dictionary called ‘colspecs’ as a
          class or instance-level variable, and passes on to
          ‘adapt_type()’.

 -- Class: sqlalchemy.engine.Dialect

     Define the behavior of a specific database and DB-API combination.

     Any aspect of metadata definition, SQL query generation, execution,
     result-set handling, or anything else which varies between
     databases is defined under the general category of the Dialect.
     The Dialect acts as a factory for other database-specific object
     implementations including ExecutionContext, Compiled,
     DefaultGenerator, and TypeEngine.

          Note: Third party dialects should not subclass Dialect
          directly.  Instead, subclass DefaultDialect
          or descendant class.

     All dialects include the following attributes.  There are many
     other attributes that may be supported as well:

     ‘name’

          identifying name for the dialect from a DBAPI-neutral point of
          view (i.e.  ‘sqlite’)

     ‘driver’

          identifying name for the dialect’s DBAPI

     ‘positional’

          True if the paramstyle for this Dialect is positional.

     ‘paramstyle’

          the paramstyle to be used (some DB-APIs support multiple
          paramstyles).

     ‘encoding’

          type of encoding to use for unicode, usually defaults to
          ‘utf-8’.

     ‘statement_compiler’

          a Compiled class used to compile SQL statements

     ‘ddl_compiler’

          a Compiled class used to compile DDL statements

     ‘server_version_info’

          a tuple containing a version number for the DB backend in use.
          This value is only available for supporting dialects, and is
          typically populated during the initial connection to the
          database.

     ‘default_schema_name’

          the name of the default schema.  This value is only available
          for supporting dialects, and is typically populated during the
          initial connection to the database.

     ‘execution_ctx_cls’

          a ExecutionContext class used to handle statement
          execution

     ‘execute_sequence_format’

          either the ‘tuple’ or ‘list’ type, depending on what
          cursor.execute() accepts for the second argument (they vary).

     ‘preparer’

          a IdentifierPreparer class used to quote
          identifiers.

     ‘supports_alter’

          ‘True’ if the database supports ‘ALTER TABLE’ - used only for
          generating foreign key constraints in certain circumstances

     ‘max_identifier_length’

          The maximum length of identifier names.

     ‘supports_sane_rowcount’

          Indicate whether the dialect properly implements rowcount for
          ‘UPDATE’ and ‘DELETE’ statements.

     ‘supports_sane_multi_rowcount’

          Indicate whether the dialect properly implements rowcount for
          ‘UPDATE’ and ‘DELETE’ statements when executed via
          executemany.

     ‘preexecute_autoincrement_sequences’

          True if ‘implicit’ primary key functions must be executed
          separately in order to get their value.  This is currently
          oriented towards PostgreSQL.

     ‘implicit_returning’

          use RETURNING or equivalent during INSERT execution in order
          to load newly generated primary keys and other column defaults
          in one execution, which are then available via
          inserted_primary_key.  If an insert statement has returning()
          specified explicitly, the “implicit” functionality is not used
          and inserted_primary_key will not be available.

     ‘colspecs’

          A dictionary of TypeEngine classes from sqlalchemy.types
          mapped to subclasses that are specific to the dialect class.
          This dictionary is class-level only and is not accessed from
          the dialect instance itself.

     ‘supports_default_values’

          Indicates if the construct ‘INSERT INTO tablename DEFAULT
          VALUES’ is supported

     ‘supports_sequences’

          Indicates if the dialect supports CREATE SEQUENCE or similar.

     ‘sequences_optional’

          If True, indicates if the “optional” flag on the Sequence()
          construct should signal to not generate a CREATE SEQUENCE.
          Applies only to dialects that support sequences.  Currently
          used only to allow PostgreSQL SERIAL to be used on a column
          that specifies Sequence() for usage on other backends.

     ‘supports_native_enum’

          Indicates if the dialect supports a native ENUM construct.
          This will prevent types.Enum from generating a CHECK
          constraint when that type is used.

     ‘supports_native_boolean’

          Indicates if the dialect supports a native boolean construct.
          This will prevent types.Boolean from generating a CHECK
          constraint when that type is used.

     ‘dbapi_exception_translation_map’

          A dictionary of names that will contain as values the names of
          pep-249 exceptions (“IntegrityError”, “OperationalError”, etc)
          keyed to alternate class names, to support the case where a
          DBAPI has exception classes that aren’t named as they are
          referred to (e.g.  IntegrityError = MyException).  In the vast
          majority of cases this dictionary is empty.

          New in version 1.0.5.

      -- Method: sqlalchemy.engine.Dialect..connect (*cargs,
               **cparams)

          Establish a connection using this dialect’s DBAPI.

          The default implementation of this method is:

               def connect(self, *cargs, **cparams):
                   return self.dbapi.connect(*cargs, **cparams)

          The ‘*cargs, **cparams’ parameters are generated directly from
          this dialect’s Dialect.create_connect_args()
          method.

          This method may be used for dialects that need to perform
          programmatic per-connection steps when a new connection is
          procured from the DBAPI.

          Parameters:

             * ‘*cargs’ – positional parameters returned from the
               Dialect.create_connect_args() method

             * ‘**cparams’ – keyword parameters returned from the
               Dialect.create_connect_args() method.

          Returns: a DBAPI connection, typically from the PEP 249(2)
          module level ‘.connect()’ function.

          See also
          ........

          See Dialect.create_connect_args().

          See Dialect.on_connect().

      -- Method: sqlalchemy.engine.Dialect..
               create_connect_args (url)

          Build DB-API compatible connection arguments.

          Given a URL object, returns a tuple consisting of
          a ‘(*args, **kwargs)’ suitable to send directly to the dbapi’s
          connect function.  The arguments are sent to the
          Dialect.connect() method which then runs the
          DBAPI-level ‘connect()’ function.

          The method typically makes use of the
          URL.translate_connect_args() method in order to
          generate a dictionary of options.

          The default implementation is:

               def create_connect_args(self, url):
                   opts = url.translate_connect_args()
                   opts.update(url.query)
                   return [[], opts]

          Parameters: ‘url’ – a URL object

          Returns: a tuple of ‘(*args, **kwargs)’ which will be passed
          to the Dialect.connect() method.

          See also
          ........

          See URL.translate_connect_args().

      -- Method: sqlalchemy.engine.Dialect..create_xid ()

          Create a two-phase transaction ID.

          This id will be passed to do_begin_twophase(),
          do_rollback_twophase(), do_commit_twophase().  Its format is
          unspecified.

      -- Method: sqlalchemy.engine.Dialect..denormalize_name
               (name)

          convert the given name to a case insensitive identifier for
          the backend if it is an all-lowercase name.

          This method is only used if the dialect defines
          requires_name_normalize=True.

      -- Method: sqlalchemy.engine.Dialect..do_begin
               (dbapi_connection)

          Provide an implementation of ‘connection.begin()’, given a
          DB-API connection.

          The DBAPI has no dedicated “begin” method and it is expected
          that transactions are implicit.  This hook is provided for
          those DBAPIs that might need additional help in this area.

          Note that Dialect.do_begin() is not called unless
          a Transaction object is in use.  The
          ‘Dialect.do_autocommit()’ hook is provided for DBAPIs that
          need some extra commands emitted after a commit in order to
          enter the next transaction, when the SQLAlchemy
          Connection is used in its default “autocommit” mode.

          Parameters: ‘dbapi_connection’ – a DBAPI connection, typically
          proxied within a ‘ConnectionFairy’.

      -- Method: sqlalchemy.engine.Dialect..
               do_begin_twophase (connection, xid)

          Begin a two phase transaction on the given connection.

          Parameters:

             * ‘connection’ – a Connection.

             * ‘xid’ – xid

      -- Method: sqlalchemy.engine.Dialect..do_close
               (dbapi_connection)

          Provide an implementation of ‘connection.close()’, given a
          DBAPI connection.

          This hook is called by the Pool when a connection
          has been detached from the pool, or is being returned beyond
          the normal capacity of the pool.

      -- Method: sqlalchemy.engine.Dialect..do_commit
               (dbapi_connection)

          Provide an implementation of ‘connection.commit()’, given a
          DB-API connection.

          Parameters: ‘dbapi_connection’ – a DBAPI connection, typically
          proxied within a ‘ConnectionFairy’.

      -- Method: sqlalchemy.engine.Dialect..
               do_commit_twophase (connection, xid,
               is_prepared=True, recover=False)

          Commit a two phase transaction on the given connection.

          Parameters:

             * ‘connection’ – a Connection.

             * ‘xid’ – xid

             * ‘is_prepared’ – whether or not
               TwoPhaseTransaction.prepare() was called.

             * ‘recover’ – if the recover flag was passed.

      -- Method: sqlalchemy.engine.Dialect..do_execute
               (cursor, statement, parameters, context=None)

          Provide an implementation of ‘cursor.execute(statement,
          parameters)’.

      -- Method: sqlalchemy.engine.Dialect..
               do_execute_no_params (cursor, statement, parameters,
               context=None)

          Provide an implementation of ‘cursor.execute(statement)’.

          The parameter collection should not be sent.

      -- Method: sqlalchemy.engine.Dialect..do_executemany
               (cursor, statement, parameters, context=None)

          Provide an implementation of ‘cursor.executemany(statement,
          parameters)’.

      -- Method: sqlalchemy.engine.Dialect..
               do_prepare_twophase (connection, xid)

          Prepare a two phase transaction on the given connection.

          Parameters:

             * ‘connection’ – a Connection.

             * ‘xid’ – xid

      -- Method: sqlalchemy.engine.Dialect..
               do_recover_twophase (connection)

          Recover list of uncommitted prepared two phase transaction
          identifiers on the given connection.

          Parameters: ‘connection’ – a Connection.

      -- Method: sqlalchemy.engine.Dialect..
               do_release_savepoint (connection, name)

          Release the named savepoint on a connection.

          Parameters:

             * ‘connection’ – a Connection.

             * ‘name’ – savepoint name.

      -- Method: sqlalchemy.engine.Dialect..do_rollback
               (dbapi_connection)

          Provide an implementation of ‘connection.rollback()’, given a
          DB-API connection.

          Parameters: ‘dbapi_connection’ – a DBAPI connection, typically
          proxied within a ‘ConnectionFairy’.

      -- Method: sqlalchemy.engine.Dialect..
               do_rollback_to_savepoint (connection, name)

          Rollback a connection to the named savepoint.

          Parameters:

             * ‘connection’ – a Connection.

             * ‘name’ – savepoint name.

      -- Method: sqlalchemy.engine.Dialect..
               do_rollback_twophase (connection, xid,
               is_prepared=True, recover=False)

          Rollback a two phase transaction on the given connection.

          Parameters:

             * ‘connection’ – a Connection.

             * ‘xid’ – xid

             * ‘is_prepared’ – whether or not
               TwoPhaseTransaction.prepare() was called.

             * ‘recover’ – if the recover flag was passed.

      -- Method: sqlalchemy.engine.Dialect..do_savepoint
               (connection, name)

          Create a savepoint with the given name.

          Parameters:

             * ‘connection’ – a Connection.

             * ‘name’ – savepoint name.

      -- Method: sqlalchemy.engine.Dialect..
               do_set_input_sizes (cursor, list_of_tuples, context)

          invoke the cursor.setinputsizes() method with appropriate
          arguments

          This hook is called if the dialect.use_inputsizes flag is set
          to True.  Parameter data is passed in a list of tuples
          (paramname, dbtype, sqltype), where ‘paramname’ is the key of
          the parameter in the statement, ‘dbtype’ is the DBAPI datatype
          and ‘sqltype’ is the SQLAlchemy type.  The order of tuples is
          in the correct parameter order.

          New in version 1.4.

      -- Method: sqlalchemy.engine.Dialect..classmethod
               engine_created (engine)

          A convenience hook called before returning the final
          Engine.

          If the dialect returned a different class from the
          get_dialect_cls() method, then the hook is called on
          both classes, first on the dialect class returned by the
          get_dialect_cls() method and then on the class on which
          the method was called.

          The hook should be used by dialects and/or wrappers to apply
          special events to the engine or its components.  In
          particular, it allows a dialect-wrapping class to apply
          dialect-level events.

          New in version 1.0.3.

      -- Method: sqlalchemy.engine.Dialect..
               get_check_constraints (connection, table_name,
               schema=None, **kw)

          Return information about check constraints in ‘table_name’.

          Given a string ‘table_name’ and an optional string ‘schema’,
          return check constraint information as a list of dicts with
          these keys:

             * ‘name’ - the check constraint’s name

             * ‘sqltext’ - the check constraint’s SQL expression

             * ‘**kw’ - other options passed to the dialect’s
               get_check_constraints() method.

          New in version 1.1.0.

      -- Method: sqlalchemy.engine.Dialect..get_columns
               (connection, table_name, schema=None, **kw)

          Return information about columns in ‘table_name’.

          Given a Connection, a string ‘table_name’, and an
          optional string ‘schema’, return column information as a list
          of dictionaries with these keys:

          name

               the column’s name

          type

               [sqlalchemy.types#TypeEngine]

          nullable

               boolean

          default

               the column’s default value

          autoincrement

               boolean

          sequence

               a dictionary of the form

                    {‘name’ : str, ‘start’ :int, ‘increment’: int, ‘minvalue’: int,

                         ‘maxvalue’: int, ‘nominvalue’: bool,
                         ‘nomaxvalue’: bool, ‘cycle’: bool, ‘cache’:
                         int, ‘order’: bool}

          Additional column attributes may be present.

      -- Method: sqlalchemy.engine.Dialect..
               get_default_isolation_level (dbapi_conn)

          Given a DBAPI connection, return its isolation level, or a
          default isolation level if one cannot be retrieved.

          This method may only raise NotImplementedError and `must not
          raise any other exception', as it is used implicitly upon
          first connect.

          The method `must return a value' for a dialect that supports
          isolation level settings, as this level is what will be
          reverted towards when a per-connection isolation level change
          is made.

          The method defaults to using the
          Dialect.get_isolation_level() method unless overridden
          by a dialect.

          New in version 1.3.22.

      -- Method: sqlalchemy.engine.Dialect..classmethod
               get_dialect_cls (url)

          Given a URL, return the Dialect that will be
          used.

          This is a hook that allows an external plugin to provide
          functionality around an existing dialect, by allowing the
          plugin to be loaded from the url based on an entrypoint, and
          then the plugin returns the actual dialect to be used.

          By default this just returns the cls.

          New in version 1.0.3.

      -- Method: sqlalchemy.engine.Dialect..get_foreign_keys
               (connection, table_name, schema=None, **kw)

          Return information about foreign_keys in ‘table_name’.

          Given a Connection, a string ‘table_name’, and an
          optional string ‘schema’, return foreign key information as a
          list of dicts with these keys:

          name

               the constraint’s name

          constrained_columns

               a list of column names that make up the foreign key

          referred_schema

               the name of the referred schema

          referred_table

               the name of the referred table

          referred_columns

               a list of column names in the referred table that
               correspond to constrained_columns

      -- Method: sqlalchemy.engine.Dialect..get_indexes
               (connection, table_name, schema=None, **kw)

          Return information about indexes in ‘table_name’.

          Given a Connection, a string ‘table_name’ and an
          optional string ‘schema’, return index information as a list
          of dictionaries with these keys:

          name

               the index’s name

          column_names

               list of column names in order

          unique

               boolean

      -- Method: sqlalchemy.engine.Dialect..
               get_isolation_level (dbapi_conn)

          Given a DBAPI connection, return its isolation level.

          When working with a Connection object, the
          corresponding DBAPI connection may be procured using the
          Connection.connection accessor.

          Note that this is a dialect-level method which is used as part
          of the implementation of the Connection and
          Engine isolation level facilities; these APIs should be
          preferred for most typical use cases.

          See also
          ........

          See Connection.get_isolation_level(). - view current
          level

          See Connection.default_isolation_level. - view default
          level

          See Connection.execution_options.isolation_level. -
          set per Connection isolation level

          See create_engine.isolation_level. - set per
          Engine isolation level

      -- Method: sqlalchemy.engine.Dialect..
               get_pk_constraint (connection, table_name,
               schema=None, **kw)

          Return information about the primary key constraint on
          table_name‘.

          Given a Connection, a string ‘table_name’, and an
          optional string ‘schema’, return primary key information as a
          dictionary with these keys:

          constrained_columns

               a list of column names that make up the primary key

          name

               optional name of the primary key constraint.

      -- Method: sqlalchemy.engine.Dialect..
               get_sequence_names (connection, schema=None, **kw)

          Return a list of all sequence names available in the database.

          Parameters: ‘schema’ – schema name to query, if not the
          default schema.

          New in version 1.4.

      -- Method: sqlalchemy.engine.Dialect..
               get_table_comment (connection, table_name,
               schema=None, **kw)

          Return the “comment” for the table identified by ‘table_name’.

          Given a string ‘table_name’ and an optional string ‘schema’,
          return table comment information as a dictionary with this
          key:

          text

               text of the comment

          Raises ‘NotImplementedError’ for dialects that don’t support
          comments.

          New in version 1.2.

      -- Method: sqlalchemy.engine.Dialect..get_table_names
               (connection, schema=None, **kw)

          Return a list of table names for ‘schema’.

      -- Method: sqlalchemy.engine.Dialect..
               get_temp_table_names (connection, schema=None, **kw)

          Return a list of temporary table names on the given
          connection, if supported by the underlying backend.

      -- Method: sqlalchemy.engine.Dialect..
               get_temp_view_names (connection, schema=None, **kw)

          Return a list of temporary view names on the given connection,
          if supported by the underlying backend.

      -- Method: sqlalchemy.engine.Dialect..
               get_unique_constraints (connection, table_name,
               schema=None, **kw)

          Return information about unique constraints in ‘table_name’.

          Given a string ‘table_name’ and an optional string ‘schema’,
          return unique constraint information as a list of dicts with
          these keys:

          name

               the unique constraint’s name

          column_names

               list of column names in order

          **kw

               other options passed to the dialect’s
               get_unique_constraints() method.

          New in version 0.9.0.

      -- Method: sqlalchemy.engine.Dialect..
               get_view_definition (connection, view_name,
               schema=None, **kw)

          Return view definition.

          Given a Connection, a string ‘view_name’, and an
          optional string ‘schema’, return the view definition.

      -- Method: sqlalchemy.engine.Dialect..get_view_names
               (connection, schema=None, **kw)

          Return a list of all view names available in the database.

          Parameters: ‘schema’ – schema name to query, if not the
          default schema.

      -- Method: sqlalchemy.engine.Dialect..has_index
               (connection, table_name, index_name, schema=None)

          Check the existence of a particular index name in the
          database.

          Given a Connection object, a string ‘table_name’
          and string index name, return True if an index of the given
          name on the given table exists, false otherwise.

          The DefaultDialect implements this in terms of
          the Dialect.has_table() and
          Dialect.get_indexes() methods, however dialects can
          implement a more performant version.

          New in version 1.4.

      -- Method: sqlalchemy.engine.Dialect..has_sequence
               (connection, sequence_name, schema=None, **kw)

          Check the existence of a particular sequence in the database.

          Given a Connection object and a string
          ‘sequence_name’, return True if the given sequence exists in
          the database, False otherwise.

      -- Method: sqlalchemy.engine.Dialect..has_table
               (connection, table_name, schema=None, **kw)

          Check the existence of a particular table in the database.

          Given a Connection object and a string
          ‘table_name’, return True if the given table (possibly within
          the specified ‘schema’) exists in the database, False
          otherwise.

      -- Method: sqlalchemy.engine.Dialect..initialize
               (connection)

          Called during strategized creation of the dialect with a
          connection.

          Allows dialects to configure options based on server version
          info or other properties.

          The connection passed here is a SQLAlchemy Connection object,
          with full capabilities.

          The initialize() method of the base dialect should be called
          via super().

               Note: as of SQLAlchemy 1.4, this method is called
               `before' any Dialect.on_connect() hooks are
               called.

      -- Method: sqlalchemy.engine.Dialect..is_disconnect
               (e, connection, cursor)

          Return True if the given DB-API error indicates an invalid
          connection

      -- Method: sqlalchemy.engine.Dialect..classmethod
               load_provisioning ()

          set up the provision.py module for this dialect.

          For dialects that include a provision.py module that sets up
          provisioning followers, this method should initiate that
          process.

          A typical implementation would be:

               @classmethod
               def load_provisioning(cls):
                   __import__("mydialect.provision")

          The default method assumes a module named ‘provision.py’
          inside the owning package of the current dialect, based on the
          ‘__module__’ attribute:

               @classmethod
               def load_provisioning(cls):
                   package = ".".join(cls.__module__.split(".")[0:-1])
                   try:
                       __import__(package + ".provision")
                   except ImportError:
                       pass

          New in version 1.3.14.

      -- Method: sqlalchemy.engine.Dialect..normalize_name
               (name)

          convert the given name to lowercase if it is detected as case
          insensitive.

          This method is only used if the dialect defines
          requires_name_normalize=True.

      -- Method: sqlalchemy.engine.Dialect..on_connect ()

          return a callable which sets up a newly created DBAPI
          connection.

          The callable should accept a single argument “conn” which is
          the DBAPI connection itself.  The inner callable has no return
          value.

          E.g.:

               class MyDialect(default.DefaultDialect):
                   # ...

                   def on_connect(self):
                       def do_on_connect(connection):
                           connection.execute("SET SPECIAL FLAGS etc")

                       return do_on_connect

          This is used to set dialect-wide per-connection options such
          as isolation modes, Unicode modes, etc.

          The “do_on_connect” callable is invoked by using the
          PoolEvents.connect() event hook, then unwrapping the
          DBAPI connection and passing it into the callable.

          Changed in version 1.4: the on_connect hook is no longer
          called twice for the first connection of a dialect.  The
          on_connect hook is still called before the
          Dialect.initialize() method however.

          If None is returned, no event listener is generated.

          Returns: a callable that accepts a single DBAPI connection as
          an argument, or None.

          See also
          ........

          See Dialect.connect(). - allows the DBAPI ‘connect()’
          sequence itself to be controlled.

      -- Method: sqlalchemy.engine.Dialect..
               reset_isolation_level (dbapi_conn)

          Given a DBAPI connection, revert its isolation to the default.

          Note that this is a dialect-level method which is used as part
          of the implementation of the Connection and
          Engine isolation level facilities; these APIs should be
          preferred for most typical use cases.

          See also
          ........

          See Connection.get_isolation_level(). - view current
          level

          See Connection.default_isolation_level. - view default
          level

          See Connection.execution_options.isolation_level. -
          set per Connection isolation level

          See create_engine.isolation_level. - set per
          Engine isolation level

      -- Method: sqlalchemy.engine.Dialect..
               set_isolation_level (dbapi_conn, level)

          Given a DBAPI connection, set its isolation level.

          Note that this is a dialect-level method which is used as part
          of the implementation of the Connection and
          Engine isolation level facilities; these APIs should be
          preferred for most typical use cases.

          See also
          ........

          See Connection.get_isolation_level(). - view current
          level

          See Connection.default_isolation_level. - view default
          level

          See Connection.execution_options.isolation_level. -
          set per Connection isolation level

          See create_engine.isolation_level. - set per
          Engine isolation level

      -- Method: sqlalchemy.engine.Dialect..classmethod
               type_descriptor (typeobj)

          Transform a generic type to a dialect-specific type.

          Dialect classes will usually use the ‘adapt_type()’ function
          in the types module to accomplish this.

          The returned result is cached `per dialect class' so can
          contain no dialect-instance state.

 -- Class: sqlalchemy.engine.default.DefaultExecutionContext

     `Class signature'

     class sqlalchemy.engine.default.DefaultExecutionContext.
     (‘sqlalchemy.engine.interfaces.ExecutionContext’)

      -- Method:
               sqlalchemy.engine.default.DefaultExecutionContext..
               create_cursor ()

          Return a new cursor generated from this ExecutionContext’s
          connection.

          Some dialects may wish to change the behavior of
          connection.cursor(), such as postgresql which may return a PG
          “server side” cursor.

      -- Attribute:
               sqlalchemy.engine.default.DefaultExecutionContext..
               current_parameters = None

          A dictionary of parameters applied to the current row.

          This attribute is only available in the context of a
          user-defined default generation function, e.g.  as described
          at Context-Sensitive Default Functions.  It
          consists of a dictionary which includes entries for each
          column/value pair that is to be part of the INSERT or UPDATE
          statement.  The keys of the dictionary will be the key value
          of each Column, which is usually synonymous with the
          name.

          Note that the
          DefaultExecutionContext.current_parameters attribute
          does not accommodate for the “multi-values” feature of the
          Insert.values() method.  The
          DefaultExecutionContext.get_current_parameters() method
          should be preferred.

          See also
          ........

          See DefaultExecutionContext.get_current_parameters().

          See Context-Sensitive Default Functions.

      -- Method:
               sqlalchemy.engine.default.DefaultExecutionContext..
               get_current_parameters
               (isolate_multiinsert_groups=True)

          Return a dictionary of parameters applied to the current row.

          This method can only be used in the context of a user-defined
          default generation function, e.g.  as described at
          Context-Sensitive Default Functions.  When invoked, a
          dictionary is returned which includes entries for each
          column/value pair that is part of the INSERT or UPDATE
          statement.  The keys of the dictionary will be the key value
          of each Column, which is usually synonymous with the
          name.

          Parameters: ‘isolate_multiinsert_groups=True’ – indicates that
          multi-valued INSERT constructs created using
          Insert.values() should be handled by returning only the
          subset of parameters that are local to the current column
          default invocation.  When ‘False’, the raw parameters of the
          statement are returned including the naming convention used in
          the case of multi-valued INSERT.

          New in version 1.2: added
          DefaultExecutionContext.get_current_parameters() which
          provides more functionality over the existing
          DefaultExecutionContext.current_parameters attribute.

          See also
          ........

          See DefaultExecutionContext.current_parameters.

          See Context-Sensitive Default Functions.

      -- Method:
               sqlalchemy.engine.default.DefaultExecutionContext..
               get_lastrowid ()

          return self.cursor.lastrowid, or equivalent, after an INSERT.

          This may involve calling special cursor functions, issuing a
          new SELECT on the cursor (or a new one), or returning a stored
          value that was calculated within post_exec().

          This function will only be called for dialects which support
          “implicit” primary key generation, keep
          preexecute_autoincrement_sequences set to False, and when no
          explicit id value was bound to the statement.

          The function is called once for an INSERT statement that would
          need to return the last inserted primary key for those
          dialects that make use of the lastrowid concept.  In these
          cases, it is called directly after
          ExecutionContext.post_exec().

      -- Method:
               sqlalchemy.engine.default.DefaultExecutionContext..
               get_out_parameter_values (names)

          Return a sequence of OUT parameter values from a cursor.

          For dialects that support OUT parameters, this method will be
          called when there is a SQLCompiler object which
          has the SQLCompiler.has_out_parameters flag set.
          This flag in turn will be set to True if the statement itself
          has BindParameter objects that have the
          ‘.isoutparam’ flag set which are consumed by the
          ‘SQLCompiler.visit_bindparam()’ method.  If the dialect
          compiler produces BindParameter objects with
          ‘.isoutparam’ set which are not handled by
          ‘SQLCompiler.visit_bindparam()’, it should set this flag
          explicitly.

          The list of names that were rendered for each bound parameter
          is passed to the method.  The method should then return a
          sequence of values corresponding to the list of parameter
          objects.  Unlike in previous SQLAlchemy versions, the values
          can be the `raw values' from the DBAPI; the execution context
          will apply the appropriate type handler based on what’s
          present in self.compiled.binds and update the values.  The
          processed dictionary will then be made available via the
          ‘.out_parameters’ collection on the result object.  Note that
          SQLAlchemy 1.4 has multiple kinds of result object as part of
          the 2.0 transition.

          New in version 1.4: - added
          ExecutionContext.get_out_parameter_values(), which is
          invoked automatically by the DefaultExecutionContext
          when there are BindParameter objects with
          the ‘.isoutparam’ flag set.  This replaces the practice of
          setting out parameters within the now-removed
          ‘get_result_proxy()’ method.

          See also
          ........

          See ExecutionContext.get_result_cursor_strategy().

      -- Method:
               sqlalchemy.engine.default.DefaultExecutionContext..
               get_result_processor (type_, colname, coltype)

          Return a ‘result processor’ for a given type as present in
          cursor.description.

          This has a default implementation that dialects can override
          for context-sensitive result type handling.

      -- Method:
               sqlalchemy.engine.default.DefaultExecutionContext..
               handle_dbapi_exception (e)

          Receive a DBAPI exception which occurred upon execute, result
          fetch, etc.

      -- Method:
               sqlalchemy.engine.default.DefaultExecutionContext..
               lastrow_has_defaults ()

          Return True if the last INSERT or UPDATE row contained inlined
          or database-side defaults.

      -- Method:
               sqlalchemy.engine.default.DefaultExecutionContext..
               post_exec ()

          Called after the execution of a compiled statement.

          If a compiled statement was passed to this ExecutionContext,
          the ‘last_insert_ids’, ‘last_inserted_params’, etc.
          datamembers should be available after this method completes.

      -- Method:
               sqlalchemy.engine.default.DefaultExecutionContext..
               pre_exec ()

          Called before an execution of a compiled statement.

          If a compiled statement was passed to this ExecutionContext,
          the ‘statement’ and ‘parameters’ datamembers must be
          initialized after this statement is complete.

      -- Method:
               sqlalchemy.engine.default.DefaultExecutionContext..
               should_autocommit_text (statement)

          Parse the given textual statement and return True if it refers
          to a “committable” statement

 -- Class: sqlalchemy.engine.ExecutionContext

     A messenger object for a Dialect that corresponds to a single
     execution.

     ExecutionContext should have these data members:

     connection

          Connection object which can be freely used by default value
          generators to execute SQL. This Connection should reference
          the same underlying connection/transactional resources of
          root_connection.

     root_connection

          Connection object which is the source of this
          ExecutionContext.  This Connection may have
          close_with_result=True set, in which case it can only be used
          once.

     dialect

          dialect which created this ExecutionContext.

     cursor

          DB-API cursor procured from the connection,

     compiled

          if passed to constructor, sqlalchemy.engine.base.Compiled
          object being executed,

     statement

          string version of the statement to be executed.  Is either
          passed to the constructor, or must be created from the
          sql.Compiled object by the time pre_exec() has completed.

     parameters

          bind parameters passed to the execute() method.  For compiled
          statements, this is a dictionary or list of dictionaries.  For
          textual statements, it should be in a format suitable for the
          dialect’s paramstyle (i.e.  dict or list of dicts for non
          positional, list or list of lists/tuples for positional).

     isinsert

          True if the statement is an INSERT.

     isupdate

          True if the statement is an UPDATE.

     should_autocommit

          True if the statement is a “committable” statement.

     prefetch_cols

          a list of Column objects for which a client-side default was
          fired off.  Applies to inserts and updates.

     postfetch_cols

          a list of Column objects for which a server-side default or
          inline SQL expression value was fired off.  Applies to inserts
          and updates.

      -- Method: sqlalchemy.engine.ExecutionContext..
               create_cursor ()

          Return a new cursor generated from this ExecutionContext’s
          connection.

          Some dialects may wish to change the behavior of
          connection.cursor(), such as postgresql which may return a PG
          “server side” cursor.

      -- Method: sqlalchemy.engine.ExecutionContext..
               get_out_parameter_values (out_param_names)

          Return a sequence of OUT parameter values from a cursor.

          For dialects that support OUT parameters, this method will be
          called when there is a SQLCompiler object which
          has the SQLCompiler.has_out_parameters flag set.
          This flag in turn will be set to True if the statement itself
          has BindParameter objects that have the
          ‘.isoutparam’ flag set which are consumed by the
          ‘SQLCompiler.visit_bindparam()’ method.  If the dialect
          compiler produces BindParameter objects with
          ‘.isoutparam’ set which are not handled by
          ‘SQLCompiler.visit_bindparam()’, it should set this flag
          explicitly.

          The list of names that were rendered for each bound parameter
          is passed to the method.  The method should then return a
          sequence of values corresponding to the list of parameter
          objects.  Unlike in previous SQLAlchemy versions, the values
          can be the `raw values' from the DBAPI; the execution context
          will apply the appropriate type handler based on what’s
          present in self.compiled.binds and update the values.  The
          processed dictionary will then be made available via the
          ‘.out_parameters’ collection on the result object.  Note that
          SQLAlchemy 1.4 has multiple kinds of result object as part of
          the 2.0 transition.

          New in version 1.4: - added
          ExecutionContext.get_out_parameter_values(), which is
          invoked automatically by the DefaultExecutionContext
          when there are BindParameter objects with
          the ‘.isoutparam’ flag set.  This replaces the practice of
          setting out parameters within the now-removed
          ‘get_result_proxy()’ method.

          See also
          ........

          See ExecutionContext.get_result_cursor_strategy().

      -- Method: sqlalchemy.engine.ExecutionContext..
               get_result_cursor_strategy (result)

          Return a result cursor strategy for a given result object.

          This method is implemented by the DefaultDialect
          and is only needed by implementing dialects in the case where
          some special steps regarding the cursor must be taken, such as
          manufacturing fake results from some other element of the
          cursor, or pre-buffering the cursor’s results.

          A simplified version of the default implementation is:

               from sqlalchemy.engine.result import DefaultCursorFetchStrategy

               class MyExecutionContext(DefaultExecutionContext):
                   def get_result_cursor_strategy(self, result):
                       return DefaultCursorFetchStrategy.create(result)

          Above, the ‘DefaultCursorFetchStrategy’ will be applied to the
          result object.  For results that are pre-buffered from a
          cursor that might be closed, an implementation might be:

               from sqlalchemy.engine.result import (
                   FullyBufferedCursorFetchStrategy
               )

               class MyExecutionContext(DefaultExecutionContext):
                   _pre_buffered_result = None

                   def pre_exec(self):
                       if self.special_condition_prebuffer_cursor():
                           self._pre_buffered_result = (
                               self.cursor.description,
                               self.cursor.fetchall()
                           )

                   def get_result_cursor_strategy(self, result):
                       if self._pre_buffered_result:
                           description, cursor_buffer = self._pre_buffered_result
                           return (
                               FullyBufferedCursorFetchStrategy.
                                   create_from_buffer(
                                       result, description, cursor_buffer
                               )
                           )
                       else:
                           return DefaultCursorFetchStrategy.create(result)

          This method replaces the previous not-quite-documented
          ‘get_result_proxy()’ method.

          New in version 1.4: - result objects now interpret cursor
          results based on a pluggable “strategy” object, which is
          delivered by the ExecutionContext via the
          ExecutionContext.get_result_cursor_strategy() method.

          See also
          ........

          See ExecutionContext.get_out_parameter_values().

      -- Method: sqlalchemy.engine.ExecutionContext..
               get_rowcount ()

          Return the DBAPI ‘cursor.rowcount’ value, or in some cases an
          interpreted value.

          See CursorResult.rowcount for details on this.

      -- Method: sqlalchemy.engine.ExecutionContext..
               handle_dbapi_exception (e)

          Receive a DBAPI exception which occurred upon execute, result
          fetch, etc.

      -- Method: sqlalchemy.engine.ExecutionContext..
               lastrow_has_defaults ()

          Return True if the last INSERT or UPDATE row contained inlined
          or database-side defaults.

      -- Method: sqlalchemy.engine.ExecutionContext..
               post_exec ()

          Called after the execution of a compiled statement.

          If a compiled statement was passed to this ExecutionContext,
          the ‘last_insert_ids’, ‘last_inserted_params’, etc.
          datamembers should be available after this method completes.

      -- Method: sqlalchemy.engine.ExecutionContext..
               pre_exec ()

          Called before an execution of a compiled statement.

          If a compiled statement was passed to this ExecutionContext,
          the ‘statement’ and ‘parameters’ datamembers must be
          initialized after this statement is complete.

      -- Method: sqlalchemy.engine.ExecutionContext..
               should_autocommit_text (statement)

          Parse the given textual statement and return True if it refers
          to a “committable” statement

 -- Class: sqlalchemy.sql.compiler.GenericTypeCompiler (dialect)

     `Class signature'

     class sqlalchemy.sql.compiler.GenericTypeCompiler.
     (‘sqlalchemy.sql.compiler.TypeCompiler’)

 -- Class: sqlalchemy.log.Identified

 -- Class: sqlalchemy.sql.compiler.IdentifierPreparer (dialect,
          initial_quote='"', final_quote=None, escape_quote='"',
          quote_case_sensitive_collations=True, omit_schema=False)

     Handle quoting and case-folding of identifiers based on options.

      -- Method: sqlalchemy.sql.compiler.IdentifierPreparer..
               __init__ (dialect, initial_quote='"',
               final_quote=None, escape_quote='"',
               quote_case_sensitive_collations=True, omit_schema=False)

          Construct a new ‘IdentifierPreparer’ object.

          initial_quote

               Character that begins a delimited identifier.

          final_quote

               Character that ends a delimited identifier.  Defaults to
               ‘initial_quote’.

          omit_schema

               Prevent prepending schema name.  Useful for databases
               that do not support schemae.

      -- Method: sqlalchemy.sql.compiler.IdentifierPreparer..
               format_column (column, use_table=False, name=None,
               table_name=None, use_schema=False)

          Prepare a quoted column name.

      -- Method: sqlalchemy.sql.compiler.IdentifierPreparer..
               format_schema (name)

          Prepare a quoted schema name.

      -- Method: sqlalchemy.sql.compiler.IdentifierPreparer..
               format_table (table, use_schema=True, name=None)

          Prepare a quoted table and schema name.

      -- Method: sqlalchemy.sql.compiler.IdentifierPreparer..
               format_table_seq (table, use_schema=True)

          Format table name and schema as a tuple.

      -- Method: sqlalchemy.sql.compiler.IdentifierPreparer..
               quote (ident, force=None)

          Conditionally quote an identifier.

          The identifier is quoted if it is a reserved word, contains
          quote-necessary characters, or is an instance of
          quoted_name which includes ‘quote’ set to ‘True’.

          Subclasses can override this to provide database-dependent
          quoting behavior for identifier names.

          Parameters:

             * ‘ident’ – string identifier

             * ‘force’ – unused

               Deprecated since version 0.9: The
               IdentifierPreparer.quote.force parameter is
               deprecated and will be removed in a future release.  This
               flag has no effect on the behavior of the
               IdentifierPreparer.quote() method; please refer to
               quoted_name.

      -- Method: sqlalchemy.sql.compiler.IdentifierPreparer..
               quote_identifier (value)

          Quote an identifier.

          Subclasses should override this to provide database-dependent
          quoting behavior.

      -- Method: sqlalchemy.sql.compiler.IdentifierPreparer..
               quote_schema (schema, force=None)

          Conditionally quote a schema name.

          The name is quoted if it is a reserved word, contains
          quote-necessary characters, or is an instance of
          quoted_name which includes ‘quote’ set to ‘True’.

          Subclasses can override this to provide database-dependent
          quoting behavior for schema names.

          Parameters:

             * ‘schema’ – string schema name

             * ‘force’ – unused

               Deprecated since version 0.9: The
               IdentifierPreparer.quote_schema.force parameter is
               deprecated and will be removed in a future release.  This
               flag has no effect on the behavior of the
               IdentifierPreparer.quote() method; please refer to
               quoted_name.

      -- Attribute: sqlalchemy.sql.compiler.IdentifierPreparer..
               schema_for_object = operator.attrgetter('schema')

          Return the .schema attribute for an object.

          For the default IdentifierPreparer, the schema for an object
          is always the value of the “.schema” attribute.  if the
          preparer is replaced with one that has a non-empty
          schema_translate_map, the value of the “.schema” attribute is
          rendered a symbol that will be converted to a real schema name
          from the mapping post-compile.

      -- Method: sqlalchemy.sql.compiler.IdentifierPreparer..
               unformat_identifiers (identifiers)

          Unpack ‘schema.table.column’-like strings into components.

      -- Method: sqlalchemy.sql.compiler.IdentifierPreparer..
               validate_sql_phrase (element, reg)

          keyword sequence filter.

          a filter for elements that are intended to represent keyword
          sequences, such as “INITIALLY”, “INITIALLY DEFERRED”, etc.  no
          special characters should be present.

          New in version 1.3.

 -- Class: sqlalchemy.sql.compiler.SQLCompiler (dialect, statement,
          cache_key=None, column_keys=None, for_executemany=False,
          linting=symbol('NO_LINTING'), **kwargs)

     Default implementation of Compiled.

     Compiles ClauseElement objects into SQL strings.

     `Class signature'

     class sqlalchemy.sql.compiler.SQLCompiler.
     (‘sqlalchemy.sql.compiler.Compiled’)

      -- Method: sqlalchemy.sql.compiler.SQLCompiler..
               __init__ (dialect, statement, cache_key=None,
               column_keys=None, for_executemany=False,
               linting=symbol('NO_LINTING'), **kwargs)

          Construct a new SQLCompiler object.

          Parameters:

             * ‘dialect’ – see Dialect to be used

             * ‘statement’ – see ClauseElement to be compiled

             * ‘column_keys’ – a list of column names to be compiled
               into an INSERT or UPDATE statement.

             * ‘for_executemany’ – whether INSERT / UPDATE statements
               should expect that they are to be invoked in an
               “executemany” style, which may impact how the statement
               will be expected to return the values of defaults and
               autoincrement / sequences and similar.  Depending on the
               backend and driver in use, support for retrieving these
               values may be disabled which means SQL expressions may be
               rendered inline, RETURNING may not be rendered, etc.

             * ‘kwargs’ – additional keyword arguments to be consumed by
               the superclass.

      -- Attribute: sqlalchemy.sql.compiler.SQLCompiler..
               ansi_bind_rules = False

          SQL 92 doesn’t allow bind parameters to be used in the columns
          clause of a SELECT, nor does it allow ambiguous expressions
          like “?  = ?”.  A compiler subclass can set this flag to False
          if the target driver/DB enforces this

      -- Method: sqlalchemy.sql.compiler.SQLCompiler..
               construct_params (params=None, _group_number=None,
               _check=True, extracted_parameters=None)

          return a dictionary of bind parameter keys and values

      -- Attribute: sqlalchemy.sql.compiler.SQLCompiler..
               current_executable

          Return the current ‘executable’ that is being compiled.

          This is currently the Select, Insert,
          Update, Delete, CompoundSelect
          object that is being compiled.  Specifically it’s assigned to
          the ‘self.stack’ list of elements.

          When a statement like the above is being compiled, it normally
          is also assigned to the ‘.statement’ attribute of the
          ‘Compiler’ object.  However, all SQL constructs are ultimately
          nestable, and this attribute should never be consulted by a
          ‘visit_’ method, as it is not guaranteed to be assigned nor
          guaranteed to correspond to the current statement being
          compiled.

          New in version 1.3.21: For compatibility with previous
          versions, use the following recipe:

               statement = getattr(self, "current_executable", False)
               if statement is False:
                   statement = self.stack[-1]["selectable"]

          For versions 1.4 and above, ensure only .current_executable is
          used; the format of “self.stack” may change.

      -- Method: sqlalchemy.sql.compiler.SQLCompiler..
               default_from ()

          Called when a SELECT statement has no froms, and no FROM
          clause is to be appended.

          Gives Oracle a chance to tack on a ‘FROM DUAL’ to the string
          output.

      -- Method: sqlalchemy.sql.compiler.SQLCompiler..
               delete_extra_from_clause (update_stmt, from_table,
               extra_froms, from_hints, **kw)

          Provide a hook to override the generation of an DELETE..FROM
          clause.

          This can be used to implement DELETE..USING for example.

          MySQL and MSSQL override this.

      -- Attribute: sqlalchemy.sql.compiler.SQLCompiler..
               escaped_bind_names = {}

          Late escaping of bound parameter names that has to be
          converted to the original name when looking in the parameter
          dictionary.

      -- Method: sqlalchemy.sql.compiler.SQLCompiler..
               get_select_precolumns (select, **kw)

          Called when building a ‘SELECT’ statement, position is just
          before column list.

      -- Method: sqlalchemy.sql.compiler.SQLCompiler..
               group_by_clause (select, **kw)

          allow dialects to customize how GROUP BY is rendered.

      -- Attribute: sqlalchemy.sql.compiler.SQLCompiler..
               has_out_parameters = False

          if True, there are bindparam() objects that have the
          isoutparam flag set.

      -- Attribute: sqlalchemy.sql.compiler.SQLCompiler..
               insert_single_values_expr = None

          When an INSERT is compiled with a single set of parameters
          inside a VALUES expression, the string is assigned here, where
          it can be used for insert batching schemes to rewrite the
          VALUES expression.

          New in version 1.3.8.

      -- Attribute: sqlalchemy.sql.compiler.SQLCompiler..
               isdelete = False

          class-level defaults which can be set at the instance level to
          define if this Compiled instance represents
          INSERT/UPDATE/DELETE

      -- Attribute: sqlalchemy.sql.compiler.SQLCompiler..
               literal_execute_params = frozenset({})

          bindparameter objects that are rendered as literal values at
          statement execution time.

      -- Method: sqlalchemy.sql.compiler.SQLCompiler..
               order_by_clause (select, **kw)

          allow dialects to customize how ORDER BY is rendered.

      -- Attribute: sqlalchemy.sql.compiler.SQLCompiler..
               params

          Return the bind param dictionary embedded into this compiled
          object, for those values that are present.

      -- Attribute: sqlalchemy.sql.compiler.SQLCompiler..
               post_compile_params = frozenset({})

          bindparameter objects that are rendered as bound parameter
          placeholders at statement execution time.

      -- Attribute: sqlalchemy.sql.compiler.SQLCompiler..
               postfetch_lastrowid = False

          if True, and this in insert, use cursor.lastrowid to populate
          result.inserted_primary_key.

      -- Method: sqlalchemy.sql.compiler.SQLCompiler..
               render_literal_value (value, type_)

          Render the value of a bind parameter as a quoted literal.

          This is used for statement sections that do not accept bind
          parameters on the target driver/database.

          This should be implemented by subclasses using the quoting
          services of the DBAPI.

      -- Attribute: sqlalchemy.sql.compiler.SQLCompiler..
               render_table_with_column_in_update_from = False

          set to True classwide to indicate the SET clause in a
          multi-table UPDATE statement should qualify columns with the
          table name (i.e.  MySQL only)

      -- Attribute: sqlalchemy.sql.compiler.SQLCompiler..
               returning = None

          holds the “returning” collection of columns if the statement
          is CRUD and defines returning columns either implicitly or
          explicitly

      -- Attribute: sqlalchemy.sql.compiler.SQLCompiler..
               returning_precedes_values = False

          set to True classwide to generate RETURNING clauses before the
          VALUES or WHERE clause (i.e.  MSSQL)

      -- Attribute: sqlalchemy.sql.compiler.SQLCompiler..
               sql_compiler

      -- Attribute: sqlalchemy.sql.compiler.SQLCompiler..
               translate_select_structure = None

          if not ‘None’, should be a callable which accepts
          ‘(select_stmt, **kw)’ and returns a select object.  this is
          used for structural changes mostly to accommodate for
          LIMIT/OFFSET schemes

      -- Method: sqlalchemy.sql.compiler.SQLCompiler..
               update_from_clause (update_stmt, from_table,
               extra_froms, from_hints, **kw)

          Provide a hook to override the generation of an UPDATE..FROM
          clause.

          MySQL and MSSQL override this.

      -- Method: sqlalchemy.sql.compiler.SQLCompiler..
               update_limit_clause (update_stmt)

          Provide a hook for MySQL to add LIMIT to the UPDATE

      -- Method: sqlalchemy.sql.compiler.SQLCompiler..
               update_tables_clause (update_stmt, from_table,
               extra_froms, **kw)

          Provide a hook to override the initial table clause in an
          UPDATE statement.

          MySQL overrides this.

 -- Class: sqlalchemy.sql.compiler.StrSQLCompiler (dialect, statement,
          cache_key=None, column_keys=None, for_executemany=False,
          linting=symbol('NO_LINTING'), **kwargs)

     A SQLCompiler subclass which allows a small selection
     of non-standard SQL features to render into a string value.

     The StrSQLCompiler is invoked whenever a Core
     expression element is directly stringified without calling upon the
     ClauseElement.compile() method.  It can render a limited
     set of non-standard SQL constructs to assist in basic
     stringification, however for more substantial custom or
     dialect-specific SQL constructs, it will be necessary to make use
     of ClauseElement.compile() directly.

     See also
     ........

     See How do I render SQL expressions as strings, possibly with bound parameters inlined?.

     `Class signature'

     class sqlalchemy.sql.compiler.StrSQLCompiler. (see
     sqlalchemy.sql.compiler.SQLCompiler)

      -- Method: sqlalchemy.sql.compiler.StrSQLCompiler..
               delete_extra_from_clause (update_stmt, from_table,
               extra_froms, from_hints, **kw)

          Provide a hook to override the generation of an DELETE..FROM
          clause.

          This can be used to implement DELETE..USING for example.

          MySQL and MSSQL override this.

      -- Method: sqlalchemy.sql.compiler.StrSQLCompiler..
               update_from_clause (update_stmt, from_table,
               extra_froms, from_hints, **kw)

          Provide a hook to override the generation of an UPDATE..FROM
          clause.

          MySQL and MSSQL override this.

   ---------- Footnotes ----------

   (1) https://www.python.org/dev/peps/pep-0249

   (2) https://www.python.org/dev/peps/pep-0249

4.7 SQLAlchemy 2.0 Future (Core)
================================

This package includes a relatively small number of transitional elements
to allow “2.0 mode” to take place within SQLAlchemy 1.4.  The primary
objects provided here are Engine and Connection,
which are both subclasses of the existing Engine and
Connection objects with essentially a smaller set of methods and
the removal of “autocommit”.

Within the 1.4 series, the “2.0” style of engines and connections is
enabled by passing the create_engine.future flag to
create_engine():

     from sqlalchemy import create_engine
     engine = create_engine("postgresql://user:pass@host/dbname", future=True)

Similarly, with the ORM, to enable “future” behavior in the ORM
Session, pass the Session.future parameter either to the
Session constructor directly, or via the sessionmaker
class:

     from sqlalchemy.orm import sessionmaker

     Session = sessionmaker(engine, future=True)

See also
........

See Migrating to SQLAlchemy 2.0. - Introduction to the 2.0 series
of SQLAlchemy

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See Connection.Provides high-level functionality for a wrapped DB-API connection.

See create_engine.(*arg,Create a new Engine instance.
**kw)

See Engine.Connects a Pool and Dialect together to provide a source of
               database connectivity and behavior.

See select.(*entities)Construct a new Select using the 2.  x style API.

 -- Class: sqlalchemy.future.Connection (engine, connection=None,
          close_with_result=False, _branch_from=None,
          _execution_options=None, _dispatch=None, _has_events=None)

     Provides high-level functionality for a wrapped DB-API connection.

     The Connection object is procured by calling the
     Engine.connect() method of the Engine object, and
     provides services for execution of SQL statements as well as
     transaction control.

     `This is the SQLAlchemy 2.0 version' of the Connection
     class.  The API and behavior of this object is largely the same,
     with the following differences in behavior:

        * The result object returned for results is the
          CursorResult object, which is a subclass of the
          Result.  This object has a slightly different API and
          behavior than the LegacyCursorResult returned for
          1.x style usage.

        * The object has Connection.commit() and
          Connection.rollback() methods which commit or roll back
          the current transaction in progress, if any.

        * The object features “autobegin” behavior, such that any call
          to Connection.execute() will unconditionally start
          a transaction which can be controlled using the above
          mentioned Connection.commit() and
          Connection.rollback() methods.

        * The object does not have any “autocommit” functionality.  Any
          SQL statement or DDL statement will not be followed by any
          COMMIT until the transaction is explicitly committed, either
          via the Connection.commit() method, or if the
          connection is being used in a context manager that commits
          such as the one returned by Engine.begin().

        * The SAVEPOINT method Connection.begin_nested().
          returns a NestedTransaction as was always the
          case, and the savepoint can be controlled by invoking
          NestedTransaction.commit() or
          NestedTransaction.rollback() as was the case before.
          However, this savepoint “transaction” is not associated with
          the transaction that is controlled by the connection itself;
          the overall transaction can be committed or rolled back
          directly which will not emit any special instructions for the
          SAVEPOINT (this will typically have the effect that one
          desires).

        * The Connection object does not support “branching”,
          which was a pattern by which a sub “connection” would be used
          that refers to this connection as a parent.

     `Class signature'

     class sqlalchemy.future.Connection. (see
     sqlalchemy.engine.Connection)

      -- Method: sqlalchemy.future.Connection..begin ()

          Begin a transaction prior to autobegin occurring.

          The Connection.begin() method in SQLAlchemy 2.0
          begins a transaction that normally will be begun in any case
          when the connection is first used to execute a statement.  The
          reason this method might be used would be to invoke the
          ConnectionEvents.begin() event at a specific time, or
          to organize code within the scope of a connection checkout in
          terms of context managed blocks, such as:

               with engine.connect() as conn:
                   with conn.begin():
                       conn.execute(...)
                       conn.execute(...)

                   with conn.begin():
                       conn.execute(...)
                       conn.execute(...)

          The above code is not fundamentally any different in its
          behavior than the following code which does not use
          Connection.begin():

               with engine.connect() as conn:
                   conn.execute(...)
                   conn.execute(...)
                   conn.commit()

                   conn.execute(...)
                   conn.execute(...)
                   conn.commit()

          In both examples, if an exception is raised, the transaction
          will not be committed.  An explicit rollback of the
          transaction will occur, including that the
          ConnectionEvents.rollback() event will be emitted, as
          connection’s context manager will call
          Connection.close(), which will call
          Connection.rollback() for any transaction in place
          (excluding that of a SAVEPOINT).

          From a database point of view, the Connection.begin()
          method does not emit any SQL or change the state of the
          underlying DBAPI connection in any way; the Python DBAPI does
          not have any concept of explicit transaction begin.

          Returns: a Transaction object.  This object
          supports context-manager operation which will commit a
          transaction or emit a rollback in case of error.

          .  If this event is not being used, then there is no real
          effect from invoking Connection.begin() ahead of
          time as the Python DBAPI does not implement any explicit BEGIN

          The returned object is an instance of Transaction.
          This object represents the “scope” of the transaction, which
          completes when either the Transaction.rollback()
          or Transaction.commit() method is called.

          Nested calls to Connection.begin() on the same
          Connection will return new Transaction
          objects that represent an emulated transaction within the
          scope of the enclosing transaction, that is:

               trans = conn.begin()   # outermost transaction
               trans2 = conn.begin()  # "nested"
               trans2.commit()        # does nothing
               trans.commit()         # actually commits

          Calls to Transaction.commit() only have an effect
          when invoked via the outermost Transaction object,
          though the Transaction.rollback() method of any
          of the Transaction objects will roll back the
          transaction.

          See also
          ........

          See Connection.begin_nested(). - use a SAVEPOINT

          ‘Connection.begin_twophase()’ - use a two phase /XID
          transaction

          See Engine.begin(). - context manager available from
          Engine.

      -- Method: sqlalchemy.future.Connection..begin_nested ()

          Begin a nested transaction and return a transaction handle.

          The returned object is an instance of NestedTransaction.

          Nested transactions require SAVEPOINT support in the
          underlying database.  Any transaction in the hierarchy may
          ‘commit’ and ‘rollback’, however the outermost transaction
          still controls the overall ‘commit’ or ‘rollback’ of the
          transaction of a whole.

          In SQLAlchemy 2.0, the NestedTransaction remains
          independent of the Connection object itself.
          Calling the Connection.commit() or
          Connection.rollback() will always affect the actual
          containing database transaction itself, and not the SAVEPOINT
          itself.  When a database transaction is committed, any
          SAVEPOINTs that have been established are cleared and the data
          changes within their scope is also committed.

          See also
          ........

          See Connection.begin().

      -- Method: sqlalchemy.future.Connection..close ()

          Close this Connection.

          This has the effect of also calling
          Connection.rollback() if any transaction is in place.

      -- Method: sqlalchemy.future.Connection..commit ()

          Commit the transaction that is currently in progress.

          This method commits the current transaction if one has been
          started.  If no transaction was started, the method has no
          effect, assuming the connection is in a non-invalidated state.

          A transaction is begun on a Connection
          automatically whenever a statement is first executed, or when
          the Connection.begin() method is called.

               Note: The Connection.commit() method only acts
               upon the primary database transaction that is linked to
               the Connection object.  It does not operate
               upon a SAVEPOINT that would have been invoked from the
               Connection.begin_nested() method; for
               control of a SAVEPOINT, call
               NestedTransaction.commit() on the
               NestedTransaction that is returned by the
               Connection.begin_nested() method itself.

      -- Method: sqlalchemy.future.Connection..execute
               (statement, parameters=None, execution_options=None)

          Executes a SQL statement construct and returns a Result.

          Parameters:

             * ‘statement’ – The statement to be executed.  This is
               always an object that is in both the ClauseElement
               and Executable hierarchies, including:

                  * Select.

                  * Insert, Update, Delete.

                  * TextClause and TextualSelect.

                  * DDL and objects which inherit from
                    DDLElement.

             * ‘parameters’ – parameters which will be bound into the
               statement.  This may be either a dictionary of parameter
               names to values, or a mutable sequence (e.g.  a list) of
               dictionaries.  When a list of dictionaries is passed, the
               underlying statement execution will make use of the DBAPI
               ‘cursor.executemany()’ method.  When a single dictionary
               is passed, the DBAPI ‘cursor.execute()’ method will be
               used.

             * ‘execution_options’ – optional dictionary of execution
               options, which will be associated with the statement
               execution.  This dictionary can provide a subset of the
               options that are accepted by
               ‘Connection.execution_options()’.

          Returns: a Result object.

      -- Method: sqlalchemy.future.Connection..rollback ()

          Roll back the transaction that is currently in progress.

          This method rolls back the current transaction if one has been
          started.  If no transaction was started, the method has no
          effect.  If a transaction was started and the connection is in
          an invalidated state, the transaction is cleared using this
          method.

          A transaction is begun on a Connection
          automatically whenever a statement is first executed, or when
          the Connection.begin() method is called.

               Note: The Connection.rollback() method only
               acts upon the primary database transaction that is linked
               to the Connection object.  It does not operate
               upon a SAVEPOINT that would have been invoked from the
               Connection.begin_nested() method; for
               control of a SAVEPOINT, call
               NestedTransaction.rollback() on the
               NestedTransaction that is returned by the
               Connection.begin_nested() method itself.

      -- Method: sqlalchemy.future.Connection..scalar
               (statement, parameters=None, execution_options=None)

          Executes a SQL statement construct and returns a scalar
          object.

          This method is shorthand for invoking the
          Result.scalar() method after invoking the
          Connection.execute() method.  Parameters are equivalent.

          Returns: a scalar Python value representing the first column
          of the first row returned.

 -- Function: sqlalchemy.future.create_engine (*arg, **kw)

     Create a new Engine instance.

     Arguments passed to create_engine() are mostly
     identical to those passed to the 1.x create_engine()
     function.  The difference is that the object returned is the
     Engine which has the 2.0 version of the API.

 -- Class: sqlalchemy.future.Engine (pool, dialect, url,
          logging_name=None, echo=None, query_cache_size=500,
          execution_options=None, hide_parameters=False)

     Connects a Pool and Dialect together to
     provide a source of database connectivity and behavior.

     `This is the SQLAlchemy 2.0 version' of the Engine.

     An Engine object is instantiated publicly using the
     create_engine() function.

     See also
     ........

     See Engine Configuration.

     See Working with Engines and Connections.

     `Class signature'

     class sqlalchemy.future.Engine. (see
     sqlalchemy.engine.Engine)

      -- Method: sqlalchemy.future.Engine..begin ()

          Return a Connection object with a transaction
          begun.

          Use of this method is similar to that of
          Engine.connect(), typically as a context manager, which
          will automatically maintain the state of the transaction when
          the block ends, either by calling Connection.commit()
          when the block succeeds normally, or
          Connection.rollback() when an exception is raised,
          before propagating the exception outwards:

               with engine.begin() as connection:
                   connection.execute(text("insert into table values ('foo')"))

          See also
          ........

          See Engine.connect().

          See Connection.begin().

      -- Method: sqlalchemy.future.Engine..connect ()

          Return a new Connection object.

          The Connection acts as a Python context manager, so
          the typical use of this method looks like:

               with engine.connect() as connection:
                   connection.execute(text("insert into table values ('foo')"))
                   connection.commit()

          Where above, after the block is completed, the connection is
          “closed” and its underlying DBAPI resources are returned to
          the connection pool.  This also has the effect of rolling back
          any transaction that was explicitly begun or was begun via
          autobegin, and will emit the
          ConnectionEvents.rollback() event if one was started
          and is still in progress.

          See also
          ........

          See Engine.begin().

 -- Function: sqlalchemy.future.select (*entities)

     Construct a new Select using the 2.  x style API.

     New in version 1.4: - The select() function now accepts
     column arguments positionally.  The top-level select()
     function will automatically use the 1.x or 2.x style API based on
     the incoming arguments; using select() from the
     ‘sqlalchemy.future’ module will enforce that only the 2.x style
     constructor is used.

     Similar functionality is also available via the
     FromClause.select() method on any FromClause.

     See also
     ........

     See Selecting. - Core Tutorial description of
     select().

     Parameters: ‘*entities’ – Entities to SELECT from.  For Core usage,
     this is typically a series of ColumnElement and / or
     FromClause objects which will form the columns clause of
     the resulting statement.  For those objects that are instances of
     FromClause. (typically Table or Alias
     objects), the FromClause.c collection is extracted
     to form a collection of ColumnElement objects.

     This parameter will also accept TextClause constructs
     as given, as well as ORM-mapped classes.

5 Dialects
**********

The `dialect' is the system SQLAlchemy uses to communicate with various
types of DBAPI implementations and databases.  The sections that follow
contain reference documentation and notes specific to the usage of each
backend, as well as notes for the various DBAPIs.

All dialects require that an appropriate DBAPI driver is installed.

5.1 Included Dialects
=====================

5.1.1 PostgreSQL
----------------

Support for the PostgreSQL database.

The following table summarizes current support levels for database
release versions.

`Supported PostgreSQL versions'

Support type                                           Versions

--------------------------------------------------------------------------------------------------------------

See Fully tested in CI.                        9.6, 10, 11, 12

See Normal support.                            9.6+

See Best effort.                               8+

5.1.1.1 DBAPI Support
.....................

The following dialect/DBAPI options are available.  Please refer to
individual DBAPI sections for connect information.

   * psycopg2.

   * pg8000.

   * asyncpg.

   * psycopg2cffi.

   * py-postgresql.

   * pygresql.

5.1.1.2 Sequences/SERIAL/IDENTITY
.................................

PostgreSQL supports sequences, and SQLAlchemy uses these as the default
means of creating new primary key values for integer-based primary key
columns.  When creating tables, SQLAlchemy will issue the ‘SERIAL’
datatype for integer-based primary key columns, which generates a
sequence and server side default corresponding to the column.

To specify a specific named sequence to be used for primary key
generation, use the Sequence() construct:

     Table('sometable', metadata,
             Column('id', Integer, Sequence('some_id_seq'), primary_key=True)
         )

When SQLAlchemy issues a single INSERT statement, to fulfill the
contract of having the “last insert identifier” available, a RETURNING
clause is added to the INSERT statement which specifies the primary key
columns should be returned after the statement completes.  The RETURNING
functionality only takes place if PostgreSQL 8.2 or later is in use.  As
a fallback approach, the sequence, whether specified explicitly or
implicitly via ‘SERIAL’, is executed independently beforehand, the
returned value to be used in the subsequent insert.  Note that when an
insert() construct is executed using “executemany” semantics,
the “last inserted identifier” functionality does not apply; no
RETURNING clause is emitted nor is the sequence pre-executed in this
case.

To force the usage of RETURNING by default off, specify the flag
‘implicit_returning=False’ to create_engine().

5.1.1.3 PostgreSQL 10 and above IDENTITY columns
................................................

PostgreSQL 10 and above have a new IDENTITY feature that supersedes the
use of SERIAL. The Identity construct in a Column
can be used to control its behavior:

     from sqlalchemy import Table, Column, MetaData, Integer, Computed

     metadata = MetaData()

     data = Table(
         "data",
         metadata,
         Column(
             'id', Integer, Identity(start=42, cycle=True), primary_key=True
         ),
         Column('data', String)
     )

The CREATE TABLE for the above Table object would be:

     CREATE TABLE data (
         id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 42 CYCLE),
         data VARCHAR,
         PRIMARY KEY (id)
     )

Changed in version 1.4: Added Identity construct in a
Column to specify the option of an autoincrementing column.

     Note: Previous versions of SQLAlchemy did not have built-in support
     for rendering of IDENTITY, and could use the following compilation
     hook to replace occurrences of SERIAL with IDENTITY:

          from sqlalchemy.schema import CreateColumn
          from sqlalchemy.ext.compiler import compiles

          @compiles(CreateColumn, 'postgresql')
          def use_identity(element, compiler, **kw):
              text = compiler.visit_create_column(element, **kw)
              text = text.replace(
                  "SERIAL", "INT GENERATED BY DEFAULT AS IDENTITY"
               )
              return text

     Using the above, a table such as:

          t = Table(
              't', m,
              Column('id', Integer, primary_key=True),
              Column('data', String)
          )

     Will generate on the backing database as:

          CREATE TABLE t (
              id INT GENERATED BY DEFAULT AS IDENTITY,
              data VARCHAR,
              PRIMARY KEY (id)
          )

5.1.1.4 Server Side Cursors
...........................

Server-side cursor support is available for the psycopg2, asyncpg
dialects and may also be available in others.

Server side cursors are enabled on a per-statement basis by using the
Connection.execution_options.stream_results connection
execution option:

     with engine.connect() as conn:
         result = conn.execution_options(stream_results=True).execute(text("select * from table"))

Note that some kinds of SQL statements may not be supported with server
side cursors; generally, only SQL statements that return rows should be
used with this option.

Deprecated since version 1.4: The dialect-level server_side_cursors flag
is deprecated and will be removed in a future release.  Please use the
Connection.stream_results execution option for unbuffered
cursor support.

See also
........

See Using Server Side Cursors (a.k.a. stream results).

5.1.1.5 Transaction Isolation Level
...................................

Most SQLAlchemy dialects support setting of transaction isolation level
using the create_engine.execution_options parameter at the
create_engine() level, and at the Connection
level via the Connection.execution_options.isolation_level
parameter.

For PostgreSQL dialects, this feature works either by making use of the
DBAPI-specific features, such as psycopg2’s isolation level flags which
will embed the isolation level setting inline with the ‘"BEGIN"’
statement, or for DBAPIs with no direct support by emitting ‘SET SESSION
CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL <level>’ ahead of the
‘"BEGIN"’ statement emitted by the DBAPI. For the special AUTOCOMMIT
isolation level, DBAPI-specific techniques are used which is typically
an ‘.autocommit’ flag on the DBAPI connection object.

To set isolation level using create_engine():

     engine = create_engine(
         "postgresql+pg8000://scott:tiger@localhost/test",
         execution_options={
             "isolation_level": "REPEATABLE READ"
         }
     )

To set using per-connection execution options:

     with engine.connect() as conn:
         conn = conn.execution_options(
             isolation_level="REPEATABLE READ"
         )
         with conn.begin():
             # ... work with transaction

Valid values for ‘isolation_level’ on most PostgreSQL dialects include:

   * ‘READ COMMITTED’

   * ‘READ UNCOMMITTED’

   * ‘REPEATABLE READ’

   * ‘SERIALIZABLE’

   * ‘AUTOCOMMIT’

See also
........

See Setting READ ONLY / DEFERRABLE.

See Setting Transaction Isolation Levels including DBAPI Autocommit.

See Psycopg2 Transaction Isolation Level.

See pg8000 Transaction Isolation Level.

5.1.1.6 Setting READ ONLY / DEFERRABLE
......................................

Most PostgreSQL dialects support setting the “READ ONLY” and
“DEFERRABLE” characteristics of the transaction, which is in addition to
the isolation level setting.  These two attributes can be established
either in conjunction with or independently of the isolation level by
passing the ‘postgresql_readonly’ and ‘postgresql_deferrable’ flags with
Connection.execution_options().  The example below
illustrates passing the ‘"SERIALIZABLE"’ isolation level at the same
time as setting “READ ONLY” and “DEFERRABLE”:

     with engine.connect() as conn:
         conn = conn.execution_options(
             isolation_level="SERIALIZABLE",
             postgresql_readonly=True,
             postgresql_deferrable=True
         )
         with conn.begin():
             #  ... work with transaction

Note that some DBAPIs such as asyncpg only support “readonly” with
SERIALIZABLE isolation.

New in version 1.4: added support for the ‘postgresql_readonly’ and
‘postgresql_deferrable’ execution options.

5.1.1.7 Setting Alternate Search Paths on Connect
.................................................

The PostgreSQL ‘search_path’ variable refers to the list of schema names
that will be implicitly referred towards when a particular table or
other object is referenced in a SQL statement.  As detailed in the next
section Remote-Schema Table Introspection and PostgreSQL search_path,
SQLAlchemy is generally organized around the concept
of keeping this variable at its default value of ‘public’, however, in
order to have it set to any arbitrary name or names when connections are
used automatically, the “SET SESSION search_path” command may be invoked
for all connections in a pool using the following event handler, as
discussed at Setting a Default Schema for New Connections:

     from sqlalchemy import event
     from sqlalchemy import create_engine

     engine = create_engine("postgresql+psycopg2://scott:tiger@host/dbname")

     @event.listens_for(engine, "connect", insert=True)
     def set_search_path(dbapi_connection, connection_record):
         existing_autocommit = dbapi_connection.autocommit
         dbapi_connection.autocommit = True
         cursor = dbapi_connection.cursor()
         cursor.execute("SET SESSION search_path='%s'" % schema_name)
         cursor.close()
         dbapi_connection.autocommit = existing_autocommit

The reason the recipe is complicated by use of the ‘.autocommit’ DBAPI
attribute is so that when the ‘SET SESSION search_path’ directive is
invoked, it is invoked outside of the scope of any transaction and
therefore will not be reverted when the DBAPI connection has a rollback.

See also
........

See Setting a Default Schema for New Connections. - in the
Describing Databases with MetaData documentation

5.1.1.8 Remote-Schema Table Introspection and PostgreSQL search_path
....................................................................

`TL;DR;': keep the ‘search_path’ variable set to its default of
‘public’, name schemas `other' than ‘public’ explicitly within ‘Table’
definitions.

The PostgreSQL dialect can reflect tables from any schema.  The
Table.schema argument, or alternatively the
MetaData.reflect.schema argument determines which schema will be
searched for the table or tables.  The reflected Table
objects will in all cases retain this ‘.schema’ attribute as was
specified.  However, with regards to tables which these Table
objects refer to via foreign key constraint, a decision must be made as
to how the ‘.schema’ is represented in those remote tables, in the case
where that remote schema name is also a member of the current PostgreSQL
search path(1).

By default, the PostgreSQL dialect mimics the behavior encouraged by
PostgreSQL’s own ‘pg_get_constraintdef()’ builtin procedure.  This
function returns a sample definition for a particular foreign key
constraint, omitting the referenced schema name from that definition
when the name is also in the PostgreSQL schema search path.  The
interaction below illustrates this behavior:

     test=> CREATE TABLE test_schema.referred(id INTEGER PRIMARY KEY);
     CREATE TABLE
     test=> CREATE TABLE referring(
     test(>         id INTEGER PRIMARY KEY,
     test(>         referred_id INTEGER REFERENCES test_schema.referred(id));
     CREATE TABLE
     test=> SET search_path TO public, test_schema;
     test=> SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM
     test-> pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n
     test-> ON n.oid = c.relnamespace
     test-> JOIN pg_catalog.pg_constraint r  ON c.oid = r.conrelid
     test-> WHERE c.relname='referring' AND r.contype = 'f'
     test-> ;
                    pg_get_constraintdef
     ---------------------------------------------------
      FOREIGN KEY (referred_id) REFERENCES referred(id)
     (1 row)

Above, we created a table ‘referred’ as a member of the remote schema
‘test_schema’, however when we added ‘test_schema’ to the PG
‘search_path’ and then asked ‘pg_get_constraintdef()’ for the ‘FOREIGN
KEY’ syntax, ‘test_schema’ was not included in the output of the
function.

On the other hand, if we set the search path back to the typical default
of ‘public’:

     test=> SET search_path TO public;
     SET

The same query against ‘pg_get_constraintdef()’ now returns the fully
schema-qualified name for us:

     test=> SELECT pg_catalog.pg_get_constraintdef(r.oid, true) FROM
     test-> pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n
     test-> ON n.oid = c.relnamespace
     test-> JOIN pg_catalog.pg_constraint r  ON c.oid = r.conrelid
     test-> WHERE c.relname='referring' AND r.contype = 'f';
                          pg_get_constraintdef
     ---------------------------------------------------------------
      FOREIGN KEY (referred_id) REFERENCES test_schema.referred(id)
     (1 row)

SQLAlchemy will by default use the return value of
‘pg_get_constraintdef()’ in order to determine the remote schema name.
That is, if our ‘search_path’ were set to include ‘test_schema’, and we
invoked a table reflection process as follows:

     >>> from sqlalchemy import Table, MetaData, create_engine, text
     >>> engine = create_engine("postgresql://scott:tiger@localhost/test")
     >>> with engine.connect() as conn:
     ...     conn.execute(text("SET search_path TO test_schema, public"))
     ...     meta = MetaData()
     ...     referring = Table('referring', meta,
     ...                       autoload_with=conn)
     ...
     <sqlalchemy.engine.result.CursorResult object at 0x101612ed0>

The above process would deliver to the MetaData.tables
collection ‘referred’ table named `without' the schema:

     >>> meta.tables['referred'].schema is None
     True

To alter the behavior of reflection such that the referred schema is
maintained regardless of the ‘search_path’ setting, use the
‘postgresql_ignore_search_path’ option, which can be specified as a
dialect-specific argument to both Table as well as
MetaData.reflect():

     >>> with engine.connect() as conn:
     ...     conn.execute(text("SET search_path TO test_schema, public"))
     ...     meta = MetaData()
     ...     referring = Table('referring', meta,
     ...                       autoload_with=conn,
     ...                       postgresql_ignore_search_path=True)
     ...
     <sqlalchemy.engine.result.CursorResult object at 0x1016126d0>

We will now have ‘test_schema.referred’ stored as schema-qualified:

     >>> meta.tables['test_schema.referred'].schema
     'test_schema'

Best Practices for PostgreSQL Schema reflection
...............................................

The description of PostgreSQL schema reflection behavior is complex, and
is the product of many years of dealing with widely varied use cases and
user preferences.  But in fact, there’s no need to understand any of it
if you just stick to the simplest use pattern: leave the ‘search_path’
set to its default of ‘public’ only, never refer to the name ‘public’ as
an explicit schema name otherwise, and refer to all other schema names
explicitly when building up a Table object.  The options
described here are only for those users who can’t, or prefer not to,
stay within these guidelines.

Note that `in all cases', the “default” schema is always reflected as
‘None’.  The “default” schema on PostgreSQL is that which is returned by
the PostgreSQL ‘current_schema()’ function.  On a typical PostgreSQL
installation, this is the name ‘public’.  So a table that refers to
another which is in the ‘public’ (i.e.  default) schema will always have
the ‘.schema’ attribute set to ‘None’.

New in version 0.9.2: Added the ‘postgresql_ignore_search_path’
dialect-level option accepted by Table and
MetaData.reflect().

See also
........

The Schema Search Path(2) - on the PostgreSQL website.

   ---------- Footnotes ----------

   (1)
http://www.postgresql.org/docs/current/static/ddl-schemas.html#DDL-SCHEMAS-PATH

   (2)
http://www.postgresql.org/docs/9.0/static/ddl-schemas.html#DDL-SCHEMAS-PATH

5.1.1.9 INSERT/UPDATE…RETURNING
...............................

The dialect supports PG 8.2’s ‘INSERT..RETURNING’, ‘UPDATE..RETURNING’
and ‘DELETE..RETURNING’ syntaxes.  ‘INSERT..RETURNING’ is used by
default for single-row INSERT statements in order to fetch newly
generated primary key identifiers.  To specify an explicit ‘RETURNING’
clause, use the ‘_UpdateBase.returning()’ method on a per-statement
basis:

     # INSERT..RETURNING
     result = table.insert().returning(table.c.col1, table.c.col2).\
         values(name='foo')
     print(result.fetchall())

     # UPDATE..RETURNING
     result = table.update().returning(table.c.col1, table.c.col2).\
         where(table.c.name=='foo').values(name='bar')
     print(result.fetchall())

     # DELETE..RETURNING
     result = table.delete().returning(table.c.col1, table.c.col2).\
         where(table.c.name=='foo')
     print(result.fetchall())

5.1.1.10 INSERT…ON CONFLICT (Upsert)
....................................

Starting with version 9.5, PostgreSQL allows “upserts” (update or
insert) of rows into a table via the ‘ON CONFLICT’ clause of the
‘INSERT’ statement.  A candidate row will only be inserted if that row
does not violate any unique constraints.  In the case of a unique
constraint violation, a secondary action can occur which can be either
“DO UPDATE”, indicating that the data in the target row should be
updated, or “DO NOTHING”, which indicates to silently skip this row.

Conflicts are determined using existing unique constraints and indexes.
These constraints may be identified either using their name as stated in
DDL, or they may be inferred by stating the columns and conditions that
comprise the indexes.

SQLAlchemy provides ‘ON CONFLICT’ support via the PostgreSQL-specific
insert() function, which provides the generative methods
Insert.on_conflict_do_update() and
Insert.on_conflict_do_nothing():

     >>> from sqlalchemy.dialects.postgresql import insert
     >>> insert_stmt = insert(my_table).values(
     ...     id='some_existing_id',
     ...     data='inserted value')
     >>> do_nothing_stmt = insert_stmt.on_conflict_do_nothing(
     ...     index_elements=['id']
     ... )
     >>> print(do_nothing_stmt)
     {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
     ON CONFLICT (id) DO NOTHING
     {stop}

     >>> do_update_stmt = insert_stmt.on_conflict_do_update(
     ...     constraint='pk_my_table',
     ...     set_=dict(data='updated value')
     ... )
     >>> print(do_update_stmt)
     {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
     ON CONFLICT ON CONSTRAINT pk_my_table DO UPDATE SET data = %(param_1)s

New in version 1.1.

See also
........

INSERT ..  ON CONFLICT(1) - in the PostgreSQL documentation.

   ---------- Footnotes ----------

   (1)
http://www.postgresql.org/docs/current/static/sql-insert.html#SQL-ON-CONFLICT

5.1.1.11 Specifying the Target
..............................

Both methods supply the “target” of the conflict using either the named
constraint or by column inference:

   * The Insert.on_conflict_do_update.index_elements.
     argument specifies a sequence containing string column names, see
     Column objects, and/or SQL expression elements, which would
     identify a unique index:

          >>> do_update_stmt = insert_stmt.on_conflict_do_update(
          ...     index_elements=['id'],
          ...     set_=dict(data='updated value')
          ... )
          >>> print(do_update_stmt)
          {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
          ON CONFLICT (id) DO UPDATE SET data = %(param_1)s
          {stop}

          >>> do_update_stmt = insert_stmt.on_conflict_do_update(
          ...     index_elements=[my_table.c.id],
          ...     set_=dict(data='updated value')
          ... )
          >>> print(do_update_stmt)
          {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
          ON CONFLICT (id) DO UPDATE SET data = %(param_1)s

   * When using Insert.on_conflict_do_update.index_elements.
     to infer an index, a partial index can be inferred by also
     specifying the use the
     Insert.on_conflict_do_update.index_where parameter:

          >>> stmt = insert(my_table).values(user_email='a@b.com', data='inserted data')
          >>> stmt = stmt.on_conflict_do_update(
          ...     index_elements=[my_table.c.user_email],
          ...     index_where=my_table.c.user_email.like('%@gmail.com'),
          ...     set_=dict(data=stmt.excluded.data)
          ... )
          >>> print(stmt)
          {opensql}INSERT INTO my_table (data, user_email)
          VALUES (%(data)s, %(user_email)s) ON CONFLICT (user_email)
          WHERE user_email LIKE %(user_email_1)s DO UPDATE SET data = excluded.data

   * The Insert.on_conflict_do_update.constraint argument
     is used to specify an index directly rather than inferring it.
     This can be the name of a UNIQUE constraint, a PRIMARY KEY
     constraint, or an INDEX:

          >>> do_update_stmt = insert_stmt.on_conflict_do_update(
          ...     constraint='my_table_idx_1',
          ...     set_=dict(data='updated value')
          ... )
          >>> print(do_update_stmt)
          {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
          ON CONFLICT ON CONSTRAINT my_table_idx_1 DO UPDATE SET data = %(param_1)s
          {stop}

          >>> do_update_stmt = insert_stmt.on_conflict_do_update(
          ...     constraint='my_table_pk',
          ...     set_=dict(data='updated value')
          ... )
          >>> print(do_update_stmt)
          {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
          ON CONFLICT ON CONSTRAINT my_table_pk DO UPDATE SET data = %(param_1)s
          {stop}

   * The Insert.on_conflict_do_update.constraint argument
     may also refer to a SQLAlchemy construct representing a constraint,
     e.g.  see UniqueConstraint, PrimaryKeyConstraint,
     Index, or ExcludeConstraint.  In this use,
     if the constraint has a name, it is used directly.  Otherwise, if
     the constraint is unnamed, then inference will be used, where the
     expressions and optional WHERE clause of the constraint will be
     spelled out in the construct.  This use is especially convenient to
     refer to the named or unnamed primary key of a Table
     using the Table.primary_key attribute:

          >>> do_update_stmt = insert_stmt.on_conflict_do_update(
          ...     constraint=my_table.primary_key,
          ...     set_=dict(data='updated value')
          ... )
          >>> print(do_update_stmt)
          {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
          ON CONFLICT (id) DO UPDATE SET data = %(param_1)s

5.1.1.12 The SET Clause
.......................

‘ON CONFLICT...DO UPDATE’ is used to perform an update of the already
existing row, using any combination of new values as well as values from
the proposed insertion.  These values are specified using the
Insert.on_conflict_do_update.set_ parameter.  This parameter
accepts a dictionary which consists of direct values for UPDATE:

     >>> stmt = insert(my_table).values(id='some_id', data='inserted value')
     >>> do_update_stmt = stmt.on_conflict_do_update(
     ...     index_elements=['id'],
     ...     set_=dict(data='updated value')
     ... )
     >>> print(do_update_stmt)
     {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
     ON CONFLICT (id) DO UPDATE SET data = %(param_1)s

     Warning: The ‘Insert.on_conflict_do_update()’ method does `not'
     take into account Python-side default UPDATE values or generation
     functions, e.g.  those specified using Column.onupdate.
     These values will not be exercised for an ON CONFLICT style of
     UPDATE, unless they are manually specified in the
     Insert.on_conflict_do_update.set_ dictionary.

5.1.1.13 Updating using the Excluded INSERT Values
..................................................

In order to refer to the proposed insertion row, the special alias
Insert.excluded is available as an attribute on the Insert
object; this object is a ColumnCollection which alias
contains all columns of the target table:

     >>> stmt = insert(my_table).values(
     ...     id='some_id',
     ...     data='inserted value',
     ...     author='jlh'
     ... )
     >>> do_update_stmt = stmt.on_conflict_do_update(
     ...     index_elements=['id'],
     ...     set_=dict(data='updated value', author=stmt.excluded.author)
     ... )
     >>> print(do_update_stmt)
     {opensql}INSERT INTO my_table (id, data, author)
     VALUES (%(id)s, %(data)s, %(author)s)
     ON CONFLICT (id) DO UPDATE SET data = %(param_1)s, author = excluded.author

5.1.1.14 Additional WHERE Criteria
..................................

The ‘Insert.on_conflict_do_update()’ method also accepts a WHERE clause
using the Insert.on_conflict_do_update.where parameter,
which will limit those rows which receive an UPDATE:

     >>> stmt = insert(my_table).values(
     ...     id='some_id',
     ...     data='inserted value',
     ...     author='jlh'
     ... )
     >>> on_update_stmt = stmt.on_conflict_do_update(
     ...     index_elements=['id'],
     ...     set_=dict(data='updated value', author=stmt.excluded.author),
     ...     where=(my_table.c.status == 2)
     ... )
     >>> print(on_update_stmt)
     {opensql}INSERT INTO my_table (id, data, author)
     VALUES (%(id)s, %(data)s, %(author)s)
     ON CONFLICT (id) DO UPDATE SET data = %(param_1)s, author = excluded.author
     WHERE my_table.status = %(status_1)s

5.1.1.15 Skipping Rows with DO NOTHING
......................................

‘ON CONFLICT’ may be used to skip inserting a row entirely if any
conflict with a unique or exclusion constraint occurs; below this is
illustrated using the Insert.on_conflict_do_nothing()
method:

     >>> stmt = insert(my_table).values(id='some_id', data='inserted value')
     >>> stmt = stmt.on_conflict_do_nothing(index_elements=['id'])
     >>> print(stmt)
     {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
     ON CONFLICT (id) DO NOTHING

If ‘DO NOTHING’ is used without specifying any columns or constraint, it
has the effect of skipping the INSERT for any unique or exclusion
constraint violation which occurs:

     >>> stmt = insert(my_table).values(id='some_id', data='inserted value')
     >>> stmt = stmt.on_conflict_do_nothing()
     >>> print(stmt)
     {opensql}INSERT INTO my_table (id, data) VALUES (%(id)s, %(data)s)
     ON CONFLICT DO NOTHING

5.1.1.16 Full Text Search
.........................

SQLAlchemy makes available the PostgreSQL ‘@@’ operator via the
ColumnElement.match() method on any textual column expression.  On
a PostgreSQL dialect, an expression like the following:

     select(sometable.c.text.match("search string"))

will emit to the database:

     SELECT text @@ to_tsquery('search string') FROM table

The PostgreSQL text search functions such as ‘to_tsquery()’ and
‘to_tsvector()’ are available explicitly using the standard func
construct.  For example:

     select(func.to_tsvector('fat cats ate rats').match('cat & rat'))

Emits the equivalent of:

     SELECT to_tsvector('fat cats ate rats') @@ to_tsquery('cat & rat')

The TSVECTOR type can provide for explicit CAST:

     from sqlalchemy.dialects.postgresql import TSVECTOR
     from sqlalchemy import select, cast
     select(cast("some text", TSVECTOR))

produces a statement equivalent to:

     SELECT CAST('some text' AS TSVECTOR) AS anon_1

Full Text Searches in PostgreSQL are influenced by a combination of: the
PostgreSQL setting of ‘default_text_search_config’, the ‘regconfig’ used
to build the GIN/GiST indexes, and the ‘regconfig’ optionally passed in
during a query.

When performing a Full Text Search against a column that has a GIN or
GiST index that is already pre-computed (which is common on full text
searches) one may need to explicitly pass in a particular PostgreSQL
‘regconfig’ value to ensure the query-planner utilizes the index and
does not re-compute the column on demand.

In order to provide for this explicit query planning, or to use
different search strategies, the ‘match’ method accepts a
‘postgresql_regconfig’ keyword argument:

     select(mytable.c.id).where(
         mytable.c.title.match('somestring', postgresql_regconfig='english')
     )

Emits the equivalent of:

     SELECT mytable.id FROM mytable
     WHERE mytable.title @@ to_tsquery('english', 'somestring')

One can also specifically pass in a ‘‘regconfig’’ value to the
‘to_tsvector()’ command as the initial argument:

     select(mytable.c.id).where(
             func.to_tsvector('english', mytable.c.title )\
             .match('somestring', postgresql_regconfig='english')
         )

produces a statement equivalent to:

     SELECT mytable.id FROM mytable
     WHERE to_tsvector('english', mytable.title) @@
         to_tsquery('english', 'somestring')

It is recommended that you use the ‘EXPLAIN ANALYZE...’ tool from
PostgreSQL to ensure that you are generating queries with SQLAlchemy
that take full advantage of any indexes you may have created for full
text search.

5.1.1.17 FROM ONLY …
....................

The dialect supports PostgreSQL’s ONLY keyword for targeting only a
particular table in an inheritance hierarchy.  This can be used to
produce the ‘SELECT ... FROM ONLY’, ‘UPDATE ONLY ...’, and ‘DELETE FROM
ONLY ...’ syntaxes.  It uses SQLAlchemy’s hints mechanism:

     # SELECT ... FROM ONLY ...
     result = table.select().with_hint(table, 'ONLY', 'postgresql')
     print(result.fetchall())

     # UPDATE ONLY ...
     table.update(values=dict(foo='bar')).with_hint('ONLY',
                                                    dialect_name='postgresql')

     # DELETE FROM ONLY ...
     table.delete().with_hint('ONLY', dialect_name='postgresql')

5.1.1.18 PostgreSQL-Specific Index Options
..........................................

Several extensions to the Index construct are available,
specific to the PostgreSQL dialect.

5.1.1.19 Covering Indexes
.........................

The ‘postgresql_include’ option renders INCLUDE(colname) for the given
string names:

     Index("my_index", table.c.x, postgresql_include=['y'])

would render the index as ‘CREATE INDEX my_index ON table (x) INCLUDE
(y)’

Note that this feature requires PostgreSQL 11 or later.

New in version 1.4.

5.1.1.20 Partial Indexes
........................

Partial indexes add criterion to the index definition so that the index
is applied to a subset of rows.  These can be specified on Index
using the ‘postgresql_where’ keyword argument:

     Index('my_index', my_table.c.id, postgresql_where=my_table.c.value > 10)

5.1.1.21 Operator Classes
.........................

PostgreSQL allows the specification of an `operator class' for each
column of an index (see
‘http://www.postgresql.org/docs/8.3/interactive/indexes-opclass.html’).
The Index construct allows these to be specified via the
‘postgresql_ops’ keyword argument:

     Index(
         'my_index', my_table.c.id, my_table.c.data,
         postgresql_ops={
             'data': 'text_pattern_ops',
             'id': 'int4_ops'
         })

Note that the keys in the ‘postgresql_ops’ dictionaries are the “key”
name of the Column, i.e.  the name used to access it from the
‘.c’ collection of Table, which can be configured to be
different than the actual name of the column as expressed in the
database.

If ‘postgresql_ops’ is to be used against a complex SQL expression such
as a function call, then to apply to the column it must be given a label
that is identified in the dictionary by name, e.g.:

     Index(
         'my_index', my_table.c.id,
         func.lower(my_table.c.data).label('data_lower'),
         postgresql_ops={
             'data_lower': 'text_pattern_ops',
             'id': 'int4_ops'
         })

Operator classes are also supported by the ExcludeConstraint
construct using the ExcludeConstraint.ops parameter.
See that parameter for details.

New in version 1.3.21: added support for operator classes with
ExcludeConstraint.

5.1.1.22 Index Types
....................

PostgreSQL provides several index types: B-Tree, Hash, GiST, and GIN, as
well as the ability for users to create their own (see
‘http://www.postgresql.org/docs/8.3/static/indexes-types.html’).  These
can be specified on Index using the ‘postgresql_using’
keyword argument:

     Index('my_index', my_table.c.data, postgresql_using='gin')

The value passed to the keyword argument will be simply passed through
to the underlying CREATE INDEX command, so it `must' be a valid index
type for your version of PostgreSQL.

5.1.1.23 Index Storage Parameters
.................................

PostgreSQL allows storage parameters to be set on indexes.  The storage
parameters available depend on the index method used by the index.
Storage parameters can be specified on Index using the
‘postgresql_with’ keyword argument:

     Index('my_index', my_table.c.data, postgresql_with={"fillfactor": 50})

New in version 1.0.6.

PostgreSQL allows to define the tablespace in which to create the index.
The tablespace can be specified on Index using the
‘postgresql_tablespace’ keyword argument:

     Index('my_index', my_table.c.data, postgresql_tablespace='my_tablespace')

New in version 1.1.

Note that the same option is available on Table as well.

5.1.1.24 Indexes with CONCURRENTLY
..................................

The PostgreSQL index option CONCURRENTLY is supported by passing the
flag ‘postgresql_concurrently’ to the Index construct:

     tbl = Table('testtbl', m, Column('data', Integer))

     idx1 = Index('test_idx1', tbl.c.data, postgresql_concurrently=True)

The above index construct will render DDL for CREATE INDEX, assuming
PostgreSQL 8.2 or higher is detected or for a connection-less dialect,
as:

     CREATE INDEX CONCURRENTLY test_idx1 ON testtbl (data)

For DROP INDEX, assuming PostgreSQL 9.2 or higher is detected or for a
connection-less dialect, it will emit:

     DROP INDEX CONCURRENTLY test_idx1

New in version 1.1: support for CONCURRENTLY on DROP INDEX. The
CONCURRENTLY keyword is now only emitted if a high enough version of
PostgreSQL is detected on the connection (or for a connection-less
dialect).

When using CONCURRENTLY, the PostgreSQL database requires that the
statement be invoked outside of a transaction block.  The Python DBAPI
enforces that even for a single statement, a transaction is present, so
to use this construct, the DBAPI’s “autocommit” mode must be used:

     metadata = MetaData()
     table = Table(
         "foo", metadata,
         Column("id", String))
     index = Index(
         "foo_idx", table.c.id, postgresql_concurrently=True)

     with engine.connect() as conn:
         with conn.execution_options(isolation_level='AUTOCOMMIT'):
             table.create(conn)

See also
........

See Transaction Isolation Level.

5.1.1.25 PostgreSQL Index Reflection
....................................

The PostgreSQL database creates a UNIQUE INDEX implicitly whenever the
UNIQUE CONSTRAINT construct is used.  When inspecting a table using
Inspector, the Inspector.get_indexes() and the
Inspector.get_unique_constraints() will report on these two
constructs distinctly; in the case of the index, the key
‘duplicates_constraint’ will be present in the index entry if it is
detected as mirroring a constraint.  When performing reflection using
‘Table(..., autoload_with=engine)’, the UNIQUE INDEX is `not' returned
in Table.indexes when it is detected as mirroring a
UniqueConstraint in the Table.constraints collection
.

Changed in version 1.0.0: - see Table reflection now includes
UniqueConstraint objects present in the
Table.constraints collection; the PostgreSQL backend will no
longer include a “mirrored” Index construct in
Table.indexes if it is detected as corresponding to a unique
constraint.

5.1.1.26 Special Reflection Options
...................................

The Inspector used for the PostgreSQL backend is an
instance of PGInspector, which offers additional methods:

     from sqlalchemy import create_engine, inspect

     engine = create_engine("postgresql+psycopg2://localhost/test")
     insp = inspect(engine)  # will be a PGInspector

     print(insp.get_enums())

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See PGInspector.

 -- Class: sqlalchemy.dialects.postgresql.base.PGInspector (bind)

     `Class signature'

     class sqlalchemy.dialects.postgresql.base.PGInspector.
     (see sqlalchemy.engine.reflection.Inspector)

      -- Method: sqlalchemy.dialects.postgresql.base.PGInspector..
               get_enums (schema=None)

          Return a list of ENUM objects.

          Each member is a dictionary containing these fields:

                  * name - name of the enum

                  * schema - the schema name for the enum.

                  * visible - boolean, whether or not this enum is
                    visible in the default search path.

                  * labels - a list of string labels that apply to the
                    enum.

          Parameters: ‘schema’ – schema name.  If None, the default
          schema (typically ‘public’) is used.  May also be set to ‘*’
          to indicate load enums for all schemas.

          New in version 1.0.0.

      -- Method: sqlalchemy.dialects.postgresql.base.PGInspector..
               get_foreign_table_names (schema=None)

          Return a list of FOREIGN TABLE names.

          Behavior is similar to that of
          Inspector.get_table_names(), except that the list is
          limited to those tables that report a ‘relkind’ value of ‘f’.

          New in version 1.0.0.

      -- Method: sqlalchemy.dialects.postgresql.base.PGInspector..
               get_table_oid (table_name, schema=None)

          Return the OID for the given table name.

      -- Method: sqlalchemy.dialects.postgresql.base.PGInspector..
               get_view_names (schema=None, include=('plain',
               'materialized'))

          Return all view names in ‘schema’.

          Parameters:

             * ‘schema’ – Optional, retrieve names from a non-default
               schema.  For special quoting, use quoted_name.

             * ‘include’ – specify which types of views to return.
               Passed as a string value (for a single type) or a tuple
               (for any number of types).  Defaults to ‘('plain',
               'materialized')’.

               New in version 1.1.

5.1.1.27 PostgreSQL Table Options
.................................

Several options for CREATE TABLE are supported directly by the
PostgreSQL dialect in conjunction with the Table construct:

   * ‘TABLESPACE’:

          Table("some_table", metadata, ..., postgresql_tablespace='some_tablespace')

     The above option is also available on the Index
     construct.

   * ‘ON COMMIT’:

          Table("some_table", metadata, ..., postgresql_on_commit='PRESERVE ROWS')

   * ‘WITH OIDS’:

          Table("some_table", metadata, ..., postgresql_with_oids=True)

   * ‘WITHOUT OIDS’:

          Table("some_table", metadata, ..., postgresql_with_oids=False)

   * ‘INHERITS’:

          Table("some_table", metadata, ..., postgresql_inherits="some_supertable")

          Table("some_table", metadata, ..., postgresql_inherits=("t1", "t2", ...))

          .. versionadded:: 1.0.0

   * ‘PARTITION BY’:

          Table("some_table", metadata, ...,
                postgresql_partition_by='LIST (part_column)')

          .. versionadded:: 1.2.6

See also
........

PostgreSQL CREATE TABLE options(1)

   ---------- Footnotes ----------

   (1)
http://www.postgresql.org/docs/current/static/sql-createtable.html

5.1.1.28 Table values, Table and Column valued functions, Row and Tuple objects
...............................................................................

PostgreSQL makes great use of modern SQL forms such as table-valued
functions, tables and rows as values.  These constructs are commonly
used as part of PostgreSQL’s support for complex datatypes such as JSON,
ARRAY, and other datatypes.  SQLAlchemy’s SQL expression language has
native support for most table-valued and row-valued forms.

5.1.1.29 Table-Valued Functions
...............................

Many PostgreSQL built-in functions are intended to be used in the FROM
clause of a SELECT statement, and are capable of returning table rows or
sets of table rows.  A large portion of PostgreSQL’s JSON functions for
example such as ‘json_array_elements()’, ‘json_object_keys()’,
‘json_each_text()’, ‘json_each()’, ‘json_to_record()’,
‘json_populate_recordset()’ use such forms.  These classes of SQL
function calling forms in SQLAlchemy are available using the
FunctionElement.table_valued() method in conjunction with
Function objects generated from the func namespace.

Examples from PostgreSQL’s reference documentation follow below:

   * ‘json_each()’:

          >>> from sqlalchemy import select, func
          >>> stmt = select(func.json_each('{"a":"foo", "b":"bar"}').table_valued("key", "value"))
          >>> print(stmt)
          SELECT anon_1.key, anon_1.value
          FROM json_each(:json_each_1) AS anon_1

   * ‘json_populate_record()’:

          >>> from sqlalchemy import select, func, literal_column
          >>> stmt = select(
          ...     func.json_populate_record(
          ...         literal_column("null::myrowtype"),
          ...         '{"a":1,"b":2}'
          ...     ).table_valued("a", "b", name="x")
          ... )
          >>> print(stmt)
          SELECT x.a, x.b
          FROM json_populate_record(null::myrowtype, :json_populate_record_1) AS x

   * ‘json_to_record()’ - this form uses a PostgreSQL specific form of
     derived columns in the alias, where we may make use of
     column() elements with types to produce them.  The
     FunctionElement.table_valued() method produces a
     TableValuedAlias construct, and the method
     TableValuedAlias.render_derived() method sets up the derived
     columns specification:

          >>> from sqlalchemy import select, func, column, Integer, Text
          >>> stmt = select(
          ...     func.json_to_record('{"a":1,"b":[1,2,3],"c":"bar"}').table_valued(
          ...         column("a", Integer), column("b", Text), column("d", Text),
          ...     ).render_derived(name="x", with_types=True)
          ... )
          >>> print(stmt)
          SELECT x.a, x.b, x.d
          FROM json_to_record(:json_to_record_1) AS x(a INTEGER, b TEXT, d TEXT)

   * ‘WITH ORDINALITY’ - part of the SQL standard, ‘WITH ORDINALITY’
     adds an ordinal counter to the output of a function and is accepted
     by a limited set of PostgreSQL functions including ‘unnest()’ and
     ‘generate_series()’.  The FunctionElement.table_valued()
     method accepts a keyword parameter ‘with_ordinality’ for this
     purpose, which accepts the string name that will be applied to the
     “ordinality” column:

          >>> from sqlalchemy import select, func
          >>> stmt = select(
          ...     func.generate_series(4, 1, -1).table_valued("value", with_ordinality="ordinality")
          ... )
          >>> print(stmt)
          SELECT anon_1.value, anon_1.ordinality
          FROM generate_series(:generate_series_1, :generate_series_2, :generate_series_3) WITH ORDINALITY AS anon_1

New in version 1.4.0b2.

See also
........

See Table-Valued Functions. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

5.1.1.30 Column Valued Functions
................................

Similar to the table valued function, a column valued function is
present in the FROM clause, but delivers itself to the columns clause as
a single scalar value.  PostgreSQL functions such as
‘json_array_elements()’, ‘unnest()’ and ‘generate_series()’ may use this
form.  Column valued functions are available using the
FunctionElement.column_valued() method of FunctionElement:

   * ‘json_array_elements()’:

          >>> from sqlalchemy import select, func
          >>> stmt = select(func.json_array_elements('["one", "two"]').column_valued("x"))
          >>> print(stmt)
          SELECT x
          FROM json_array_elements(:json_array_elements_1) AS x

   * ‘unnest()’ - in order to generate a PostgreSQL ARRAY literal, the
     array() construct may be used:

          >>> from sqlalchemy.dialects.postgresql import array
          >>> from sqlalchemy import select, func
          >>> stmt = select(func.unnest(array([1, 2])).column_valued())
          >>> print(stmt)
          SELECT anon_1
          FROM unnest(ARRAY[%(param_1)s, %(param_2)s]) AS anon_1

     The function can of course be used against an existing table-bound
     column that’s of type ARRAY:

          >>> from sqlalchemy import table, column, ARRAY, Integer
          >>> from sqlalchemy import select, func
          >>> t = table("t", column('value', ARRAY(Integer)))
          >>> stmt = select(func.unnest(t.c.value).column_valued("unnested_value"))
          >>> print(stmt)
          SELECT unnested_value
          FROM unnest(t.value) AS unnested_value

See also
........

See Column Valued Functions - Table Valued Function as a Scalar Column.
- in the SQLAlchemy 1.4 / 2.0 Tutorial.

5.1.1.31 Row Types
..................

Built-in support for rendering a ‘ROW’ may be approximated using
‘func.ROW’ with the ‘sqlalchemy.func’ namespace, or by using the
tuple_() construct:

     >>> from sqlalchemy import table, column, func, tuple_
     >>> t = table("t", column("id"), column("fk"))
     >>> stmt = t.select().where(
     ...     tuple_(t.c.id, t.c.fk) > (1,2)
     ... ).where(
     ...     func.ROW(t.c.id, t.c.fk) < func.ROW(3, 7)
     ... )
     >>> print(stmt)
     SELECT t.id, t.fk
     FROM t
     WHERE (t.id, t.fk) > (:param_1, :param_2) AND ROW(t.id, t.fk) < ROW(:ROW_1, :ROW_2)

See also
........

PostgreSQL Row Constructors(1)

PostgreSQL Row Constructor Comparison(2)

   ---------- Footnotes ----------

   (1)
https://www.postgresql.org/docs/current/sql-expressions.html#SQL-SYNTAX-ROW-CONSTRUCTORS

   (2)
https://www.postgresql.org/docs/current/functions-comparisons.html#ROW-WISE-COMPARISON

5.1.1.32 Table Types passed to Functions
........................................

PostgreSQL supports passing a table as an argument to a function, which
it refers towards as a “record” type.  SQLAlchemy FromClause
objects such as Table support this special form using the
FromClause.table_valued() method, which is comparable to the
FunctionElement.table_valued() method except that the
collection of columns is already established by that of the
FromClause itself:

     >>> from sqlalchemy import table, column, func, select
     >>> a = table( "a", column("id"), column("x"), column("y"))
     >>> stmt = select(func.row_to_json(a.table_valued()))
     >>> print(stmt)
     SELECT row_to_json(a) AS row_to_json_1
     FROM a

New in version 1.4.0b2.

5.1.1.33 ARRAY Types
....................

The PostgreSQL dialect supports arrays, both as multidimensional column
types as well as array literals:

   * ARRAY. - ARRAY datatype

   * array. - array literal

   * array_agg(). - ARRAY_AGG SQL function

   * aggregate_order_by. - helper for PG’s ORDER BY
     aggregate function syntax.

5.1.1.34 JSON Types
...................

The PostgreSQL dialect supports both JSON and JSONB datatypes, including
psycopg2’s native support and support for all of PostgreSQL’s special
operators:

   * JSON.

   * JSONB.

5.1.1.35 HSTORE Type
....................

The PostgreSQL HSTORE type as well as hstore literals are supported:

   * HSTORE. - HSTORE datatype

   * hstore. - hstore literal

5.1.1.36 ENUM Types
...................

PostgreSQL has an independently creatable TYPE structure which is used
to implement an enumerated type.  This approach introduces significant
complexity on the SQLAlchemy side in terms of when this type should be
CREATED and DROPPED. The type object is also an independently
reflectable entity.  The following sections should be consulted:

   * ENUM. - DDL and typing support for ENUM.

   * PGInspector.get_enums(). - retrieve a listing of
     current ENUM types

   * ENUM.create(). , ENUM.drop(). - individual
     CREATE and DROP commands for ENUM.

5.1.1.37 Using ENUM with ARRAY
..............................

The combination of ENUM and ARRAY is not directly supported by backend
DBAPIs at this time.  Prior to SQLAlchemy 1.3.17, a special workaround
was needed in order to allow this combination to work, described below.

Changed in version 1.3.17: The combination of ENUM and ARRAY is now
directly handled by SQLAlchemy’s implementation without any workarounds
needed.

     from sqlalchemy import TypeDecorator
     from sqlalchemy.dialects.postgresql import ARRAY

     class ArrayOfEnum(TypeDecorator):
         impl = ARRAY

         def bind_expression(self, bindvalue):
             return sa.cast(bindvalue, self)

         def result_processor(self, dialect, coltype):
             super_rp = super(ArrayOfEnum, self).result_processor(
                 dialect, coltype)

             def handle_raw_string(value):
                 inner = re.match(r"^{(.*)}$", value).group(1)
                 return inner.split(",") if inner else []

             def process(value):
                 if value is None:
                     return None
                 return super_rp(handle_raw_string(value))
             return process

E.g.:

     Table(
         'mydata', metadata,
         Column('id', Integer, primary_key=True),
         Column('data', ArrayOfEnum(ENUM('a', 'b, 'c', name='myenum')))

     )

This type is not included as a built-in type as it would be incompatible
with a DBAPI that suddenly decides to support ARRAY of ENUM directly in
a new version.

5.1.1.38 Using JSON/JSONB with ARRAY
....................................

Similar to using ENUM, prior to SQLAlchemy 1.3.17, for an ARRAY of
JSON/JSONB we need to render the appropriate CAST. Current psycopg2
drivers accommodate the result set correctly without any special steps.

Changed in version 1.3.17: The combination of JSON/JSONB and ARRAY is
now directly handled by SQLAlchemy’s implementation without any
workarounds needed.

     class CastingArray(ARRAY):
         def bind_expression(self, bindvalue):
             return sa.cast(bindvalue, self)

E.g.:

     Table(
         'mydata', metadata,
         Column('id', Integer, primary_key=True),
         Column('data', CastingArray(JSONB))
     )

5.1.1.39 PostgreSQL Data Types and Custom SQL Constructs
........................................................

As with all SQLAlchemy dialects, all UPPERCASE types that are known to
be valid with PostgreSQL are importable from the top level dialect,
whether they originate from sqlalchemy.types or from the
local dialect:

     from sqlalchemy.dialects.postgresql import \
         ARRAY, BIGINT, BIT, BOOLEAN, BYTEA, CHAR, CIDR, DATE, \
         DOUBLE_PRECISION, ENUM, FLOAT, HSTORE, INET, INTEGER, \
         INTERVAL, JSON, JSONB, MACADDR, MONEY, NUMERIC, OID, REAL, SMALLINT, TEXT, \
         TIME, TIMESTAMP, UUID, VARCHAR, INT4RANGE, INT8RANGE, NUMRANGE, \
         DATERANGE, TSRANGE, TSTZRANGE, TSVECTOR

Types which are specific to PostgreSQL, or have PostgreSQL-specific
construction arguments, are as follows:

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See aggregate_order_by.Represent a PostgreSQL aggregate order by expression.

See All.(other,A synonym for the Comparator.all() method.
arrexpr[,
operator])

See Any.(other,A synonym for the Comparator.any() method.
arrexpr[,
operator])

See array.A PostgreSQL ARRAY literal.

See ARRAY.PostgreSQL ARRAY type.

See array_agg.(*arg,PostgreSQL-specific form of array_agg, ensures return type is ARRAY.
**kw)          and not the plain ARRAY, unless an explicit ‘type_’ is passed.

See BIT.

See BYTEA.

See CIDR.

See DOUBLE_PRECISION.

See ENUM.PostgreSQL ENUM type.

See HSTORE.Represent the PostgreSQL HSTORE type.

See hstore.Construct an hstore value within a SQL expression using the PostgreSQL ‘hstore()’ function.

See INET.

See INTERVAL.PostgreSQL INTERVAL type.

See JSON.Represent the PostgreSQL JSON type.

See JSONB.Represent the PostgreSQL JSONB type.

See MACADDR.

See MONEY.Provide the PostgreSQL MONEY type.

See OID.Provide the PostgreSQL OID type.

See REAL.The SQL REAL type.

See REGCLASS.Provide the PostgreSQL REGCLASS type.

See TSVECTOR.The TSVECTOR type implements the PostgreSQL text search type TSVECTOR.

See UUID.PostgreSQL UUID type.

 -- Class: sqlalchemy.dialects.postgresql.aggregate_order_by (target,
          *order_by)

     Represent a PostgreSQL aggregate order by expression.

     E.g.:

          from sqlalchemy.dialects.postgresql import aggregate_order_by
          expr = func.array_agg(aggregate_order_by(table.c.a, table.c.b.desc()))
          stmt = select(expr)

     would represent the expression:

          SELECT array_agg(a ORDER BY b DESC) FROM table;

     Similarly:

          expr = func.string_agg(
              table.c.a,
              aggregate_order_by(literal_column("','"), table.c.a)
          )
          stmt = select(expr)

     Would represent:

          SELECT string_agg(a, ',' ORDER BY a) FROM table;

     New in version 1.1.

     Changed in version 1.2.13: - the ORDER BY argument may be multiple
     terms

     See also
     ........

     See array_agg.

     `Class signature'

     class sqlalchemy.dialects.postgresql.aggregate_order_by.
     (see sqlalchemy.sql.expression.ColumnElement)

 -- Class: sqlalchemy.dialects.postgresql.array (clauses, **kw)

     A PostgreSQL ARRAY literal.

     This is used to produce ARRAY literals in SQL expressions, e.g.:

          from sqlalchemy.dialects.postgresql import array
          from sqlalchemy.dialects import postgresql
          from sqlalchemy import select, func

          stmt = select(array([1,2]) + array([3,4,5]))

          print(stmt.compile(dialect=postgresql.dialect()))

     Produces the SQL:

          SELECT ARRAY[%(param_1)s, %(param_2)s] ||
              ARRAY[%(param_3)s, %(param_4)s, %(param_5)s]) AS anon_1

     An instance of array will always have the datatype
     ARRAY.  The “inner” type of the array is inferred from
     the values present, unless the ‘type_’ keyword argument is passed:

          array(['foo', 'bar'], type_=CHAR)

     Multidimensional arrays are produced by nesting array
     constructs.  The dimensionality of the final ARRAY type
     is calculated by recursively adding the dimensions of the inner
     ARRAY type:

          stmt = select(
              array([
                  array([1, 2]), array([3, 4]), array([column('q'), column('x')])
              ])
          )
          print(stmt.compile(dialect=postgresql.dialect()))

     Produces:

          SELECT ARRAY[ARRAY[%(param_1)s, %(param_2)s],
          ARRAY[%(param_3)s, %(param_4)s], ARRAY[q, x]] AS anon_1

     New in version 1.3.6: added support for multidimensional array
     literals

     See also
     ........

     See ARRAY.

     `Class signature'

     class sqlalchemy.dialects.postgresql.array. (see
     sqlalchemy.sql.expression.ClauseList,
     sqlalchemy.sql.expression.ColumnElement)

 -- Class: sqlalchemy.dialects.postgresql.ARRAY (item_type,
          as_tuple=False, dimensions=None, zero_indexes=False)

     PostgreSQL ARRAY type.

     Changed in version 1.1: The ARRAY type is now a
     subclass of the core ARRAY type.

     The ARRAY type is constructed in the same way as the
     core ARRAY type; a member type is required, and a
     number of dimensions is recommended if the type is to be used for
     more than one dimension:

          from sqlalchemy.dialects import postgresql

          mytable = Table("mytable", metadata,
                  Column("data", postgresql.ARRAY(Integer, dimensions=2))
              )

     The ARRAY type provides all operations defined on the
     core ARRAY type, including support for “dimensions”,
     indexed access, and simple matching such as Comparator.any()
     and Comparator.all().  ARRAY class
     also provides PostgreSQL-specific methods for containment
     operations, including Comparator.contains(). See
     Comparator.contained_by(), and Comparator.overlap(),
     e.g.:

          mytable.c.data.contains([1, 2])

     The ARRAY type may not be supported on all PostgreSQL
     DBAPIs; it is currently known to work on psycopg2 only.

     Additionally, the ARRAY type does not work directly in
     conjunction with the ENUM type.  For a workaround, see
     the special type at Using ENUM with ARRAY.

     See also
     ........

     See ARRAY. - base array type

     See array. - produces a literal array value.

     `Class signature'

     class sqlalchemy.dialects.postgresql.ARRAY. (see
     sqlalchemy.types.ARRAY)

      -- Class: Comparator (expr)

          Define comparison operations for ARRAY.

          Note that these operations are in addition to those provided
          by the base Comparator class, including
          Comparator.any() and Comparator.all().

          `Class signature'

          class sqlalchemy.dialects.postgresql.ARRAY.Comparator.
          (‘sqlalchemy.types.Comparator’)

           -- Method:
                    sqlalchemy.dialects.postgresql.ARRAY.Comparator..
                    contained_by (other)

               Boolean expression.  Test if elements are a proper subset
               of the elements of the argument array expression.

           -- Method:
                    sqlalchemy.dialects.postgresql.ARRAY.Comparator..
                    contains (other, **kwargs)

               Boolean expression.  Test if elements are a superset of
               the elements of the argument array expression.

           -- Method:
                    sqlalchemy.dialects.postgresql.ARRAY.Comparator..
                    overlap (other)

               Boolean expression.  Test if array has elements in common
               with an argument array expression.

      -- Method: sqlalchemy.dialects.postgresql.ARRAY..
               __init__ (item_type, as_tuple=False, dimensions=None,
               zero_indexes=False)

          Construct an ARRAY.

          E.g.:

               Column('myarray', ARRAY(Integer))

          Arguments are:

          Parameters:

             * ‘item_type’ – The data type of items of this array.  Note
               that dimensionality is irrelevant here, so
               multi-dimensional arrays like ‘INTEGER[][]’, are
               constructed as ‘ARRAY(Integer)’, not as
               ‘ARRAY(ARRAY(Integer))’ or such.

             * ‘as_tuple=False’ – Specify whether return results should
               be converted to tuples from lists.  DBAPIs such as
               psycopg2 return lists by default.  When tuples are
               returned, the results are hashable.

             * ‘dimensions’ – if non-None, the ARRAY will assume a fixed
               number of dimensions.  This will cause the DDL emitted
               for this ARRAY to include the exact number of bracket
               clauses ‘[]’, and will also optimize the performance of
               the type overall.  Note that PG arrays are always
               implicitly “non-dimensioned”, meaning they can store any
               number of dimensions no matter how they were declared.

             * ‘zero_indexes=False’ – when True, index values will be
               converted between Python zero-based and PostgreSQL
               one-based indexes, e.g.  a value of one will be added to
               all index values before passing to the database.

               New in version 0.9.5.

 -- Function: sqlalchemy.dialects.postgresql.array_agg (*arg, **kw)

     PostgreSQL-specific form of array_agg, ensures return
     type is ARRAY and not the plain ARRAY,
     unless an explicit ‘type_’ is passed.

     New in version 1.1.

 -- Function: sqlalchemy.dialects.postgresql.Any (other, arrexpr,
          operator=<built-in function eq>)

     A synonym for the Comparator.any() method.

     This method is legacy and is here for backwards-compatibility.

     See also
     ........

     See any_().

 -- Function: sqlalchemy.dialects.postgresql.All (other, arrexpr,
          operator=<built-in function eq>)

     A synonym for the Comparator.all() method.

     This method is legacy and is here for backwards-compatibility.

     See also
     ........

     See all_().

 -- Class: sqlalchemy.dialects.postgresql.BIT (length=None,
          varying=False)

     `Class signature'

     class sqlalchemy.dialects.postgresql.BIT. (see
     sqlalchemy.types.TypeEngine)

 -- Class: sqlalchemy.dialects.postgresql.BYTEA (length=None)

     `Class signature'

     class sqlalchemy.dialects.postgresql.BYTEA. (see
     sqlalchemy.types.LargeBinary)

      -- Method: sqlalchemy.dialects.postgresql.BYTEA..
               __init__ (length=None)

          `inherited from the' ‘sqlalchemy.types.LargeBinary.__init__’
          `method of' LargeBinary.

          Construct a LargeBinary type.

          Parameters: ‘length’ – optional, a length for the column for
          use in DDL statements, for those binary types that accept a
          length, such as the MySQL BLOB type.

 -- Class: sqlalchemy.dialects.postgresql.CIDR

     `Class signature'

     class sqlalchemy.dialects.postgresql.CIDR. (see
     sqlalchemy.types.TypeEngine)

 -- Class: sqlalchemy.dialects.postgresql.DOUBLE_PRECISION
          (precision=None, asdecimal=False, decimal_return_scale=None)

     `Class signature'

     class sqlalchemy.dialects.postgresql.DOUBLE_PRECISION.
     (see sqlalchemy.types.Float)

      -- Method: sqlalchemy.dialects.postgresql.DOUBLE_PRECISION..
               __init__ (precision=None, asdecimal=False,
               decimal_return_scale=None)

          `inherited from the' ‘sqlalchemy.types.Float.__init__’ `method
          of' Float.

          Construct a Float.

          Parameters:

             * ‘precision’ – the numeric precision for use in DDL
               ‘CREATE TABLE’.

             * ‘asdecimal’ – the same flag as that of Numeric,
               but defaults to ‘False’.  Note that setting this
               flag to ‘True’ results in floating point conversion.

             * ‘decimal_return_scale’ – Default scale to use when
               converting from floats to Python decimals.  Floating
               point values will typically be much longer due to decimal
               inaccuracy, and most floating point database types don’t
               have a notion of “scale”, so by default the float type
               looks for the first ten decimal places when converting.
               Specifying this value will override that length.  Note
               that the MySQL float types, which do include “scale”,
               will use “scale” as the default for decimal_return_scale,
               if not otherwise specified.

               New in version 0.9.0.

 -- Class: sqlalchemy.dialects.postgresql.ENUM (*enums, **kw)

     PostgreSQL ENUM type.

     This is a subclass of Enum which includes support for
     PG’s ‘CREATE TYPE’ and ‘DROP TYPE’.

     When the builtin type Enum is used and the
     Enum.native_enum flag is left at its default of True, the
     PostgreSQL backend will use a ENUM type as the
     implementation, so the special create/drop rules will be used.

     The create/drop behavior of ENUM is necessarily intricate, due to
     the awkward relationship the ENUM type has in relationship to the
     parent table, in that it may be “owned” by just a single table, or
     may be shared among many tables.

     When using Enum or ENUM in an “inline”
     fashion, the ‘CREATE TYPE’ and ‘DROP TYPE’ is emitted corresponding
     to when the Table.create() and Table.drop()
     methods are called:

          table = Table('sometable', metadata,
              Column('some_enum', ENUM('a', 'b', 'c', name='myenum'))
          )

          table.create(engine)  # will emit CREATE ENUM and CREATE TABLE
          table.drop(engine)  # will emit DROP TABLE and DROP ENUM

     To use a common enumerated type between multiple tables, the best
     practice is to declare the Enum or ENUM
     independently, and associate it with the MetaData object
     itself:

          my_enum = ENUM('a', 'b', 'c', name='myenum', metadata=metadata)

          t1 = Table('sometable_one', metadata,
              Column('some_enum', myenum)
          )

          t2 = Table('sometable_two', metadata,
              Column('some_enum', myenum)
          )

     When this pattern is used, care must still be taken at the level of
     individual table creates.  Emitting CREATE TABLE without also
     specifying ‘checkfirst=True’ will still cause issues:

          t1.create(engine) # will fail: no such type 'myenum'

     If we specify ‘checkfirst=True’, the individual table-level create
     operation will check for the ‘ENUM’ and create if not exists:

          # will check if enum exists, and emit CREATE TYPE if not
          t1.create(engine, checkfirst=True)

     When using a metadata-level ENUM type, the type will always be
     created and dropped if either the metadata-wide create/drop is
     called:

          metadata.create_all(engine)  # will emit CREATE TYPE
          metadata.drop_all(engine)  # will emit DROP TYPE

     The type can also be created and dropped directly:

          my_enum.create(engine)
          my_enum.drop(engine)

     Changed in version 1.0.0: The PostgreSQL ENUM type now
     behaves more strictly with regards to CREATE/DROP. A metadata-level
     ENUM type will only be created and dropped at the metadata level,
     not the table level, with the exception of
     ‘table.create(checkfirst=True)’.  The ‘table.drop()’ call will now
     emit a DROP TYPE for a table-level enumerated type.

     `Class signature'

     class sqlalchemy.dialects.postgresql.ENUM.
     (‘sqlalchemy.types.NativeForEmulated’, see sqlalchemy.types.Enum)

      -- Method: sqlalchemy.dialects.postgresql.ENUM..
               __init__ (*enums, **kw)

          Construct an ENUM.

          Arguments are the same as that of Enum, but also
          including the following parameters.

          Parameters: ‘create_type’ – Defaults to True.  Indicates that
          ‘CREATE TYPE’ should be emitted, after optionally checking for
          the presence of the type, when the parent table is being
          created; and additionally that ‘DROP TYPE’ is called when the
          table is dropped.  When ‘False’, no check will be performed
          and no ‘CREATE TYPE’ or ‘DROP TYPE’ is emitted, unless
          ENUM.create() or ENUM.drop() are called
          directly.  Setting to ‘False’ is helpful when invoking a
          creation scheme to a SQL file without access to the actual
          database - the ENUM.create() and
          ENUM.drop() methods can be used to emit SQL to a target
          bind.

      -- Method: sqlalchemy.dialects.postgresql.ENUM..create
               (bind=None, checkfirst=True)

          Emit ‘CREATE TYPE’ for this ENUM.

          If the underlying dialect does not support PostgreSQL CREATE
          TYPE, no action is taken.

          Parameters:

             * ‘bind’ – a connectable Engine,
               Connection, or similar object to emit SQL.

             * ‘checkfirst’ – if ‘True’, a query against the PG catalog
               will be first performed to see if the type does not exist
               already before creating.

      -- Method: sqlalchemy.dialects.postgresql.ENUM..drop
               (bind=None, checkfirst=True)

          Emit ‘DROP TYPE’ for this ENUM.

          If the underlying dialect does not support PostgreSQL DROP
          TYPE, no action is taken.

          Parameters:

             * ‘bind’ – a connectable Engine,
               Connection, or similar object to emit SQL.

             * ‘checkfirst’ – if ‘True’, a query against the PG catalog
               will be first performed to see if the type actually
               exists before dropping.

 -- Class: sqlalchemy.dialects.postgresql.HSTORE (text_type=None)

     Represent the PostgreSQL HSTORE type.

     The HSTORE type stores dictionaries containing strings,
     e.g.:

          data_table = Table('data_table', metadata,
              Column('id', Integer, primary_key=True),
              Column('data', HSTORE)
          )

          with engine.connect() as conn:
              conn.execute(
                  data_table.insert(),
                  data = {"key1": "value1", "key2": "value2"}
              )

     HSTORE provides for a wide range of operations,
     including:

        * Index operations:

               data_table.c.data['some key'] == 'some value'

        * Containment operations:

               data_table.c.data.has_key('some key')

               data_table.c.data.has_all(['one', 'two', 'three'])

        * Concatenation:

               data_table.c.data + {"k1": "v1"}

     For a full list of special methods see ‘comparator_factory’.

     For usage with the SQLAlchemy ORM, it may be desirable to combine
     the usage of HSTORE with MutableDict
     dictionary now part of the sqlalchemy.ext.mutable
     extension.  This extension will allow “in-place” changes to the
     dictionary, e.g.  addition of new keys or replacement/removal of
     existing keys to/from the current dictionary, to produce events
     which will be detected by the unit of work:

          from sqlalchemy.ext.mutable import MutableDict

          class MyClass(Base):
              __tablename__ = 'data_table'

              id = Column(Integer, primary_key=True)
              data = Column(MutableDict.as_mutable(HSTORE))

          my_object = session.query(MyClass).one()

          # in-place mutation, requires Mutable extension
          # in order for the ORM to detect
          my_object.data['some_key'] = 'some value'

          session.commit()

     When the sqlalchemy.ext.mutable extension is not used,
     the ORM will not be alerted to any changes to the contents of an
     existing dictionary, unless that dictionary value is re-assigned to
     the HSTORE-attribute itself, thus generating a change event.

     See also
     ........

     See hstore. - render the PostgreSQL ‘hstore()’ function.

     `Class signature'

     class sqlalchemy.dialects.postgresql.HSTORE. (see
     sqlalchemy.types.Indexable,
     sqlalchemy.types.Concatenable,
     sqlalchemy.types.TypeEngine)

      -- Class: Comparator (expr)

          Define comparison operations for HSTORE.

          `Class signature'

          class sqlalchemy.dialects.postgresql.HSTORE.Comparator.
          (‘sqlalchemy.types.Comparator’,
          ‘sqlalchemy.types.Comparator’)

           -- Method:
                    sqlalchemy.dialects.postgresql.HSTORE.Comparator..
                    array ()

               Text array expression.  Returns array of alternating keys
               and values.

           -- Method:
                    sqlalchemy.dialects.postgresql.HSTORE.Comparator..
                    contained_by (other)

               Boolean expression.  Test if keys are a proper subset of
               the keys of the argument jsonb expression.

           -- Method:
                    sqlalchemy.dialects.postgresql.HSTORE.Comparator..
                    contains (other, **kwargs)

               Boolean expression.  Test if keys (or array) are a
               superset of/contained the keys of the argument jsonb
               expression.

           -- Method:
                    sqlalchemy.dialects.postgresql.HSTORE.Comparator..
                    defined (key)

               Boolean expression.  Test for presence of a non-NULL
               value for the key.  Note that the key may be a SQLA
               expression.

           -- Method:
                    sqlalchemy.dialects.postgresql.HSTORE.Comparator..
                    delete (key)

               HStore expression.  Returns the contents of this hstore
               with the given key deleted.  Note that the key may be a
               SQLA expression.

           -- Method:
                    sqlalchemy.dialects.postgresql.HSTORE.Comparator..
                    has_all (other)

               Boolean expression.  Test for presence of all keys in
               jsonb

           -- Method:
                    sqlalchemy.dialects.postgresql.HSTORE.Comparator..
                    has_any (other)

               Boolean expression.  Test for presence of any key in
               jsonb

           -- Method:
                    sqlalchemy.dialects.postgresql.HSTORE.Comparator..
                    has_key (other)

               Boolean expression.  Test for presence of a key.  Note
               that the key may be a SQLA expression.

           -- Method:
                    sqlalchemy.dialects.postgresql.HSTORE.Comparator..
                    keys ()

               Text array expression.  Returns array of keys.

           -- Method:
                    sqlalchemy.dialects.postgresql.HSTORE.Comparator..
                    matrix ()

               Text array expression.  Returns array of [key, value]
               pairs.

           -- Method:
                    sqlalchemy.dialects.postgresql.HSTORE.Comparator..
                    slice (array)

               HStore expression.  Returns a subset of an hstore defined
               by array of keys.

           -- Method:
                    sqlalchemy.dialects.postgresql.HSTORE.Comparator..
                    vals ()

               Text array expression.  Returns array of values.

      -- Method: sqlalchemy.dialects.postgresql.HSTORE..
               __init__ (text_type=None)

          Construct a new HSTORE.

          Parameters: ‘text_type’ – the type that should be used for
          indexed values.  Defaults to Text.

          New in version 1.1.0.

      -- Method: sqlalchemy.dialects.postgresql.HSTORE..
               bind_processor (dialect)

          Return a conversion function for processing bind values.

          Returns a callable which will receive a bind parameter value
          as the sole positional argument and will return a value to
          send to the DB-API.

          If processing is not necessary, the method should return
          ‘None’.

          Parameters: ‘dialect’ – Dialect instance in use.

      -- Attribute: sqlalchemy.dialects.postgresql.HSTORE..
               comparator_factory

          alias of
          ‘sqlalchemy.dialects.postgresql.hstore.HSTORE.Comparator’

      -- Method: sqlalchemy.dialects.postgresql.HSTORE..
               result_processor (dialect, coltype)

          Return a conversion function for processing result row values.

          Returns a callable which will receive a result row column
          value as the sole positional argument and will return a value
          to return to the user.

          If processing is not necessary, the method should return
          ‘None’.

          Parameters:

             * ‘dialect’ – Dialect instance in use.

             * ‘coltype’ – DBAPI coltype argument received in
               cursor.description.

 -- Class: sqlalchemy.dialects.postgresql.hstore (*args, **kwargs)

     Construct an hstore value within a SQL expression using the
     PostgreSQL ‘hstore()’ function.

     The hstore function accepts one or two arguments as
     described in the PostgreSQL documentation.

     E.g.:

          from sqlalchemy.dialects.postgresql import array, hstore

          select(hstore('key1', 'value1'))

          select(
              hstore(
                  array(['key1', 'key2', 'key3']),
                  array(['value1', 'value2', 'value3'])
              )
          )

     See also
     ........

     See HSTORE. - the PostgreSQL ‘HSTORE’ datatype.

     `Class signature'

     class sqlalchemy.dialects.postgresql.hstore. (see
     sqlalchemy.sql.functions.GenericFunction)

      -- Attribute: sqlalchemy.dialects.postgresql.hstore..
               type

          alias of ‘sqlalchemy.dialects.postgresql.hstore.HSTORE’

 -- Class: sqlalchemy.dialects.postgresql.INET

     `Class signature'

     class sqlalchemy.dialects.postgresql.INET. (see
     sqlalchemy.types.TypeEngine)

 -- Class: sqlalchemy.dialects.postgresql.INTERVAL (precision=None,
          fields=None)

     PostgreSQL INTERVAL type.

     `Class signature'

     class sqlalchemy.dialects.postgresql.INTERVAL.
     (‘sqlalchemy.types.NativeForEmulated’,
     ‘sqlalchemy.types._AbstractInterval’)

      -- Method: sqlalchemy.dialects.postgresql.INTERVAL..
               __init__ (precision=None, fields=None)

          Construct an INTERVAL.

          Parameters:

             * ‘precision’ – optional integer precision value

             * ‘fields’ – string fields specifier.  allows storage of
               fields to be limited, such as ‘"YEAR"’, ‘"MONTH"’, ‘"DAY
               TO HOUR"’, etc.

               New in version 1.2.

 -- Class: sqlalchemy.dialects.postgresql.JSON (none_as_null=False,
          astext_type=None)

     Represent the PostgreSQL JSON type.

     JSON is used automatically whenever the base
     JSON datatype is used against a PostgreSQL backend, however
     base JSON datatype does not provide Python accessors
     for PostgreSQL-specific comparison methods such as
     Comparator.astext(); additionally, to use PostgreSQL
     ‘JSONB’, the JSONB datatype should be used explicitly.

     See also
     ........

     See JSON. - main documentation for the generic
     cross-platform JSON datatype.

     The operators provided by the PostgreSQL version of JSON
     include:

        * Index operations (the ‘->’ operator):

               data_table.c.data['some key']

               data_table.c.data[5]

        * Index operations returning text (the ‘->>’ operator):

               data_table.c.data['some key'].astext == 'some value'

          Note that equivalent functionality is available via the
          Comparator.as_string accessor.

        * Index operations with CAST (equivalent to ‘CAST(col ->> ['some
          key'] AS <type>)’):

               data_table.c.data['some key'].astext.cast(Integer) == 5

          Note that equivalent functionality is available via the
          Comparator.as_integer and similar accessors.

        * Path index operations (the ‘#>’ operator):

               data_table.c.data[('key_1', 'key_2', 5, ..., 'key_n')]

        * Path index operations returning text (the ‘#>>’ operator):

               data_table.c.data[('key_1', 'key_2', 5, ..., 'key_n')].astext == 'some value'

     Changed in version 1.1: The ColumnElement.cast()
     operator on JSON objects now requires that the
     Comparator.astext modifier be called explicitly, if the cast
     works only from a textual string.

     Index operations return an expression object whose type defaults to
     JSON by default, so that further JSON-oriented
     instructions may be called upon the result type.

     Custom serializers and deserializers are specified at the dialect
     level, that is using create_engine().  The reason for
     this is that when using psycopg2, the DBAPI only allows serializers
     at the per-cursor or per-connection level.  E.g.:

          engine = create_engine("postgresql://scott:tiger@localhost/test",
                                  json_serializer=my_serialize_fn,
                                  json_deserializer=my_deserialize_fn
                          )

     When using the psycopg2 dialect, the json_deserializer is
     registered against the database using
     ‘psycopg2.extras.register_default_json’.

     See also
     ........

     See JSON. - Core level JSON type

     See JSONB.

     Changed in version 1.1: JSON is now a PostgreSQL-
     specific specialization of the new JSON type.

     `Class signature'

     class sqlalchemy.dialects.postgresql.JSON. (see
     sqlalchemy.types.JSON)

      -- Class: Comparator (expr)

          Define comparison operations for JSON.

          `Class signature'

          class sqlalchemy.dialects.postgresql.JSON.Comparator.
          (‘sqlalchemy.types.Comparator’)

           -- Attribute:
                    sqlalchemy.dialects.postgresql.JSON.Comparator..
                    astext

               On an indexed expression, use the “astext” (e.g.  “->>”)
               conversion when rendered in SQL.

               E.g.:

                    select(data_table.c.data['some key'].astext)

               See also
               ........

               See ColumnElement.cast().

      -- Method: sqlalchemy.dialects.postgresql.JSON..
               __init__ (none_as_null=False, astext_type=None)

          Construct a JSON type.

          Parameters:

             * ‘none_as_null’ – if True, persist the value ‘None’ as a
               SQL NULL value, not the JSON encoding of ‘null’.  Note
               that when this flag is False, the null()
               construct can still be used to persist a NULL value:

                    from sqlalchemy import null
                    conn.execute(table.insert(), data=null())

               Changed in version 0.9.8: - Added ‘none_as_null’, and
               null() is now supported in order to persist a
               NULL value.

               See also
               ........

               See JSON.NULL.

             * ‘astext_type’ – the type to use for the
               Comparator.astext accessor on indexed attributes.
               Defaults to Text.

               New in version 1.1.

      -- Attribute: sqlalchemy.dialects.postgresql.JSON..
               comparator_factory

          alias of ‘sqlalchemy.dialects.postgresql.json.JSON.Comparator’

 -- Class: sqlalchemy.dialects.postgresql.JSONB (none_as_null=False,
          astext_type=None)

     Represent the PostgreSQL JSONB type.

     The JSONB type stores arbitrary JSONB format data,
     e.g.:

          data_table = Table('data_table', metadata,
              Column('id', Integer, primary_key=True),
              Column('data', JSONB)
          )

          with engine.connect() as conn:
              conn.execute(
                  data_table.insert(),
                  data = {"key1": "value1", "key2": "value2"}
              )

     The JSONB type includes all operations provided by
     JSON, including the same behaviors for indexing
     operations.  It also adds additional operators specific to JSONB,
     including Comparator.has_key(),
     Comparator.has_all(), Comparator.has_any(),
     Comparator.contains(), and Comparator.contained_by().

     Like the JSON type, the JSONB type does
     not detect in-place changes when used with the ORM, unless the
     sqlalchemy.ext.mutable extension is used.

     Custom serializers and deserializers are shared with the
     JSON class, using the ‘json_serializer’ and
     ‘json_deserializer’ keyword arguments.  These must be specified at
     the dialect level using create_engine().  When using
     psycopg2, the serializers are associated with the jsonb type using
     ‘psycopg2.extras.register_default_jsonb’ on a per-connection basis,
     in the same way that ‘psycopg2.extras.register_default_json’ is
     used to register these handlers with the json type.

     New in version 0.9.7.

     See also
     ........

     See JSON.

     `Class signature'

     class sqlalchemy.dialects.postgresql.JSONB.
     (‘sqlalchemy.dialects.postgresql.json.JSON’)

      -- Class: Comparator (expr)

          Define comparison operations for JSON.

          `Class signature'

          class sqlalchemy.dialects.postgresql.JSONB.Comparator.
          (‘sqlalchemy.dialects.postgresql.json.Comparator’)

           -- Method:
                    sqlalchemy.dialects.postgresql.JSONB.Comparator..
                    contained_by (other)

               Boolean expression.  Test if keys are a proper subset of
               the keys of the argument jsonb expression.

           -- Method:
                    sqlalchemy.dialects.postgresql.JSONB.Comparator..
                    contains (other, **kwargs)

               Boolean expression.  Test if keys (or array) are a
               superset of/contained the keys of the argument jsonb
               expression.

           -- Method:
                    sqlalchemy.dialects.postgresql.JSONB.Comparator..
                    has_all (other)

               Boolean expression.  Test for presence of all keys in
               jsonb

           -- Method:
                    sqlalchemy.dialects.postgresql.JSONB.Comparator..
                    has_any (other)

               Boolean expression.  Test for presence of any key in
               jsonb

           -- Method:
                    sqlalchemy.dialects.postgresql.JSONB.Comparator..
                    has_key (other)

               Boolean expression.  Test for presence of a key.  Note
               that the key may be a SQLA expression.

      -- Attribute: sqlalchemy.dialects.postgresql.JSONB..
               comparator_factory

          alias of
          ‘sqlalchemy.dialects.postgresql.json.JSONB.Comparator’

 -- Class: sqlalchemy.dialects.postgresql.MACADDR

     `Class signature'

     class sqlalchemy.dialects.postgresql.MACADDR. (see
     sqlalchemy.types.TypeEngine)

 -- Class: sqlalchemy.dialects.postgresql.MONEY

     Provide the PostgreSQL MONEY type.

     Depending on driver, result rows using this type may return a
     string value which includes currency symbols.

     For this reason, it may be preferable to provide conversion to a
     numerically-based currency datatype using TypeDecorator:

          import re
          import decimal
          from sqlalchemy import TypeDecorator

          class NumericMoney(TypeDecorator):
              impl = MONEY

              def process_result_value(self, value: Any, dialect: Any) -> None:
                  if value is not None:
                      # adjust this for the currency and numeric
                      m = re.match(r"\$([\d.]+)", value)
                      if m:
                          value = decimal.Decimal(m.group(1))
                  return value

     Alternatively, the conversion may be applied as a CAST using the
     TypeDecorator.column_expression() method as follows:

          import decimal
          from sqlalchemy import cast
          from sqlalchemy import TypeDecorator

          class NumericMoney(TypeDecorator):
              impl = MONEY

              def column_expression(self, column: Any):
                  return cast(column, Numeric())

     New in version 1.2.

     `Class signature'

     class sqlalchemy.dialects.postgresql.MONEY. (see
     sqlalchemy.types.TypeEngine)

 -- Class: sqlalchemy.dialects.postgresql.OID

     Provide the PostgreSQL OID type.

     New in version 0.9.5.

     `Class signature'

     class sqlalchemy.dialects.postgresql.OID. (see
     sqlalchemy.types.TypeEngine)

 -- Class: sqlalchemy.dialects.postgresql.REAL (precision=None,
          asdecimal=False, decimal_return_scale=None)

     The SQL REAL type.

     `Class signature'

     class sqlalchemy.dialects.postgresql.REAL. (see
     sqlalchemy.types.Float)

      -- Method: sqlalchemy.dialects.postgresql.REAL..
               __init__ (precision=None, asdecimal=False,
               decimal_return_scale=None)

          `inherited from the' ‘sqlalchemy.types.Float.__init__’ `method
          of' Float.

          Construct a Float.

          Parameters:

             * ‘precision’ – the numeric precision for use in DDL
               ‘CREATE TABLE’.

             * ‘asdecimal’ – the same flag as that of Numeric,
               but defaults to ‘False’.  Note that setting this
               flag to ‘True’ results in floating point conversion.

             * ‘decimal_return_scale’ – Default scale to use when
               converting from floats to Python decimals.  Floating
               point values will typically be much longer due to decimal
               inaccuracy, and most floating point database types don’t
               have a notion of “scale”, so by default the float type
               looks for the first ten decimal places when converting.
               Specifying this value will override that length.  Note
               that the MySQL float types, which do include “scale”,
               will use “scale” as the default for decimal_return_scale,
               if not otherwise specified.

               New in version 0.9.0.

 -- Class: sqlalchemy.dialects.postgresql.REGCLASS

     Provide the PostgreSQL REGCLASS type.

     New in version 1.2.7.

     `Class signature'

     class sqlalchemy.dialects.postgresql.REGCLASS. (see
     sqlalchemy.types.TypeEngine)

 -- Class: sqlalchemy.dialects.postgresql.TSVECTOR

     The TSVECTOR type implements the PostgreSQL text
     search type TSVECTOR.

     It can be used to do full text queries on natural language
     documents.

     New in version 0.9.0.

     See also
     ........

     See Full Text Search.

     `Class signature'

     class sqlalchemy.dialects.postgresql.TSVECTOR. (see
     sqlalchemy.types.TypeEngine)

 -- Class: sqlalchemy.dialects.postgresql.UUID (as_uuid=False)

     PostgreSQL UUID type.

     Represents the UUID column type, interpreting data either as
     natively returned by the DBAPI or as Python uuid objects.

     The UUID type may not be supported on all DBAPIs.  It is known to
     work on psycopg2 and not pg8000.

     `Class signature'

     class sqlalchemy.dialects.postgresql.UUID. (see
     sqlalchemy.types.TypeEngine)

      -- Method: sqlalchemy.dialects.postgresql.UUID..
               __init__ (as_uuid=False)

          Construct a UUID type.

          Parameters: ‘as_uuid=False’ – if True, values will be
          interpreted as Python uuid objects, converting to/from string
          via the DBAPI.

5.1.1.40 Range Types
....................

The new range column types found in PostgreSQL 9.2 onwards are catered
for by the following types:

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See DATERANGE.Represent the PostgreSQL DATERANGE type.

See INT4RANGE.Represent the PostgreSQL INT4RANGE type.

See INT8RANGE.Represent the PostgreSQL INT8RANGE type.

See NUMRANGE.Represent the PostgreSQL NUMRANGE type.

See RangeOperators.This mixin provides functionality for the Range Operators listed in Table 9-44 of the
               PostgreSQL documentation(1) for Range Functions and Operators.  It is used by all the range
               types provided in the ‘postgres’ dialect and can likely be used for any range types you
               create yourself.

See TSRANGE.Represent the PostgreSQL TSRANGE type.

See TSTZRANGE.Represent the PostgreSQL TSTZRANGE type.

 -- Class: sqlalchemy.dialects.postgresql.INT4RANGE

     Represent the PostgreSQL INT4RANGE type.

     `Class signature'

     class sqlalchemy.dialects.postgresql.INT4RANGE. (see
     sqlalchemy.dialects.postgresql.ranges.RangeOperators,
     sqlalchemy.types.TypeEngine)

 -- Class: sqlalchemy.dialects.postgresql.INT8RANGE

     Represent the PostgreSQL INT8RANGE type.

     `Class signature'

     class sqlalchemy.dialects.postgresql.INT8RANGE. (see
     sqlalchemy.dialects.postgresql.ranges.RangeOperators,
     sqlalchemy.types.TypeEngine)

 -- Class: sqlalchemy.dialects.postgresql.NUMRANGE

     Represent the PostgreSQL NUMRANGE type.

     `Class signature'

     class sqlalchemy.dialects.postgresql.NUMRANGE. (see
     sqlalchemy.dialects.postgresql.ranges.RangeOperators,
     sqlalchemy.types.TypeEngine)

 -- Class: sqlalchemy.dialects.postgresql.DATERANGE

     Represent the PostgreSQL DATERANGE type.

     `Class signature'

     class sqlalchemy.dialects.postgresql.DATERANGE. (see
     sqlalchemy.dialects.postgresql.ranges.RangeOperators,
     sqlalchemy.types.TypeEngine)

 -- Class: sqlalchemy.dialects.postgresql.TSRANGE

     Represent the PostgreSQL TSRANGE type.

     `Class signature'

     class sqlalchemy.dialects.postgresql.TSRANGE. (see
     sqlalchemy.dialects.postgresql.ranges.RangeOperators,
     sqlalchemy.types.TypeEngine)

 -- Class: sqlalchemy.dialects.postgresql.TSTZRANGE

     Represent the PostgreSQL TSTZRANGE type.

     `Class signature'

     class sqlalchemy.dialects.postgresql.TSTZRANGE. (see
     sqlalchemy.dialects.postgresql.ranges.RangeOperators,
     sqlalchemy.types.TypeEngine)

The types above get most of their functionality from the following
mixin:

 -- Class: sqlalchemy.dialects.postgresql.ranges.RangeOperators

     This mixin provides functionality for the Range Operators listed in
     Table 9-44 of the PostgreSQL documentation(2) for Range Functions
     and Operators.  It is used by all the range types provided in the
     ‘postgres’ dialect and can likely be used for any range types you
     create yourself.

     No extra support is provided for the Range Functions listed in
     Table 9-45 of the PostgreSQL documentation.  For these, the normal
     func() object should be used.

      -- Class: comparator_factory (expr)

          Define comparison operations for range types.

          `Class signature'

          class
          sqlalchemy.dialects.postgresql.ranges.RangeOperators.comparator_factory.
          (‘sqlalchemy.types.Comparator’)

           -- Method:
                    sqlalchemy.dialects.postgresql.ranges.RangeOperators.comparator_factory..
                    __ne__ (other)

               Boolean expression.  Returns true if two ranges are not
               equal

           -- Method:
                    sqlalchemy.dialects.postgresql.ranges.RangeOperators.comparator_factory..
                    adjacent_to (other)

               Boolean expression.  Returns true if the range in the
               column is adjacent to the range in the operand.

           -- Method:
                    sqlalchemy.dialects.postgresql.ranges.RangeOperators.comparator_factory..
                    contained_by (other)

               Boolean expression.  Returns true if the column is
               contained within the right hand operand.

           -- Method:
                    sqlalchemy.dialects.postgresql.ranges.RangeOperators.comparator_factory..
                    contains (other, **kw)

               Boolean expression.  Returns true if the right hand
               operand, which can be an element or a range, is contained
               within the column.

           -- Method:
                    sqlalchemy.dialects.postgresql.ranges.RangeOperators.comparator_factory..
                    not_extend_left_of (other)

               Boolean expression.  Returns true if the range in the
               column does not extend left of the range in the operand.

           -- Method:
                    sqlalchemy.dialects.postgresql.ranges.RangeOperators.comparator_factory..
                    not_extend_right_of (other)

               Boolean expression.  Returns true if the range in the
               column does not extend right of the range in the operand.

           -- Method:
                    sqlalchemy.dialects.postgresql.ranges.RangeOperators.comparator_factory..
                    overlaps (other)

               Boolean expression.  Returns true if the column overlaps
               (has points in common with) the right hand operand.

           -- Method:
                    sqlalchemy.dialects.postgresql.ranges.RangeOperators.comparator_factory..
                    strictly_left_of (other)

               Boolean expression.  Returns true if the column is
               strictly left of the right hand operand.

           -- Method:
                    sqlalchemy.dialects.postgresql.ranges.RangeOperators.comparator_factory..
                    strictly_right_of (other)

               Boolean expression.  Returns true if the column is
               strictly right of the right hand operand.

     Warning: The range type DDL support should work with any PostgreSQL
     DBAPI driver, however the data types returned may vary.  If you are
     using ‘psycopg2’, it’s recommended to upgrade to version 2.5 or
     later before using these column types.

When instantiating models that use these column types, you should pass
whatever data type is expected by the DBAPI driver you’re using for the
column type.  For ‘psycopg2’ these are ‘psycopg2.extras.NumericRange’,
‘psycopg2.extras.DateRange’, ‘psycopg2.extras.DateTimeRange’ and
‘psycopg2.extras.DateTimeTZRange’ or the class you’ve registered with
‘psycopg2.extras.register_range’.

For example:

     from psycopg2.extras import DateTimeRange
     from sqlalchemy.dialects.postgresql import TSRANGE

     class RoomBooking(Base):

         __tablename__ = 'room_booking'

         room = Column(Integer(), primary_key=True)
         during = Column(TSRANGE())

     booking = RoomBooking(
         room=101,
         during=DateTimeRange(datetime(2013, 3, 23), None)
     )

   ---------- Footnotes ----------

   (1) http://www.postgresql.org/docs/devel/static/functions-range.html

   (2) http://www.postgresql.org/docs/devel/static/functions-range.html

5.1.1.41 PostgreSQL Constraint Types
....................................

SQLAlchemy supports PostgreSQL EXCLUDE constraints via the
ExcludeConstraint class:

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See ExcludeConstraint.A table-level EXCLUDE constraint.

 -- Class: sqlalchemy.dialects.postgresql.ExcludeConstraint (*elements,
          **kw)

     A table-level EXCLUDE constraint.

     Defines an EXCLUDE constraint as described in the PostgreSQL
     documentation(1).

     `Class signature'

     class sqlalchemy.dialects.postgresql.ExcludeConstraint.
     (see sqlalchemy.schema.ColumnCollectionConstraint)

      -- Method:
               sqlalchemy.dialects.postgresql.ExcludeConstraint..
               __init__ (*elements, **kw)

          Create an ExcludeConstraint object.

          E.g.:

               const = ExcludeConstraint(
                   (Column('period'), '&&'),
                   (Column('group'), '='),
                   where=(Column('group') != 'some group'),
                   ops={'group': 'my_operator_class'}
               )

          The constraint is normally embedded into the Table
          construct directly, or added later using
          append_constraint():

               some_table = Table(
                   'some_table', metadata,
                   Column('id', Integer, primary_key=True),
                   Column('period', TSRANGE()),
                   Column('group', String)
               )

               some_table.append_constraint(
                   ExcludeConstraint(
                       (some_table.c.period, '&&'),
                       (some_table.c.group, '='),
                       where=some_table.c.group != 'some group',
                       name='some_table_excl_const',
                       ops={'group': 'my_operator_class'}
                   )
               )

          Parameters:

             * ‘*elements’ – A sequence of two tuples of the form
               ‘(column, operator)’ where “column” is a SQL expression
               element or a raw SQL string, most typically a
               Column object, and “operator” is a string containing
               the operator to use.  In order to specify a column name
               when a Column object is not available, while
               ensuring that any necessary quoting rules take effect, an
               ad-hoc Column or column() object
               should be used.

             * ‘name’ – Optional, the in-database name of this
               constraint.

             * ‘deferrable’ – Optional bool.  If set, emit DEFERRABLE or
               NOT DEFERRABLE when issuing DDL for this constraint.

             * ‘initially’ – Optional string.  If set, emit INITIALLY
               <value> when issuing DDL for this constraint.

             * ‘using’ – Optional string.  If set, emit USING
               <index_method> when issuing DDL for this constraint.
               Defaults to ‘gist’.

             * ‘where’ – Optional SQL expression construct or literal
               SQL string.  If set, emit WHERE <predicate> when issuing
               DDL for this constraint.

                    Warning: The ExcludeConstraint.where
                    argument to ExcludeConstraint can be
                    passed as a Python string argument, which will be
                    treated as `trusted SQL text' and rendered as given.
                    `DO NOT PASS UNTRUSTED INPUT TO THIS PARAMETER'.

             * ‘ops’ – Optional dictionary.  Used to define operator
               classes for the elements; works the same way as that of
               the postgresql_ops parameter specified to
               the Index construct.

               New in version 1.3.21.

               See also
               ........

               See Operator Classes. - general description of
               how PostgreSQL operator classes are specified.

For example:

     from sqlalchemy.dialects.postgresql import ExcludeConstraint, TSRANGE

     class RoomBooking(Base):

         __tablename__ = 'room_booking'

         room = Column(Integer(), primary_key=True)
         during = Column(TSRANGE())

         __table_args__ = (
             ExcludeConstraint(('room', '='), ('during', '&&')),
         )

   ---------- Footnotes ----------

   (1)
http://www.postgresql.org/docs/9.0/static/sql-createtable.html#SQL-CREATETABLE-EXCLUDE

5.1.1.42 PostgreSQL DML Constructs
..................................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See insert.(table[,Construct an Insert object.
values,
inline,
bind, ...],
**dialect_kw)

See Insert.PostgreSQL-specific implementation of INSERT.

 -- Function: sqlalchemy.dialects.postgresql.insert (table, values=None,
          inline=False, bind=None, prefixes=None, returning=None,
          return_defaults=False, **dialect_kw)

     Construct an Insert object.

     This documentation is inherited from
     sqlalchemy.sql.expression.insert(); this constructor, see
     sqlalchemy.dialects.postgresql.insert(), creates a
     sqlalchemy.dialects.postgresql.Insert object.  See that
     class for additional details describing this subclass.

     E.g.:

          from sqlalchemy import insert

          stmt = (
              insert(user_table).
              values(name='username', fullname='Full Username')
          )

     Similar functionality is available via the
     TableClause.insert() method on Table.

     See also
     ........

     See Insert Expressions. - in the 1.x tutorial.

     See Core Insert. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

     Parameters:

        * ‘table’ – see TableClause which is the subject of the
          insert.

        * ‘values’ – collection of values to be inserted; see
          Insert.values() for a description of allowed formats
          here.  Can be omitted entirely; a Insert construct
          will also dynamically render the VALUES clause at execution
          time based on the parameters passed to
          Connection.execute().

          Deprecated since version 1.4: The insert.values
          parameter will be removed in SQLAlchemy 2.0.  Please refer to
          the Insert.values() method.

        * ‘inline’ – if True, no attempt will be made to retrieve the
          SQL-generated default values to be provided within the
          statement; in particular, this allows SQL expressions to be
          rendered ‘inline’ within the statement without the need to
          pre-execute them beforehand; for backends that support
          “returning”, this turns off the “implicit returning” feature
          for the statement.

          Deprecated since version 1.4: The insert.inline
          parameter will be removed in SQLAlchemy 2.0.  Please use the
          Insert.inline() method.

     If both Insert.values and compile-time bind parameters
     are present, the compile-time bind parameters override the
     information specified within Insert.values on a per-key
     basis.

     The keys within Insert.values can be either
     Column objects or their string identifiers.  Each key may
     reference one of:

        * a literal data value (i.e.  string, number, etc.);

        * a Column object;

        * a SELECT statement.

     If a ‘SELECT’ statement is specified which references this ‘INSERT’
     statement’s table, the statement will be correlated against the
     ‘INSERT’ statement.

     See also
     ........

     See Insert Expressions. - SQL Expression Tutorial

     See Inserts, Updates and Deletes. - SQL Expression Tutorial

 -- Class: sqlalchemy.dialects.postgresql.Insert (table, values=None,
          inline=False, bind=None, prefixes=None, returning=None,
          return_defaults=False, **dialect_kw)

     PostgreSQL-specific implementation of INSERT.

     Adds methods for PG-specific syntaxes such as ON CONFLICT.

     The Insert object is created using the
     sqlalchemy.dialects.postgresql.insert() function.

     New in version 1.1.

     `Class signature'

     class sqlalchemy.dialects.postgresql.Insert. (see
     sqlalchemy.sql.expression.Insert)

      -- Attribute: sqlalchemy.dialects.postgresql.Insert..
               excluded

          Provide the ‘excluded’ namespace for an ON CONFLICT statement

          PG’s ON CONFLICT clause allows reference to the row that would
          be inserted, known as ‘excluded’.  This attribute provides all
          columns in this row to be referenceable.

          See also
          ........

          See INSERT…ON CONFLICT (Upsert). - example of how to
          use ‘Insert.excluded’

      -- Method: sqlalchemy.dialects.postgresql.Insert..
               on_conflict_do_nothing (constraint=None,
               index_elements=None, index_where=None)

          Specifies a DO NOTHING action for ON CONFLICT clause.

          The ‘constraint’ and ‘index_elements’ arguments are optional,
          but only one of these can be specified.

          Parameters:

             * ‘constraint’ – The name of a unique or exclusion
               constraint on the table, or the constraint object itself
               if it has a .name attribute.

             * ‘index_elements’ – A sequence consisting of string column
               names, see Column objects, or other column
               expression objects that will be used to infer a target
               index.

             * ‘index_where’ – Additional WHERE criterion that can be
               used to infer a conditional target index.

               New in version 1.1.

          See also
          ........

          See INSERT…ON CONFLICT (Upsert).

      -- Method: sqlalchemy.dialects.postgresql.Insert..
               on_conflict_do_update (constraint=None,
               index_elements=None, index_where=None, set_=None,
               where=None)

          Specifies a DO UPDATE SET action for ON CONFLICT clause.

          Either the ‘constraint’ or ‘index_elements’ argument is
          required, but only one of these can be specified.

          Parameters:

             * ‘constraint’ – The name of a unique or exclusion
               constraint on the table, or the constraint object itself
               if it has a .name attribute.

             * ‘index_elements’ – A sequence consisting of string column
               names, see Column objects, or other column
               expression objects that will be used to infer a target
               index.

             * ‘index_where’ – Additional WHERE criterion that can be
               used to infer a conditional target index.

             * ‘set_’ – A dictionary or other mapping object where the
               keys are either names of columns in the target table, or
               Column objects or other ORM-mapped columns
               matching that of the target table, and expressions or
               literals as values, specifying the ‘SET’ actions to take.

               New in version 1.4: The
               Insert.on_conflict_do_update.set_ parameter
               supports Column objects from the target
               Table as keys.

                    Warning: This dictionary does `not' take into
                    account Python-specified default UPDATE values or
                    generation functions, e.g.  those specified using
                    Column.onupdate.  These values will not
                    be exercised for an ON CONFLICT style of UPDATE,
                    unless they are manually specified in the
                    Insert.on_conflict_do_update.set_ dictionary.

             * ‘where’ – Optional argument.  If present, can be a
               literal SQL string or an acceptable expression for a
               ‘WHERE’ clause that restricts the rows affected by ‘DO
               UPDATE SET’.  Rows not meeting the ‘WHERE’ condition will
               not be updated (effectively a ‘DO NOTHING’ for those
               rows).

               New in version 1.1.

          See also
          ........

          See INSERT…ON CONFLICT (Upsert).

5.1.1.43 psycopg2
.................

Support for the PostgreSQL database via the psycopg2 driver.

5.1.1.44 DBAPI
..............

Documentation and download information (if applicable) for psycopg2 is
available at: ‘http://pypi.python.org/pypi/psycopg2/’

5.1.1.45 Connecting
...................

Connect String:
     postgresql+psycopg2://user:password@host:port/dbname[?key=value&key=value...]

5.1.1.46 psycopg2 Connect Arguments
...................................

psycopg2-specific keyword arguments which are accepted by
create_engine() are:

   * ‘isolation_level’: This option, available for all PostgreSQL
     dialects, includes the ‘AUTOCOMMIT’ isolation level when using the
     psycopg2 dialect.

     See also
     ........

     See Psycopg2 Transaction Isolation Level.

   * ‘client_encoding’: sets the client encoding in a libpq-agnostic
     way, using psycopg2’s ‘set_client_encoding()’ method.

     See also
     ........

     See Unicode with Psycopg2.

   * ‘use_native_unicode’: Under Python 2 only, this can be set to False
     to disable the use of psycopg2’s native Unicode support.

     See also
     ........

     See Disabling Native Unicode.

   * ‘executemany_mode’, ‘executemany_batch_page_size’,
     ‘executemany_values_page_size’: Allows use of psycopg2 extensions
     for optimizing “executemany”-stye queries.  See the referenced
     section below for details.

     See also
     ........

     See Psycopg2 Fast Execution Helpers.

5.1.1.47 Unix Domain Connections
................................

psycopg2 supports connecting via Unix domain connections.  When the
‘host’ portion of the URL is omitted, SQLAlchemy passes ‘None’ to
psycopg2, which specifies Unix-domain communication rather than TCP/IP
communication:

     create_engine("postgresql+psycopg2://user:password@/dbname")

By default, the socket file used is to connect to a Unix-domain socket
in ‘/tmp’, or whatever socket directory was specified when PostgreSQL
was built.  This value can be overridden by passing a pathname to
psycopg2, using ‘host’ as an additional keyword argument:

     create_engine("postgresql+psycopg2://user:password@/dbname?host=/var/lib/postgresql")

See also
........

PQconnectdbParams(1)

   ---------- Footnotes ----------

   (1)
http://www.postgresql.org/docs/9.1/static/libpq-connect.html#LIBPQ-PQCONNECTDBPARAMS

5.1.1.48 Specifiying multiple fallback hosts
............................................

psycopg2 supports multiple connection points in the connection string.
When the ‘host’ parameter is used multiple times in the query section of
the URL, SQLAlchemy will create a single string of the host and port
information provided to make the connections:

     create_engine(
         "postgresql+psycopg2://user:password@/dbname?host=HostA:port1&host=HostB&host=HostC"
     )

A connection to each host is then attempted until either a connection is
successful or all connections are unsuccessful in which case an error is
raised.

New in version 1.3.20: Support for multiple hosts in PostgreSQL
connection string.

See also
........

PQConnString(1)

   ---------- Footnotes ----------

   (1)
https://www.postgresql.org/docs/10/libpq-connect.html#LIBPQ-CONNSTRING

5.1.1.49 Empty DSN Connections / Environment Variable Connections
.................................................................

The psycopg2 DBAPI can connect to PostgreSQL by passing an empty DSN to
the libpq client library, which by default indicates to connect to a
localhost PostgreSQL database that is open for “trust” connections.
This behavior can be further tailored using a particular set of
environment variables which are prefixed with ‘PG_...’, which are
consumed by ‘libpq’ to take the place of any or all elements of the
connection string.

For this form, the URL can be passed without any elements other than the
initial scheme:

     engine = create_engine('postgresql+psycopg2://')

In the above form, a blank “dsn” string is passed to the
‘psycopg2.connect()’ function which in turn represents an empty DSN
passed to libpq.

New in version 1.3.2: support for parameter-less connections with
psycopg2.

See also
........

Environment Variables(1) - PostgreSQL documentation on how to use
‘PG_...’ environment variables for connections.

   ---------- Footnotes ----------

   (1) https://www.postgresql.org/docs/current/libpq-envars.html

5.1.1.50 Per-Statement/Connection Execution Options
...................................................

The following DBAPI-specific options are respected when used with
Connection.execution_options(),
Executable.execution_options(), Query.execution_options(),
in addition to those not specific to DBAPIs:

   * ‘isolation_level’ - Set the transaction isolation level for the
     lifespan of a Connection. (can only be set on a
     connection, not a statement or query).  See Psycopg2 Transaction Isolation Level.

   * ‘stream_results’ - Enable or disable usage of psycopg2 server side
     cursors - this feature makes use of “named” cursors in combination
     with special result handling methods so that result rows are not
     fully buffered.  Defaults to False, meaning cursors are buffered by
     default.

   * ‘max_row_buffer’ - when using ‘stream_results’, an integer value
     that specifies the maximum number of rows to buffer at a time.
     This is interpreted by the ‘BufferedRowCursorResult’, and if
     omitted the buffer will grow to ultimately store 1000 rows at a
     time.

     Changed in version 1.4: The ‘max_row_buffer’ size can now be
     greater than 1000, and the buffer will grow to that size.

5.1.1.51 Psycopg2 Fast Execution Helpers
........................................

Modern versions of psycopg2 include a feature known as Fast Execution
Helpers(1), which have been shown in benchmarking to improve psycopg2’s
executemany() performance, primarily with INSERT statements, by multiple
orders of magnitude.  SQLAlchemy internally makes use of these
extensions for ‘executemany()’ style calls, which correspond to lists of
parameters being passed to Connection.execute() as detailed
in multiple parameter sets.  The ORM also uses this mode
internally whenever possible.

The two available extensions on the psycopg2 side are the
‘execute_values()’ and ‘execute_batch()’ functions.  The psycopg2
dialect defaults to using the ‘execute_values()’ extension for all
qualifying INSERT statements.

Changed in version 1.4: The psycopg2 dialect now defaults to a new mode
‘"values_only"’ for ‘executemany_mode’, which allows an order of
magnitude performance improvement for INSERT statements, but does not
include “batch” mode for UPDATE and DELETE statements which removes the
ability of ‘cursor.rowcount’ to function correctly.

The use of these extensions is controlled by the ‘executemany_mode’ flag
which may be passed to create_engine():

     engine = create_engine(
         "postgresql+psycopg2://scott:tiger@host/dbname",
         executemany_mode='values_plus_batch')

Possible options for ‘executemany_mode’ include:

   * ‘values_only’ - this is the default value.  the psycopg2
     execute_values() extension is used for qualifying INSERT
     statements, which rewrites the INSERT to include multiple VALUES
     clauses so that many parameter sets can be inserted with one
     statement.

     New in version 1.4: Added ‘"values_only"’ setting for
     ‘executemany_mode’ which is also now the default.

   * ‘None’ - No psycopg2 extensions are not used, and the usual
     ‘cursor.executemany()’ method is used when invoking statements with
     multiple parameter sets.

   * ‘'batch'’ - Uses ‘psycopg2.extras.execute_batch’ for all qualifying
     INSERT, UPDATE and DELETE statements, so that multiple copies of a
     SQL query, each one corresponding to a parameter set passed to
     ‘executemany()’, are joined into a single SQL string separated by a
     semicolon.  When using this mode, the CursorResult.rowcount
     attribute will not contain a value for executemany-style
     executions.

   * ‘'values_plus_batch'’- ‘execute_values’ is used for qualifying
     INSERT statements, ‘execute_batch’ is used for UPDATE and DELETE.
     When using this mode, the CursorResult.rowcount
     attribute will not contain a value for executemany-style executions
     against UPDATE and DELETE statements.

By “qualifying statements”, we mean that the statement being executed
must be a Core insert(), update() or
delete() construct, and not a plain textual SQL string or one
constructed using text().  When using the ORM, all
insert/update/delete statements used by the ORM flush process are
qualifying.

The “page size” for the “values” and “batch” strategies can be affected
by using the ‘executemany_batch_page_size’ and
‘executemany_values_page_size’ engine parameters.  These control how
many parameter sets should be represented in each execution.  The
“values” page size defaults to 1000, which is different that psycopg2’s
default.  The “batch” page size defaults to 100.  These can be affected
by passing new values to ‘create_engine()’:

     engine = create_engine(
         "postgresql+psycopg2://scott:tiger@host/dbname",
         executemany_mode='values',
         executemany_values_page_size=10000, executemany_batch_page_size=500)

Changed in version 1.4: The default for ‘executemany_values_page_size’
is now 1000, up from 100.

See also
........

See Executing Multiple Statements. - General information on using
the Connection object to execute statements in such a way as
to make use of the DBAPI ‘.executemany()’ method.

   ---------- Footnotes ----------

   (1) http://initd.org/psycopg/docs/extras.html#fast-execution-helpers

5.1.1.52 Unicode with Psycopg2
..............................

The psycopg2 DBAPI driver supports Unicode data transparently.  Under
Python 2 only, the SQLAlchemy psycopg2 dialect will enable the
‘psycopg2.extensions.UNICODE’ extension by default to ensure Unicode is
handled properly; under Python 3, this is psycopg2’s default behavior.

The client character encoding can be controlled for the psycopg2 dialect
in the following ways:

   * For PostgreSQL 9.1 and above, the ‘client_encoding’ parameter may
     be passed in the database URL; this parameter is consumed by the
     underlying ‘libpq’ PostgreSQL client library:

          engine = create_engine("postgresql+psycopg2://user:pass@host/dbname?client_encoding=utf8")

     Alternatively, the above ‘client_encoding’ value may be passed
     using create_engine.connect_args for programmatic
     establishment with ‘libpq’:

          engine = create_engine(
              "postgresql+psycopg2://user:pass@host/dbname",
              connect_args={'client_encoding': 'utf8'}
          )

   * For all PostgreSQL versions, psycopg2 supports a client-side
     encoding value that will be passed to database connections when
     they are first established.  The SQLAlchemy psycopg2 dialect
     supports this using the ‘client_encoding’ parameter passed to
     create_engine():

          engine = create_engine(
              "postgresql+psycopg2://user:pass@host/dbname",
              client_encoding="utf8"
          )

          Tip: The above ‘client_encoding’ parameter admittedly is very
          similar in appearance to usage of the parameter within the
          create_engine.connect_args dictionary; the
          difference above is that the parameter is consumed by psycopg2
          and is passed to the database connection using ‘SET
          client_encoding TO 'utf8'’; in the previously mentioned style,
          the parameter is instead passed through psycopg2 and consumed
          by the ‘libpq’ library.

   * A common way to set up client encoding with PostgreSQL databases is
     to ensure it is configured within the server-side postgresql.conf
     file; this is the recommended way to set encoding for a server that
     is consistently of one encoding in all databases:

          # postgresql.conf file

          # client_encoding = sql_ascii # actually, defaults to database
                                       # encoding
          client_encoding = utf8

5.1.1.53 Disabling Native Unicode
.................................

Under Python 2 only, SQLAlchemy can also be instructed to skip the usage
of the psycopg2 ‘UNICODE’ extension and to instead utilize its own
unicode encode/decode services, which are normally reserved only for
those DBAPIs that don’t fully support unicode directly.  Passing
‘use_native_unicode=False’ to create_engine() will disable
usage of ‘psycopg2.extensions. UNICODE’.  SQLAlchemy will instead encode
data itself into Python bytestrings on the way in and coerce from bytes
on the way back, using the value of the create_engine().
‘encoding’ parameter, which defaults to ‘utf-8’.  SQLAlchemy’s own
unicode encode/decode functionality is steadily becoming obsolete as
most DBAPIs now support unicode fully.

5.1.1.54 Transactions
.....................

The psycopg2 dialect fully supports SAVEPOINT and two-phase commit
operations.

5.1.1.55 Psycopg2 Transaction Isolation Level
.............................................

As discussed in Transaction Isolation Level, all PostgreSQL
dialects support setting of transaction isolation level both via the
‘isolation_level’ parameter passed to create_engine(). , as
well as the ‘isolation_level’ argument used by
Connection.execution_options().  When using the psycopg2 dialect ,
these options make use of psycopg2’s ‘set_isolation_level()’ connection
method, rather than emitting a PostgreSQL directive; this is because
psycopg2’s API-level setting is always emitted at the start of each
transaction in any case.

The psycopg2 dialect supports these constants for isolation level:

   * ‘READ COMMITTED’

   * ‘READ UNCOMMITTED’

   * ‘REPEATABLE READ’

   * ‘SERIALIZABLE’

   * ‘AUTOCOMMIT’

See also
........

See Transaction Isolation Level.

See pg8000 Transaction Isolation Level.

5.1.1.56 NOTICE logging
.......................

The psycopg2 dialect will log PostgreSQL NOTICE messages via the
‘sqlalchemy.dialects.postgresql’ logger.  When this logger is set to the
‘logging.INFO’ level, notice messages will be logged:

     import logging

     logging.getLogger('sqlalchemy.dialects.postgresql').setLevel(logging.INFO)

Above, it is assumed that logging is configured externally.  If this is
not the case, configuration such as ‘logging.basicConfig()’ must be
utilized:

     import logging

     logging.basicConfig()   # log messages to stdout
     logging.getLogger('sqlalchemy.dialects.postgresql').setLevel(logging.INFO)

See also
........

Logging HOWTO(1) - on the python.org website

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/howto/logging.html

5.1.1.57 HSTORE type
....................

The ‘psycopg2’ DBAPI includes an extension to natively handle
marshalling of the HSTORE type.  The SQLAlchemy psycopg2 dialect will
enable this extension by default when psycopg2 version 2.4 or greater is
used, and it is detected that the target database has the HSTORE type
set up for use.  In other words, when the dialect makes the first
connection, a sequence like the following is performed:

  1. Request the available HSTORE oids using
     ‘psycopg2.extras.HstoreAdapter.get_oids()’.  If this function
     returns a list of HSTORE identifiers, we then determine that the
     ‘HSTORE’ extension is present.  This function is `skipped' if the
     version of psycopg2 installed is less than version 2.4.

  2. If the ‘use_native_hstore’ flag is at its default of ‘True’, and
     we’ve detected that ‘HSTORE’ oids are available, the
     ‘psycopg2.extensions.register_hstore()’ extension is invoked for
     all connections.

The ‘register_hstore()’ extension has the effect of `all Python
dictionaries being accepted as parameters regardless of the type of
target column in SQL'. The dictionaries are converted by this extension
into a textual HSTORE expression.  If this behavior is not desired,
disable the use of the hstore extension by setting ‘use_native_hstore’
to ‘False’ as follows:

     engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test",
                 use_native_hstore=False)

The ‘HSTORE’ type is `still supported' when the
‘psycopg2.extensions.register_hstore()’ extension is not used.  It
merely means that the coercion between Python dictionaries and the
HSTORE string format, on both the parameter side and the result side,
will take place within SQLAlchemy’s own marshalling logic, and not that
of ‘psycopg2’ which may be more performant.

5.1.1.58 pg8000
...............

Support for the PostgreSQL database via the pg8000 driver.

5.1.1.59 DBAPI
..............

Documentation and download information (if applicable) for pg8000 is
available at: ‘https://pypi.org/project/pg8000/’

5.1.1.60 Connecting
...................

Connect String:
     postgresql+pg8000://user:password@host:port/dbname[?key=value&key=value...]

Changed in version 1.4: The pg8000 dialect has been updated for version
1.16.6 and higher, and is again part of SQLAlchemy’s continuous
integration with full feature support.

5.1.1.61 Unicode
................

pg8000 will encode / decode string values between it and the server
using the PostgreSQL ‘client_encoding’ parameter; by default this is the
value in the ‘postgresql.conf’ file, which often defaults to
‘SQL_ASCII’.  Typically, this can be changed to ‘utf-8’, as a more
useful default:

     #client_encoding = sql_ascii # actually, defaults to database
                                  # encoding
     client_encoding = utf8

The ‘client_encoding’ can be overridden for a session by executing the
SQL:

SET CLIENT_ENCODING TO ‘utf8’;

SQLAlchemy will execute this SQL on all new connections based on the
value passed to create_engine() using the ‘client_encoding’
parameter:

     engine = create_engine(
         "postgresql+pg8000://user:pass@host/dbname", client_encoding='utf8')

5.1.1.62 pg8000 Transaction Isolation Level
...........................................

The pg8000 dialect offers the same isolation level settings as that of
the psycopg2 dialect:

   * ‘READ COMMITTED’

   * ‘READ UNCOMMITTED’

   * ‘REPEATABLE READ’

   * ‘SERIALIZABLE’

   * ‘AUTOCOMMIT’

See also
........

See Transaction Isolation Level.

See Psycopg2 Transaction Isolation Level.

5.1.1.63 asyncpg
................

Support for the PostgreSQL database via the asyncpg driver.

5.1.1.64 DBAPI
..............

Documentation and download information (if applicable) for asyncpg is
available at: ‘https://magicstack.github.io/asyncpg/’

5.1.1.65 Connecting
...................

Connect String:
     postgresql+asyncpg://user:password@host:port/dbname[?key=value&key=value...]

The asyncpg dialect is SQLAlchemy’s first Python asyncio dialect.

Using a special asyncio mediation layer, the asyncpg dialect is usable
as the backend for the SQLAlchemy asyncio extension package.

This dialect should normally be used only with the
create_async_engine() engine creation function:

     from sqlalchemy.ext.asyncio import create_async_engine
     engine = create_async_engine("postgresql+asyncpg://user:pass@hostname/dbname")

The dialect can also be run as a “synchronous” dialect within the
create_engine() function, which will pass “await” calls into an
ad-hoc event loop.  This mode of operation is of `limited use' and is
for special testing scenarios only.  The mode can be enabled by adding
the SQLAlchemy-specific flag ‘async_fallback’ to the URL in conjunction
with create_engine():

     # for testing purposes only; do not use in production!
     engine = create_engine("postgresql+asyncpg://user:pass@hostname/dbname?async_fallback=true")

New in version 1.4.

     Note: By default asyncpg does not decode the ‘json’ and ‘jsonb’
     types and returns them as strings.  SQLAlchemy sets default type
     decoder for ‘json’ and ‘jsonb’ types using the python builtin
     ‘json.loads’ function.  The json implementation used can be changed
     by setting the attribute ‘json_deserializer’ when creating the
     engine with ‘create_engine()’ or ‘create_async_engine()’.

5.1.1.66 Prepared Statement Cache
.................................

The asyncpg SQLAlchemy dialect makes use of
‘asyncpg.connection.prepare()’ for all statements.  The prepared
statement objects are cached after construction which appears to grant a
10% or more performance improvement for statement invocation.  The cache
is on a per-DBAPI connection basis, which means that the primary storage
for prepared statements is within DBAPI connections pooled within the
connection pool.  The size of this cache defaults to 100 statements per
DBAPI connection and may be adjusted using the
‘prepared_statement_cache_size’ DBAPI argument (note that while this
argument is implemented by SQLAlchemy, it is part of the DBAPI emulation
portion of the asyncpg dialect, therefore is handled as a DBAPI
argument, not a dialect argument):

     engine = create_async_engine("postgresql+asyncpg://user:pass@hostname/dbname?prepared_statement_cache_size=500")

To disable the prepared statement cache, use a value of zero:

     engine = create_async_engine("postgresql+asyncpg://user:pass@hostname/dbname?prepared_statement_cache_size=0")

New in version 1.4.0b2: Added ‘prepared_statement_cache_size’ for
asyncpg.

     Warning: The ‘asyncpg’ database driver necessarily uses caches for
     PostgreSQL type OIDs, which become stale when custom PostgreSQL
     datatypes such as ‘ENUM’ objects are changed via DDL operations.
     Additionally, prepared statements themselves which are optionally
     cached by SQLAlchemy’s driver as described above may also become
     “stale” when DDL has been emitted to the PostgreSQL database which
     modifies the tables or other objects involved in a particular
     prepared statement.

     The SQLAlchemy asyncpg dialect will invalidate these caches within
     its local process when statements that represent DDL are emitted on
     a local connection, but this is only controllable within a single
     Python process / database engine.  If DDL changes are made from
     other database engines and/or processes, a running application may
     encounter asyncpg exceptions ‘InvalidCachedStatementError’ and/or
     ‘InternalServerError("cache lookup failed for type <oid>")’ if it
     refers to pooled database connections which operated upon the
     previous structures.  The SQLAlchemy asyncpg dialect will recover
     from these error cases when the driver raises these exceptions by
     clearing its internal caches as well as those of the asyncpg driver
     in response to them, but cannot prevent them from being raised in
     the first place if the cached prepared statement or asyncpg type
     caches have gone stale, nor can it retry the statement as the
     PostgreSQL transaction is invalidated when these errors occur.

5.1.1.67 psycopg2cffi
.....................

Support for the PostgreSQL database via the psycopg2cffi driver.

5.1.1.68 DBAPI
..............

Documentation and download information (if applicable) for psycopg2cffi
is available at: ‘http://pypi.python.org/pypi/psycopg2cffi/’

5.1.1.69 Connecting
...................

Connect String:
     postgresql+psycopg2cffi://user:password@host:port/dbname[?key=value&key=value...]

‘psycopg2cffi’ is an adaptation of ‘psycopg2’, using CFFI for the C
layer.  This makes it suitable for use in e.g.  PyPy.  Documentation is
as per ‘psycopg2’.

New in version 1.0.0.

See also
........

See sqlalchemy.dialects.postgresql.psycopg2.

5.1.1.70 py-postgresql
......................

Support for the PostgreSQL database via the py-postgresql driver.

5.1.1.71 DBAPI
..............

Documentation and download information (if applicable) for py-postgresql
is available at: ‘http://python.projects.pgfoundry.org/’

5.1.1.72 Connecting
...................

Connect String:
     postgresql+pypostgresql://user:password@host:port/dbname[?key=value&key=value...]

     Note: The pypostgresql dialect is `not tested as part of
     SQLAlchemy’s continuous integration' and may have unresolved
     issues.  The recommended PostgreSQL driver is psycopg2.

Deprecated since version 1.4: The py-postgresql DBAPI is deprecated and
will be removed in a future version.  This DBAPI is superseded by the
external version available at external-dialect(1).  Please use the
external version or one of the supported DBAPIs to connect to
PostgreSQL.

   ---------- Footnotes ----------

   (1) https://github.com/PyGreSQL

5.1.1.73 pygresql
.................

Support for the PostgreSQL database via the pygresql driver.

5.1.1.74 DBAPI
..............

Documentation and download information (if applicable) for pygresql is
available at: ‘http://www.pygresql.org/’

5.1.1.75 Connecting
...................

Connect String:
     postgresql+pygresql://user:password@host:port/dbname[?key=value&key=value...]

     Note: The pygresql dialect is `not tested as part of SQLAlchemy’s
     continuous integration' and may have unresolved issues.  The
     recommended PostgreSQL dialect is psycopg2.

Deprecated since version 1.4: The pygresql DBAPI is deprecated and will
be removed in a future version.  Please use one of the supported DBAPIs
to connect to PostgreSQL.

5.1.2 MySQL and MariaDB
-----------------------

Support for the MySQL / MariaDB database.

The following table summarizes current support levels for database
release versions.

`Supported MySQL / MariaDB versions'

Support type                                           Versions

--------------------------------------------------------------------------------------------------------------

See Fully tested in CI.                        5.6, 5.7, 8.0 / 10.4, 10.5

See Normal support.                            5.6+ / 10+

See Best effort.                               5.0.2+ / 5.0.2+

5.1.2.1 DBAPI Support
.....................

The following dialect/DBAPI options are available.  Please refer to
individual DBAPI sections for connect information.

   * mysqlclient (maintained fork of MySQL-Python).

   * PyMySQL.

   * MySQL Connector/Python.

   * aiomysql.

   * CyMySQL.

   * OurSQL.

   * PyODBC.

5.1.2.2 Supported Versions and Features
.......................................

SQLAlchemy supports MySQL starting with version 5.0.2 through modern
releases, as well as all modern versions of MariaDB. See the official
MySQL documentation for detailed information about features supported in
any given server release.

Changed in version 1.4: minimum MySQL version supported is now 5.0.2.

5.1.2.3 MariaDB Support
.......................

The MariaDB variant of MySQL retains fundamental compatibility with
MySQL’s protocols however the development of these two products
continues to diverge.  Within the realm of SQLAlchemy, the two databases
have a small number of syntactical and behavioral differences that
SQLAlchemy accommodates automatically.  To connect to a MariaDB
database, no changes to the database URL are required:

     engine = create_engine("mysql+pymsql://user:pass@some_mariadb/dbname?charset=utf8mb4")

Upon first connect, the SQLAlchemy dialect employs a server version
detection scheme that determines if the backing database reports as
MariaDB. Based on this flag, the dialect can make different choices in
those of areas where its behavior must be different.

5.1.2.4 MariaDB-Only Mode
.........................

The dialect also supports an `optional' “MariaDB-only” mode of
connection, which may be useful for the case where an application makes
use of MariaDB-specific features and is not compatible with a MySQL
database.  To use this mode of operation, replace the “mysql” token in
the above URL with “mariadb”:

     engine = create_engine("mariadb+pymsql://user:pass@some_mariadb/dbname?charset=utf8mb4")

The above engine, upon first connect, will raise an error if the server
version detection detects that the backing database is not MariaDB.

When using an engine with ‘"mariadb"’ as the dialect name, `all
mysql-specific options that include the name “mysql” in them are now
named with “mariadb”'.  This means options like ‘mysql_engine’ should be
named ‘mariadb_engine’, etc.  Both “mysql” and “mariadb” options can be
used simultaneously for applications that use URLs with both “mysql” and
“mariadb” dialects:

     my_table = Table(
         "mytable",
         metadata,
         Column("id", Integer, primary_key=True),
         Column("textdata", String(50)),
         mariadb_engine="InnoDB",
         mysql_engine="InnoDB",
     )

     Index(
         "textdata_ix",
         my_table.c.textdata,
         mysql_prefix="FULLTEXT",
         mariadb_prefix="FULLTEXT",
     )

Similar behavior will occur when the above structures are reflected,
i.e.  the “mariadb” prefix will be present in the option names when the
database URL is based on the “mariadb” name.

New in version 1.4: Added “mariadb” dialect name supporting
“MariaDB-only mode” for the MySQL dialect.

5.1.2.5 Connection Timeouts and Disconnects
...........................................

MySQL / MariaDB feature an automatic connection close behavior, for
connections that have been idle for a fixed period of time, defaulting
to eight hours.  To circumvent having this issue, use the
create_engine.pool_recycle option which ensures that a connection
will be discarded and replaced with a new one if it has been present in
the pool for a fixed number of seconds:

     engine = create_engine('mysql+mysqldb://...', pool_recycle=3600)

For more comprehensive disconnect detection of pooled connections,
including accommodation of server restarts and network issues, a
pre-ping approach may be employed.  See Dealing with Disconnects
for current approaches.

See also
........

See Dealing with Disconnects. - Background on several techniques
for dealing with timed out connections as well as database restarts.

5.1.2.6 CREATE TABLE arguments including Storage Engines
........................................................

Both MySQL’s and MariaDB’s CREATE TABLE syntax includes a wide array of
special options, including ‘ENGINE’, ‘CHARSET’, ‘MAX_ROWS’,
‘ROW_FORMAT’, ‘INSERT_METHOD’, and many more.  To accommodate the
rendering of these arguments, specify the form
‘mysql_argument_name="value"’.  For example, to specify a table with
‘ENGINE’ of ‘InnoDB’, ‘CHARSET’ of ‘utf8mb4’, and ‘KEY_BLOCK_SIZE’ of
‘1024’:

     Table('mytable', metadata,
           Column('data', String(32)),
           mysql_engine='InnoDB',
           mysql_charset='utf8mb4',
           mysql_key_block_size="1024"
          )

When supporting MariaDB-Only Mode mode, similar keys
against the “mariadb” prefix must be included as well.  The values can
of course vary independently so that different settings on MySQL vs.
MariaDB may be maintained:

     # support both "mysql" and "mariadb-only" engine URLs

     Table('mytable', metadata,
           Column('data', String(32)),

           mysql_engine='InnoDB',
           mariadb_engine='InnoDB',

           mysql_charset='utf8mb4',
           mariadb_charset='utf8',

           mysql_key_block_size="1024"
           mariadb_key_block_size="1024"

          )

The MySQL / MariaDB dialects will normally transfer any keyword
specified as ‘mysql_keyword_name’ to be rendered as ‘KEYWORD_NAME’ in
the ‘CREATE TABLE’ statement.  A handful of these names will render with
a space instead of an underscore; to support this, the MySQL dialect has
awareness of these particular names, which include ‘DATA DIRECTORY’
(e.g.  ‘mysql_data_directory’), ‘CHARACTER SET’ (e.g.
‘mysql_character_set’) and ‘INDEX DIRECTORY’ (e.g.
‘mysql_index_directory’).

The most common argument is ‘mysql_engine’, which refers to the storage
engine for the table.  Historically, MySQL server installations would
default to ‘MyISAM’ for this value, although newer versions may be
defaulting to ‘InnoDB’.  The ‘InnoDB’ engine is typically preferred for
its support of transactions and foreign keys.

A Table that is created in a MySQL / MariaDB database with a
storage engine of ‘MyISAM’ will be essentially non-transactional,
meaning any INSERT/UPDATE/DELETE statement referring to this table will
be invoked as autocommit.  It also will have no support for foreign key
constraints; while the ‘CREATE TABLE’ statement accepts foreign key
options, when using the ‘MyISAM’ storage engine these arguments are
discarded.  Reflecting such a table will also produce no foreign key
constraint information.

For fully atomic transactions as well as support for foreign key
constraints, all participating ‘CREATE TABLE’ statements must specify a
transactional engine, which in the vast majority of cases is ‘InnoDB’.

5.1.2.7 Case Sensitivity and Table Reflection
.............................................

Both MySQL and MariaDB have inconsistent support for case-sensitive
identifier names, basing support on specific details of the underlying
operating system.  However, it has been observed that no matter what
case sensitivity behavior is present, the names of tables in foreign key
declarations are `always' received from the database as all-lower case,
making it impossible to accurately reflect a schema where inter-related
tables use mixed-case identifier names.

Therefore it is strongly advised that table names be declared as all
lower case both within SQLAlchemy as well as on the MySQL / MariaDB
database itself, especially if database reflection features are to be
used.

5.1.2.8 Transaction Isolation Level
...................................

All MySQL / MariaDB dialects support setting of transaction isolation
level both via a dialect-specific parameter
create_engine.isolation_level accepted by create_engine(),
as well as the Connection.execution_options.isolation_level
argument as passed to Connection.execution_options().
This feature works by issuing the command ‘SET SESSION TRANSACTION
ISOLATION LEVEL <level>’ for each new connection.  For the special
AUTOCOMMIT isolation level, DBAPI-specific techniques are used.

To set isolation level using create_engine():

     engine = create_engine(
                     "mysql://scott:tiger@localhost/test",
                     isolation_level="READ UNCOMMITTED"
                 )

To set using per-connection execution options:

     connection = engine.connect()
     connection = connection.execution_options(
         isolation_level="READ COMMITTED"
     )

Valid values for ‘isolation_level’ include:

   * ‘READ COMMITTED’

   * ‘READ UNCOMMITTED’

   * ‘REPEATABLE READ’

   * ‘SERIALIZABLE’

   * ‘AUTOCOMMIT’

The special ‘AUTOCOMMIT’ value makes use of the various “autocommit”
attributes provided by specific DBAPIs, and is currently supported by
MySQLdb, MySQL-Client, MySQL-Connector Python, and PyMySQL. Using it,
the database connection will return true for the value of ‘SELECT
@@autocommit;’.

See also
........

See Setting Transaction Isolation Levels including DBAPI Autocommit.

5.1.2.9 AUTO_INCREMENT Behavior
...............................

When creating tables, SQLAlchemy will automatically set ‘AUTO_INCREMENT’
on the first Integer primary key column which is not marked
as a foreign key:

     >>> t = Table('mytable', metadata,
     ...   Column('mytable_id', Integer, primary_key=True)
     ... )
     >>> t.create()
     CREATE TABLE mytable (
             id INTEGER NOT NULL AUTO_INCREMENT,
             PRIMARY KEY (id)
     )

You can disable this behavior by passing ‘False’ to the
Column.autoincrement argument of Column.  This flag can
also be used to enable auto-increment on a secondary column in a
multi-column key for some storage engines:

     Table('mytable', metadata,
           Column('gid', Integer, primary_key=True, autoincrement=False),
           Column('id', Integer, primary_key=True)
          )

5.1.2.10 Server Side Cursors
............................

Server-side cursor support is available for the mysqlclient, PyMySQL,
mariadbconnector dialects and may also be available in others.  This
makes use of either the “buffered=True/False” flag if available or by
using a class such as ‘MySQLdb.cursors.SSCursor’ or
‘pymysql.cursors.SSCursor’ internally.

Server side cursors are enabled on a per-statement basis by using the
Connection.execution_options.stream_results connection
execution option:

     with engine.connect() as conn:
         result = conn.execution_options(stream_results=True).execute(text("select * from table"))

Note that some kinds of SQL statements may not be supported with server
side cursors; generally, only SQL statements that return rows should be
used with this option.

Deprecated since version 1.4: The dialect-level server_side_cursors flag
is deprecated and will be removed in a future release.  Please use the
Connection.stream_results execution option for unbuffered
cursor support.

See also
........

See Using Server Side Cursors (a.k.a. stream results).

5.1.2.11 Unicode
................

5.1.2.12 Charset Selection
..........................

Most MySQL / MariaDB DBAPIs offer the option to set the client character
set for a connection.  This is typically delivered using the ‘charset’
parameter in the URL, such as:

     e = create_engine(
         "mysql+pymysql://scott:tiger@localhost/test?charset=utf8mb4")

This charset is the `client character set' for the connection.  Some
MySQL DBAPIs will default this to a value such as ‘latin1’, and some
will make use of the ‘default-character-set’ setting in the ‘my.cnf’
file as well.  Documentation for the DBAPI in use should be consulted
for specific behavior.

The encoding used for Unicode has traditionally been ‘'utf8'’.  However,
for MySQL versions 5.5.3 and MariaDB 5.5 on forward, a new
MySQL-specific encoding ‘'utf8mb4'’ has been introduced, and as of MySQL
8.0 a warning is emitted by the server if plain ‘utf8’ is specified
within any server-side directives, replaced with ‘utf8mb3’.  The
rationale for this new encoding is due to the fact that MySQL’s legacy
utf-8 encoding only supports codepoints up to three bytes instead of
four.  Therefore, when communicating with a MySQL or MariaDB database
that includes codepoints more than three bytes in size, this new charset
is preferred, if supported by both the database as well as the client
DBAPI, as in:

     e = create_engine(
         "mysql+pymysql://scott:tiger@localhost/test?charset=utf8mb4")

All modern DBAPIs should support the ‘utf8mb4’ charset.

In order to use ‘utf8mb4’ encoding for a schema that was created with
legacy ‘utf8’, changes to the MySQL/MariaDB schema and/or server
configuration may be required.

See also
........

The utf8mb4 Character Set(1) - in the MySQL documentation

   ---------- Footnotes ----------

   (1)
http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html

5.1.2.13 Dealing with Binary Data Warnings and Unicode
......................................................

MySQL versions 5.6, 5.7 and later (not MariaDB at the time of this
writing) now emit a warning when attempting to pass binary data to the
database, while a character set encoding is also in place, when the
binary data itself is not valid for that encoding:

     default.py:509: Warning: (1300, "Invalid utf8mb4 character string:
     'F9876A'")
       cursor.execute(statement, parameters)

This warning is due to the fact that the MySQL client library is
attempting to interpret the binary string as a unicode object even if a
datatype such as LargeBinary is in use.  To resolve this,
the SQL statement requires a binary “character set introducer” be
present before any non-NULL value that renders like this:

     INSERT INTO table (data) VALUES (_binary %s)

These character set introducers are provided by the DBAPI driver,
assuming the use of mysqlclient or PyMySQL (both of which are
recommended).  Add the query string parameter ‘binary_prefix=true’ to
the URL to repair this warning:

     # mysqlclient
     engine = create_engine(
         "mysql+mysqldb://scott:tiger@localhost/test?charset=utf8mb4&binary_prefix=true")

     # PyMySQL
     engine = create_engine(
         "mysql+pymysql://scott:tiger@localhost/test?charset=utf8mb4&binary_prefix=true")

The ‘binary_prefix’ flag may or may not be supported by other MySQL
drivers.

SQLAlchemy itself cannot render this ‘_binary’ prefix reliably, as it
does not work with the NULL value, which is valid to be sent as a bound
parameter.  As the MySQL driver renders parameters directly into the SQL
string, it’s the most efficient place for this additional keyword to be
passed.

See also
........

Character set introducers(1) - on the MySQL website

   ---------- Footnotes ----------

   (1) https://dev.mysql.com/doc/refman/5.7/en/charset-introducer.html

5.1.2.14 ANSI Quoting Style
...........................

MySQL / MariaDB feature two varieties of identifier “quoting style”, one
using backticks and the other using quotes, e.g.  ‘`some_identifier`’
vs.  ‘"some_identifier"’.  All MySQL dialects detect which version is in
use by checking the value of ‘sql_mode’ when a connection is first
established with a particular Engine.  This quoting style
comes into play when rendering table and column names as well as when
reflecting existing database structures.  The detection is entirely
automatic and no special configuration is needed to use either quoting
style.

5.1.2.15 MySQL / MariaDB SQL Extensions
.......................................

Many of the MySQL / MariaDB SQL extensions are handled through
SQLAlchemy’s generic function and operator support:

     table.select(table.c.password==func.md5('plaintext'))
     table.select(table.c.username.op('regexp')('^[a-d]'))

And of course any valid SQL statement can be executed as a string as
well.

Some limited direct support for MySQL / MariaDB extensions to SQL is
currently available.

   * INSERT..ON DUPLICATE KEY UPDATE: See INSERT…ON DUPLICATE KEY UPDATE (Upsert).

   * SELECT pragma, use Select.prefix_with() and
     Query.prefix_with():

          select(...).prefix_with(['HIGH_PRIORITY', 'SQL_SMALL_RESULT'])

   * UPDATE with LIMIT:

          update(..., mysql_limit=10, mariadb_limit=10)

   * optimizer hints, use Select.prefix_with() and
     Query.prefix_with():

          select(...).prefix_with("/*+ NO_RANGE_OPTIMIZATION(t4 PRIMARY) */")

   * index hints, use Select.with_hint() and
     Query.with_hint():

          select(...).with_hint(some_table, "USE INDEX xyz")

5.1.2.16 INSERT…ON DUPLICATE KEY UPDATE (Upsert)
................................................

MySQL / MariaDB allow “upserts” (update or insert) of rows into a table
via the ‘ON DUPLICATE KEY UPDATE’ clause of the ‘INSERT’ statement.  A
candidate row will only be inserted if that row does not match an
existing primary or unique key in the table; otherwise, an UPDATE will
be performed.  The statement allows for separate specification of the
values to INSERT versus the values for UPDATE.

SQLAlchemy provides ‘ON DUPLICATE KEY UPDATE’ support via the
MySQL-specific insert() function, which provides the
generative method Insert.on_duplicate_key_update():

     >>> from sqlalchemy.dialects.mysql import insert

     >>> insert_stmt = insert(my_table).values(
     ...     id='some_existing_id',
     ...     data='inserted value')

     >>> on_duplicate_key_stmt = insert_stmt.on_duplicate_key_update(
     ...     data=insert_stmt.inserted.data,
     ...     status='U'
     ... )
     >>> print(on_duplicate_key_stmt)
     {opensql}INSERT INTO my_table (id, data) VALUES (%s, %s)
     ON DUPLICATE KEY UPDATE data = VALUES(data), status = %s

Unlike PostgreSQL’s “ON CONFLICT” phrase, the “ON DUPLICATE KEY UPDATE”
phrase will always match on any primary key or unique key, and will
always perform an UPDATE if there’s a match; there are no options for it
to raise an error or to skip performing an UPDATE.

‘ON DUPLICATE KEY UPDATE’ is used to perform an update of the already
existing row, using any combination of new values as well as values from
the proposed insertion.  These values are normally specified using
keyword arguments passed to the Insert.on_duplicate_key_update()
given column key values (usually the name of the column, unless it
specifies Column.key. ) as keys and literal or SQL
expressions as values:

     >>> insert_stmt = insert(my_table).values(
     ...          id='some_existing_id',
     ...          data='inserted value')

     >>> on_duplicate_key_stmt = insert_stmt.on_duplicate_key_update(
     ...     data="some data",
     ...     updated_at=func.current_timestamp(),
     ... )

     >>> print(on_duplicate_key_stmt)
     {opensql}INSERT INTO my_table (id, data) VALUES (%s, %s)
     ON DUPLICATE KEY UPDATE data = %s, updated_at = CURRENT_TIMESTAMP

In a manner similar to that of ‘UpdateBase.values()’, other parameter
forms are accepted, including a single dictionary:

     >>> on_duplicate_key_stmt = insert_stmt.on_duplicate_key_update(
     ...     {"data": "some data", "updated_at": func.current_timestamp()},
     ... )

as well as a list of 2-tuples, which will automatically provide a
parameter-ordered UPDATE statement in a manner similar to that described
at Parameter-Ordered Updates.  Unlike the Update
object, no special flag is needed to specify the intent since the
argument form is this context is unambiguous:

     >>> on_duplicate_key_stmt = insert_stmt.on_duplicate_key_update(
     ...     [
     ...         ("data", "some data"),
     ...         ("updated_at", func.current_timestamp()),
     ...     ]
     ... )

     >>> print(on_duplicate_key_stmt)
     {opensql}INSERT INTO my_table (id, data) VALUES (%s, %s)
     ON DUPLICATE KEY UPDATE data = %s, updated_at = CURRENT_TIMESTAMP

Changed in version 1.3: support for parameter-ordered UPDATE clause
within MySQL ON DUPLICATE KEY UPDATE

     Warning: The Insert.on_duplicate_key_update() method
     does `not' take into account Python-side default UPDATE values or
     generation functions, e.g.  e.g.  those specified using
     Column.onupdate.  These values will not be exercised for an ON
     DUPLICATE KEY style of UPDATE, unless they are manually specified
     explicitly in the parameters.

In order to refer to the proposed insertion row, the special alias
Insert.inserted is available as an attribute on the Insert
object; this object is a ColumnCollection which
contains all columns of the target table:

     >>> stmt = insert(my_table).values(
     ...     id='some_id',
     ...     data='inserted value',
     ...     author='jlh')

     >>> do_update_stmt = stmt.on_duplicate_key_update(
     ...     data="updated value",
     ...     author=stmt.inserted.author
     ... )

     >>> print(do_update_stmt)
     {opensql}INSERT INTO my_table (id, data, author) VALUES (%s, %s, %s)
     ON DUPLICATE KEY UPDATE data = %s, author = VALUES(author)

When rendered, the “inserted” namespace will produce the expression
‘VALUES(<columnname>)’.

New in version 1.2: Added support for MySQL ON DUPLICATE KEY UPDATE
clause

5.1.2.17 rowcount Support
.........................

SQLAlchemy standardizes the DBAPI ‘cursor.rowcount’ attribute to be the
usual definition of “number of rows matched by an UPDATE or DELETE”
statement.  This is in contradiction to the default setting on most
MySQL DBAPI drivers, which is “number of rows actually
modified/deleted”.  For this reason, the SQLAlchemy MySQL dialects
always add the ‘constants.CLIENT.FOUND_ROWS’ flag, or whatever is
equivalent for the target dialect, upon connection.  This setting is
currently hardcoded.

See also
........

See CursorResult.rowcount.

5.1.2.18 MySQL / MariaDB- Specific Index Options
................................................

MySQL and MariaDB-specific extensions to the Index construct
are available.

5.1.2.19 Index Length
.....................

MySQL and MariaDB both provide an option to create index entries with a
certain length, where “length” refers to the number of characters or
bytes in each value which will become part of the index.  SQLAlchemy
provides this feature via the ‘mysql_length’ and/or ‘mariadb_length’
parameters:

     Index('my_index', my_table.c.data, mysql_length=10, mariadb_length=10)

     Index('a_b_idx', my_table.c.a, my_table.c.b, mysql_length={'a': 4,
                                                                'b': 9})

     Index('a_b_idx', my_table.c.a, my_table.c.b, mariadb_length={'a': 4,
                                                                'b': 9})

Prefix lengths are given in characters for nonbinary string types and in
bytes for binary string types.  The value passed to the keyword argument
`must' be either an integer (and, thus, specify the same prefix length
value for all columns of the index) or a dict in which keys are column
names and values are prefix length values for corresponding columns.
MySQL and MariaDB only allow a length for a column of an index if it is
for a CHAR, VARCHAR, TEXT, BINARY, VARBINARY and BLOB.

5.1.2.20 Index Prefixes
.......................

MySQL storage engines permit you to specify an index prefix when
creating an index.  SQLAlchemy provides this feature via the
‘mysql_prefix’ parameter on Index:

     Index('my_index', my_table.c.data, mysql_prefix='FULLTEXT')

The value passed to the keyword argument will be simply passed through
to the underlying CREATE INDEX, so it `must' be a valid index prefix for
your MySQL storage engine.

New in version 1.1.5.

See also
........

CREATE INDEX(1) - MySQL documentation

   ---------- Footnotes ----------

   (1) http://dev.mysql.com/doc/refman/5.0/en/create-index.html

5.1.2.21 Index Types
....................

Some MySQL storage engines permit you to specify an index type when
creating an index or primary key constraint.  SQLAlchemy provides this
feature via the ‘mysql_using’ parameter on Index:

     Index('my_index', my_table.c.data, mysql_using='hash', mariadb_using='hash')

As well as the ‘mysql_using’ parameter on PrimaryKeyConstraint:

     PrimaryKeyConstraint("data", mysql_using='hash', mariadb_using='hash')

The value passed to the keyword argument will be simply passed through
to the underlying CREATE INDEX or PRIMARY KEY clause, so it `must' be a
valid index type for your MySQL storage engine.

More information can be found at:

‘http://dev.mysql.com/doc/refman/5.0/en/create-index.html’

‘http://dev.mysql.com/doc/refman/5.0/en/create-table.html’

5.1.2.22 Index Parsers
......................

CREATE FULLTEXT INDEX in MySQL also supports a “WITH PARSER” option.
This is available using the keyword argument ‘mysql_with_parser’:

     Index(
         'my_index', my_table.c.data,
         mysql_prefix='FULLTEXT', mysql_with_parser="ngram",
         mariadb_prefix='FULLTEXT', mariadb_with_parser="ngram",
     )

New in version 1.3.

5.1.2.23 MySQL / MariaDB Foreign Keys
.....................................

MySQL and MariaDB’s behavior regarding foreign keys has some important
caveats.

5.1.2.24 Foreign Key Arguments to Avoid
.......................................

Neither MySQL nor MariaDB support the foreign key arguments
“DEFERRABLE”, “INITIALLY”, or “MATCH”.  Using the ‘deferrable’ or
‘initially’ keyword argument with ForeignKeyConstraint or
ForeignKey will have the effect of these keywords being
rendered in a DDL expression, which will then raise an error on MySQL or
MariaDB. In order to use these keywords on a foreign key while having
them ignored on a MySQL / MariaDB backend, use a custom compile rule:

     from sqlalchemy.ext.compiler import compiles
     from sqlalchemy.schema import ForeignKeyConstraint

     @compiles(ForeignKeyConstraint, "mysql", "mariadb")
     def process(element, compiler, **kw):
         element.deferrable = element.initially = None
         return compiler.visit_foreign_key_constraint(element, **kw)

The “MATCH” keyword is in fact more insidious, and is explicitly
disallowed by SQLAlchemy in conjunction with the MySQL or MariaDB
backends.  This argument is silently ignored by MySQL / MariaDB, but in
addition has the effect of ON UPDATE and ON DELETE options also being
ignored by the backend.  Therefore MATCH should never be used with the
MySQL / MariaDB backends; as is the case with DEFERRABLE and INITIALLY,
custom compilation rules can be used to correct a ForeignKeyConstraint
at DDL definition time.

5.1.2.25 Reflection of Foreign Key Constraints
..............................................

Not all MySQL / MariaDB storage engines support foreign keys.  When
using the very common ‘MyISAM’ MySQL storage engine, the information
loaded by table reflection will not include foreign keys.  For these
tables, you may supply a ‘ForeignKeyConstraint’ at reflection time:

     Table('mytable', metadata,
           ForeignKeyConstraint(['other_id'], ['othertable.other_id']),
           autoload_with=engine
          )

See also
........

See CREATE TABLE arguments including Storage Engines.

5.1.2.26 MySQL / MariaDB Unique Constraints and Reflection
..........................................................

SQLAlchemy supports both the Index construct with the flag
‘unique=True’, indicating a UNIQUE index, as well as the
UniqueConstraint construct, representing a UNIQUE constraint.
Both objects/syntaxes are supported by MySQL / MariaDB when emitting DDL
to create these constraints.  However, MySQL / MariaDB does not have a
unique constraint construct that is separate from a unique index; that
is, the “UNIQUE” constraint on MySQL / MariaDB is equivalent to creating
a “UNIQUE INDEX”.

When reflecting these constructs, the Inspector.get_indexes()
and the Inspector.get_unique_constraints() methods
will `both' return an entry for a UNIQUE index in MySQL / MariaDB.
However, when performing full table reflection using ‘Table(...,
autoload_with=engine)’, the UniqueConstraint construct is
`not' part of the fully reflected Table construct under any
circumstances; this construct is always represented by a Index
with the ‘unique=True’ setting present in the Table.indexes
collection.

5.1.2.27 TIMESTAMP / DATETIME issues
....................................

5.1.2.28 Rendering ON UPDATE CURRENT TIMESTAMP for MySQL / MariaDB’s explicit_defaults_for_timestamp
....................................................................................................

MySQL / MariaDB have historically expanded the DDL for the
TIMESTAMP datatype into the phrase “TIMESTAMP DEFAULT
CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP”, which includes
non-standard SQL that automatically updates the column with the current
timestamp when an UPDATE occurs, eliminating the usual need to use a
trigger in such a case where server-side update changes are desired.

MySQL 5.6 introduced a new flag explicit_defaults_for_timestamp(1) which
disables the above behavior, and in MySQL 8 this flag defaults to true,
meaning in order to get a MySQL “on update timestamp” without changing
this flag, the above DDL must be rendered explicitly.  Additionally, the
same DDL is valid for use of the ‘DATETIME’ datatype as well.

SQLAlchemy’s MySQL dialect does not yet have an option to generate
MySQL’s “ON UPDATE CURRENT_TIMESTAMP” clause, noting that this is not a
general purpose “ON UPDATE” as there is no such syntax in standard SQL.
SQLAlchemy’s Column.server_onupdate parameter is currently
not related to this special MySQL behavior.

To generate this DDL, make use of the Column.server_default
parameter and pass a textual clause that also includes the ON UPDATE
clause:

     from sqlalchemy import Table, MetaData, Column, Integer, String, TIMESTAMP
     from sqlalchemy import text

     metadata = MetaData()

     mytable = Table(
         "mytable",
         metadata,
         Column('id', Integer, primary_key=True),
         Column('data', String(50)),
         Column(
             'last_updated',
             TIMESTAMP,
             server_default=text("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
         )
     )

The same instructions apply to use of the DateTime and
DATETIME datatypes:

     from sqlalchemy import DateTime

     mytable = Table(
         "mytable",
         metadata,
         Column('id', Integer, primary_key=True),
         Column('data', String(50)),
         Column(
             'last_updated',
             DateTime,
             server_default=text("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
         )
     )

Even though the Column.server_onupdate feature does not
generate this DDL, it still may be desirable to signal to the ORM that
this updated value should be fetched.  This syntax looks like the
following:

     from sqlalchemy.schema import FetchedValue

     class MyClass(Base):
         __tablename__ = 'mytable'

         id = Column(Integer, primary_key=True)
         data = Column(String(50))
         last_updated = Column(
             TIMESTAMP,
             server_default=text("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"),
             server_onupdate=FetchedValue()
         )

   ---------- Footnotes ----------

   (1)
http://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html#sysvar_explicit_defaults_for_timestamp

5.1.2.29 TIMESTAMP Columns and NULL
...................................

MySQL historically enforces that a column which specifies the TIMESTAMP
datatype implicitly includes a default value of CURRENT_TIMESTAMP, even
though this is not stated, and additionally sets the column as NOT NULL,
the opposite behavior vs.  that of all other datatypes:

     mysql> CREATE TABLE ts_test (
         -> a INTEGER,
         -> b INTEGER NOT NULL,
         -> c TIMESTAMP,
         -> d TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
         -> e TIMESTAMP NULL);
     Query OK, 0 rows affected (0.03 sec)

     mysql> SHOW CREATE TABLE ts_test;
     +---------+-----------------------------------------------------
     | Table   | Create Table
     +---------+-----------------------------------------------------
     | ts_test | CREATE TABLE `ts_test` (
       `a` int(11) DEFAULT NULL,
       `b` int(11) NOT NULL,
       `c` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
       `d` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
       `e` timestamp NULL DEFAULT NULL
     ) ENGINE=MyISAM DEFAULT CHARSET=latin1

Above, we see that an INTEGER column defaults to NULL, unless it is
specified with NOT NULL. But when the column is of type TIMESTAMP, an
implicit default of CURRENT_TIMESTAMP is generated which also coerces
the column to be a NOT NULL, even though we did not specify it as such.

This behavior of MySQL can be changed on the MySQL side using the
explicit_defaults_for_timestamp(1) configuration flag introduced in
MySQL 5.6.  With this server setting enabled, TIMESTAMP columns behave
like any other datatype on the MySQL side with regards to defaults and
nullability.

However, to accommodate the vast majority of MySQL databases that do not
specify this new flag, SQLAlchemy emits the “NULL” specifier explicitly
with any TIMESTAMP column that does not specify ‘nullable=False’.  In
order to accommodate newer databases that specify
‘explicit_defaults_for_timestamp’, SQLAlchemy also emits NOT NULL for
TIMESTAMP columns that do specify ‘nullable=False’.  The following
example illustrates:

     from sqlalchemy import MetaData, Integer, Table, Column, text
     from sqlalchemy.dialects.mysql import TIMESTAMP

     m = MetaData()
     t = Table('ts_test', m,
             Column('a', Integer),
             Column('b', Integer, nullable=False),
             Column('c', TIMESTAMP),
             Column('d', TIMESTAMP, nullable=False)
         )

     from sqlalchemy import create_engine
     e = create_engine("mysql://scott:tiger@localhost/test", echo=True)
     m.create_all(e)

output:

     CREATE TABLE ts_test (
         a INTEGER,
         b INTEGER NOT NULL,
         c TIMESTAMP NULL,
         d TIMESTAMP NOT NULL
     )

Changed in version 1.0.0: - SQLAlchemy now renders NULL or NOT NULL in
all cases for TIMESTAMP columns, to accommodate
‘explicit_defaults_for_timestamp’.  Prior to this version, it will not
render “NOT NULL” for a TIMESTAMP column that is ‘nullable=False’.

   ---------- Footnotes ----------

   (1)
http://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html#sysvar_explicit_defaults_for_timestamp

5.1.2.30 MySQL Data Types
.........................

As with all SQLAlchemy dialects, all UPPERCASE types that are known to
be valid with MySQL are importable from the top level dialect:

     from sqlalchemy.dialects.mysql import \
             BIGINT, BINARY, BIT, BLOB, BOOLEAN, CHAR, DATE, \
             DATETIME, DECIMAL, DECIMAL, DOUBLE, ENUM, FLOAT, INTEGER, \
             LONGBLOB, LONGTEXT, MEDIUMBLOB, MEDIUMINT, MEDIUMTEXT, NCHAR, \
             NUMERIC, NVARCHAR, REAL, SET, SMALLINT, TEXT, TIME, TIMESTAMP, \
             TINYBLOB, TINYINT, TINYTEXT, VARBINARY, VARCHAR, YEAR

Types which are specific to MySQL, or have MySQL-specific construction
arguments, are as follows:

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See BIGINT.MySQL BIGINTEGER type.

See BINARY.The SQL BINARY type.

See BIT.MySQL BIT type.

See BLOB.The SQL BLOB type.

See BOOLEAN.The SQL BOOLEAN type.

See CHAR.MySQL CHAR type, for fixed-length character data.

See DATE.The SQL DATE type.

See DATETIME.MySQL DATETIME type.

See DECIMAL.MySQL DECIMAL type.

See DOUBLE.MySQL DOUBLE type.

See ENUM.MySQL ENUM type.

See FLOAT.MySQL FLOAT type.

See INTEGER.MySQL INTEGER type.

See JSON.MySQL JSON type.

See LONGBLOB.MySQL LONGBLOB type, for binary data up to 2^32 bytes.

See LONGTEXT.MySQL LONGTEXT type, for text up to 2^32 characters.

See MEDIUMBLOB.MySQL MEDIUMBLOB type, for binary data up to 2^24 bytes.

See MEDIUMINT.MySQL MEDIUMINTEGER type.

See MEDIUMTEXT.MySQL MEDIUMTEXT type, for text up to 2^24 characters.

See NCHAR.MySQL NCHAR type.

See NUMERIC.MySQL NUMERIC type.

See NVARCHAR.MySQL NVARCHAR type.

See REAL.MySQL REAL type.

See SET.MySQL SET type.

See SMALLINT.MySQL SMALLINTEGER type.

See TEXT.MySQL TEXT type, for text up to 2^16 characters.

See TIME.MySQL TIME type.

See TIMESTAMP.MySQL TIMESTAMP type.

See TINYBLOB.MySQL TINYBLOB type, for binary data up to 2^8 bytes.

See TINYINT.MySQL TINYINT type.

See TINYTEXT.MySQL TINYTEXT type, for text up to 2^8 characters.

See VARBINARY.The SQL VARBINARY type.

See VARCHAR.MySQL VARCHAR type, for variable-length character data.

See YEAR.MySQL YEAR type, for single byte storage of years 1901-2155.

 -- Class: sqlalchemy.dialects.mysql.BIGINT (display_width=None, **kw)

     MySQL BIGINTEGER type.

     `Class signature'

     class sqlalchemy.dialects.mysql.BIGINT.
     (‘sqlalchemy.dialects.mysql.types._IntegerType’, see
     sqlalchemy.types.BIGINT)

      -- Method: sqlalchemy.dialects.mysql.BIGINT..__init__
               (display_width=None, **kw)

          Construct a BIGINTEGER.

          Parameters:

             * ‘display_width’ – Optional, maximum display width for
               this number.

             * ‘unsigned’ – a boolean, optional.

             * ‘zerofill’ – Optional.  If true, values will be stored as
               strings left-padded with zeros.  Note that this does not
               effect the values returned by the underlying database
               API, which continue to be numeric.

 -- Class: sqlalchemy.dialects.mysql.BINARY (length=None)

     The SQL BINARY type.

     `Class signature'

     class sqlalchemy.dialects.mysql.BINARY.
     (‘sqlalchemy.types._Binary’)

      -- Method: sqlalchemy.dialects.mysql.BINARY..__init__
               (length=None)

          `inherited from the' ‘sqlalchemy.types._Binary.__init__’
          `method of' ‘sqlalchemy.types._Binary’

          Initialize self.  See help(type(self)) for accurate signature.

 -- Class: sqlalchemy.dialects.mysql.BIT (length=None)

     MySQL BIT type.

     This type is for MySQL 5.0.3 or greater for MyISAM, and 5.0.5 or
     greater for MyISAM, MEMORY, InnoDB and BDB. For older versions, use
     a MSTinyInteger() type.

     `Class signature'

     class sqlalchemy.dialects.mysql.BIT. (see
     sqlalchemy.types.TypeEngine)

      -- Method: sqlalchemy.dialects.mysql.BIT..__init__
               (length=None)

          Construct a BIT.

          Parameters: ‘length’ – Optional, number of bits.

 -- Class: sqlalchemy.dialects.mysql.BLOB (length=None)

     The SQL BLOB type.

     `Class signature'

     class sqlalchemy.dialects.mysql.BLOB. (see
     sqlalchemy.types.LargeBinary)

      -- Method: sqlalchemy.dialects.mysql.BLOB..__init__
               (length=None)

          `inherited from the' ‘sqlalchemy.types.LargeBinary.__init__’
          `method of' LargeBinary.

          Construct a LargeBinary type.

          Parameters: ‘length’ – optional, a length for the column for
          use in DDL statements, for those binary types that accept a
          length, such as the MySQL BLOB type.

 -- Class: sqlalchemy.dialects.mysql.BOOLEAN (create_constraint=False,
          name=None, _create_events=True)

     The SQL BOOLEAN type.

     `Class signature'

     class sqlalchemy.dialects.mysql.BOOLEAN. (see
     sqlalchemy.types.Boolean)

      -- Method: sqlalchemy.dialects.mysql.BOOLEAN..__init__
               (create_constraint=False, name=None, _create_events=True)

          `inherited from the' ‘sqlalchemy.types.Boolean.__init__’
          `method of' Boolean.

          Construct a Boolean.

          Parameters:

             * ‘create_constraint’ – defaults to False.  If the boolean
               is generated as an int/smallint, also create a CHECK
               constraint on the table that ensures 1 or 0 as a value.

                    Note: it is strongly recommended that the CHECK
                    constraint have an explicit name in order to support
                    schema-management concerns.  This can be established
                    either by setting the Boolean.name
                    parameter or by setting up an appropriate naming
                    convention; see Configuring Constraint Naming Conventions
                    for background.

               Changed in version 1.4: - this flag now defaults to
               False, meaning no CHECK constraint is generated for a
               non-native enumerated type.

             * ‘name’ – if a CHECK constraint is generated, specify the
               name of the constraint.

 -- Class: sqlalchemy.dialects.mysql.CHAR (length=None, **kwargs)

     MySQL CHAR type, for fixed-length character data.

     `Class signature'

     class sqlalchemy.dialects.mysql.CHAR.
     (‘sqlalchemy.dialects.mysql.types._StringType’, see
     sqlalchemy.types.CHAR)

      -- Method: sqlalchemy.dialects.mysql.CHAR..__init__
               (length=None, **kwargs)

          Construct a CHAR.

          Parameters:

             * ‘length’ – Maximum data length, in characters.

             * ‘binary’ – Optional, use the default binary collation for
               the national character set.  This does not affect the
               type of data stored, use a BINARY type for binary data.

             * ‘collation’ – Optional, request a particular collation.
               Must be compatible with the national character set.

 -- Class: sqlalchemy.dialects.mysql.DATE

     The SQL DATE type.

     `Class signature'

     class sqlalchemy.dialects.mysql.DATE. (see
     sqlalchemy.types.Date)

      -- Method: sqlalchemy.dialects.mysql.DATE..__init__ ()

          `inherited from the' ‘builtins.object.__init__’ `method of'
          ‘builtins.object’

          Initialize self.  See help(type(self)) for accurate signature.

 -- Class: sqlalchemy.dialects.mysql.DATETIME (timezone=False, fsp=None)

     MySQL DATETIME type.

     `Class signature'

     class sqlalchemy.dialects.mysql.DATETIME. (see
     sqlalchemy.types.DATETIME)

      -- Method: sqlalchemy.dialects.mysql.DATETIME..
               __init__ (timezone=False, fsp=None)

          Construct a MySQL DATETIME type.

          Parameters:

             * ‘timezone’ – not used by the MySQL dialect.

             * ‘fsp’ – fractional seconds precision value.  MySQL 5.6.4
               supports storage of fractional seconds; this parameter
               will be used when emitting DDL for the DATETIME type.

                    Note: DBAPI driver support for fractional seconds
                    may be limited; current support includes MySQL
                    Connector/Python.

 -- Class: sqlalchemy.dialects.mysql.DECIMAL (precision=None,
          scale=None, asdecimal=True, **kw)

     MySQL DECIMAL type.

     `Class signature'

     class sqlalchemy.dialects.mysql.DECIMAL.
     (‘sqlalchemy.dialects.mysql.types._NumericType’, see
     sqlalchemy.types.DECIMAL)

      -- Method: sqlalchemy.dialects.mysql.DECIMAL..__init__
               (precision=None, scale=None, asdecimal=True, **kw)

          Construct a DECIMAL.

          Parameters:

             * ‘precision’ – Total digits in this number.  If scale and
               precision are both None, values are stored to limits
               allowed by the server.

             * ‘scale’ – The number of digits after the decimal point.

             * ‘unsigned’ – a boolean, optional.

             * ‘zerofill’ – Optional.  If true, values will be stored as
               strings left-padded with zeros.  Note that this does not
               effect the values returned by the underlying database
               API, which continue to be numeric.

 -- Class: sqlalchemy.dialects.mysql.DOUBLE (precision=None, scale=None,
          asdecimal=True, **kw)

     MySQL DOUBLE type.

     `Class signature'

     class sqlalchemy.dialects.mysql.DOUBLE.
     (‘sqlalchemy.dialects.mysql.types._FloatType’)

      -- Method: sqlalchemy.dialects.mysql.DOUBLE..__init__
               (precision=None, scale=None, asdecimal=True, **kw)

          Construct a DOUBLE.

               Note: The DOUBLE type by default converts
               from float to Decimal, using a truncation that defaults
               to 10 digits.  Specify either ‘scale=n’ or
               ‘decimal_return_scale=n’ in order to change this scale,
               or ‘asdecimal=False’ to return values directly as Python
               floating points.

          Parameters:

             * ‘precision’ – Total digits in this number.  If scale and
               precision are both None, values are stored to limits
               allowed by the server.

             * ‘scale’ – The number of digits after the decimal point.

             * ‘unsigned’ – a boolean, optional.

             * ‘zerofill’ – Optional.  If true, values will be stored as
               strings left-padded with zeros.  Note that this does not
               effect the values returned by the underlying database
               API, which continue to be numeric.

 -- Class: sqlalchemy.dialects.mysql.ENUM (*enums, **kw)

     MySQL ENUM type.

     `Class signature'

     class sqlalchemy.dialects.mysql.ENUM.
     (‘sqlalchemy.types.NativeForEmulated’, see sqlalchemy.types.Enum,
     ‘sqlalchemy.dialects.mysql.types._StringType’)

      -- Method: sqlalchemy.dialects.mysql.ENUM..__init__
               (*enums, **kw)

          Construct an ENUM.

          E.g.:

               Column('myenum', ENUM("foo", "bar", "baz"))

          Parameters:

             * ‘enums’ – The range of valid values for this ENUM. Values
               in enums are not quoted, they will be escaped and
               surrounded by single quotes when generating the schema.
               This object may also be a PEP-435-compliant enumerated
               type.

             * ‘strict’ – This flag has no effect.

               Changed in version The: MySQL ENUM type as well as the
               base Enum type now validates all Python data values.

             * ‘charset’ – Optional, a column-level character set for
               this string value.  Takes precedence to ‘ascii’ or
               ‘unicode’ short-hand.

             * ‘collation’ – Optional, a column-level collation for this
               string value.  Takes precedence to ‘binary’ short-hand.

             * ‘ascii’ – Defaults to False: short-hand for the ‘latin1’
               character set, generates ASCII in schema.

             * ‘unicode’ – Defaults to False: short-hand for the ‘ucs2’
               character set, generates UNICODE in schema.

             * ‘binary’ – Defaults to False: short-hand, pick the binary
               collation type that matches the column’s character set.
               Generates BINARY in schema.  This does not affect the
               type of data stored, only the collation of character
               data.

             * ‘quoting’ – Not used.  A warning will be raised if
               provided.

 -- Class: sqlalchemy.dialects.mysql.FLOAT (precision=None, scale=None,
          asdecimal=False, **kw)

     MySQL FLOAT type.

     `Class signature'

     class sqlalchemy.dialects.mysql.FLOAT.
     (‘sqlalchemy.dialects.mysql.types._FloatType’, see
     sqlalchemy.types.FLOAT)

      -- Method: sqlalchemy.dialects.mysql.FLOAT..__init__
               (precision=None, scale=None, asdecimal=False, **kw)

          Construct a FLOAT.

          Parameters:

             * ‘precision’ – Total digits in this number.  If scale and
               precision are both None, values are stored to limits
               allowed by the server.

             * ‘scale’ – The number of digits after the decimal point.

             * ‘unsigned’ – a boolean, optional.

             * ‘zerofill’ – Optional.  If true, values will be stored as
               strings left-padded with zeros.  Note that this does not
               effect the values returned by the underlying database
               API, which continue to be numeric.

 -- Class: sqlalchemy.dialects.mysql.INTEGER (display_width=None, **kw)

     MySQL INTEGER type.

     `Class signature'

     class sqlalchemy.dialects.mysql.INTEGER.
     (‘sqlalchemy.dialects.mysql.types._IntegerType’, see
     sqlalchemy.types.INTEGER)

      -- Method: sqlalchemy.dialects.mysql.INTEGER..__init__
               (display_width=None, **kw)

          Construct an INTEGER.

          Parameters:

             * ‘display_width’ – Optional, maximum display width for
               this number.

             * ‘unsigned’ – a boolean, optional.

             * ‘zerofill’ – Optional.  If true, values will be stored as
               strings left-padded with zeros.  Note that this does not
               effect the values returned by the underlying database
               API, which continue to be numeric.

 -- Class: sqlalchemy.dialects.mysql.JSON (none_as_null=False)

     MySQL JSON type.

     MySQL supports JSON as of version 5.7.  MariaDB supports JSON (as
     an alias for LONGTEXT) as of version 10.2.

     JSON is used automatically whenever the base
     JSON datatype is used against a MySQL or MariaDB backend.

     See also
     ........

     See JSON. - main documentation for the generic
     cross-platform JSON datatype.

     The JSON type supports persistence of JSON values as
     well as the core index operations provided by JSON
     datatype, by adapting the operations to render the ‘JSON_EXTRACT’
     function at the database level.

     New in version 1.1.

     `Class signature'

     class sqlalchemy.dialects.mysql.JSON. (see
     sqlalchemy.types.JSON)

 -- Class: sqlalchemy.dialects.mysql.LONGBLOB (length=None)

     MySQL LONGBLOB type, for binary data up to 2^32 bytes.

     `Class signature'

     class sqlalchemy.dialects.mysql.LONGBLOB.
     (‘sqlalchemy.types._Binary’)

      -- Method: sqlalchemy.dialects.mysql.LONGBLOB..
               __init__ (length=None)

          `inherited from the' ‘sqlalchemy.types._Binary.__init__’
          `method of' ‘sqlalchemy.types._Binary’

          Initialize self.  See help(type(self)) for accurate signature.

 -- Class: sqlalchemy.dialects.mysql.LONGTEXT (**kwargs)

     MySQL LONGTEXT type, for text up to 2^32 characters.

     `Class signature'

     class sqlalchemy.dialects.mysql.LONGTEXT.
     (‘sqlalchemy.dialects.mysql.types._StringType’)

      -- Method: sqlalchemy.dialects.mysql.LONGTEXT..
               __init__ (**kwargs)

          Construct a LONGTEXT.

          Parameters:

             * ‘charset’ – Optional, a column-level character set for
               this string value.  Takes precedence to ‘ascii’ or
               ‘unicode’ short-hand.

             * ‘collation’ – Optional, a column-level collation for this
               string value.  Takes precedence to ‘binary’ short-hand.

             * ‘ascii’ – Defaults to False: short-hand for the ‘latin1’
               character set, generates ASCII in schema.

             * ‘unicode’ – Defaults to False: short-hand for the ‘ucs2’
               character set, generates UNICODE in schema.

             * ‘national’ – Optional.  If true, use the server’s
               configured national character set.

             * ‘binary’ – Defaults to False: short-hand, pick the binary
               collation type that matches the column’s character set.
               Generates BINARY in schema.  This does not affect the
               type of data stored, only the collation of character
               data.

 -- Class: sqlalchemy.dialects.mysql.MEDIUMBLOB (length=None)

     MySQL MEDIUMBLOB type, for binary data up to 2^24 bytes.

     `Class signature'

     class sqlalchemy.dialects.mysql.MEDIUMBLOB.
     (‘sqlalchemy.types._Binary’)

      -- Method: sqlalchemy.dialects.mysql.MEDIUMBLOB..
               __init__ (length=None)

          `inherited from the' ‘sqlalchemy.types._Binary.__init__’
          `method of' ‘sqlalchemy.types._Binary’

          Initialize self.  See help(type(self)) for accurate signature.

 -- Class: sqlalchemy.dialects.mysql.MEDIUMINT (display_width=None,
          **kw)

     MySQL MEDIUMINTEGER type.

     `Class signature'

     class sqlalchemy.dialects.mysql.MEDIUMINT.
     (‘sqlalchemy.dialects.mysql.types._IntegerType’)

      -- Method: sqlalchemy.dialects.mysql.MEDIUMINT..
               __init__ (display_width=None, **kw)

          Construct a MEDIUMINTEGER

          Parameters:

             * ‘display_width’ – Optional, maximum display width for
               this number.

             * ‘unsigned’ – a boolean, optional.

             * ‘zerofill’ – Optional.  If true, values will be stored as
               strings left-padded with zeros.  Note that this does not
               effect the values returned by the underlying database
               API, which continue to be numeric.

 -- Class: sqlalchemy.dialects.mysql.MEDIUMTEXT (**kwargs)

     MySQL MEDIUMTEXT type, for text up to 2^24 characters.

     `Class signature'

     class sqlalchemy.dialects.mysql.MEDIUMTEXT.
     (‘sqlalchemy.dialects.mysql.types._StringType’)

      -- Method: sqlalchemy.dialects.mysql.MEDIUMTEXT..
               __init__ (**kwargs)

          Construct a MEDIUMTEXT.

          Parameters:

             * ‘charset’ – Optional, a column-level character set for
               this string value.  Takes precedence to ‘ascii’ or
               ‘unicode’ short-hand.

             * ‘collation’ – Optional, a column-level collation for this
               string value.  Takes precedence to ‘binary’ short-hand.

             * ‘ascii’ – Defaults to False: short-hand for the ‘latin1’
               character set, generates ASCII in schema.

             * ‘unicode’ – Defaults to False: short-hand for the ‘ucs2’
               character set, generates UNICODE in schema.

             * ‘national’ – Optional.  If true, use the server’s
               configured national character set.

             * ‘binary’ – Defaults to False: short-hand, pick the binary
               collation type that matches the column’s character set.
               Generates BINARY in schema.  This does not affect the
               type of data stored, only the collation of character
               data.

 -- Class: sqlalchemy.dialects.mysql.NCHAR (length=None, **kwargs)

     MySQL NCHAR type.

     For fixed-length character data in the server’s configured national
     character set.

     `Class signature'

     class sqlalchemy.dialects.mysql.NCHAR.
     (‘sqlalchemy.dialects.mysql.types._StringType’, see
     sqlalchemy.types.NCHAR)

      -- Method: sqlalchemy.dialects.mysql.NCHAR..__init__
               (length=None, **kwargs)

          Construct an NCHAR.

          Parameters:

             * ‘length’ – Maximum data length, in characters.

             * ‘binary’ – Optional, use the default binary collation for
               the national character set.  This does not affect the
               type of data stored, use a BINARY type for binary data.

             * ‘collation’ – Optional, request a particular collation.
               Must be compatible with the national character set.

 -- Class: sqlalchemy.dialects.mysql.NUMERIC (precision=None,
          scale=None, asdecimal=True, **kw)

     MySQL NUMERIC type.

     `Class signature'

     class sqlalchemy.dialects.mysql.NUMERIC.
     (‘sqlalchemy.dialects.mysql.types._NumericType’, see
     sqlalchemy.types.NUMERIC)

      -- Method: sqlalchemy.dialects.mysql.NUMERIC..__init__
               (precision=None, scale=None, asdecimal=True, **kw)

          Construct a NUMERIC.

          Parameters:

             * ‘precision’ – Total digits in this number.  If scale and
               precision are both None, values are stored to limits
               allowed by the server.

             * ‘scale’ – The number of digits after the decimal point.

             * ‘unsigned’ – a boolean, optional.

             * ‘zerofill’ – Optional.  If true, values will be stored as
               strings left-padded with zeros.  Note that this does not
               effect the values returned by the underlying database
               API, which continue to be numeric.

 -- Class: sqlalchemy.dialects.mysql.NVARCHAR (length=None, **kwargs)

     MySQL NVARCHAR type.

     For variable-length character data in the server’s configured
     national character set.

     `Class signature'

     class sqlalchemy.dialects.mysql.NVARCHAR.
     (‘sqlalchemy.dialects.mysql.types._StringType’, see
     sqlalchemy.types.NVARCHAR)

      -- Method: sqlalchemy.dialects.mysql.NVARCHAR..
               __init__ (length=None, **kwargs)

          Construct an NVARCHAR.

          Parameters:

             * ‘length’ – Maximum data length, in characters.

             * ‘binary’ – Optional, use the default binary collation for
               the national character set.  This does not affect the
               type of data stored, use a BINARY type for binary data.

             * ‘collation’ – Optional, request a particular collation.
               Must be compatible with the national character set.

 -- Class: sqlalchemy.dialects.mysql.REAL (precision=None, scale=None,
          asdecimal=True, **kw)

     MySQL REAL type.

     `Class signature'

     class sqlalchemy.dialects.mysql.REAL.
     (‘sqlalchemy.dialects.mysql.types._FloatType’, see
     sqlalchemy.types.REAL)

      -- Method: sqlalchemy.dialects.mysql.REAL..__init__
               (precision=None, scale=None, asdecimal=True, **kw)

          Construct a REAL.

               Note: The REAL type by default converts from
               float to Decimal, using a truncation that defaults to 10
               digits.  Specify either ‘scale=n’ or
               ‘decimal_return_scale=n’ in order to change this scale,
               or ‘asdecimal=False’ to return values directly as Python
               floating points.

          Parameters:

             * ‘precision’ – Total digits in this number.  If scale and
               precision are both None, values are stored to limits
               allowed by the server.

             * ‘scale’ – The number of digits after the decimal point.

             * ‘unsigned’ – a boolean, optional.

             * ‘zerofill’ – Optional.  If true, values will be stored as
               strings left-padded with zeros.  Note that this does not
               effect the values returned by the underlying database
               API, which continue to be numeric.

 -- Class: sqlalchemy.dialects.mysql.SET (*values, **kw)

     MySQL SET type.

     `Class signature'

     class sqlalchemy.dialects.mysql.SET.
     (‘sqlalchemy.dialects.mysql.types._StringType’)

      -- Method: sqlalchemy.dialects.mysql.SET..__init__
               (*values, **kw)

          Construct a SET.

          E.g.:

               Column('myset', SET("foo", "bar", "baz"))

          The list of potential values is required in the case that this
          set will be used to generate DDL for a table, or if the
          SET.retrieve_as_bitwise flag is set to True.

          Parameters:

             * ‘values’ – The range of valid values for this SET. The
               values are not quoted, they will be escaped and
               surrounded by single quotes when generating the schema.

             * ‘convert_unicode’ – Same flag as that of
               String.convert_unicode.

             * ‘collation’ – same as that of String.collation.

             * ‘charset’ – same as that of VARCHAR.charset.

             * ‘ascii’ – same as that of VARCHAR.ascii.

             * ‘unicode’ – same as that of VARCHAR.unicode.

             * ‘binary’ – same as that of VARCHAR.binary.

             * ‘retrieve_as_bitwise’ – if True, the data for the set
               type will be persisted and selected using an integer
               value, where a set is coerced into a bitwise mask for
               persistence.  MySQL allows this mode which has the
               advantage of being able to store values unambiguously,
               such as the blank string ‘''’.  The datatype will appear
               as the expression ‘col + 0’ in a SELECT statement, so
               that the value is coerced into an integer value in result
               sets.  This flag is required if one wishes to persist a
               set that can store the blank string ‘''’ as a value.

                    Warning: When using SET.retrieve_as_bitwise,
                    it is essential that the list of set values is
                    expressed in the `exact same order' as exists on the
                    MySQL database.

               New in version 1.0.0.

             * ‘quoting’ – Not used.  A warning will be raised if
               passed.

 -- Class: sqlalchemy.dialects.mysql.SMALLINT (display_width=None, **kw)

     MySQL SMALLINTEGER type.

     `Class signature'

     class sqlalchemy.dialects.mysql.SMALLINT.
     (‘sqlalchemy.dialects.mysql.types._IntegerType’, see
     sqlalchemy.types.SMALLINT)

      -- Method: sqlalchemy.dialects.mysql.SMALLINT..
               __init__ (display_width=None, **kw)

          Construct a SMALLINTEGER.

          Parameters:

             * ‘display_width’ – Optional, maximum display width for
               this number.

             * ‘unsigned’ – a boolean, optional.

             * ‘zerofill’ – Optional.  If true, values will be stored as
               strings left-padded with zeros.  Note that this does not
               effect the values returned by the underlying database
               API, which continue to be numeric.

 -- Class: sqlalchemy.dialects.mysql.TEXT (length=None, **kw)

     MySQL TEXT type, for text up to 2^16 characters.

     `Class signature'

     class sqlalchemy.dialects.mysql.TEXT.
     (‘sqlalchemy.dialects.mysql.types._StringType’, see
     sqlalchemy.types.TEXT)

      -- Method: sqlalchemy.dialects.mysql.TEXT..__init__
               (length=None, **kw)

          Construct a TEXT.

          Parameters:

             * ‘length’ – Optional, if provided the server may optimize
               storage by substituting the smallest TEXT type sufficient
               to store ‘length’ characters.

             * ‘charset’ – Optional, a column-level character set for
               this string value.  Takes precedence to ‘ascii’ or
               ‘unicode’ short-hand.

             * ‘collation’ – Optional, a column-level collation for this
               string value.  Takes precedence to ‘binary’ short-hand.

             * ‘ascii’ – Defaults to False: short-hand for the ‘latin1’
               character set, generates ASCII in schema.

             * ‘unicode’ – Defaults to False: short-hand for the ‘ucs2’
               character set, generates UNICODE in schema.

             * ‘national’ – Optional.  If true, use the server’s
               configured national character set.

             * ‘binary’ – Defaults to False: short-hand, pick the binary
               collation type that matches the column’s character set.
               Generates BINARY in schema.  This does not affect the
               type of data stored, only the collation of character
               data.

 -- Class: sqlalchemy.dialects.mysql.TIME (timezone=False, fsp=None)

     MySQL TIME type.

     `Class signature'

     class sqlalchemy.dialects.mysql.TIME. (see
     sqlalchemy.types.TIME)

      -- Method: sqlalchemy.dialects.mysql.TIME..__init__
               (timezone=False, fsp=None)

          Construct a MySQL TIME type.

          Parameters:

             * ‘timezone’ – not used by the MySQL dialect.

             * ‘fsp’ – fractional seconds precision value.  MySQL 5.6
               supports storage of fractional seconds; this parameter
               will be used when emitting DDL for the TIME type.

                    Note: DBAPI driver support for fractional seconds
                    may be limited; current support includes MySQL
                    Connector/Python.

 -- Class: sqlalchemy.dialects.mysql.TIMESTAMP (timezone=False,
          fsp=None)

     MySQL TIMESTAMP type.

     `Class signature'

     class sqlalchemy.dialects.mysql.TIMESTAMP. (see
     sqlalchemy.types.TIMESTAMP)

      -- Method: sqlalchemy.dialects.mysql.TIMESTAMP..
               __init__ (timezone=False, fsp=None)

          Construct a MySQL TIMESTAMP type.

          Parameters:

             * ‘timezone’ – not used by the MySQL dialect.

             * ‘fsp’ – fractional seconds precision value.  MySQL 5.6.4
               supports storage of fractional seconds; this parameter
               will be used when emitting DDL for the TIMESTAMP type.

                    Note: DBAPI driver support for fractional seconds
                    may be limited; current support includes MySQL
                    Connector/Python.

 -- Class: sqlalchemy.dialects.mysql.TINYBLOB (length=None)

     MySQL TINYBLOB type, for binary data up to 2^8 bytes.

     `Class signature'

     class sqlalchemy.dialects.mysql.TINYBLOB.
     (‘sqlalchemy.types._Binary’)

      -- Method: sqlalchemy.dialects.mysql.TINYBLOB..
               __init__ (length=None)

          `inherited from the' ‘sqlalchemy.types._Binary.__init__’
          `method of' ‘sqlalchemy.types._Binary’

          Initialize self.  See help(type(self)) for accurate signature.

 -- Class: sqlalchemy.dialects.mysql.TINYINT (display_width=None, **kw)

     MySQL TINYINT type.

     `Class signature'

     class sqlalchemy.dialects.mysql.TINYINT.
     (‘sqlalchemy.dialects.mysql.types._IntegerType’)

      -- Method: sqlalchemy.dialects.mysql.TINYINT..__init__
               (display_width=None, **kw)

          Construct a TINYINT.

          Parameters:

             * ‘display_width’ – Optional, maximum display width for
               this number.

             * ‘unsigned’ – a boolean, optional.

             * ‘zerofill’ – Optional.  If true, values will be stored as
               strings left-padded with zeros.  Note that this does not
               effect the values returned by the underlying database
               API, which continue to be numeric.

 -- Class: sqlalchemy.dialects.mysql.TINYTEXT (**kwargs)

     MySQL TINYTEXT type, for text up to 2^8 characters.

     `Class signature'

     class sqlalchemy.dialects.mysql.TINYTEXT.
     (‘sqlalchemy.dialects.mysql.types._StringType’)

      -- Method: sqlalchemy.dialects.mysql.TINYTEXT..
               __init__ (**kwargs)

          Construct a TINYTEXT.

          Parameters:

             * ‘charset’ – Optional, a column-level character set for
               this string value.  Takes precedence to ‘ascii’ or
               ‘unicode’ short-hand.

             * ‘collation’ – Optional, a column-level collation for this
               string value.  Takes precedence to ‘binary’ short-hand.

             * ‘ascii’ – Defaults to False: short-hand for the ‘latin1’
               character set, generates ASCII in schema.

             * ‘unicode’ – Defaults to False: short-hand for the ‘ucs2’
               character set, generates UNICODE in schema.

             * ‘national’ – Optional.  If true, use the server’s
               configured national character set.

             * ‘binary’ – Defaults to False: short-hand, pick the binary
               collation type that matches the column’s character set.
               Generates BINARY in schema.  This does not affect the
               type of data stored, only the collation of character
               data.

 -- Class: sqlalchemy.dialects.mysql.VARBINARY (length=None)

     The SQL VARBINARY type.

     `Class signature'

     class sqlalchemy.dialects.mysql.VARBINARY.
     (‘sqlalchemy.types._Binary’)

      -- Method: sqlalchemy.dialects.mysql.VARBINARY..
               __init__ (length=None)

          `inherited from the' ‘sqlalchemy.types._Binary.__init__’
          `method of' ‘sqlalchemy.types._Binary’

          Initialize self.  See help(type(self)) for accurate signature.

 -- Class: sqlalchemy.dialects.mysql.VARCHAR (length=None, **kwargs)

     MySQL VARCHAR type, for variable-length character data.

     `Class signature'

     class sqlalchemy.dialects.mysql.VARCHAR.
     (‘sqlalchemy.dialects.mysql.types._StringType’, see
     sqlalchemy.types.VARCHAR)

      -- Method: sqlalchemy.dialects.mysql.VARCHAR..__init__
               (length=None, **kwargs)

          Construct a VARCHAR.

          Parameters:

             * ‘charset’ – Optional, a column-level character set for
               this string value.  Takes precedence to ‘ascii’ or
               ‘unicode’ short-hand.

             * ‘collation’ – Optional, a column-level collation for this
               string value.  Takes precedence to ‘binary’ short-hand.

             * ‘ascii’ – Defaults to False: short-hand for the ‘latin1’
               character set, generates ASCII in schema.

             * ‘unicode’ – Defaults to False: short-hand for the ‘ucs2’
               character set, generates UNICODE in schema.

             * ‘national’ – Optional.  If true, use the server’s
               configured national character set.

             * ‘binary’ – Defaults to False: short-hand, pick the binary
               collation type that matches the column’s character set.
               Generates BINARY in schema.  This does not affect the
               type of data stored, only the collation of character
               data.

 -- Class: sqlalchemy.dialects.mysql.YEAR (display_width=None)

     MySQL YEAR type, for single byte storage of years 1901-2155.

     `Class signature'

     class sqlalchemy.dialects.mysql.YEAR. (see
     sqlalchemy.types.TypeEngine)

      -- Method: sqlalchemy.dialects.mysql.YEAR..__init__
               (display_width=None)

          Initialize self.  See help(type(self)) for accurate signature.

5.1.2.31 MySQL DML Constructs
.............................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See insert.(table[,Construct an Insert object.
values,
inline,
bind, ...],
**dialect_kw)

See Insert.MySQL-specific implementation of INSERT.

 -- Function: sqlalchemy.dialects.mysql.insert (table, values=None,
          inline=False, bind=None, prefixes=None, returning=None,
          return_defaults=False, **dialect_kw)

     Construct an Insert object.

     This documentation is inherited from
     sqlalchemy.sql.expression.insert(); this constructor, see
     sqlalchemy.dialects.mysql.insert(), creates a
     sqlalchemy.dialects.mysql.Insert object.  See that class for
     additional details describing this subclass.

     E.g.:

          from sqlalchemy import insert

          stmt = (
              insert(user_table).
              values(name='username', fullname='Full Username')
          )

     Similar functionality is available via the
     TableClause.insert() method on Table.

     See also
     ........

     See Insert Expressions. - in the 1.x tutorial.

     See Core Insert. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

     Parameters:

        * ‘table’ – see TableClause which is the subject of the
          insert.

        * ‘values’ – collection of values to be inserted; see
          Insert.values() for a description of allowed formats
          here.  Can be omitted entirely; a Insert construct
          will also dynamically render the VALUES clause at execution
          time based on the parameters passed to
          Connection.execute().

          Deprecated since version 1.4: The insert.values
          parameter will be removed in SQLAlchemy 2.0.  Please refer to
          the Insert.values() method.

        * ‘inline’ – if True, no attempt will be made to retrieve the
          SQL-generated default values to be provided within the
          statement; in particular, this allows SQL expressions to be
          rendered ‘inline’ within the statement without the need to
          pre-execute them beforehand; for backends that support
          “returning”, this turns off the “implicit returning” feature
          for the statement.

          Deprecated since version 1.4: The insert.inline
          parameter will be removed in SQLAlchemy 2.0.  Please use the
          Insert.inline() method.

     If both Insert.values and compile-time bind parameters
     are present, the compile-time bind parameters override the
     information specified within Insert.values on a per-key
     basis.

     The keys within Insert.values can be either
     Column objects or their string identifiers.  Each key may
     reference one of:

        * a literal data value (i.e.  string, number, etc.);

        * a Column object;

        * a SELECT statement.

     If a ‘SELECT’ statement is specified which references this ‘INSERT’
     statement’s table, the statement will be correlated against the
     ‘INSERT’ statement.

     See also
     ........

     See Insert Expressions. - SQL Expression Tutorial

     See Inserts, Updates and Deletes. - SQL Expression Tutorial

 -- Class: sqlalchemy.dialects.mysql.Insert (table, values=None,
          inline=False, bind=None, prefixes=None, returning=None,
          return_defaults=False, **dialect_kw)

     MySQL-specific implementation of INSERT.

     Adds methods for MySQL-specific syntaxes such as ON DUPLICATE KEY
     UPDATE.

     The Insert object is created using the
     sqlalchemy.dialects.mysql.insert() function.

     New in version 1.2.

     `Class signature'

     class sqlalchemy.dialects.mysql.Insert. (see
     sqlalchemy.sql.expression.Insert)

      -- Attribute: sqlalchemy.dialects.mysql.Insert..
               inserted

          Provide the “inserted” namespace for an ON DUPLICATE KEY
          UPDATE statement

          MySQL’s ON DUPLICATE KEY UPDATE clause allows reference to the
          row that would be inserted, via a special function called
          ‘VALUES()’.  This attribute provides all columns in this row
          to be referenceable such that they will render within a
          ‘VALUES()’ function inside the ON DUPLICATE KEY UPDATE clause.
          The attribute is named ‘.inserted’ so as not to conflict with
          the existing Insert.values() method.

          See also
          ........

          See INSERT…ON DUPLICATE KEY UPDATE (Upsert). - example
          of how to use ‘Insert.inserted’

      -- Method: sqlalchemy.dialects.mysql.Insert..
               on_duplicate_key_update (*args, **kw)

          Specifies the ON DUPLICATE KEY UPDATE clause.

          Parameters: ‘**kw’ – Column keys linked to UPDATE values.  The
          values may be any SQL expression or supported literal Python
          values.

               Warning: This dictionary does `not' take into account
               Python-specified default UPDATE values or generation
               functions, e.g.  those specified using
               Column.onupdate.  These values will not be exercised
               for an ON DUPLICATE KEY UPDATE style of UPDATE, unless
               values are manually specified here.

          Parameters: ‘*args’ – As an alternative to passing key/value
          parameters, a dictionary or list of 2-tuples can be passed as
          a single positional argument.

          Passing a single dictionary is equivalent to the keyword
          argument form:

               insert().on_duplicate_key_update({"name": "some name"})

          Passing a list of 2-tuples indicates that the parameter
          assignments in the UPDATE clause should be ordered as sent, in
          a manner similar to that described for the Update
          construct overall in Parameter-Ordered Updates:

               insert().on_duplicate_key_update(
                   [("name", "some name"), ("value", "some value")])

          Changed in version 1.3: parameters can be specified as a
          dictionary or list of 2-tuples; the latter form provides for
          parameter ordering.

          New in version 1.2.

          See also
          ........

          See INSERT…ON DUPLICATE KEY UPDATE (Upsert).

5.1.2.32 mysqlclient (fork of MySQL-Python)
...........................................

Support for the MySQL / MariaDB database via the mysqlclient (maintained
fork of MySQL-Python) driver.

5.1.2.33 DBAPI
..............

Documentation and download information (if applicable) for mysqlclient
(maintained fork of MySQL-Python) is available at:
‘https://pypi.org/project/mysqlclient/’

5.1.2.34 Connecting
...................

Connect String:
     mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname>

5.1.2.35 Driver Status
......................

The mysqlclient DBAPI is a maintained fork of the MySQL-Python(1) DBAPI
that is no longer maintained.  mysqlclient(2) supports Python 2 and
Python 3 and is very stable.

   ---------- Footnotes ----------

   (1) http://sourceforge.net/projects/mysql-python

   (2) https://github.com/PyMySQL/mysqlclient-python

5.1.2.36 Unicode
................

Please see Unicode for current recommendations on unicode
handling.

5.1.2.37 Using MySQLdb with Google Cloud SQL
............................................

Google Cloud SQL now recommends use of the MySQLdb dialect.  Connect
using a URL like the following:

     mysql+mysqldb://root@/<dbname>?unix_socket=/cloudsql/<projectid>:<instancename>

5.1.2.38 Server Side Cursors
............................

The mysqldb dialect supports server-side cursors.  See Server Side Cursors.

5.1.2.39 PyMySQL
................

Support for the MySQL / MariaDB database via the PyMySQL driver.

5.1.2.40 DBAPI
..............

Documentation and download information (if applicable) for PyMySQL is
available at: ‘https://pymysql.readthedocs.io/’

5.1.2.41 Connecting
...................

Connect String:
     mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]

5.1.2.42 Unicode
................

Please see Unicode for current recommendations on unicode
handling.

5.1.2.43 MySQL-Python Compatibility
...................................

The pymysql DBAPI is a pure Python port of the MySQL-python (MySQLdb)
driver, and targets 100% compatibility.  Most behavioral notes for
MySQL-python apply to the pymysql driver as well.

5.1.2.44 MySQL-Connector
........................

Support for the MySQL / MariaDB database via the MySQL Connector/Python
driver.

5.1.2.45 DBAPI
..............

Documentation and download information (if applicable) for MySQL
Connector/Python is available at:
‘https://pypi.org/project/mysql-connector-python/’

5.1.2.46 Connecting
...................

Connect String:
     mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname>

     Note: The MySQL Connector/Python DBAPI has had many issues since
     its release, some of which may remain unresolved, and the
     mysqlconnector dialect is `not tested as part of SQLAlchemy’s
     continuous integration'.  The recommended MySQL dialects are
     mysqlclient and PyMySQL.

5.1.2.47 aiomysql
.................

Support for the MySQL / MariaDB database via the aiomysql driver.

5.1.2.48 DBAPI
..............

Documentation and download information (if applicable) for aiomysql is
available at: ‘https://github.com/aio-libs/aiomysql’

5.1.2.49 Connecting
...................

Connect String:
     mysql+aiomysql://user:password@host:port/dbname[?key=value&key=value...]

The aiomysql dialect is SQLAlchemy’s second Python asyncio dialect.

Using a special asyncio mediation layer, the aiomysql dialect is usable
as the backend for the SQLAlchemy asyncio extension package.

This dialect should normally be used only with the
create_async_engine() engine creation function:

     from sqlalchemy.ext.asyncio import create_async_engine
     engine = create_async_engine("mysql+aiomysql://user:pass@hostname/dbname")

5.1.2.50 Unicode
................

Please see Unicode for current recommendations on unicode
handling.

5.1.2.51 cymysql
................

Support for the MySQL / MariaDB database via the CyMySQL driver.

5.1.2.52 DBAPI
..............

Documentation and download information (if applicable) for CyMySQL is
available at: ‘https://github.com/nakagami/CyMySQL’

5.1.2.53 Connecting
...................

Connect String:
     mysql+cymysql://<username>:<password>@<host>/<dbname>[?<options>]

     Note: The CyMySQL dialect is `not tested as part of SQLAlchemy’s
     continuous integration' and may have unresolved issues.  The
     recommended MySQL dialects are mysqlclient and PyMySQL.

5.1.2.54 OurSQL
...............

Support for the MySQL / MariaDB database via the OurSQL driver.

5.1.2.55 DBAPI
..............

Documentation and download information (if applicable) for OurSQL is
available at: ‘http://packages.python.org/oursql/’

5.1.2.56 Connecting
...................

Connect String:
     mysql+oursql://<user>:<password>@<host>[:<port>]/<dbname>

     Note: The OurSQL MySQL dialect is legacy and is no longer supported
     upstream, and is `not tested as part of SQLAlchemy’s continuous
     integration'.  The recommended MySQL dialects are mysqlclient and
     PyMySQL.

Deprecated since version 1.4: The OurSQL DBAPI is deprecated and will be
removed in a future version.  Please use one of the supported DBAPIs to
connect to mysql.

5.1.2.57 Unicode
................

Please see Unicode for current recommendations on unicode
handling.

5.1.2.58 pyodbc
...............

Support for the MySQL / MariaDB database via the PyODBC driver.

5.1.2.59 DBAPI
..............

Documentation and download information (if applicable) for PyODBC is
available at: ‘http://pypi.python.org/pypi/pyodbc/’

5.1.2.60 Connecting
...................

Connect String:
     mysql+pyodbc://<username>:<password>@<dsnname>

     Note: The PyODBC for MySQL dialect is `not tested as part of
     SQLAlchemy’s continuous integration'.  The recommended MySQL
     dialects are mysqlclient and PyMySQL. However, if you want to use
     the mysql+pyodbc dialect and require full support for ‘utf8mb4’
     characters (including supplementary characters like emoji) be sure
     to use a current release of MySQL Connector/ODBC and specify the
     “ANSI” (`not' “Unicode”) version of the driver in your DSN or
     connection string.

Pass through exact pyodbc connection string:

     import urllib
     connection_string = (
         'DRIVER=MySQL ODBC 8.0 ANSI Driver;'
         'SERVER=localhost;'
         'PORT=3307;'
         'DATABASE=mydb;'
         'UID=root;'
         'PWD=(whatever);'
         'charset=utf8mb4;'
     )
     params = urllib.parse.quote_plus(connection_string)
     connection_uri = "mysql+pyodbc:///?odbc_connect=%s" % params

5.1.3 SQLite
------------

Support for the SQLite database.

The following table summarizes current support levels for database
release versions.

`Supported SQLite versions'

Support type                                           Versions

--------------------------------------------------------------------------------------------------------------

See Fully tested in CI.                        3.21, 3.28+

See Normal support.                            3.12+

See Best effort.                               3.7.16+

5.1.3.1 DBAPI Support
.....................

The following dialect/DBAPI options are available.  Please refer to
individual DBAPI sections for connect information.

   * pysqlite.

   * pysqlcipher.

5.1.3.2 Date and Time Types
...........................

SQLite does not have built-in DATE, TIME, or DATETIME types, and
pysqlite does not provide out of the box functionality for translating
values between Python ‘datetime’ objects and a SQLite-supported format.
SQLAlchemy’s own DateTime and related types provide date
formatting and parsing functionality when SQLite is used.  The
implementation classes are DATETIME, DATE and
TIME.  These types represent dates and times as ISO
formatted strings, which also nicely support ordering.  There’s no
reliance on typical “libc” internals for these functions so historical
dates are fully supported.

5.1.3.3 Ensuring Text affinity
..............................

The DDL rendered for these types is the standard ‘DATE’, ‘TIME’ and
‘DATETIME’ indicators.  However, custom storage formats can also be
applied to these types.  When the storage format is detected as
containing no alpha characters, the DDL for these types is rendered as
‘DATE_CHAR’, ‘TIME_CHAR’, and ‘DATETIME_CHAR’, so that the column
continues to have textual affinity.

See also
........

Type Affinity(1) - in the SQLite documentation

   ---------- Footnotes ----------

   (1) http://www.sqlite.org/datatype3.html#affinity

5.1.3.4 SQLite Auto Incrementing Behavior
.........................................

Background on SQLite’s autoincrement is at:
‘http://sqlite.org/autoinc.html’

Key concepts:

   * SQLite has an implicit “auto increment” feature that takes place
     for any non-composite primary-key column that is specifically
     created using “INTEGER PRIMARY KEY” for the type + primary key.

   * SQLite also has an explicit “AUTOINCREMENT” keyword, that is `not'
     equivalent to the implicit autoincrement feature; this keyword is
     not recommended for general use.  SQLAlchemy does not render this
     keyword unless a special SQLite-specific directive is used (see
     below).  However, it still requires that the column’s type is named
     “INTEGER”.

5.1.3.5 Using the AUTOINCREMENT Keyword
.......................................

To specifically render the AUTOINCREMENT keyword on the primary key
column when rendering DDL, add the flag ‘sqlite_autoincrement=True’ to
the Table construct:

     Table('sometable', metadata,
             Column('id', Integer, primary_key=True),
             sqlite_autoincrement=True)

5.1.3.6 Allowing autoincrement behavior SQLAlchemy types other than Integer/INTEGER
...................................................................................

SQLite’s typing model is based on naming conventions.  Among other
things, this means that any type name which contains the substring
‘"INT"’ will be determined to be of “integer affinity”.  A type named
‘"BIGINT"’, ‘"SPECIAL_INT"’ or even ‘"XYZINTQPR"’, will be considered by
SQLite to be of “integer” affinity.  However, `the SQLite autoincrement
feature, whether implicitly or explicitly enabled, requires that the
name of the column’s type is exactly the string “INTEGER”'.  Therefore,
if an application uses a type like BigInteger for a primary
key, on SQLite this type will need to be rendered as the name
‘"INTEGER"’ when emitting the initial ‘CREATE TABLE’ statement in order
for the autoincrement behavior to be available.

One approach to achieve this is to use Integer on SQLite only
using TypeEngine.with_variant():

     table = Table(
         "my_table", metadata,
         Column("id", BigInteger().with_variant(Integer, "sqlite"), primary_key=True)
     )

Another is to use a subclass of BigInteger that overrides
its DDL name to be ‘INTEGER’ when compiled against SQLite:

     from sqlalchemy import BigInteger
     from sqlalchemy.ext.compiler import compiles

     class SLBigInteger(BigInteger):
         pass

     @compiles(SLBigInteger, 'sqlite')
     def bi_c(element, compiler, **kw):
         return "INTEGER"

     @compiles(SLBigInteger)
     def bi_c(element, compiler, **kw):
         return compiler.visit_BIGINT(element, **kw)

     table = Table(
         "my_table", metadata,
         Column("id", SLBigInteger(), primary_key=True)
     )

See also
........

See TypeEngine.with_variant().

See Custom SQL Constructs and Compilation Extension.

Datatypes In SQLite Version 3(1)

   ---------- Footnotes ----------

   (1) http://sqlite.org/datatype3.html

5.1.3.7 Database Locking Behavior / Concurrency
...............................................

SQLite is not designed for a high level of write concurrency.  The
database itself, being a file, is locked completely during write
operations within transactions, meaning exactly one “connection” (in
reality a file handle) has exclusive access to the database during this
period - all other “connections” will be blocked during this time.

The Python DBAPI specification also calls for a connection model that is
always in a transaction; there is no ‘connection.begin()’ method, only
‘connection.commit()’ and ‘connection.rollback()’, upon which a new
transaction is to be begun immediately.  This may seem to imply that the
SQLite driver would in theory allow only a single filehandle on a
particular database file at any time; however, there are several factors
both within SQLite itself as well as within the pysqlite driver which
loosen this restriction significantly.

However, no matter what locking modes are used, SQLite will still always
lock the database file once a transaction is started and DML (e.g.
INSERT, UPDATE, DELETE) has at least been emitted, and this will block
other transactions at least at the point that they also attempt to emit
DML. By default, the length of time on this block is very short before
it times out with an error.

This behavior becomes more critical when used in conjunction with the
SQLAlchemy ORM. SQLAlchemy’s Session object by default runs
within a transaction, and with its autoflush model, may emit DML
preceding any SELECT statement.  This may lead to a SQLite database that
locks more quickly than is expected.  The locking mode of SQLite and the
pysqlite driver can be manipulated to some degree, however it should be
noted that achieving a high degree of write-concurrency with SQLite is a
losing battle.

For more information on SQLite’s lack of write concurrency by design,
please see Situations Where Another RDBMS May Work Better - High
Concurrency(1) near the bottom of the page.

The following subsections introduce areas that are impacted by SQLite’s
file-based architecture and additionally will usually require
workarounds to work when using the pysqlite driver.

   ---------- Footnotes ----------

   (1) http://www.sqlite.org/whentouse.html

5.1.3.8 Transaction Isolation Level / Autocommit
................................................

SQLite supports “transaction isolation” in a non-standard way, along two
axes.  One is that of the PRAGMA read_uncommitted(1) instruction.  This
setting can essentially switch SQLite between its default mode of
‘SERIALIZABLE’ isolation, and a “dirty read” isolation mode normally
referred to as ‘READ UNCOMMITTED’.

SQLAlchemy ties into this PRAGMA statement using the
create_engine.isolation_level parameter of create_engine().
Valid values for this parameter when used with SQLite are
‘"SERIALIZABLE"’ and ‘"READ UNCOMMITTED"’ corresponding to a value of 0
and 1, respectively.  SQLite defaults to ‘SERIALIZABLE’, however its
behavior is impacted by the pysqlite driver’s default behavior.

When using the pysqlite driver, the ‘"AUTOCOMMIT"’ isolation level is
also available, which will alter the pysqlite connection using the
‘.isolation_level’ attribute on the DBAPI connection and set it to None
for the duration of the setting.

New in version 1.3.16: added support for SQLite AUTOCOMMIT isolation
level when using the pysqlite / sqlite3 SQLite driver.

The other axis along which SQLite’s transactional locking is impacted is
via the nature of the ‘BEGIN’ statement used.  The three varieties are
“deferred”, “immediate”, and “exclusive”, as described at BEGIN
TRANSACTION(2). A straight ‘BEGIN’ statement uses the “deferred” mode,
where the database file is not locked until the first read or write
operation, and read access remains open to other transactions until the
first write operation.  But again, it is critical to note that the
pysqlite driver interferes with this behavior by `not even emitting
BEGIN' until the first write operation.

     Warning: SQLite’s transactional scope is impacted by unresolved
     issues in the pysqlite driver, which defers BEGIN statements to a
     greater degree than is often feasible.  See the section
     Serializable isolation / Savepoints / Transactional DDL for
     techniques to work around this behavior.

See also
........

See Setting Transaction Isolation Levels including DBAPI Autocommit.

   ---------- Footnotes ----------

   (1) http://www.sqlite.org/pragma.html#pragma_read_uncommitted

   (2) http://sqlite.org/lang_transaction.html

5.1.3.9 SAVEPOINT Support
.........................

SQLite supports SAVEPOINTs, which only function once a transaction is
begun.  SQLAlchemy’s SAVEPOINT support is available using the
Connection.begin_nested() method at the Core level, and
Session.begin_nested() at the ORM level.  However, SAVEPOINTs
won’t work at all with pysqlite unless workarounds are taken.

     Warning: SQLite’s SAVEPOINT feature is impacted by unresolved
     issues in the pysqlite driver, which defers BEGIN statements to a
     greater degree than is often feasible.  See the section
     Serializable isolation / Savepoints / Transactional DDL for
     techniques to work around this behavior.

5.1.3.10 Transactional DDL
..........................

The SQLite database supports transactional DDL as well.  In this case,
the pysqlite driver is not only failing to start transactions, it also
is ending any existing transaction when DDL is detected, so again,
workarounds are required.

     Warning: SQLite’s transactional DDL is impacted by unresolved
     issues in the pysqlite driver, which fails to emit BEGIN and
     additionally forces a COMMIT to cancel any transaction when DDL is
     encountered.  See the section Serializable isolation / Savepoints / Transactional DDL
     for techniques to work around
     this behavior.

5.1.3.11 Foreign Key Support
............................

SQLite supports FOREIGN KEY syntax when emitting CREATE statements for
tables, however by default these constraints have no effect on the
operation of the table.

Constraint checking on SQLite has three prerequisites:

   * At least version 3.6.19 of SQLite must be in use

   * The SQLite library must be compiled `without' the
     SQLITE_OMIT_FOREIGN_KEY or SQLITE_OMIT_TRIGGER symbols enabled.

   * The ‘PRAGMA foreign_keys = ON’ statement must be emitted on all
     connections before use.

SQLAlchemy allows for the ‘PRAGMA’ statement to be emitted automatically
for new connections through the usage of events:

     from sqlalchemy.engine import Engine
     from sqlalchemy import event

     @event.listens_for(Engine, "connect")
     def set_sqlite_pragma(dbapi_connection, connection_record):
         cursor = dbapi_connection.cursor()
         cursor.execute("PRAGMA foreign_keys=ON")
         cursor.close()

     Warning: When SQLite foreign keys are enabled, it is `not possible'
     to emit CREATE or DROP statements for tables that contain
     mutually-dependent foreign key constraints; to emit the DDL for
     these tables requires that ALTER TABLE be used to create or drop
     these constraints separately, for which SQLite has no support.

See also
........

SQLite Foreign Key Support(1) - on the SQLite web site.

See Events. - SQLAlchemy event API.

See Creating/Dropping Foreign Key Constraints via ALTER. - more information on SQLAlchemy’s facilities for handling

     mutually-dependent foreign key constraints.

   ---------- Footnotes ----------

   (1) http://www.sqlite.org/foreignkeys.html

5.1.3.12 ON CONFLICT support for constraints
............................................

See also
........

This section describes the DDL version of “ON CONFLICT” for SQLite,
which occurs within a CREATE TABLE statement.  For “ON CONFLICT” as
applied to an INSERT statement, see INSERT…ON CONFLICT (Upsert).

SQLite supports a non-standard DDL clause known as ON CONFLICT which can
be applied to primary key, unique, check, and not null constraints.  In
DDL, it is rendered either within the “CONSTRAINT” clause or within the
column definition itself depending on the location of the target
constraint.  To render this clause within DDL, the extension parameter
‘sqlite_on_conflict’ can be specified with a string conflict resolution
algorithm within the PrimaryKeyConstraint,
UniqueConstraint, CheckConstraint objects.  Within
the Column object, there are individual parameters
‘sqlite_on_conflict_not_null’, ‘sqlite_on_conflict_primary_key’,
‘sqlite_on_conflict_unique’ which each correspond to the three types of
relevant constraint types that can be indicated from a Column
object.

See also
........

ON CONFLICT(1) - in the SQLite documentation

New in version 1.3.

The ‘sqlite_on_conflict’ parameters accept a string argument which is
just the resolution name to be chosen, which on SQLite can be one of
ROLLBACK, ABORT, FAIL, IGNORE, and REPLACE. For example, to add a UNIQUE
constraint that specifies the IGNORE algorithm:

     some_table = Table(
         'some_table', metadata,
         Column('id', Integer, primary_key=True),
         Column('data', Integer),
         UniqueConstraint('id', 'data', sqlite_on_conflict='IGNORE')
     )

The above renders CREATE TABLE DDL as:

     CREATE TABLE some_table (
         id INTEGER NOT NULL,
         data INTEGER,
         PRIMARY KEY (id),
         UNIQUE (id, data) ON CONFLICT IGNORE
     )

When using the Column.unique flag to add a UNIQUE
constraint to a single column, the ‘sqlite_on_conflict_unique’ parameter
can be added to the Column as well, which will be added to
the UNIQUE constraint in the DDL:

     some_table = Table(
         'some_table', metadata,
         Column('id', Integer, primary_key=True),
         Column('data', Integer, unique=True,
                sqlite_on_conflict_unique='IGNORE')
     )

rendering:

     CREATE TABLE some_table (
         id INTEGER NOT NULL,
         data INTEGER,
         PRIMARY KEY (id),
         UNIQUE (data) ON CONFLICT IGNORE
     )

To apply the FAIL algorithm for a NOT NULL constraint,
‘sqlite_on_conflict_not_null’ is used:

     some_table = Table(
         'some_table', metadata,
         Column('id', Integer, primary_key=True),
         Column('data', Integer, nullable=False,
                sqlite_on_conflict_not_null='FAIL')
     )

this renders the column inline ON CONFLICT phrase:

     CREATE TABLE some_table (
         id INTEGER NOT NULL,
         data INTEGER NOT NULL ON CONFLICT FAIL,
         PRIMARY KEY (id)
     )

Similarly, for an inline primary key, use
‘sqlite_on_conflict_primary_key’:

     some_table = Table(
         'some_table', metadata,
         Column('id', Integer, primary_key=True,
                sqlite_on_conflict_primary_key='FAIL')
     )

SQLAlchemy renders the PRIMARY KEY constraint separately, so the
conflict resolution algorithm is applied to the constraint itself:

     CREATE TABLE some_table (
         id INTEGER NOT NULL,
         PRIMARY KEY (id) ON CONFLICT FAIL
     )

   ---------- Footnotes ----------

   (1) https://www.sqlite.org/lang_conflict.html

5.1.3.13 INSERT…ON CONFLICT (Upsert)
....................................

See also
........

This section describes the DML version of “ON CONFLICT” for SQLite,
which occurs within an INSERT statement.  For “ON CONFLICT” as applied
to a CREATE TABLE statement, see ON CONFLICT support for constraints.

From version 3.24.0 onwards, SQLite supports “upserts” (update or
insert) of rows into a table via the ‘ON CONFLICT’ clause of the
‘INSERT’ statement.  A candidate row will only be inserted if that row
does not violate any unique or primary key constraints.  In the case of
a unique constraint violation, a secondary action can occur which can be
either “DO UPDATE”, indicating that the data in the target row should be
updated, or “DO NOTHING”, which indicates to silently skip this row.

Conflicts are determined using columns that are part of existing unique
constraints and indexes.  These constraints are identified by stating
the columns and conditions that comprise the indexes.

SQLAlchemy provides ‘ON CONFLICT’ support via the SQLite-specific
insert() function, which provides the generative methods
Insert.on_conflict_do_update() and
Insert.on_conflict_do_nothing():

     >>> from sqlalchemy.dialects.sqlite import insert

     >>> insert_stmt = insert(my_table).values(
     ...     id='some_existing_id',
     ...     data='inserted value')

     >>> do_update_stmt = insert_stmt.on_conflict_do_update(
     ...     index_elements=['id'],
     ...     set_=dict(data='updated value')
     ... )

     >>> print(do_update_stmt)
     {opensql}INSERT INTO my_table (id, data) VALUES (?, ?)
     ON CONFLICT (id) DO UPDATE SET data = ?{stop}

     >>> do_nothing_stmt = insert_stmt.on_conflict_do_nothing(
     ...     index_elements=['id']
     ... )

     >>> print(do_nothing_stmt)
     {opensql}INSERT INTO my_table (id, data) VALUES (?, ?)
     ON CONFLICT (id) DO NOTHING

New in version 1.4.

See also
........

Upsert(1) - in the SQLite documentation.

   ---------- Footnotes ----------

   (1) https://sqlite.org/lang_UPSERT.html

5.1.3.14 Specifying the Target
..............................

Both methods supply the “target” of the conflict using column inference:

   * The Insert.on_conflict_do_update.index_elements.
     argument specifies a sequence containing string column names, see
     Column objects, and/or SQL expression elements, which would
     identify a unique index or unique constraint.

   * When using Insert.on_conflict_do_update.index_elements.
     to infer an index, a partial index can be inferred by also
     specifying the Insert.on_conflict_do_update.index_where
     parameter:

          >>> stmt = insert(my_table).values(user_email='a@b.com', data='inserted data')

          >>> do_update_stmt = stmt.on_conflict_do_update(
          ...     index_elements=[my_table.c.user_email],
          ...     index_where=my_table.c.user_email.like('%@gmail.com'),
          ...     set_=dict(data=stmt.excluded.data)
          ...     )

          >>> print(do_update_stmt)
          {opensql}INSERT INTO my_table (data, user_email) VALUES (?, ?)
          ON CONFLICT (user_email)
          WHERE user_email LIKE '%@gmail.com'
          DO UPDATE SET data = excluded.data
          >>>

5.1.3.15 The SET Clause
.......................

‘ON CONFLICT...DO UPDATE’ is used to perform an update of the already
existing row, using any combination of new values as well as values from
the proposed insertion.  These values are specified using the
Insert.on_conflict_do_update.set_ parameter.  This parameter
accepts a dictionary which consists of direct values for UPDATE:

     >>> stmt = insert(my_table).values(id='some_id', data='inserted value')

     >>> do_update_stmt = stmt.on_conflict_do_update(
     ...     index_elements=['id'],
     ...     set_=dict(data='updated value')
     ... )

     >>> print(do_update_stmt)

     {opensql}INSERT INTO my_table (id, data) VALUES (?, ?)
     ON CONFLICT (id) DO UPDATE SET data = ?

     Warning: The Insert.on_conflict_do_update() method
     does `not' take into account Python-side default UPDATE values or
     generation functions, e.g.  those specified using
     Column.onupdate.  These values will not be exercised for an ON
     CONFLICT style of UPDATE, unless they are manually specified in the
     Insert.on_conflict_do_update.set_ dictionary.

5.1.3.16 Updating using the Excluded INSERT Values
..................................................

In order to refer to the proposed insertion row, the special alias
Insert.excluded is available as an attribute on the Insert
object; this object creates an “excluded.” prefix on a column,
that informs the DO UPDATE to update the row with the value that would
have been inserted had the constraint not failed:

     >>> stmt = insert(my_table).values(
     ...     id='some_id',
     ...     data='inserted value',
     ...     author='jlh'
     ... )

     >>> do_update_stmt = stmt.on_conflict_do_update(
     ...     index_elements=['id'],
     ...     set_=dict(data='updated value', author=stmt.excluded.author)
     ... )

     >>> print(do_update_stmt)
     {opensql}INSERT INTO my_table (id, data, author) VALUES (?, ?, ?)
     ON CONFLICT (id) DO UPDATE SET data = ?, author = excluded.author

5.1.3.17 Additional WHERE Criteria
..................................

The Insert.on_conflict_do_update() method also accepts a
WHERE clause using the Insert.on_conflict_do_update.where
parameter, which will limit those rows which receive an UPDATE:

     >>> stmt = insert(my_table).values(
     ...     id='some_id',
     ...     data='inserted value',
     ...     author='jlh'
     ... )

     >>> on_update_stmt = stmt.on_conflict_do_update(
     ...     index_elements=['id'],
     ...     set_=dict(data='updated value', author=stmt.excluded.author),
     ...     where=(my_table.c.status == 2)
     ... )
     >>> print(on_update_stmt)
     {opensql}INSERT INTO my_table (id, data, author) VALUES (?, ?, ?)
     ON CONFLICT (id) DO UPDATE SET data = ?, author = excluded.author
     WHERE my_table.status = ?

5.1.3.18 Skipping Rows with DO NOTHING
......................................

‘ON CONFLICT’ may be used to skip inserting a row entirely if any
conflict with a unique constraint occurs; below this is illustrated
using the Insert.on_conflict_do_nothing() method:

     >>> stmt = insert(my_table).values(id='some_id', data='inserted value')
     >>> stmt = stmt.on_conflict_do_nothing(index_elements=['id'])
     >>> print(stmt)
     {opensql}INSERT INTO my_table (id, data) VALUES (?, ?) ON CONFLICT (id) DO NOTHING

If ‘DO NOTHING’ is used without specifying any columns or constraint, it
has the effect of skipping the INSERT for any unique violation which
occurs:

     >>> stmt = insert(my_table).values(id='some_id', data='inserted value')
     >>> stmt = stmt.on_conflict_do_nothing()
     >>> print(stmt)
     {opensql}INSERT INTO my_table (id, data) VALUES (?, ?) ON CONFLICT DO NOTHING

5.1.3.19 Type Reflection
........................

SQLite types are unlike those of most other database backends, in that
the string name of the type usually does not correspond to a “type” in a
one-to-one fashion.  Instead, SQLite links per-column typing behavior to
one of five so-called “type affinities” based on a string matching
pattern for the type.

SQLAlchemy’s reflection process, when inspecting types, uses a simple
lookup table to link the keywords returned to provided SQLAlchemy types.
This lookup table is present within the SQLite dialect as it is for all
other dialects.  However, the SQLite dialect has a different “fallback”
routine for when a particular type name is not located in the lookup
map; it instead implements the SQLite “type affinity” scheme located at
‘http://www.sqlite.org/datatype3.html’ section 2.1.

The provided typemap will make direct associations from an exact string
name match for the following types:

BIGINT, BLOB, BOOLEAN,
BOOLEAN, CHAR, DATE, DATETIME,
FLOAT, DECIMAL, FLOAT,
INTEGER, INTEGER, NUMERIC, REAL,
see SMALLINT, TEXT, TIME,
TIMESTAMP, VARCHAR, NVARCHAR, NCHAR.

When a type name does not match one of the above types, the “type
affinity” lookup is used instead:

   * INTEGER is returned if the type name includes the
     string ‘INT’

   * TEXT is returned if the type name includes the string
     ‘CHAR’, ‘CLOB’ or ‘TEXT’

   * NullType is returned if the type name includes the
     string ‘BLOB’

   * REAL is returned if the type name includes the string
     ‘REAL’, ‘FLOA’ or ‘DOUB’.

   * Otherwise, the NUMERIC type is used.

New in version 0.9.3: Support for SQLite type affinity rules when
reflecting columns.

5.1.3.20 Partial Indexes
........................

A partial index, e.g.  one which uses a WHERE clause, can be specified
with the DDL system using the argument ‘sqlite_where’:

     tbl = Table('testtbl', m, Column('data', Integer))
     idx = Index('test_idx1', tbl.c.data,
                 sqlite_where=and_(tbl.c.data > 5, tbl.c.data < 10))

The index will be rendered at create time as:

     CREATE INDEX test_idx1 ON testtbl (data)
     WHERE data > 5 AND data < 10

New in version 0.9.9.

5.1.3.21 Dotted Column Names
............................

Using table or column names that explicitly have periods in them is `not
recommended'.  While this is generally a bad idea for relational
databases in general, as the dot is a syntactically significant
character, the SQLite driver up until version `3.10.0' of SQLite has a
bug which requires that SQLAlchemy filter out these dots in result sets.

Changed in version 1.1: The following SQLite issue has been resolved as
of version 3.10.0 of SQLite.  SQLAlchemy as of `1.1' automatically
disables its internal workarounds based on detection of this version.

The bug, entirely outside of SQLAlchemy, can be illustrated thusly:

     import sqlite3

     assert sqlite3.sqlite_version_info < (3, 10, 0), "bug is fixed in this version"

     conn = sqlite3.connect(":memory:")
     cursor = conn.cursor()

     cursor.execute("create table x (a integer, b integer)")
     cursor.execute("insert into x (a, b) values (1, 1)")
     cursor.execute("insert into x (a, b) values (2, 2)")

     cursor.execute("select x.a, x.b from x")
     assert [c[0] for c in cursor.description] == ['a', 'b']

     cursor.execute('''
         select x.a, x.b from x where a=1
         union
         select x.a, x.b from x where a=2
     ''')
     assert [c[0] for c in cursor.description] == ['a', 'b'], \
         [c[0] for c in cursor.description]

The second assertion fails:

     Traceback (most recent call last):
       File "test.py", line 19, in <module>
         [c[0] for c in cursor.description]
     AssertionError: ['x.a', 'x.b']

Where above, the driver incorrectly reports the names of the columns
including the name of the table, which is entirely inconsistent vs.
when the UNION is not present.

SQLAlchemy relies upon column names being predictable in how they match
to the original statement, so the SQLAlchemy dialect has no choice but
to filter these out:

     from sqlalchemy import create_engine

     eng = create_engine("sqlite://")
     conn = eng.connect()

     conn.exec_driver_sql("create table x (a integer, b integer)")
     conn.exec_driver_sql("insert into x (a, b) values (1, 1)")
     conn.exec_driver_sql("insert into x (a, b) values (2, 2)")

     result = conn.exec_driver_sql("select x.a, x.b from x")
     assert result.keys() == ["a", "b"]

     result = conn.exec_driver_sql('''
         select x.a, x.b from x where a=1
         union
         select x.a, x.b from x where a=2
     ''')
     assert result.keys() == ["a", "b"]

Note that above, even though SQLAlchemy filters out the dots, `both
names are still addressable':

     >>> row = result.first()
     >>> row["a"]
     1
     >>> row["x.a"]
     1
     >>> row["b"]
     1
     >>> row["x.b"]
     1

Therefore, the workaround applied by SQLAlchemy only impacts
CursorResult.keys() and Row.keys() in the public
API. In the very specific case where an application is forced to use
column names that contain dots, and the functionality of
CursorResult.keys() and Row.keys() is required to
return these dotted names unmodified, the ‘sqlite_raw_colnames’
execution option may be provided, either on a per-see Connection
basis:

     result = conn.execution_options(sqlite_raw_colnames=True).exec_driver_sql('''
         select x.a, x.b from x where a=1
         union
         select x.a, x.b from x where a=2
     ''')
     assert result.keys() == ["x.a", "x.b"]

or on a per-see Engine basis:

     engine = create_engine("sqlite://", execution_options={"sqlite_raw_colnames": True})

When using the per-see Engine execution option, note that `Core
and ORM queries that use UNION may not function properly'.

5.1.3.22 SQLite-specific table options
......................................

One option for CREATE TABLE is supported directly by the SQLite dialect
in conjunction with the Table construct:

   * ‘WITHOUT ROWID’:

          Table("some_table", metadata, ..., sqlite_with_rowid=False)

See also
........

SQLite CREATE TABLE options(1)

   ---------- Footnotes ----------

   (1) https://www.sqlite.org/lang_createtable.html

5.1.3.23 SQLite Data Types
..........................

As with all SQLAlchemy dialects, all UPPERCASE types that are known to
be valid with SQLite are importable from the top level dialect, whether
they originate from sqlalchemy.types or from the local
dialect:

     from sqlalchemy.dialects.sqlite import \
                 BLOB, BOOLEAN, CHAR, DATE, DATETIME, DECIMAL, FLOAT, \
                 INTEGER, NUMERIC, JSON, SMALLINT, TEXT, TIME, TIMESTAMP, \
                 VARCHAR

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See DATE.Represent a Python date object in SQLite using a string.

See DATETIME.Represent a Python datetime object in SQLite using a string.

See JSON.SQLite JSON type.

See TIME.Represent a Python time object in SQLite using a string.

 -- Class: sqlalchemy.dialects.sqlite.DATETIME (*args, **kwargs)

     Represent a Python datetime object in SQLite using a string.

     The default string storage format is:

          "%(year)04d-%(month)02d-%(day)02d %(hour)02d:%(minute)02d:%(second)02d.%(microsecond)06d"

     e.g.:

          2011-03-15 12:05:57.10558

     The storage format can be customized to some degree using the
     ‘storage_format’ and ‘regexp’ parameters, such as:

          import re
          from sqlalchemy.dialects.sqlite import DATETIME

          dt = DATETIME(storage_format="%(year)04d/%(month)02d/%(day)02d "
                                       "%(hour)02d:%(minute)02d:%(second)02d",
                        regexp=r"(\d+)/(\d+)/(\d+) (\d+)-(\d+)-(\d+)"
          )

     Parameters:

        * ‘storage_format’ – format string which will be applied to the
          dict with keys year, month, day, hour, minute, second, and
          microsecond.

        * ‘regexp’ – regular expression which will be applied to
          incoming result rows.  If the regexp contains named groups,
          the resulting match dict is applied to the Python datetime()
          constructor as keyword arguments.  Otherwise, if positional
          groups are used, the datetime() constructor is called with
          positional arguments via ‘*map(int, match_obj.groups(0))’.

     `Class signature'

     class sqlalchemy.dialects.sqlite.DATETIME.
     (‘sqlalchemy.dialects.sqlite.base._DateTimeMixin’, see
     sqlalchemy.types.DateTime)

 -- Class: sqlalchemy.dialects.sqlite.DATE (storage_format=None,
          regexp=None, **kw)

     Represent a Python date object in SQLite using a string.

     The default string storage format is:

          "%(year)04d-%(month)02d-%(day)02d"

     e.g.:

          2011-03-15

     The storage format can be customized to some degree using the
     ‘storage_format’ and ‘regexp’ parameters, such as:

          import re
          from sqlalchemy.dialects.sqlite import DATE

          d = DATE(
                  storage_format="%(month)02d/%(day)02d/%(year)04d",
                  regexp=re.compile("(?P<month>\d+)/(?P<day>\d+)/(?P<year>\d+)")
              )

     Parameters:

        * ‘storage_format’ – format string which will be applied to the
          dict with keys year, month, and day.

        * ‘regexp’ – regular expression which will be applied to
          incoming result rows.  If the regexp contains named groups,
          the resulting match dict is applied to the Python date()
          constructor as keyword arguments.  Otherwise, if positional
          groups are used, the date() constructor is called with
          positional arguments via ‘*map(int, match_obj.groups(0))’.

     `Class signature'

     class sqlalchemy.dialects.sqlite.DATE.
     (‘sqlalchemy.dialects.sqlite.base._DateTimeMixin’, see
     sqlalchemy.types.Date)

 -- Class: sqlalchemy.dialects.sqlite.JSON (none_as_null=False)

     SQLite JSON type.

     SQLite supports JSON as of version 3.9 through its JSON1(1)
     extension.  Note that JSON1(2) is a loadable extension(3) and as
     such may not be available, or may require run-time loading.

     JSON is used automatically whenever the base
     JSON datatype is used against a SQLite backend.

     See also
     ........

     See JSON. - main documentation for the generic
     cross-platform JSON datatype.

     The JSON type supports persistence of JSON values as
     well as the core index operations provided by JSON
     datatype, by adapting the operations to render the ‘JSON_EXTRACT’
     function wrapped in the ‘JSON_QUOTE’ function at the database
     level.  Extracted values are quoted in order to ensure that the
     results are always JSON string values.

     New in version 1.3.

     `Class signature'

     class sqlalchemy.dialects.sqlite.JSON. (see
     sqlalchemy.types.JSON)

 -- Class: sqlalchemy.dialects.sqlite.TIME (*args, **kwargs)

     Represent a Python time object in SQLite using a string.

     The default string storage format is:

          "%(hour)02d:%(minute)02d:%(second)02d.%(microsecond)06d"

     e.g.:

          12:05:57.10558

     The storage format can be customized to some degree using the
     ‘storage_format’ and ‘regexp’ parameters, such as:

          import re
          from sqlalchemy.dialects.sqlite import TIME

          t = TIME(storage_format="%(hour)02d-%(minute)02d-"
                                  "%(second)02d-%(microsecond)06d",
                   regexp=re.compile("(\d+)-(\d+)-(\d+)-(?:-(\d+))?")
          )

     Parameters:

        * ‘storage_format’ – format string which will be applied to the
          dict with keys hour, minute, second, and microsecond.

        * ‘regexp’ – regular expression which will be applied to
          incoming result rows.  If the regexp contains named groups,
          the resulting match dict is applied to the Python time()
          constructor as keyword arguments.  Otherwise, if positional
          groups are used, the time() constructor is called with
          positional arguments via ‘*map(int, match_obj.groups(0))’.

     `Class signature'

     class sqlalchemy.dialects.sqlite.TIME.
     (‘sqlalchemy.dialects.sqlite.base._DateTimeMixin’, see
     sqlalchemy.types.Time)

   ---------- Footnotes ----------

   (1) https://www.sqlite.org/json1.html

   (2) https://www.sqlite.org/json1.html

   (3) https://www.sqlite.org/loadext.html

5.1.3.24 SQLite DML Constructs
..............................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See insert.(table[,Construct an Insert object.
values,
inline,
bind, ...],
**dialect_kw)

See Insert.SQLite-specific implementation of INSERT.

 -- Function: sqlalchemy.dialects.sqlite.insert (table, values=None,
          inline=False, bind=None, prefixes=None, returning=None,
          return_defaults=False, **dialect_kw)

     Construct an Insert object.

     This documentation is inherited from
     sqlalchemy.sql.expression.insert(); this constructor, see
     sqlalchemy.dialects.sqlite.insert(), creates a
     sqlalchemy.dialects.sqlite.Insert object.  See that class
     for additional details describing this subclass.

     E.g.:

          from sqlalchemy import insert

          stmt = (
              insert(user_table).
              values(name='username', fullname='Full Username')
          )

     Similar functionality is available via the
     TableClause.insert() method on Table.

     See also
     ........

     See Insert Expressions. - in the 1.x tutorial.

     See Core Insert. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

     Parameters:

        * ‘table’ – see TableClause which is the subject of the
          insert.

        * ‘values’ – collection of values to be inserted; see
          Insert.values() for a description of allowed formats
          here.  Can be omitted entirely; a Insert construct
          will also dynamically render the VALUES clause at execution
          time based on the parameters passed to
          Connection.execute().

          Deprecated since version 1.4: The insert.values
          parameter will be removed in SQLAlchemy 2.0.  Please refer to
          the Insert.values() method.

        * ‘inline’ – if True, no attempt will be made to retrieve the
          SQL-generated default values to be provided within the
          statement; in particular, this allows SQL expressions to be
          rendered ‘inline’ within the statement without the need to
          pre-execute them beforehand; for backends that support
          “returning”, this turns off the “implicit returning” feature
          for the statement.

          Deprecated since version 1.4: The insert.inline
          parameter will be removed in SQLAlchemy 2.0.  Please use the
          Insert.inline() method.

     If both Insert.values and compile-time bind parameters
     are present, the compile-time bind parameters override the
     information specified within Insert.values on a per-key
     basis.

     The keys within Insert.values can be either
     Column objects or their string identifiers.  Each key may
     reference one of:

        * a literal data value (i.e.  string, number, etc.);

        * a Column object;

        * a SELECT statement.

     If a ‘SELECT’ statement is specified which references this ‘INSERT’
     statement’s table, the statement will be correlated against the
     ‘INSERT’ statement.

     See also
     ........

     See Insert Expressions. - SQL Expression Tutorial

     See Inserts, Updates and Deletes. - SQL Expression Tutorial

 -- Class: sqlalchemy.dialects.sqlite.Insert (table, values=None,
          inline=False, bind=None, prefixes=None, returning=None,
          return_defaults=False, **dialect_kw)

     SQLite-specific implementation of INSERT.

     Adds methods for SQLite-specific syntaxes such as ON CONFLICT.

     The Insert object is created using the
     sqlalchemy.dialects.sqlite.insert() function.

     New in version 1.4.

     See also
     ........

     See INSERT…ON CONFLICT (Upsert).

     `Class signature'

     class sqlalchemy.dialects.sqlite.Insert. (see
     sqlalchemy.sql.expression.Insert)

      -- Attribute: sqlalchemy.dialects.sqlite.Insert..
               excluded

          Provide the ‘excluded’ namespace for an ON CONFLICT statement

          SQLite’s ON CONFLICT clause allows reference to the row that
          would be inserted, known as ‘excluded’.  This attribute
          provides all columns in this row to be referenceable.

      -- Method: sqlalchemy.dialects.sqlite.Insert..
               on_conflict_do_nothing (index_elements=None,
               index_where=None)

          Specifies a DO NOTHING action for ON CONFLICT clause.

          Parameters:

             * ‘index_elements’ – A sequence consisting of string column
               names, see Column objects, or other column
               expression objects that will be used to infer a target
               index or unique constraint.

             * ‘index_where’ – Additional WHERE criterion that can be
               used to infer a conditional target index.

      -- Method: sqlalchemy.dialects.sqlite.Insert..
               on_conflict_do_update (index_elements=None,
               index_where=None, set_=None, where=None)

          Specifies a DO UPDATE SET action for ON CONFLICT clause.

          Parameters:

             * ‘index_elements’ – A sequence consisting of string column
               names, see Column objects, or other column
               expression objects that will be used to infer a target
               index or unique constraint.

             * ‘index_where’ – Additional WHERE criterion that can be
               used to infer a conditional target index.

             * ‘set_’ – A dictionary or other mapping object where the
               keys are either names of columns in the target table, or
               Column objects or other ORM-mapped columns
               matching that of the target table, and expressions or
               literals as values, specifying the ‘SET’ actions to take.

               New in version 1.4: The
               Insert.on_conflict_do_update.set_ parameter
               supports Column objects from the target
               Table as keys.

                    Warning: This dictionary does `not' take into
                    account Python-specified default UPDATE values or
                    generation functions, e.g.  those specified using
                    Column.onupdate.  These values will not
                    be exercised for an ON CONFLICT style of UPDATE,
                    unless they are manually specified in the
                    Insert.on_conflict_do_update.set_ dictionary.

             * ‘where’ – Optional argument.  If present, can be a
               literal SQL string or an acceptable expression for a
               ‘WHERE’ clause that restricts the rows affected by ‘DO
               UPDATE SET’.  Rows not meeting the ‘WHERE’ condition will
               not be updated (effectively a ‘DO NOTHING’ for those
               rows).

5.1.3.25 Pysqlite
.................

Support for the SQLite database via the pysqlite driver.  Note that
‘pysqlite’ is the same driver as the ‘sqlite3’ module included with the
Python distribution.

5.1.3.26 DBAPI
..............

Documentation and download information (if applicable) for pysqlite is
available at: ‘http://docs.python.org/library/sqlite3.html’

5.1.3.27 Connecting
...................

Connect String:
     sqlite+pysqlite:///file_path

5.1.3.28 Driver
...............

The ‘sqlite3’ Python DBAPI is standard on all modern Python versions;
for cPython and Pypy, no additional installation is necessary.

5.1.3.29 Connect Strings
........................

The file specification for the SQLite database is taken as the
“database” portion of the URL. Note that the format of a SQLAlchemy url
is:

     driver://user:pass@host/database

This means that the actual filename to be used starts with the
characters to the `right' of the third slash.  So connecting to a
relative filepath looks like:

     # relative path
     e = create_engine('sqlite:///path/to/database.db')

An absolute path, which is denoted by starting with a slash, means you
need `four' slashes:

     # absolute path
     e = create_engine('sqlite:////path/to/database.db')

To use a Windows path, regular drive specifications and backslashes can
be used.  Double backslashes are probably needed:

     # absolute path on Windows
     e = create_engine('sqlite:///C:\\path\\to\\database.db')

The sqlite ‘:memory:’ identifier is the default if no filepath is
present.  Specify ‘sqlite://’ and nothing else:

     # in-memory database
     e = create_engine('sqlite://')

5.1.3.30 URI Connections
........................

Modern versions of SQLite support an alternative system of connecting
using a driver level URI(1), which has the advantage that additional
driver-level arguments can be passed including options such as “read
only”.  The Python sqlite3 driver supports this mode under modern Python
3 versions.  The SQLAlchemy pysqlite driver supports this mode of use by
specifying “uri=true” in the URL query string.  The SQLite-level “URI”
is kept as the “database” portion of the SQLAlchemy url (that is,
following a slash):

     e = create_engine("sqlite:///file:path/to/database?mode=ro&uri=true")

     Note: The “uri=true” parameter must appear in the `query string' of
     the URL. It will not currently work as expected if it is only
     present in the create_engine.connect_args parameter
     dictionary.

The logic reconciles the simultaneous presence of SQLAlchemy’s query
string and SQLite’s query string by separating out the parameters that
belong to the Python sqlite3 driver vs.  those that belong to the SQLite
URI. This is achieved through the use of a fixed list of parameters
known to be accepted by the Python side of the driver.  For example, to
include a URL that indicates the Python sqlite3 “timeout” and
“check_same_thread” parameters, along with the SQLite “mode” and
“nolock” parameters, they can all be passed together on the query
string:

     e = create_engine(
         "sqlite:///file:path/to/database?"
         "check_same_thread=true&timeout=10&mode=ro&nolock=1&uri=true"
     )

Above, the pysqlite / sqlite3 DBAPI would be passed arguments as:

     sqlite3.connect(
         "file:path/to/database?mode=ro&nolock=1",
         check_same_thread=True, timeout=10, uri=True
     )

Regarding future parameters added to either the Python or native
drivers.  new parameter names added to the SQLite URI scheme should be
automatically accommodated by this scheme.  New parameter names added to
the Python driver side can be accommodated by specifying them in the
create_engine.connect_args dictionary, until dialect
support is added by SQLAlchemy.  For the less likely case that the
native SQLite driver adds a new parameter name that overlaps with one of
the existing, known Python driver parameters (such as “timeout”
perhaps), SQLAlchemy’s dialect would require adjustment for the URL
scheme to continue to support this.

As is always the case for all SQLAlchemy dialects, the entire “URL”
process can be bypassed in create_engine() through the use of
the create_engine.creator parameter which allows for a
custom callable that creates a Python sqlite3 driver level connection
directly.

New in version 1.3.9.

See also
........

Uniform Resource Identifiers(2) - in the SQLite documentation

   ---------- Footnotes ----------

   (1) https://www.sqlite.org/uri.html

   (2) https://www.sqlite.org/uri.html

5.1.3.31 Regular Expression Support
...................................

New in version 1.4.

Support for the ColumnOperators.regexp_match() operator is
provided using Python’s re.search(1) function.  SQLite itself does not
include a working regular expression operator; instead, it includes a
non-implemented placeholder operator ‘REGEXP’ that calls a user-defined
function that must be provided.

SQLAlchemy’s implementation makes use of the pysqlite create_function(2)
hook as follows:

     def regexp(a, b):
         return re.search(a, b) is not None

     sqlite_connection.create_function(
         "regexp", 2, regexp,
     )

There is currently no support for regular expression flags as a separate
argument, as these are not supported by SQLite’s REGEXP operator,
however these may be included inline within the regular expression
string.  See Python regular expressions(3) for details.

See also
........

Python regular expressions(4): Documentation for Python’s regular
expression syntax.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/re.html#re.search

   (2)
https://docs.python.org/3/library/sqlite3.html#sqlite3.Connection.create_function

   (3) https://docs.python.org/3/library/re.html#re.search

   (4) https://docs.python.org/3/library/re.html#re.search

5.1.3.32 Compatibility with sqlite3 “native” date and datetime types
....................................................................

The pysqlite driver includes the sqlite3.PARSE_DECLTYPES and
sqlite3.PARSE_COLNAMES options, which have the effect of any column or
expression explicitly cast as “date” or “timestamp” will be converted to
a Python date or datetime object.  The date and datetime types provided
with the pysqlite dialect are not currently compatible with these
options, since they render the ISO date/datetime including microseconds,
which pysqlite’s driver does not.  Additionally, SQLAlchemy does not at
this time automatically render the “cast” syntax required for the
freestanding functions “current_timestamp” and “current_date” to return
datetime/date types natively.  Unfortunately, pysqlite does not provide
the standard DBAPI types in ‘cursor.description’, leaving SQLAlchemy
with no way to detect these types on the fly without expensive per-row
type checks.

Keeping in mind that pysqlite’s parsing option is not recommended, nor
should be necessary, for use with SQLAlchemy, usage of PARSE_DECLTYPES
can be forced if one configures “native_datetime=True” on
create_engine():

     engine = create_engine('sqlite://',
         connect_args={'detect_types':
             sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES},
         native_datetime=True
     )

With this flag enabled, the DATE and TIMESTAMP types (but note - not the
DATETIME or TIME types…confused yet ?)  will not perform any bind
parameter or result processing.  Execution of “func.current_date()” will
return a string.  “func.current_timestamp()” is registered as returning
a DATETIME type in SQLAlchemy, so this function still receives
SQLAlchemy-level result processing.

5.1.3.33 Threading/Pooling Behavior
...................................

Pysqlite’s default behavior is to prohibit the usage of a single
connection in more than one thread.  This is originally intended to work
with older versions of SQLite that did not support multithreaded
operation under various circumstances.  In particular, older SQLite
versions did not allow a ‘:memory:’ database to be used in multiple
threads under any circumstances.

Pysqlite does include a now-undocumented flag known as
‘check_same_thread’ which will disable this check, however note that
pysqlite connections are still not safe to use in concurrently in
multiple threads.  In particular, any statement execution calls would
need to be externally mutexed, as Pysqlite does not provide for
thread-safe propagation of error messages among other things.  So while
even ‘:memory:’ databases can be shared among threads in modern SQLite,
Pysqlite doesn’t provide enough thread-safety to make this usage worth
it.

SQLAlchemy sets up pooling to work with Pysqlite’s default behavior:

   * When a ‘:memory:’ SQLite database is specified, the dialect by
     default will use SingletonThreadPool.  This pool
     maintains a single connection per thread, so that all access to the
     engine within the current thread use the same ‘:memory:’ database -
     other threads would access a different ‘:memory:’ database.

   * When a file-based database is specified, the dialect will use
     NullPool as the source of connections.  This pool closes and
     discards connections which are returned to the pool immediately.
     SQLite file-based connections have extremely low overhead, so
     pooling is not necessary.  The scheme also prevents a connection
     from being used again in a different thread and works best with
     SQLite’s coarse-grained file locking.

5.1.3.34 Using a Memory Database in Multiple Threads
....................................................

To use a ‘:memory:’ database in a multithreaded scenario, the same
connection object must be shared among threads, since the database
exists only within the scope of that connection.  The StaticPool
implementation will maintain a single connection globally, and the
‘check_same_thread’ flag can be passed to Pysqlite as ‘False’:

     from sqlalchemy.pool import StaticPool
     engine = create_engine('sqlite://',
                         connect_args={'check_same_thread':False},
                         poolclass=StaticPool)

Note that using a ‘:memory:’ database in multiple threads requires a
recent version of SQLite.

5.1.3.35 Using Temporary Tables with SQLite
...........................................

Due to the way SQLite deals with temporary tables, if you wish to use a
temporary table in a file-based SQLite database across multiple
checkouts from the connection pool, such as when using an ORM
Session where the temporary table should continue to remain after
Session.commit() or Session.rollback() is called,
a pool which maintains a single connection must be used.  Use
SingletonThreadPool if the scope is only needed within the
current thread, or StaticPool is scope is needed within
multiple threads for this case:

     # maintain the same connection per thread
     from sqlalchemy.pool import SingletonThreadPool
     engine = create_engine('sqlite:///mydb.db',
                         poolclass=SingletonThreadPool)

     # maintain the same connection across all threads
     from sqlalchemy.pool import StaticPool
     engine = create_engine('sqlite:///mydb.db',
                         poolclass=StaticPool)

Note that SingletonThreadPool should be configured for the
number of threads that are to be used; beyond that number, connections
will be closed out in a non deterministic way.

5.1.3.36 Unicode
................

The pysqlite driver only returns Python ‘unicode’ objects in result
sets, never plain strings, and accommodates ‘unicode’ objects within
bound parameter values in all cases.  Regardless of the SQLAlchemy
string type in use, string-based result values will by Python ‘unicode’
in Python 2.  The Unicode type should still be used to
indicate those columns that require unicode, however, so that
non-‘unicode’ values passed inadvertently will emit a warning.  Pysqlite
will emit an error if a non-‘unicode’ string is passed containing
non-ASCII characters.

5.1.3.37 Dealing with Mixed String / Binary Columns in Python 3
...............................................................

The SQLite database is weakly typed, and as such it is possible when
using binary values, which in Python 3 are represented as ‘b'some
string'’, that a particular SQLite database can have data values within
different rows where some of them will be returned as a ‘b''’ value by
the Pysqlite driver, and others will be returned as Python strings, e.g.
‘''’  values.  This situation is not known to occur if the SQLAlchemy
LargeBinary datatype is used consistently, however if a
particular SQLite database has data that was inserted using the Pysqlite
driver directly, or when using the SQLAlchemy String type
which was later changed to LargeBinary, the table will not
be consistently readable because SQLAlchemy’s LargeBinary
datatype does not handle strings so it has no way of “encoding” a value
that is in string format.

To deal with a SQLite table that has mixed string / binary data in the
same column, use a custom type that will check each row individually:

     # note this is Python 3 only

     from sqlalchemy import String
     from sqlalchemy import TypeDecorator

     class MixedBinary(TypeDecorator):
         impl = String

         def process_result_value(self, value, dialect):
             if isinstance(value, str):
                 value = bytes(value, 'utf-8')
             elif value is not None:
                 value = bytes(value)

             return value

Then use the above ‘MixedBinary’ datatype in the place where
LargeBinary would normally be used.

5.1.3.38 Serializable isolation / Savepoints / Transactional DDL
................................................................

In the section Database Locking Behavior / Concurrency, we
refer to the pysqlite driver’s assortment of issues that prevent several
features of SQLite from working correctly.  The pysqlite DBAPI driver
has several long-standing bugs which impact the correctness of its
transactional behavior.  In its default mode of operation, SQLite
features such as SERIALIZABLE isolation, transactional DDL, and
SAVEPOINT support are non-functional, and in order to use these
features, workarounds must be taken.

The issue is essentially that the driver attempts to second-guess the
user’s intent, failing to start transactions and sometimes ending them
prematurely, in an effort to minimize the SQLite databases’s file
locking behavior, even though SQLite itself uses “shared” locks for
read-only activities.

SQLAlchemy chooses to not alter this behavior by default, as it is the
long-expected behavior of the pysqlite driver; if and when the pysqlite
driver attempts to repair these issues, that will be more of a driver
towards defaults for SQLAlchemy.

The good news is that with a few events, we can implement transactional
support fully, by disabling pysqlite’s feature entirely and emitting
BEGIN ourselves.  This is achieved using two event listeners:

     from sqlalchemy import create_engine, event

     engine = create_engine("sqlite:///myfile.db")

     @event.listens_for(engine, "connect")
     def do_connect(dbapi_connection, connection_record):
         # disable pysqlite's emitting of the BEGIN statement entirely.
         # also stops it from emitting COMMIT before any DDL.
         dbapi_connection.isolation_level = None

     @event.listens_for(engine, "begin")
     def do_begin(conn):
         # emit our own BEGIN
         conn.exec_driver_sql("BEGIN")

     Warning: When using the above recipe, it is advised to not use the
     Connection.execution_options.isolation_level setting
     on Connection and create_engine() with the
     SQLite driver, as this function necessarily will also alter the
     “.isolation_level” setting.

Above, we intercept a new pysqlite connection and disable any
transactional integration.  Then, at the point at which SQLAlchemy knows
that transaction scope is to begin, we emit ‘"BEGIN"’ ourselves.

When we take control of ‘"BEGIN"’, we can also control directly SQLite’s
locking modes, introduced at BEGIN TRANSACTION(1), by adding the desired
locking mode to our ‘"BEGIN"’:

     @event.listens_for(engine, "begin")
     def do_begin(conn):
         conn.exec_driver_sql("BEGIN EXCLUSIVE")

See also
........

BEGIN TRANSACTION(2) - on the SQLite site

sqlite3 SELECT does not BEGIN a transaction(3) - on the Python bug
tracker

sqlite3 module breaks transactions and potentially corrupts data(4) - on
the Python bug tracker

   ---------- Footnotes ----------

   (1) http://sqlite.org/lang_transaction.html

   (2) http://sqlite.org/lang_transaction.html

   (3) http://bugs.python.org/issue9924

   (4) http://bugs.python.org/issue10740

5.1.3.39 Pysqlcipher
....................

Support for the SQLite database via the pysqlcipher driver.
‘pysqlcipher’ is a fork of the standard ‘pysqlite’ driver to make use of
the SQLCipher(1) backend.

‘pysqlcipher3’ is a fork of ‘pysqlcipher’ for Python 3.  This dialect
will attempt to import it if ‘pysqlcipher’ is non-present.

New in version 1.1.4: - added fallback import for pysqlcipher3

New in version 0.9.9: - added pysqlcipher dialect

   ---------- Footnotes ----------

   (1) https://www.zetetic.net/sqlcipher

5.1.3.40 DBAPI
..............

Documentation and download information (if applicable) for pysqlcipher
is available at: ‘https://pypi.python.org/pypi/pysqlcipher’

5.1.3.41 Connecting
...................

Connect String:
     sqlite+pysqlcipher://:passphrase/file_path[?kdf_iter=<iter>]

5.1.3.42 Driver
...............

The driver here is the pysqlcipher(1) driver, which makes use of the
SQLCipher engine.  This system essentially introduces new PRAGMA
commands to SQLite which allows the setting of a passphrase and other
encryption parameters, allowing the database file to be encrypted.

‘pysqlcipher3’ is a fork of ‘pysqlcipher’ with support for Python 3, the
driver is the same.

   ---------- Footnotes ----------

   (1) https://pypi.python.org/pypi/pysqlcipher

5.1.3.43 Connect Strings
........................

The format of the connect string is in every way the same as that of the
pysqlite driver, except that the “password” field is now
accepted, which should contain a passphrase:

     e = create_engine('sqlite+pysqlcipher://:testing@/foo.db')

For an absolute file path, two leading slashes should be used for the
database name:

     e = create_engine('sqlite+pysqlcipher://:testing@//path/to/foo.db')

A selection of additional encryption-related pragmas supported by
SQLCipher as documented at
‘https://www.zetetic.net/sqlcipher/sqlcipher-api/’ can be passed in the
query string, and will result in that PRAGMA being called for each new
connection.  Currently, ‘cipher’, ‘kdf_iter’ ‘cipher_page_size’ and
‘cipher_use_hmac’ are supported:

     e = create_engine('sqlite+pysqlcipher://:testing@/foo.db?cipher=aes-256-cfb&kdf_iter=64000')

5.1.3.44 Pooling Behavior
.........................

The driver makes a change to the default pool behavior of pysqlite as
described in Threading/Pooling Behavior.  The pysqlcipher
driver has been observed to be significantly slower on connection than
the pysqlite driver, most likely due to the encryption overhead, so the
dialect here defaults to using the SingletonThreadPool
implementation, instead of the NullPool pool used by
pysqlite.  As always, the pool implementation is entirely configurable
using the create_engine.poolclass parameter; the ‘
StaticPool’ may be more feasible for single-threaded use, or
NullPool may be used to prevent unencrypted connections from being
held open for long periods of time, at the expense of slower startup
time for new connections.

5.1.4 Oracle
------------

Support for the Oracle database.

The following table summarizes current support levels for database
release versions.

`Supported Oracle versions'

Support type                                           Versions

--------------------------------------------------------------------------------------------------------------

See Fully tested in CI.                        11.2, 18c

See Normal support.                            11+

See Best effort.                               8+

5.1.4.1 DBAPI Support
.....................

The following dialect/DBAPI options are available.  Please refer to
individual DBAPI sections for connect information.

   * cx-Oracle.

5.1.4.2 Auto Increment Behavior
...............................

SQLAlchemy Table objects which include integer primary keys are usually
assumed to have “autoincrementing” behavior, meaning they can generate
their own primary key values upon INSERT. For use within Oracle, two
options are available, which are the use of IDENTITY columns (Oracle 12
and above only) or the association of a SEQUENCE with the column.

5.1.4.3 Specifying GENERATED AS IDENTITY (Oracle 12 and above)
..............................................................

Starting from version 12 Oracle can make use of identity columns using
the ‘Identity’ to specify the autoincrementing behavior:

     t = Table('mytable', metadata,
         Column('id', Integer, Identity(start=3), primary_key=True),
         Column(...), ...
     )

The CREATE TABLE for the above Table object would be:

     CREATE TABLE mytable (
         id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 3),
         ...,
         PRIMARY KEY (id)
     )

The Identity object support many options to control the
“autoincrementing” behavior of the column, like the starting value, the
incrementing value, etc.  In addition to the standard options, Oracle
supports setting Identity.always to ‘None’ to use the
default generated mode, rendering GENERATED AS IDENTITY in the DDL. It
also supports setting Identity.on_null to ‘True’ to specify
ON NULL in conjunction with a ‘BY DEFAULT’ identity column.

5.1.4.4 Using a SEQUENCE (all Oracle versions)
..............................................

Older version of Oracle had no “autoincrement” feature, SQLAlchemy
relies upon sequences to produce these values.  With the older Oracle
versions, `a sequence must always be explicitly specified to enable
autoincrement'.  This is divergent with the majority of documentation
examples which assume the usage of an autoincrement-capable database.
To specify sequences, use the sqlalchemy.schema.Sequence object which is
passed to a Column construct:

     t = Table('mytable', metadata,
           Column('id', Integer, Sequence('id_seq'), primary_key=True),
           Column(...), ...
     )

This step is also required when using table reflection, i.e.
autoload_with=engine:

     t = Table('mytable', metadata,
           Column('id', Integer, Sequence('id_seq'), primary_key=True),
           autoload_with=engine
     )

Changed in version 1.4: Added Identity construct in a
Column to specify the option of an autoincrementing column.

5.1.4.5 Transaction Isolation Level / Autocommit
................................................

The Oracle database supports “READ COMMITTED” and “SERIALIZABLE” modes
of isolation.  The AUTOCOMMIT isolation level is also supported by the
cx_Oracle dialect.

To set using per-connection execution options:

     connection = engine.connect()
     connection = connection.execution_options(
         isolation_level="AUTOCOMMIT"
     )

For ‘READ COMMITTED’ and ‘SERIALIZABLE’, the Oracle dialect sets the
level at the session level using ‘ALTER SESSION’, which is reverted back
to its default setting when the connection is returned to the connection
pool.

Valid values for ‘isolation_level’ include:

   * ‘READ COMMITTED’

   * ‘AUTOCOMMIT’

   * ‘SERIALIZABLE’

     Note: The implementation for the
     Connection.get_isolation_level() method as implemented by
     the Oracle dialect necessarily forces the start of a transaction
     using the Oracle LOCAL_TRANSACTION_ID function; otherwise no level
     is normally readable.

     Additionally, the Connection.get_isolation_level()
     method will raise an exception if the ‘v$transaction’ view is not
     available due to permissions or other reasons, which is a common
     occurrence in Oracle installations.

     The cx_Oracle dialect attempts to call the
     Connection.get_isolation_level() method when the dialect
     makes its first connection to the database in order to acquire the
     “default”isolation level.  This default level is necessary so that
     the level can be reset on a connection after it has been
     temporarily modified using Connection.execution_options()
     method.  In the common event that the
     Connection.get_isolation_level() method raises an exception
     due to ‘v$transaction’ not being readable as well as any other
     database-related failure, the level is assumed to be “READ
     COMMITTED”.  No warning is emitted for this initial first-connect
     condition as it is expected to be a common restriction on Oracle
     databases.

New in version 1.3.16: added support for AUTOCOMMIT to the cx_oracle
dialect as well as the notion of a default isolation level

New in version 1.3.21: Added support for SERIALIZABLE as well as live
reading of the isolation level.

Changed in version 1.3.22: In the event that the default isolation level
cannot be read due to permissions on the v$transaction view as is common
in Oracle installations, the default isolation level is hardcoded to
“READ COMMITTED” which was the behavior prior to 1.3.21.

See also
........

See Setting Transaction Isolation Levels including DBAPI Autocommit.

5.1.4.6 Identifier Casing
.........................

In Oracle, the data dictionary represents all case insensitive
identifier names using UPPERCASE text.  SQLAlchemy on the other hand
considers an all-lower case identifier name to be case insensitive.  The
Oracle dialect converts all case insensitive identifiers to and from
those two formats during schema level communication, such as reflection
of tables and indexes.  Using an UPPERCASE name on the SQLAlchemy side
indicates a case sensitive identifier, and SQLAlchemy will quote the
name - this will cause mismatches against data dictionary data received
from Oracle, so unless identifier names have been truly created as case
sensitive (i.e.  using quoted names), all lowercase names should be used
on the SQLAlchemy side.

5.1.4.7 Max Identifier Lengths
..............................

Oracle has changed the default max identifier length as of Oracle Server
version 12.2.  Prior to this version, the length was 30, and for 12.2
and greater it is now 128.  This change impacts SQLAlchemy in the area
of generated SQL label names as well as the generation of constraint
names, particularly in the case where the constraint naming convention
feature described at Configuring Constraint Naming Conventions
is being used.

To assist with this change and others, Oracle includes the concept of a
“compatibility” version, which is a version number that is independent
of the actual server version in order to assist with migration of Oracle
databases, and may be configured within the Oracle server itself.  This
compatibility version is retrieved using the query ‘SELECT value FROM
v$parameter WHERE name = 'compatible';’.  The SQLAlchemy Oracle dialect,
when tasked with determining the default max identifier length, will
attempt to use this query upon first connect in order to determine the
effective compatibility version of the server, which determines what the
maximum allowed identifier length is for the server.  If the table is
not available, the server version information is used instead.

As of SQLAlchemy 1.4, the default max identifier length for the Oracle
dialect is 128 characters.  Upon first connect, the compatibility
version is detected and if it is less than Oracle version 12.2, the max
identifier length is changed to be 30 characters.  In all cases, setting
the create_engine.max_identifier_length parameter will
bypass this change and the value given will be used as is:

     engine = create_engine(
         "oracle+cx_oracle://scott:tiger@oracle122",
         max_identifier_length=30)

The maximum identifier length comes into play both when generating
anonymized SQL labels in SELECT statements, but more crucially when
generating constraint names from a naming convention.  It is this area
that has created the need for SQLAlchemy to change this default
conservatively.  For example, the following naming convention produces
two very different constraint names based on the identifier length:

     from sqlalchemy import Column
     from sqlalchemy import Index
     from sqlalchemy import Integer
     from sqlalchemy import MetaData
     from sqlalchemy import Table
     from sqlalchemy.dialects import oracle
     from sqlalchemy.schema import CreateIndex

     m = MetaData(naming_convention={"ix": "ix_%(column_0N_name)s"})

     t = Table(
         "t",
         m,
         Column("some_column_name_1", Integer),
         Column("some_column_name_2", Integer),
         Column("some_column_name_3", Integer),
     )

     ix = Index(
         None,
         t.c.some_column_name_1,
         t.c.some_column_name_2,
         t.c.some_column_name_3,
     )

     oracle_dialect = oracle.dialect(max_identifier_length=30)
     print(CreateIndex(ix).compile(dialect=oracle_dialect))

With an identifier length of 30, the above CREATE INDEX looks like:

     CREATE INDEX ix_some_column_name_1s_70cd ON t
     (some_column_name_1, some_column_name_2, some_column_name_3)

However with length=128, it becomes:

     CREATE INDEX ix_some_column_name_1some_column_name_2some_column_name_3 ON t
     (some_column_name_1, some_column_name_2, some_column_name_3)

Applications which have run versions of SQLAlchemy prior to 1.4 on an
Oracle server version 12.2 or greater are therefore subject to the
scenario of a database migration that wishes to “DROP CONSTRAINT” on a
name that was previously generated with the shorter length.  This
migration will fail when the identifier length is changed without the
name of the index or constraint first being adjusted.  Such applications
are strongly advised to make use of
create_engine.max_identifier_length in order to maintain control
of the generation of truncated names, and to fully review and test all
database migrations in a staging environment when changing this value to
ensure that the impact of this change has been mitigated.

Changed in version 1.4: the default max_identifier_length for Oracle is
128 characters, which is adjusted down to 30 upon first connect if an
older version of Oracle server (compatibility version < 12.2) is
detected.

5.1.4.8 LIMIT/OFFSET Support
............................

Oracle has no direct support for LIMIT and OFFSET until version 12c.  To
achieve this behavior across all widely used versions of Oracle starting
with the 8 series, SQLAlchemy currently makes use of ROWNUM to achieve
LIMIT/OFFSET; the exact methodology is taken from
‘https://blogs.oracle.com/oraclemagazine/on-rownum-and-limiting-results’
.

There is currently a single option to affect its behavior:

   * the “FIRST_ROWS()” optimization keyword is not used by default.  To
     enable the usage of this optimization directive, specify
     ‘optimize_limits=True’ to create_engine().

Changed in version 1.4: The Oracle dialect renders limit/offset integer
values using a “post compile” scheme which renders the integer directly
before passing the statement to the cursor for execution.  The
‘use_binds_for_limits’ flag no longer has an effect.

See also
........

See New “post compile” bound parameters used for LIMIT/OFFSET in Oracle, SQL Server.

Support for changing the row number strategy, which would include one
that makes use of the ‘row_number()’ window function as well as one that
makes use of the Oracle 12c “FETCH FIRST N ROW / OFFSET N ROWS” keywords
may be added in a future release.

5.1.4.9 RETURNING Support
.........................

The Oracle database supports a limited form of RETURNING, in order to
retrieve result sets of matched rows from INSERT, UPDATE and DELETE
statements.  Oracle’s RETURNING..INTO syntax only supports one row being
returned, as it relies upon OUT parameters in order to function.  In
addition, supported DBAPIs have further limitations (see RETURNING Support).

SQLAlchemy’s “implicit returning” feature, which employs RETURNING
within an INSERT and sometimes an UPDATE statement in order to fetch
newly generated primary key values and other SQL defaults and
expressions, is normally enabled on the Oracle backend.  By default,
“implicit returning” typically only fetches the value of a single
‘nextval(some_seq)’ expression embedded into an INSERT in order to
increment a sequence within an INSERT statement and get the value back
at the same time.  To disable this feature across the board, specify
‘implicit_returning=False’ to create_engine():

     engine = create_engine("oracle://scott:tiger@dsn",
                            implicit_returning=False)

Implicit returning can also be disabled on a table-by-table basis as a
table option:

     # Core Table
     my_table = Table("my_table", metadata, ..., implicit_returning=False)

     # declarative
     class MyClass(Base):
         __tablename__ = 'my_table'
         __table_args__ = {"implicit_returning": False}

See also
........

See RETURNING Support. - additional cx_oracle-specific
restrictions on implicit returning.

5.1.4.10 ON UPDATE CASCADE
..........................

Oracle doesn’t have native ON UPDATE CASCADE functionality.  A trigger
based solution is available at
‘http://asktom.oracle.com/tkyte/update_cascade/index.html’ .

When using the SQLAlchemy ORM, the ORM has limited ability to manually
issue cascading updates - specify ForeignKey objects using the
“deferrable=True, initially=’deferred’” keyword arguments, and specify
“passive_updates=False” on each relationship().

5.1.4.11 Oracle 8 Compatibility
...............................

When Oracle 8 is detected, the dialect internally configures itself to
the following behaviors:

   * the use_ansi flag is set to False.  This has the effect of
     converting all JOIN phrases into the WHERE clause, and in the case
     of LEFT OUTER JOIN makes use of Oracle’s (+) operator.

   * the NVARCHAR2 and NCLOB datatypes are no longer generated as DDL
     when the Unicode is used - VARCHAR2 and CLOB are issued
     instead.  This because these types don’t seem to work correctly on
     Oracle 8 even though they are available.  The NVARCHAR
     and NCLOB types will always generate NVARCHAR2 and
     NCLOB.

   * the “native unicode” mode is disabled when using cx_oracle, i.e.
     SQLAlchemy encodes all Python unicode objects to “string” before
     passing in as bind parameters.

5.1.4.12 Synonym/DBLINK Reflection
..................................

When using reflection with Table objects, the dialect can optionally
search for tables indicated by synonyms, either in local or remote
schemas or accessed over DBLINK, by passing the flag
‘oracle_resolve_synonyms=True’ as a keyword argument to the Table
construct:

     some_table = Table('some_table', autoload_with=some_engine,
                                 oracle_resolve_synonyms=True)

When this flag is set, the given name (such as ‘some_table’ above) will
be searched not just in the ‘ALL_TABLES’ view, but also within the
‘ALL_SYNONYMS’ view to see if this name is actually a synonym to another
name.  If the synonym is located and refers to a DBLINK, the oracle
dialect knows how to locate the table’s information using DBLINK
syntax(e.g.  ‘@dblink’).

‘oracle_resolve_synonyms’ is accepted wherever reflection arguments are
accepted, including methods such as MetaData.reflect() and
Inspector.get_columns().

If synonyms are not in use, this flag should be left disabled.

5.1.4.13 Constraint Reflection
..............................

The Oracle dialect can return information about foreign key, unique, and
CHECK constraints, as well as indexes on tables.

Raw information regarding these constraints can be acquired using
Inspector.get_foreign_keys(),
Inspector.get_unique_constraints(),
Inspector.get_check_constraints(), and
Inspector.get_indexes().

Changed in version 1.2: The Oracle dialect can now reflect UNIQUE and
CHECK constraints.

When using reflection at the Table level, the Table
will also include these constraints.

Note the following caveats:

   * When using the Inspector.get_check_constraints().
     method, Oracle builds a special “IS NOT NULL” constraint for
     columns that specify “NOT NULL”.  This constraint is `not' returned
     by default; to include the “IS NOT NULL” constraints, pass the flag
     ‘include_all=True’:

          from sqlalchemy import create_engine, inspect

          engine = create_engine("oracle+cx_oracle://s:t@dsn")
          inspector = inspect(engine)
          all_check_constraints = inspector.get_check_constraints(
              "some_table", include_all=True)

   * in most cases, when reflecting a Table, a UNIQUE
     constraint will `not' be available as a UniqueConstraint
     object, as Oracle mirrors unique constraints with a UNIQUE
     index in most cases (the exception seems to be when two or more
     unique constraints represent the same columns); the Table
     will instead represent these using Index with the
     ‘unique=True’ flag set.

   * Oracle creates an implicit index for the primary key of a table;
     this index is `excluded' from all index results.

   * the list of columns reflected for an index will not include column
     names that start with SYS_NC.

5.1.4.14 Table names with SYSTEM/SYSAUX tablespaces
...................................................

The Inspector.get_table_names() and
Inspector.get_temp_table_names() methods each return a list of
table names for the current engine.  These methods are also part of the
reflection which occurs within an operation such as
MetaData.reflect().  By default, these operations exclude the
‘SYSTEM’ and ‘SYSAUX’ tablespaces from the operation.  In order to
change this, the default list of tablespaces excluded can be changed at
the engine level using the ‘exclude_tablespaces’ parameter:

     # exclude SYSAUX and SOME_TABLESPACE, but not SYSTEM
     e = create_engine(
       "oracle://scott:tiger@xe",
       exclude_tablespaces=["SYSAUX", "SOME_TABLESPACE"])

New in version 1.1.

5.1.4.15 DateTime Compatibility
...............................

Oracle has no datatype known as ‘DATETIME’, it instead has only ‘DATE’,
which can actually store a date and time value.  For this reason, the
Oracle dialect provides a type DATE which is a subclass of
DateTime.  This type has no special behavior, and is only
present as a “marker” for this type; additionally, when a database
column is reflected and the type is reported as ‘DATE’, the
time-supporting DATE type is used.

Changed in version 0.9.4: Added DATE to subclass
DateTime.  This is a change as previous versions would reflect a
‘DATE’ column as DATE, which subclasses Date.
The only significance here is for schemes that are examining the type of
column for use in special Python translations or for migrating schemas
to other database backends.

5.1.4.16 Oracle Table Options
.............................

The CREATE TABLE phrase supports the following options with Oracle in
conjunction with the Table construct:

   * ‘ON COMMIT’:

          Table(
              "some_table", metadata, ...,
              prefixes=['GLOBAL TEMPORARY'], oracle_on_commit='PRESERVE ROWS')

New in version 1.0.0.

   * ‘COMPRESS’:

           Table('mytable', metadata, Column('data', String(32)),
               oracle_compress=True)

           Table('mytable', metadata, Column('data', String(32)),
               oracle_compress=6)

          The ``oracle_compress`` parameter accepts either an integer compression
          level, or ``True`` to use the default compression level.

New in version 1.0.0.

5.1.4.17 Oracle Specific Index Options
......................................

5.1.4.18 Bitmap Indexes
.......................

You can specify the ‘oracle_bitmap’ parameter to create a bitmap index
instead of a B-tree index:

     Index('my_index', my_table.c.data, oracle_bitmap=True)

Bitmap indexes cannot be unique and cannot be compressed.  SQLAlchemy
will not check for such limitations, only the database will.

New in version 1.0.0.

5.1.4.19 Index compression
..........................

Oracle has a more efficient storage mode for indexes containing lots of
repeated values.  Use the ‘oracle_compress’ parameter to turn on key
compression:

     Index('my_index', my_table.c.data, oracle_compress=True)

     Index('my_index', my_table.c.data1, my_table.c.data2, unique=True,
            oracle_compress=1)

The ‘oracle_compress’ parameter accepts either an integer specifying the
number of prefix columns to compress, or ‘True’ to use the default (all
columns for non-unique indexes, all but the last column for unique
indexes).

New in version 1.0.0.

5.1.4.20 Oracle Data Types
..........................

As with all SQLAlchemy dialects, all UPPERCASE types that are known to
be valid with Oracle are importable from the top level dialect, whether
they originate from sqlalchemy.types or from the local
dialect:

     from sqlalchemy.dialects.oracle import \
                 BFILE, BLOB, CHAR, CLOB, DATE, \
                 DOUBLE_PRECISION, FLOAT, INTERVAL, LONG, NCLOB, NCHAR, \
                 NUMBER, NVARCHAR, NVARCHAR2, RAW, TIMESTAMP, VARCHAR, \
                 VARCHAR2

New in version 1.2.19: Added NCHAR to the list of datatypes
exported by the Oracle dialect.

Types which are specific to Oracle, or have Oracle-specific construction
arguments, are as follows:

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See BFILE.

See DATE.Provide the oracle DATE type.

See DOUBLE_PRECISION.

See INTERVAL.

See LONG.

See NCLOB.

See NUMBER.

See RAW.

 -- Class: sqlalchemy.dialects.oracle.BFILE (length=None)

     `Class signature'

     class sqlalchemy.dialects.oracle.BFILE. (see
     sqlalchemy.types.LargeBinary)

      -- Method: sqlalchemy.dialects.oracle.BFILE..__init__
               (length=None)

          `inherited from the' ‘sqlalchemy.types.LargeBinary.__init__’
          `method of' LargeBinary.

          Construct a LargeBinary type.

          Parameters: ‘length’ – optional, a length for the column for
          use in DDL statements, for those binary types that accept a
          length, such as the MySQL BLOB type.

 -- Class: sqlalchemy.dialects.oracle.DATE (timezone=False)

     Provide the oracle DATE type.

     This type has no special Python behavior, except that it subclasses
     DateTime; this is to suit the fact that the Oracle
     ‘DATE’ type supports a time value.

     New in version 0.9.4.

     `Class signature'

     class sqlalchemy.dialects.oracle.DATE. (see
     sqlalchemy.types.DateTime)

      -- Method: sqlalchemy.dialects.oracle.DATE..__init__
               (timezone=False)

          `inherited from the' ‘sqlalchemy.types.DateTime.__init__’
          `method of' DateTime.

          Construct a new DateTime.

          Parameters: ‘timezone’ – boolean.  Indicates that the datetime
          type should enable timezone support, if available on the `base
          date/time-holding type only'.  It is recommended to make use
          of the TIMESTAMP datatype directly when using this
          flag, as some databases include separate generic
          date/time-holding types distinct from the timezone-capable
          TIMESTAMP datatype, such as Oracle.

 -- Class: sqlalchemy.dialects.oracle.DOUBLE_PRECISION (precision=None,
          asdecimal=False, decimal_return_scale=None)

     `Class signature'

     class sqlalchemy.dialects.oracle.DOUBLE_PRECISION.
     (see sqlalchemy.types.Float)

      -- Method: sqlalchemy.dialects.oracle.DOUBLE_PRECISION..
               __init__ (precision=None, asdecimal=False,
               decimal_return_scale=None)

          `inherited from the' ‘sqlalchemy.types.Float.__init__’ `method
          of' Float.

          Construct a Float.

          Parameters:

             * ‘precision’ – the numeric precision for use in DDL
               ‘CREATE TABLE’.

             * ‘asdecimal’ – the same flag as that of Numeric,
               but defaults to ‘False’.  Note that setting this
               flag to ‘True’ results in floating point conversion.

             * ‘decimal_return_scale’ – Default scale to use when
               converting from floats to Python decimals.  Floating
               point values will typically be much longer due to decimal
               inaccuracy, and most floating point database types don’t
               have a notion of “scale”, so by default the float type
               looks for the first ten decimal places when converting.
               Specifying this value will override that length.  Note
               that the MySQL float types, which do include “scale”,
               will use “scale” as the default for decimal_return_scale,
               if not otherwise specified.

               New in version 0.9.0.

 -- Class: sqlalchemy.dialects.oracle.INTERVAL (day_precision=None,
          second_precision=None)

     `Class signature'

     class sqlalchemy.dialects.oracle.INTERVAL.
     (‘sqlalchemy.types.NativeForEmulated’,
     ‘sqlalchemy.types._AbstractInterval’)

      -- Method: sqlalchemy.dialects.oracle.INTERVAL..
               __init__ (day_precision=None, second_precision=None)

          Construct an INTERVAL.

          Note that only DAY TO SECOND intervals are currently
          supported.  This is due to a lack of support for YEAR TO MONTH
          intervals within available DBAPIs.

          Parameters:

             * ‘day_precision’ – the day precision value.  this is the
               number of digits to store for the day field.  Defaults to
               “2”

             * ‘second_precision’ – the second precision value.  this is
               the number of digits to store for the fractional seconds
               field.  Defaults to “6”.

 -- Class: sqlalchemy.dialects.oracle.NCLOB (length=None,
          collation=None, convert_unicode=False, unicode_error=None,
          _warn_on_bytestring=False, _expect_unicode=False)

     `Class signature'

     class sqlalchemy.dialects.oracle.NCLOB. (see
     sqlalchemy.types.Text)

      -- Method: sqlalchemy.dialects.oracle.NCLOB..__init__
               (length=None, collation=None, convert_unicode=False,
               unicode_error=None, _warn_on_bytestring=False,
               _expect_unicode=False)

          `inherited from the' ‘sqlalchemy.types.String.__init__’
          `method of' String.

          Create a string-holding type.

          Parameters:

             * ‘length’ – optional, a length for the column for use in
               DDL and CAST expressions.  May be safely omitted if no
               ‘CREATE TABLE’ will be issued.  Certain databases may
               require a ‘length’ for use in DDL, and will raise an
               exception when the ‘CREATE TABLE’ DDL is issued if a
               ‘VARCHAR’ with no length is included.  Whether the value
               is interpreted as bytes or characters is database
               specific.

             * ‘collation’ – Optional, a column-level collation for use
               in DDL and CAST expressions.  Renders using the COLLATE
               keyword supported by SQLite, MySQL, and PostgreSQL. E.g.:

                    >>> from sqlalchemy import cast, select, String
                    >>> print(select(cast('some string', String(collation='utf8'))))
                    SELECT CAST(:param_1 AS VARCHAR COLLATE utf8) AS anon_1

             * ‘convert_unicode’ – When set to ‘True’, the String
               type will assume that input is to be passed as Python
               Unicode objects under Python 2, and results returned as
               Python Unicode objects.  In the rare circumstance that
               the DBAPI does not support Python unicode under Python 2,
               SQLAlchemy will use its own encoder/decoder functionality
               on strings, referring to the value of the
               create_engine.encoding parameter parameter passed
               to create_engine() as the encoding.

               Deprecated since version 1.3: The
               String.convert_unicode parameter is deprecated and
               will be removed in a future release.  All modern DBAPIs
               now support Python Unicode directly and this parameter is
               unnecessary.

               For the extremely rare case that Python Unicode is to be
               encoded/decoded by SQLAlchemy on a backend that `does'
               natively support Python Unicode, the string value
               ‘"force"’ can be passed here which will cause
               SQLAlchemy’s encode/decode services to be used
               unconditionally.

                    Note: SQLAlchemy’s unicode-conversion flags and
                    features only apply to Python 2; in Python 3, all
                    string objects are Unicode objects.  For this
                    reason, as well as the fact that virtually all
                    modern DBAPIs now support Unicode natively even
                    under Python 2, the String.convert_unicode
                    flag is inherently a legacy feature.

                    Note: In the vast majority of cases, the
                    Unicode or UnicodeText datatypes
                    should be used for a Column that expects
                    to store non-ascii data.  These datatypes will
                    ensure that the correct types are used on the
                    database side as well as set up the correct Unicode
                    behaviors under Python 2.

               See also
               ........

               See create_engine.convert_unicode. - see
               Engine.-wide parameter

             * ‘unicode_error’ – Optional, a method to use to handle
               Unicode conversion errors.  Behaves like the ‘errors’
               keyword argument to the standard library’s
               ‘string.decode()’ functions, requires that
               String.convert_unicode is set to ‘"force"’

               Deprecated since version 1.3: The
               String.unicode_errors parameter is deprecated and
               will be removed in a future release.  This parameter is
               unnecessary for modern Python DBAPIs and degrades
               performance significantly.

 -- Class: sqlalchemy.dialects.oracle.NUMBER (precision=None,
          scale=None, asdecimal=None)

     `Class signature'

     class sqlalchemy.dialects.oracle.NUMBER. (see
     sqlalchemy.types.Numeric, sqlalchemy.types.Integer)

      -- Method: sqlalchemy.dialects.oracle.NUMBER..__init__
               (precision=None, scale=None, asdecimal=None)

          Construct a Numeric.

          Parameters:

             * ‘precision’ – the numeric precision for use in DDL
               ‘CREATE TABLE’.

             * ‘scale’ – the numeric scale for use in DDL ‘CREATE
               TABLE’.

             * ‘asdecimal’ – default True.  Return whether or not values
               should be sent as Python Decimal objects, or as floats.
               Different DBAPIs send one or the other based on datatypes
               - the Numeric type will ensure that return values are one
               or the other across DBAPIs consistently.

             * ‘decimal_return_scale’ – Default scale to use when
               converting from floats to Python decimals.  Floating
               point values will typically be much longer due to decimal
               inaccuracy, and most floating point database types don’t
               have a notion of “scale”, so by default the float type
               looks for the first ten decimal places when converting.
               Specifying this value will override that length.  Types
               which do include an explicit “.scale” value, such as the
               base Numeric as well as the MySQL float
               types, will use the value of “.scale” as the default for
               decimal_return_scale, if not otherwise specified.

               New in version 0.9.0.

          When using the ‘Numeric’ type, care should be taken to ensure
          that the asdecimal setting is appropriate for the DBAPI in use
          - when Numeric applies a conversion from Decimal->float or
          float-> Decimal, this conversion incurs an additional
          performance overhead for all result columns received.

          DBAPIs that return Decimal natively (e.g.  psycopg2) will have
          better accuracy and higher performance with a setting of
          ‘True’, as the native translation to Decimal reduces the
          amount of floating- point issues at play, and the Numeric type
          itself doesn’t need to apply any further conversions.
          However, another DBAPI which returns floats natively `will'
          incur an additional conversion overhead, and is still subject
          to floating point data loss - in which case ‘asdecimal=False’
          will at least remove the extra conversion overhead.

 -- Class: sqlalchemy.dialects.oracle.LONG (length=None, collation=None,
          convert_unicode=False, unicode_error=None,
          _warn_on_bytestring=False, _expect_unicode=False)

     `Class signature'

     class sqlalchemy.dialects.oracle.LONG. (see
     sqlalchemy.types.Text)

      -- Method: sqlalchemy.dialects.oracle.LONG..__init__
               (length=None, collation=None, convert_unicode=False,
               unicode_error=None, _warn_on_bytestring=False,
               _expect_unicode=False)

          `inherited from the' ‘sqlalchemy.types.String.__init__’
          `method of' String.

          Create a string-holding type.

          Parameters:

             * ‘length’ – optional, a length for the column for use in
               DDL and CAST expressions.  May be safely omitted if no
               ‘CREATE TABLE’ will be issued.  Certain databases may
               require a ‘length’ for use in DDL, and will raise an
               exception when the ‘CREATE TABLE’ DDL is issued if a
               ‘VARCHAR’ with no length is included.  Whether the value
               is interpreted as bytes or characters is database
               specific.

             * ‘collation’ – Optional, a column-level collation for use
               in DDL and CAST expressions.  Renders using the COLLATE
               keyword supported by SQLite, MySQL, and PostgreSQL. E.g.:

                    >>> from sqlalchemy import cast, select, String
                    >>> print(select(cast('some string', String(collation='utf8'))))
                    SELECT CAST(:param_1 AS VARCHAR COLLATE utf8) AS anon_1

             * ‘convert_unicode’ – When set to ‘True’, the String
               type will assume that input is to be passed as Python
               Unicode objects under Python 2, and results returned as
               Python Unicode objects.  In the rare circumstance that
               the DBAPI does not support Python unicode under Python 2,
               SQLAlchemy will use its own encoder/decoder functionality
               on strings, referring to the value of the
               create_engine.encoding parameter parameter passed
               to create_engine() as the encoding.

               Deprecated since version 1.3: The
               String.convert_unicode parameter is deprecated and
               will be removed in a future release.  All modern DBAPIs
               now support Python Unicode directly and this parameter is
               unnecessary.

               For the extremely rare case that Python Unicode is to be
               encoded/decoded by SQLAlchemy on a backend that `does'
               natively support Python Unicode, the string value
               ‘"force"’ can be passed here which will cause
               SQLAlchemy’s encode/decode services to be used
               unconditionally.

                    Note: SQLAlchemy’s unicode-conversion flags and
                    features only apply to Python 2; in Python 3, all
                    string objects are Unicode objects.  For this
                    reason, as well as the fact that virtually all
                    modern DBAPIs now support Unicode natively even
                    under Python 2, the String.convert_unicode
                    flag is inherently a legacy feature.

                    Note: In the vast majority of cases, the
                    Unicode or UnicodeText datatypes
                    should be used for a Column that expects
                    to store non-ascii data.  These datatypes will
                    ensure that the correct types are used on the
                    database side as well as set up the correct Unicode
                    behaviors under Python 2.

               See also
               ........

               See create_engine.convert_unicode. - see
               Engine.-wide parameter

             * ‘unicode_error’ – Optional, a method to use to handle
               Unicode conversion errors.  Behaves like the ‘errors’
               keyword argument to the standard library’s
               ‘string.decode()’ functions, requires that
               String.convert_unicode is set to ‘"force"’

               Deprecated since version 1.3: The
               String.unicode_errors parameter is deprecated and
               will be removed in a future release.  This parameter is
               unnecessary for modern Python DBAPIs and degrades
               performance significantly.

 -- Class: sqlalchemy.dialects.oracle.RAW (length=None)

     `Class signature'

     class sqlalchemy.dialects.oracle.RAW.
     (‘sqlalchemy.types._Binary’)

      -- Method: sqlalchemy.dialects.oracle.RAW..__init__
               (length=None)

          `inherited from the' ‘sqlalchemy.types._Binary.__init__’
          `method of' ‘sqlalchemy.types._Binary’

          Initialize self.  See help(type(self)) for accurate signature.

5.1.4.21 cx_Oracle
..................

Support for the Oracle database via the cx-Oracle driver.

5.1.4.22 DBAPI
..............

Documentation and download information (if applicable) for cx-Oracle is
available at: ‘https://oracle.github.io/python-cx_Oracle/’

5.1.4.23 Connecting
...................

Connect String:
     oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...]

5.1.4.24 DSN vs. Hostname connections
.....................................

The dialect will connect to a DSN if no database name portion is
presented, such as:

     engine = create_engine("oracle+cx_oracle://scott:tiger@oracle1120/?encoding=UTF-8&nencoding=UTF-8")

Above, ‘oracle1120’ is passed to cx_Oracle as an Oracle datasource name.

Alternatively, if a database name is present, the ‘cx_Oracle.makedsn()’
function is used to create an ad-hoc “datasource” name assuming host and
port:

     engine = create_engine("oracle+cx_oracle://scott:tiger@hostname:1521/dbname?encoding=UTF-8&nencoding=UTF-8")

Above, the DSN would be created as follows:

     >>> import cx_Oracle
     >>> cx_Oracle.makedsn("hostname", 1521, sid="dbname")
     '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=hostname)(PORT=1521))(CONNECT_DATA=(SID=dbname)))'

The ‘service_name’ parameter, also consumed by ‘cx_Oracle.makedsn()’,
may be specified in the URL query string, e.g.
‘?service_name=my_service’.

5.1.4.25 Passing cx_Oracle connect arguments
............................................

Additional connection arguments can usually be passed via the URL query
string; particular symbols like ‘cx_Oracle.SYSDBA’ are intercepted and
converted to the correct symbol:

     e = create_engine(
         "oracle+cx_oracle://user:pass@dsn?encoding=UTF-8&nencoding=UTF-8&mode=SYSDBA&events=true")

Changed in version 1.3: the cx_oracle dialect now accepts all argument
names within the URL string itself, to be passed to the cx_Oracle DBAPI.
As was the case earlier but not correctly documented, the
create_engine.connect_args parameter also accepts all cx_Oracle
DBAPI connect arguments.

To pass arguments directly to ‘.connect()’ without using the query
string, use the create_engine.connect_args dictionary.  Any
cx_Oracle parameter value and/or constant may be passed, such as:

     import cx_Oracle
     e = create_engine(
         "oracle+cx_oracle://user:pass@dsn",
         connect_args={
             "encoding": "UTF-8",
             "nencoding": "UTF-8",
             "mode": cx_Oracle.SYSDBA,
             "events": True
         }
     )

5.1.4.26 Options consumed by the SQLAlchemy cx_Oracle dialect outside of the driver
...................................................................................

There are also options that are consumed by the SQLAlchemy cx_oracle
dialect itself.  These options are always passed directly to
create_engine(). , such as:

     e = create_engine(
         "oracle+cx_oracle://user:pass@dsn", coerce_to_unicode=False)

The parameters accepted by the cx_oracle dialect are as follows:

   * ‘arraysize’ - set the cx_oracle.arraysize value on cursors,
     defaulted to 50.  This setting is significant with cx_Oracle as the
     contents of LOB objects are only readable within a “live” row (e.g.
     within a batch of 50 rows).

   * ‘auto_convert_lobs’ - defaults to True; See LOB Objects.

   * ‘coerce_to_unicode’ - see Unicode for detail.

   * ‘coerce_to_decimal’ - see Precision Numerics for
     detail.

   * ‘encoding_errors’ - see Encoding Errors for detail.

5.1.4.27 Using cx_Oracle SessionPool
....................................

The cx_Oracle library provides its own connectivity services that may be
used in place of SQLAlchemy’s pooling functionality.  This can be
achieved by using the create_engine.creator parameter to
provide a function that returns a new connection, along with setting
create_engine.pool_class to ‘NullPool’ to disable
SQLAlchemy’s pooling:

     import cx_Oracle
     from sqlalchemy import create_engine
     from sqlalchemy.pool import NullPool

     pool = cx_Oracle.SessionPool(
         user="scott", password="tiger", dsn="oracle1120",
         min=2, max=5, increment=1, threaded=True
     )

     engine = create_engine("oracle://", creator=pool.acquire, poolclass=NullPool)

The above engine may then be used normally where cx_Oracle’s pool
handles connection pooling:

     with engine.connect() as conn:
         print(conn.scalar("select 1 FROM dual"))

5.1.4.28 Unicode
................

As is the case for all DBAPIs under Python 3, all strings are inherently
Unicode strings.  Under Python 2, cx_Oracle also supports Python Unicode
objects directly.  In all cases however, the driver requires an explicit
encoding configuration.

5.1.4.29 Ensuring the Correct Client Encoding
.............................................

The long accepted standard for establishing client encoding for nearly
all Oracle related software is via the NLS_LANG(1) environment variable.
cx_Oracle like most other Oracle drivers will use this environment
variable as the source of its encoding configuration.  The format of
this variable is idiosyncratic; a typical value would be
‘AMERICAN_AMERICA.AL32UTF8’.

The cx_Oracle driver also supports a programmatic alternative which is
to pass the ‘encoding’ and ‘nencoding’ parameters directly to its
‘.connect()’ function.  These can be present in the URL as follows:

     engine = create_engine("oracle+cx_oracle://scott:tiger@oracle1120/?encoding=UTF-8&nencoding=UTF-8")

For the meaning of the ‘encoding’ and ‘nencoding’ parameters, please
consult Characters Sets and National Language Support (NLS)(2).

See also
........

Characters Sets and National Language Support (NLS)(3) - in the
cx_Oracle documentation.

   ---------- Footnotes ----------

   (1) https://www.oracle.com/database/technologies/faq-nls-lang.html

   (2)
https://cx-oracle.readthedocs.io/en/latest/user_guide/globalization.html#globalization

   (3)
https://cx-oracle.readthedocs.io/en/latest/user_guide/globalization.html#globalization

5.1.4.30 Unicode-specific Column datatypes
..........................................

The Core expression language handles unicode data by use of the
Unicode and UnicodeText datatypes.  These types
correspond to the VARCHAR2 and CLOB Oracle datatypes by default.  When
using these datatypes with Unicode data, it is expected that the Oracle
database is configured with a Unicode-aware character set, as well as
that the ‘NLS_LANG’ environment variable is set appropriately, so that
the VARCHAR2 and CLOB datatypes can accommodate the data.

In the case that the Oracle database is not configured with a Unicode
character set, the two options are to use the NCHAR and
NCLOB datatypes explicitly, or to pass the flag
‘use_nchar_for_unicode=True’ to create_engine(), which will
cause the SQLAlchemy dialect to use NCHAR/NCLOB for the Unicode.
/ see UnicodeText datatypes instead of VARCHAR/CLOB.

Changed in version 1.3: The Unicode and UnicodeText
datatypes now correspond to the ‘VARCHAR2’ and ‘CLOB’ Oracle
datatypes unless the ‘use_nchar_for_unicode=True’ is passed to the
dialect when create_engine() is called.

5.1.4.31 Unicode Coercion of result rows under Python 2
.......................................................

When result sets are fetched that include strings, under Python 3 the
cx_Oracle DBAPI returns all strings as Python Unicode objects, since
Python 3 only has a Unicode string type.  This occurs for data fetched
from datatypes such as VARCHAR2, CHAR, CLOB, NCHAR, NCLOB, etc.  In
order to provide cross- compatibility under Python 2, the SQLAlchemy
cx_Oracle dialect will add Unicode-conversion to string data under
Python 2 as well.  Historically, this made use of converters that were
supplied by cx_Oracle but were found to be non-performant; SQLAlchemy’s
own converters are used for the string to Unicode conversion under
Python 2.  To disable the Python 2 Unicode conversion for VARCHAR2,
CHAR, and CLOB, the flag ‘coerce_to_unicode=False’ can be passed to
create_engine().

Changed in version 1.3: Unicode conversion is applied to all string
values by default under python 2.  The ‘coerce_to_unicode’ now defaults
to True and can be set to False to disable the Unicode coercion of
strings that are delivered as VARCHAR2/CHAR/CLOB data.

5.1.4.32 Encoding Errors
........................

For the unusual case that data in the Oracle database is present with a
broken encoding, the dialect accepts a parameter ‘encoding_errors’ which
will be passed to Unicode decoding functions in order to affect how
decoding errors are handled.  The value is ultimately consumed by the
Python decode(1) function, and is passed both via cx_Oracle’s
‘encodingErrors’ parameter consumed by ‘Cursor.var()’, as well as
SQLAlchemy’s own decoding function, as the cx_Oracle dialect makes use
of both under different circumstances.

New in version 1.3.11.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#bytes.decode

5.1.4.33 Fine grained control over cx_Oracle data binding performance with setinputsizes
........................................................................................

The cx_Oracle DBAPI has a deep and fundamental reliance upon the usage
of the DBAPI ‘setinputsizes()’ call.  The purpose of this call is to
establish the datatypes that are bound to a SQL statement for Python
values being passed as parameters.  While virtually no other DBAPI
assigns any use to the ‘setinputsizes()’ call, the cx_Oracle DBAPI
relies upon it heavily in its interactions with the Oracle client
interface, and in some scenarios it is not possible for SQLAlchemy to
know exactly how data should be bound, as some settings can cause
profoundly different performance characteristics, while altering the
type coercion behavior at the same time.

Users of the cx_Oracle dialect are `strongly encouraged' to read through
cx_Oracle’s list of built-in datatype symbols at
‘http://cx-oracle.readthedocs.io/en/latest/module.html#database-types’.
Note that in some cases, significant performance degradation can occur
when using these types vs.  not, in particular when specifying
‘cx_Oracle.CLOB’.

On the SQLAlchemy side, the DialectEvents.do_setinputsizes()
event can be used both for runtime visibility (e.g.  logging) of
the setinputsizes step as well as to fully control how ‘setinputsizes()’
is used on a per-statement basis.

New in version 1.2.9: Added ‘DialectEvents.setinputsizes()’

5.1.4.34 Example 1 - logging all setinputsizes calls
....................................................

The following example illustrates how to log the intermediary values
from a SQLAlchemy perspective before they are converted to the raw
‘setinputsizes()’ parameter dictionary.  The keys of the dictionary are
BindParameter objects which have a ‘.key’ and a ‘.type’
attribute:

     from sqlalchemy import create_engine, event

     engine = create_engine("oracle+cx_oracle://scott:tiger@host/xe")

     @event.listens_for(engine, "do_setinputsizes")
     def _log_setinputsizes(inputsizes, cursor, statement, parameters, context):
         for bindparam, dbapitype in inputsizes.items():
                 log.info(
                     "Bound parameter name: %s  SQLAlchemy type: %r  "
                     "DBAPI object: %s",
                     bindparam.key, bindparam.type, dbapitype)

5.1.4.35 Example 2 - remove all bindings to CLOB
................................................

The ‘CLOB’ datatype in cx_Oracle incurs a significant performance
overhead, however is set by default for the ‘Text’ type within the
SQLAlchemy 1.2 series.  This setting can be modified as follows:

     from sqlalchemy import create_engine, event
     from cx_Oracle import CLOB

     engine = create_engine("oracle+cx_oracle://scott:tiger@host/xe")

     @event.listens_for(engine, "do_setinputsizes")
     def _remove_clob(inputsizes, cursor, statement, parameters, context):
         for bindparam, dbapitype in list(inputsizes.items()):
             if dbapitype is CLOB:
                 del inputsizes[bindparam]

5.1.4.36 RETURNING Support
..........................

The cx_Oracle dialect implements RETURNING using OUT parameters.  The
dialect supports RETURNING fully, however cx_Oracle 6 is recommended for
complete support.

5.1.4.37 LOB Objects
....................

cx_oracle returns oracle LOBs using the cx_oracle.LOB object.
SQLAlchemy converts these to strings so that the interface of the Binary
type is consistent with that of other backends, which takes place within
a cx_Oracle outputtypehandler.

cx_Oracle prior to version 6 would require that LOB objects be read
before a new batch of rows would be read, as determined by the
‘cursor.arraysize’.  As of the 6 series, this limitation has been
lifted.  Nevertheless, because SQLAlchemy pre-reads these LOBs up front,
this issue is avoided in any case.

To disable the auto “read()” feature of the dialect, the flag
‘auto_convert_lobs=False’ may be passed to create_engine().
Under the cx_Oracle 5 series, having this flag turned off means there is
the chance of reading from a stale LOB object if not read as it is
fetched.  With cx_Oracle 6, this issue is resolved.

Changed in version 1.2: the LOB handling system has been greatly
simplified internally to make use of outputtypehandlers, and no longer
makes use of alternate “buffered” result set objects.

5.1.4.38 Two Phase Transactions Not Supported
.............................................

Two phase transactions are `not supported' under cx_Oracle due to poor
driver support.  As of cx_Oracle 6.0b1, the interface for two phase
transactions has been changed to be more of a direct pass-through to the
underlying OCI layer with less automation.  The additional logic to
support this system is not implemented in SQLAlchemy.

5.1.4.39 Precision Numerics
...........................

SQLAlchemy’s numeric types can handle receiving and returning values as
Python ‘Decimal’ objects or float objects.  When a Numeric
object, or a subclass such as Float, DOUBLE_PRECISION
etc.  is in use, the Numeric.asdecimal flag
determines if values should be coerced to ‘Decimal’ upon return, or
returned as float objects.  To make matters more complicated under
Oracle, Oracle’s ‘NUMBER’ type can also represent integer values if the
“scale” is zero, so the Oracle-specific NUMBER type takes
this into account as well.

The cx_Oracle dialect makes extensive use of connection- and
cursor-level “outputtypehandler” callables in order to coerce numeric
values as requested.  These callables are specific to the specific
flavor of Numeric in use, as well as if no SQLAlchemy typing
objects are present.  There are observed scenarios where Oracle may
sends incomplete or ambiguous information about the numeric types being
returned, such as a query where the numeric types are buried under
multiple levels of subquery.  The type handlers do their best to make
the right decision in all cases, deferring to the underlying cx_Oracle
DBAPI for all those cases where the driver can make the best decision.

When no typing objects are present, as when executing plain SQL strings,
a default “outputtypehandler” is present which will generally return
numeric values which specify precision and scale as Python ‘Decimal’
objects.  To disable this coercion to decimal for performance reasons,
pass the flag ‘coerce_to_decimal=False’ to create_engine():

     engine = create_engine("oracle+cx_oracle://dsn", coerce_to_decimal=False)

The ‘coerce_to_decimal’ flag only impacts the results of plain string
SQL statements that are not otherwise associated with a Numeric.
SQLAlchemy type (or a subclass of such).

Changed in version 1.2: The numeric handling system for cx_Oracle has
been reworked to take advantage of newer cx_Oracle features as well as
better integration of outputtypehandlers.

5.1.5 Microsoft SQL Server
--------------------------

Support for the Microsoft SQL Server database.

The following table summarizes current support levels for database
release versions.

`Supported Microsoft SQL Server versions'

Support type                                           Versions

--------------------------------------------------------------------------------------------------------------

See Fully tested in CI.                        2017

See Normal support.                            2012+

See Best effort.                               2005+

5.1.5.1 DBAPI Support
.....................

The following dialect/DBAPI options are available.  Please refer to
individual DBAPI sections for connect information.

   * PyODBC.

   * mxODBC.

   * pymssql.

5.1.5.2 External Dialects
.........................

In addition to the above DBAPI layers with native SQLAlchemy support,
there are third-party dialects for other DBAPI layers that are
compatible with SQL Server.  See the “External Dialects” list on the
Dialects page.

5.1.5.3 Auto Increment Behavior / IDENTITY Columns
..................................................

SQL Server provides so-called “auto incrementing” behavior using the
‘IDENTITY’ construct, which can be placed on any single integer column
in a table.  SQLAlchemy considers ‘IDENTITY’ within its default
“autoincrement” behavior for an integer primary key column, described at
Column.autoincrement.  This means that by default, the first
integer primary key column in a Table will be considered to
be the identity column - unless it is associated with a Sequence.
- and will generate DDL as such:

     from sqlalchemy import Table, MetaData, Column, Integer

     m = MetaData()
     t = Table('t', m,
             Column('id', Integer, primary_key=True),
             Column('x', Integer))
     m.create_all(engine)

The above example will generate DDL as:

     CREATE TABLE t (
         id INTEGER NOT NULL IDENTITY,
         x INTEGER NULL,
         PRIMARY KEY (id)
     )

For the case where this default generation of ‘IDENTITY’ is not desired,
specify ‘False’ for the Column.autoincrement flag, on the
first integer primary key column:

     m = MetaData()
     t = Table('t', m,
             Column('id', Integer, primary_key=True, autoincrement=False),
             Column('x', Integer))
     m.create_all(engine)

To add the ‘IDENTITY’ keyword to a non-primary key column, specify
‘True’ for the Column.autoincrement flag on the desired
Column object, and ensure that Column.autoincrement
is set to ‘False’ on any integer primary key column:

     m = MetaData()
     t = Table('t', m,
             Column('id', Integer, primary_key=True, autoincrement=False),
             Column('x', Integer, autoincrement=True))
     m.create_all(engine)

Changed in version 1.4: Added Identity construct in a
Column to specify the start and increment parameters of an
IDENTITY. These replace the use of the Sequence object in
order to specify these values.

Deprecated since version 1.4: The ‘mssql_identity_start’ and
‘mssql_identity_increment’ parameters to Column are
deprecated and should we replaced by an Identity object.
Specifying both ways of configuring an IDENTITY will result in a compile
error.  These options are also no longer returned as part of the
‘dialect_options’ key in Inspector.get_columns().  Use the
information in the ‘identity’ key instead.

Deprecated since version 1.3: The use of Sequence to specify
IDENTITY characteristics is deprecated and will be removed in a future
release.  Please use the Identity object parameters
Identity.start and Identity.increment.

Changed in version 1.4: Removed the ability to use a Sequence
object to modify IDENTITY characteristics.  Sequence
objects now only manipulate true T-SQL SEQUENCE types.

     Note: There can only be one IDENTITY column on the table.  When
     using ‘autoincrement=True’ to enable the IDENTITY keyword,
     SQLAlchemy does not guard against multiple columns specifying the
     option simultaneously.  The SQL Server database will instead reject
     the ‘CREATE TABLE’ statement.

     Note: An INSERT statement which attempts to provide a value for a
     column that is marked with IDENTITY will be rejected by SQL Server.
     In order for the value to be accepted, a session-level option “SET
     IDENTITY_INSERT” must be enabled.  The SQLAlchemy SQL Server
     dialect will perform this operation automatically when using a core
     Insert construct; if the execution specifies a value for
     the IDENTITY column, the “IDENTITY_INSERT” option will be enabled
     for the span of that statement’s invocation.However, this scenario
     is not high performing and should not be relied upon for normal
     use.  If a table doesn’t actually require IDENTITY behavior in its
     integer primary key column, the keyword should be disabled when
     creating the table by ensuring that ‘autoincrement=False’ is set.

5.1.5.4 Controlling “Start” and “Increment”
...........................................

Specific control over the “start” and “increment” values for the
‘IDENTITY’ generator are provided using the Identity.start
and Identity.increment parameters passed to the
Identity object:

     from sqlalchemy import Table, Integer, Column, Identity

     test = Table(
         'test', metadata,
         Column(
             'id',
             Integer,
             primary_key=True,
             Identity(start=100, increment=10)
         ),
         Column('name', String(20))
     )

The CREATE TABLE for the above Table object would be:

     CREATE TABLE test (
       id INTEGER NOT NULL IDENTITY(100,10) PRIMARY KEY,
       name VARCHAR(20) NULL,
       )

     Note: The Identity object supports many other
     parameter in addition to ‘start’ and ‘increment’.  These are not
     supported by SQL Server and will be ignored when generating the
     CREATE TABLE ddl.

Changed in version 1.3.19: The Identity object is now used
to affect the ‘IDENTITY’ generator for a Column under SQL
Server.  Previously, the Sequence object was used.  As SQL
Server now supports real sequences as a separate construct, see
Sequence will be functional in the normal way starting from
SQLAlchemy version 1.4.

5.1.5.5 INSERT behavior
.......................

Handling of the ‘IDENTITY’ column at INSERT time involves two key
techniques.  The most common is being able to fetch the “last inserted
value” for a given ‘IDENTITY’ column, a process which SQLAlchemy
performs implicitly in many cases, most importantly within the ORM.

The process for fetching this value has several variants:

   * In the vast majority of cases, RETURNING is used in conjunction
     with INSERT statements on SQL Server in order to get newly
     generated primary key values:

          INSERT INTO t (x) OUTPUT inserted.id VALUES (?)

   * When RETURNING is not available or has been disabled via
     ‘implicit_returning=False’, either the ‘scope_identity()’ function
     or the ‘@@identity’ variable is used; behavior varies by backend:

        * when using PyODBC, the phrase ‘; select scope_identity()’ will
          be appended to the end of the INSERT statement; a second
          result set will be fetched in order to receive the value.
          Given a table as:

               t = Table('t', m, Column('id', Integer, primary_key=True),
                       Column('x', Integer),
                       implicit_returning=False)

          an INSERT will look like:

               INSERT INTO t (x) VALUES (?); select scope_identity()

        * Other dialects such as pymssql will call upon ‘SELECT
          scope_identity() AS lastrowid’ subsequent to an INSERT
          statement.  If the flag ‘use_scope_identity=False’ is passed
          to create_engine(), the statement ‘SELECT @@identity
          AS lastrowid’ is used instead.

A table that contains an ‘IDENTITY’ column will prohibit an INSERT
statement that refers to the identity column explicitly.  The SQLAlchemy
dialect will detect when an INSERT construct, created using a core
insert() construct (not a plain string SQL), refers to the identity
column, and in this case will emit ‘SET IDENTITY_INSERT ON’ prior to the
insert statement proceeding, and ‘SET IDENTITY_INSERT OFF’ subsequent to
the execution.  Given this example:

     m = MetaData()
     t = Table('t', m, Column('id', Integer, primary_key=True),
                     Column('x', Integer))
     m.create_all(engine)

     with engine.begin() as conn:
         conn.execute(t.insert(), {'id': 1, 'x':1}, {'id':2, 'x':2})

The above column will be created with IDENTITY, however the INSERT
statement we emit is specifying explicit values.  In the echo output we
can see how SQLAlchemy handles this:

     CREATE TABLE t (
         id INTEGER NOT NULL IDENTITY(1,1),
         x INTEGER NULL,
         PRIMARY KEY (id)
     )

     COMMIT
     SET IDENTITY_INSERT t ON
     INSERT INTO t (id, x) VALUES (?, ?)
     ((1, 1), (2, 2))
     SET IDENTITY_INSERT t OFF
     COMMIT

This is an auxiliary use case suitable for testing and bulk insert
scenarios.

5.1.5.6 SEQUENCE support
........................

The Sequence object now creates “real” sequences, i.e.,
‘CREATE SEQUENCE’.  To provide compatibility with other dialects, see
Sequence defaults to a start value of 1, even though the T-SQL
defaults is -9223372036854775808.

New in version 1.4.0.

5.1.5.7 MAX on VARCHAR / NVARCHAR
.................................

SQL Server supports the special string “MAX” within the VARCHAR
and NVARCHAR datatypes, to indicate “maximum length
possible”.  The dialect currently handles this as a length of “None” in
the base type, rather than supplying a dialect-specific version of these
types, so that a base type specified such as ‘VARCHAR(None)’ can assume
“unlengthed” behavior on more than one backend without using
dialect-specific types.

To build a SQL Server VARCHAR or NVARCHAR with MAX length, use None:

     my_table = Table(
         'my_table', metadata,
         Column('my_data', VARCHAR(None)),
         Column('my_n_data', NVARCHAR(None))
     )

5.1.5.8 Collation Support
.........................

Character collations are supported by the base string types, specified
by the string argument “collation”:

     from sqlalchemy import VARCHAR
     Column('login', VARCHAR(32, collation='Latin1_General_CI_AS'))

When such a column is associated with a Table, the CREATE
TABLE statement for this column will yield:

     login VARCHAR(32) COLLATE Latin1_General_CI_AS NULL

5.1.5.9 LIMIT/OFFSET Support
............................

MSSQL has added support for LIMIT / OFFSET as of SQL Server 2012, via
the “OFFSET n ROWS” and “FETCH NEXT n ROWS” clauses.  SQLAlchemy
supports these syntaxes automatically if SQL Server 2012 or greater is
detected.

Changed in version 1.4: support added for SQL Server “OFFSET n ROWS” and
“FETCH NEXT n ROWS” syntax.

For statements that specify only LIMIT and no OFFSET, all versions of
SQL Server support the TOP keyword.  This syntax is used for all SQL
Server versions when no OFFSET clause is present.  A statement such as:

     select(some_table).limit(5)

will render similarly to:

     SELECT TOP 5 col1, col2.. FROM table

For versions of SQL Server prior to SQL Server 2012, a statement that
uses LIMIT and OFFSET, or just OFFSET alone, will be rendered using the
‘ROW_NUMBER()’ window function.  A statement such as:

     select(some_table).order_by(some_table.c.col3).limit(5).offset(10)

will render similarly to:

     SELECT anon_1.col1, anon_1.col2 FROM (SELECT col1, col2,
     ROW_NUMBER() OVER (ORDER BY col3) AS
     mssql_rn FROM table WHERE t.x = :x_1) AS
     anon_1 WHERE mssql_rn > :param_1 AND mssql_rn <= :param_2 + :param_1

Note that when using LIMIT and/or OFFSET, whether using the older or
newer SQL Server syntaxes, the statement must have an ORDER BY as well,
else a CompileError is raised.

5.1.5.10 Transaction Isolation Level
....................................

All SQL Server dialects support setting of transaction isolation level
both via a dialect-specific parameter
create_engine.isolation_level accepted by create_engine(),
as well as the Connection.execution_options.isolation_level
argument as passed to Connection.execution_options().
This feature works by issuing the command ‘SET TRANSACTION ISOLATION
LEVEL <level>’ for each new connection.

To set isolation level using create_engine():

     engine = create_engine(
         "mssql+pyodbc://scott:tiger@ms_2008",
         isolation_level="REPEATABLE READ"
     )

To set using per-connection execution options:

     connection = engine.connect()
     connection = connection.execution_options(
         isolation_level="READ COMMITTED"
     )

Valid values for ‘isolation_level’ include:

   * ‘AUTOCOMMIT’ - pyodbc / pymssql-specific

   * ‘READ COMMITTED’

   * ‘READ UNCOMMITTED’

   * ‘REPEATABLE READ’

   * ‘SERIALIZABLE’

   * ‘SNAPSHOT’ - specific to SQL Server

New in version 1.2: added AUTOCOMMIT isolation level setting

See also
........

See Setting Transaction Isolation Levels including DBAPI Autocommit.

5.1.5.11 Nullability
....................

MSSQL has support for three levels of column nullability.  The default
nullability allows nulls and is explicit in the CREATE TABLE construct:

     name VARCHAR(20) NULL

If ‘nullable=None’ is specified then no specification is made.  In other
words the database’s configured default is used.  This will render:

     name VARCHAR(20)

If ‘nullable’ is ‘True’ or ‘False’ then the column will be ‘NULL’ or
‘NOT NULL’ respectively.

5.1.5.12 Date / Time Handling
.............................

DATE and TIME are supported.  Bind parameters are converted to
datetime.datetime() objects as required by most MSSQL drivers, and
results are processed from strings if needed.  The DATE and TIME types
are not available for MSSQL 2005 and previous - if a server version
below 2008 is detected, DDL for these types will be issued as DATETIME.

5.1.5.13 Large Text/Binary Type Deprecation
...........................................

Per SQL Server 2012/2014 Documentation(1), the ‘NTEXT’, ‘TEXT’ and
‘IMAGE’ datatypes are to be removed from SQL Server in a future release.
SQLAlchemy normally relates these types to the UnicodeText,
TextClause and LargeBinary datatypes.

In order to accommodate this change, a new flag ‘deprecate_large_types’
is added to the dialect, which will be automatically set based on
detection of the server version in use, if not otherwise set by the
user.  The behavior of this flag is as follows:

   * When this flag is ‘True’, the UnicodeText,
     TextClause and LargeBinary datatypes, when used
     to render DDL, will render the types ‘NVARCHAR(max)’,
     ‘VARCHAR(max)’, and ‘VARBINARY(max)’, respectively.  This is a new
     behavior as of the addition of this flag.

   * When this flag is ‘False’, the UnicodeText,
     TextClause and LargeBinary datatypes, when used
     to render DDL, will render the types ‘NTEXT’, ‘TEXT’, and ‘IMAGE’,
     respectively.  This is the long-standing behavior of these types.

   * The flag begins with the value ‘None’, before a database connection
     is established.  If the dialect is used to render DDL without the
     flag being set, it is interpreted the same as ‘False’.

   * On first connection, the dialect detects if SQL Server version 2012
     or greater is in use; if the flag is still at ‘None’, it sets it to
     ‘True’ or ‘False’ based on whether 2012 or greater is detected.

   * The flag can be set to either ‘True’ or ‘False’ when the dialect is
     created, typically via create_engine():

          eng = create_engine("mssql+pymssql://user:pass@host/db",
                          deprecate_large_types=True)

   * Complete control over whether the “old” or “new” types are rendered
     is available in all SQLAlchemy versions by using the UPPERCASE type
     objects instead: NVARCHAR, VARCHAR,
     VARBINARY, TEXT, NTEXT, IMAGE
     will always remain fixed and always output exactly that type.

New in version 1.0.0.

   ---------- Footnotes ----------

   (1) http://technet.microsoft.com/en-us/library/ms187993.aspx

5.1.5.14 Multipart Schema Names
...............................

SQL Server schemas sometimes require multiple parts to their “schema”
qualifier, that is, including the database name and owner name as
separate tokens, such as ‘mydatabase.dbo.some_table’.  These multipart
names can be set at once using the Table.schema argument of
Table:

     Table(
         "some_table", metadata,
         Column("q", String(50)),
         schema="mydatabase.dbo"
     )

When performing operations such as table or component reflection, a
schema argument that contains a dot will be split into separate
“database” and “owner” components in order to correctly query the SQL
Server information schema tables, as these two values are stored
separately.  Additionally, when rendering the schema name for DDL or
SQL, the two components will be quoted separately for case sensitive
names and other special characters.  Given an argument as below:

     Table(
         "some_table", metadata,
         Column("q", String(50)),
         schema="MyDataBase.dbo"
     )

The above schema would be rendered as ‘[MyDataBase].dbo’, and also in
reflection, would be reflected using “dbo” as the owner and “MyDataBase”
as the database name.

To control how the schema name is broken into database / owner, specify
brackets (which in SQL Server are quoting characters) in the name.
Below, the “owner” will be considered as ‘MyDataBase.dbo’ and the
“database” will be None:

     Table(
         "some_table", metadata,
         Column("q", String(50)),
         schema="[MyDataBase.dbo]"
     )

To individually specify both database and owner name with special
characters or embedded dots, use two sets of brackets:

     Table(
         "some_table", metadata,
         Column("q", String(50)),
         schema="[MyDataBase.Period].[MyOwner.Dot]"
     )

Changed in version 1.2: the SQL Server dialect now treats brackets as
identifier delimeters splitting the schema into separate database and
owner tokens, to allow dots within either name itself.

5.1.5.15 Legacy Schema Mode
...........................

Very old versions of the MSSQL dialect introduced the behavior such that
a schema-qualified table would be auto-aliased when used in a SELECT
statement; given a table:

     account_table = Table(
         'account', metadata,
         Column('id', Integer, primary_key=True),
         Column('info', String(100)),
         schema="customer_schema"
     )

this legacy mode of rendering would assume that
“customer_schema.account” would not be accepted by all parts of the SQL
statement, as illustrated below:

     >>> eng = create_engine("mssql+pymssql://mydsn", legacy_schema_aliasing=True)
     >>> print(account_table.select().compile(eng))
     SELECT account_1.id, account_1.info
     FROM customer_schema.account AS account_1

This mode of behavior is now off by default, as it appears to have
served no purpose; however in the case that legacy applications rely
upon it, it is available using the ‘legacy_schema_aliasing’ argument to
create_engine() as illustrated above.

Changed in version 1.1: the ‘legacy_schema_aliasing’ flag introduced in
version 1.0.5 to allow disabling of legacy mode for schemas now defaults
to False.

Deprecated since version 1.4: The ‘legacy_schema_aliasing’ flag is now
deprecated and will be removed in a future release.

5.1.5.16 Clustered Index Support
................................

The MSSQL dialect supports clustered indexes (and primary keys) via the
‘mssql_clustered’ option.  This option is available to Index,
UniqueConstraint.  and PrimaryKeyConstraint.

To generate a clustered index:

     Index("my_index", table.c.x, mssql_clustered=True)

which renders the index as ‘CREATE CLUSTERED INDEX my_index ON table
(x)’.

To generate a clustered primary key use:

     Table('my_table', metadata,
           Column('x', ...),
           Column('y', ...),
           PrimaryKeyConstraint("x", "y", mssql_clustered=True))

which will render the table, for example, as:

     CREATE TABLE my_table (x INTEGER NOT NULL, y INTEGER NOT NULL,
                            PRIMARY KEY CLUSTERED (x, y))

Similarly, we can generate a clustered unique constraint using:

     Table('my_table', metadata,
           Column('x', ...),
           Column('y', ...),
           PrimaryKeyConstraint("x"),
           UniqueConstraint("y", mssql_clustered=True),
           )

To explicitly request a non-clustered primary key (for example, when a
separate clustered index is desired), use:

     Table('my_table', metadata,
           Column('x', ...),
           Column('y', ...),
           PrimaryKeyConstraint("x", "y", mssql_clustered=False))

which will render the table, for example, as:

     CREATE TABLE my_table (x INTEGER NOT NULL, y INTEGER NOT NULL,
                            PRIMARY KEY NONCLUSTERED (x, y))

Changed in version 1.1: the ‘mssql_clustered’ option now defaults to
None, rather than False.  ‘mssql_clustered=False’ now explicitly renders
the NONCLUSTERED clause, whereas None omits the CLUSTERED clause
entirely, allowing SQL Server defaults to take effect.

5.1.5.17 MSSQL-Specific Index Options
.....................................

In addition to clustering, the MSSQL dialect supports other special
options for Index.

5.1.5.18 INCLUDE
................

The ‘mssql_include’ option renders INCLUDE(colname) for the given string
names:

     Index("my_index", table.c.x, mssql_include=['y'])

would render the index as ‘CREATE INDEX my_index ON table (x) INCLUDE
(y)’

5.1.5.19 Filtered Indexes
.........................

The ‘mssql_where’ option renders WHERE(condition) for the given string
names:

     Index("my_index", table.c.x, mssql_where=table.c.x > 10)

would render the index as ‘CREATE INDEX my_index ON table (x) WHERE x >
10’.

New in version 1.3.4.

5.1.5.20 Index ordering
.......................

Index ordering is available via functional expressions, such as:

     Index("my_index", table.c.x.desc())

would render the index as ‘CREATE INDEX my_index ON table (x DESC)’

See also
........

See Functional Indexes.

5.1.5.21 Compatibility Levels
.............................

MSSQL supports the notion of setting compatibility levels at the
database level.  This allows, for instance, to run a database that is
compatible with SQL2000 while running on a SQL2005 database server.
‘server_version_info’ will always return the database server version
information (in this case SQL2005) and not the compatibility level
information.  Because of this, if running under a backwards
compatibility mode SQLAlchemy may attempt to use T-SQL statements that
are unable to be parsed by the database server.

5.1.5.22 Triggers
.................

SQLAlchemy by default uses OUTPUT INSERTED to get at newly generated
primary key values via IDENTITY columns or other server side defaults.
MS-SQL does not allow the usage of OUTPUT INSERTED on tables that have
triggers.  To disable the usage of OUTPUT INSERTED on a per-table basis,
specify ‘implicit_returning=False’ for each Table which has
triggers:

     Table('mytable', metadata,
         Column('id', Integer, primary_key=True),
         # ...,
         implicit_returning=False
     )

Declarative form:

     class MyClass(Base):
         # ...
         __table_args__ = {'implicit_returning':False}

This option can also be specified engine-wide using the
‘implicit_returning=False’ argument on create_engine().

5.1.5.23 Rowcount Support / ORM Versioning
..........................................

The SQL Server drivers may have limited ability to return the number of
rows updated from an UPDATE or DELETE statement.

As of this writing, the PyODBC driver is not able to return a rowcount
when OUTPUT INSERTED is used.  This impacts the SQLAlchemy ORM’s
versioning feature in many cases where server-side value generators are
in use in that while the versioning operations can succeed, the ORM
cannot always check that an UPDATE or DELETE statement matched the
number of rows expected, which is how it verifies that the version
identifier matched.  When this condition occurs, a warning will be
emitted but the operation will proceed.

The use of OUTPUT INSERTED can be disabled by setting the
Table.implicit_returning flag to ‘False’ on a particular
Table, which in declarative looks like:

     class MyTable(Base):
         __tablename__ = 'mytable'
         id = Column(Integer, primary_key=True)
         stuff = Column(String(10))
         timestamp = Column(TIMESTAMP(), default=text('DEFAULT'))
         __mapper_args__ = {
             'version_id_col': timestamp,
             'version_id_generator': False,
         }
         __table_args__ = {
             'implicit_returning': False
         }

5.1.5.24 Enabling Snapshot Isolation
....................................

SQL Server has a default transaction isolation mode that locks entire
tables, and causes even mildly concurrent applications to have long held
locks and frequent deadlocks.  Enabling snapshot isolation for the
database as a whole is recommended for modern levels of concurrency
support.  This is accomplished via the following ALTER DATABASE commands
executed at the SQL prompt:

     ALTER DATABASE MyDatabase SET ALLOW_SNAPSHOT_ISOLATION ON

     ALTER DATABASE MyDatabase SET READ_COMMITTED_SNAPSHOT ON

Background on SQL Server snapshot isolation is available at
‘http://msdn.microsoft.com/en-us/library/ms175095.aspx’.

5.1.5.25 SQL Server SQL Constructs
..................................

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See try_cast.(*arg,Create a TRY_CAST expression.
**kw)

 -- Function: sqlalchemy.dialects.mssql.try_cast (*arg, **kw)

     Create a TRY_CAST expression.

     ‘TryCast’ is a subclass of SQLAlchemy’s Cast construct,
     and works in the same way, except that the SQL expression rendered
     is “TRY_CAST” rather than “CAST”:

          from sqlalchemy import select
          from sqlalchemy import Numeric
          from sqlalchemy.dialects.mssql import try_cast

          stmt = select(
              try_cast(product_table.c.unit_price, Numeric(10, 4))
          )

     The above would render:

          SELECT TRY_CAST (product_table.unit_price AS NUMERIC(10, 4))
          FROM product_table

     New in version 1.3.7.

5.1.5.26 SQL Server Data Types
..............................

As with all SQLAlchemy dialects, all UPPERCASE types that are known to
be valid with SQL server are importable from the top level dialect,
whether they originate from sqlalchemy.types or from the
local dialect:

     from sqlalchemy.dialects.mssql import \
         BIGINT, BINARY, BIT, CHAR, DATE, DATETIME, DATETIME2, \
         DATETIMEOFFSET, DECIMAL, FLOAT, IMAGE, INTEGER, JSON, MONEY, \
         NCHAR, NTEXT, NUMERIC, NVARCHAR, REAL, SMALLDATETIME, \
         SMALLINT, SMALLMONEY, SQL_VARIANT, TEXT, TIME, \
         TIMESTAMP, TINYINT, UNIQUEIDENTIFIER, VARBINARY, VARCHAR

Types which are specific to SQL Server, or have SQL Server-specific
construction arguments, are as follows:

Object Name    Description
--------------------------------------------------------------------------------------------------------------

See BIT.

See CHAR.The SQL CHAR type.

See DATETIME2.

See DATETIMEOFFSET.

See IMAGE.

See JSON.MSSQL JSON type.

See MONEY.

See NCHAR.The SQL NCHAR type.

See NTEXT.MSSQL NTEXT type, for variable-length unicode text up to 2^30 characters.

See NVARCHAR.The SQL NVARCHAR type.

See REAL.

See ROWVERSION.Implement the SQL Server ROWVERSION type.

See SMALLDATETIME.

See SMALLMONEY.

See SQL_VARIANT.

See TEXT.The SQL TEXT type.

See TIME.

See TIMESTAMP.Implement the SQL Server TIMESTAMP type.

See TINYINT.

See UNIQUEIDENTIFIER.

See VARCHAR.The SQL VARCHAR type.

See XML.MSSQL XML type.

 -- Class: sqlalchemy.dialects.mssql.BIT

     `Class signature'

     class sqlalchemy.dialects.mssql.BIT. (see
     sqlalchemy.types.TypeEngine)

      -- Method: sqlalchemy.dialects.mssql.BIT..__init__ ()

          `inherited from the' ‘builtins.object.__init__’ `method of'
          ‘builtins.object’

          Initialize self.  See help(type(self)) for accurate signature.

 -- Class: sqlalchemy.dialects.mssql.CHAR (length=None, collation=None,
          convert_unicode=False, unicode_error=None,
          _warn_on_bytestring=False, _expect_unicode=False)

     The SQL CHAR type.

     `Class signature'

     class sqlalchemy.dialects.mssql.CHAR. (see
     sqlalchemy.types.String)

      -- Method: sqlalchemy.dialects.mssql.CHAR..__init__
               (length=None, collation=None, convert_unicode=False,
               unicode_error=None, _warn_on_bytestring=False,
               _expect_unicode=False)

          `inherited from the' ‘sqlalchemy.types.String.__init__’
          `method of' String.

          Create a string-holding type.

          Parameters:

             * ‘length’ – optional, a length for the column for use in
               DDL and CAST expressions.  May be safely omitted if no
               ‘CREATE TABLE’ will be issued.  Certain databases may
               require a ‘length’ for use in DDL, and will raise an
               exception when the ‘CREATE TABLE’ DDL is issued if a
               ‘VARCHAR’ with no length is included.  Whether the value
               is interpreted as bytes or characters is database
               specific.

             * ‘collation’ – Optional, a column-level collation for use
               in DDL and CAST expressions.  Renders using the COLLATE
               keyword supported by SQLite, MySQL, and PostgreSQL. E.g.:

                    >>> from sqlalchemy import cast, select, String
                    >>> print(select(cast('some string', String(collation='utf8'))))
                    SELECT CAST(:param_1 AS VARCHAR COLLATE utf8) AS anon_1

             * ‘convert_unicode’ – When set to ‘True’, the String
               type will assume that input is to be passed as Python
               Unicode objects under Python 2, and results returned as
               Python Unicode objects.  In the rare circumstance that
               the DBAPI does not support Python unicode under Python 2,
               SQLAlchemy will use its own encoder/decoder functionality
               on strings, referring to the value of the
               create_engine.encoding parameter parameter passed
               to create_engine() as the encoding.

               Deprecated since version 1.3: The
               String.convert_unicode parameter is deprecated and
               will be removed in a future release.  All modern DBAPIs
               now support Python Unicode directly and this parameter is
               unnecessary.

               For the extremely rare case that Python Unicode is to be
               encoded/decoded by SQLAlchemy on a backend that `does'
               natively support Python Unicode, the string value
               ‘"force"’ can be passed here which will cause
               SQLAlchemy’s encode/decode services to be used
               unconditionally.

                    Note: SQLAlchemy’s unicode-conversion flags and
                    features only apply to Python 2; in Python 3, all
                    string objects are Unicode objects.  For this
                    reason, as well as the fact that virtually all
                    modern DBAPIs now support Unicode natively even
                    under Python 2, the String.convert_unicode
                    flag is inherently a legacy feature.

                    Note: In the vast majority of cases, the
                    Unicode or UnicodeText datatypes
                    should be used for a Column that expects
                    to store non-ascii data.  These datatypes will
                    ensure that the correct types are used on the
                    database side as well as set up the correct Unicode
                    behaviors under Python 2.

               See also
               ........

               See create_engine.convert_unicode. - see
               Engine.-wide parameter

             * ‘unicode_error’ – Optional, a method to use to handle
               Unicode conversion errors.  Behaves like the ‘errors’
               keyword argument to the standard library’s
               ‘string.decode()’ functions, requires that
               String.convert_unicode is set to ‘"force"’

               Deprecated since version 1.3: The
               String.unicode_errors parameter is deprecated and
               will be removed in a future release.  This parameter is
               unnecessary for modern Python DBAPIs and degrades
               performance significantly.

 -- Class: sqlalchemy.dialects.mssql.DATETIME2 (precision=None, **kw)

     `Class signature'

     class sqlalchemy.dialects.mssql.DATETIME2.
     (‘sqlalchemy.dialects.mssql.base._DateTimeBase’, see
     sqlalchemy.types.DateTime)

      -- Method: sqlalchemy.dialects.mssql.DATETIME2..
               __init__ (precision=None, **kw)

          Initialize self.  See help(type(self)) for accurate signature.

 -- Class: sqlalchemy.dialects.mssql.DATETIMEOFFSET (precision=None,
          **kw)

     `Class signature'

     class sqlalchemy.dialects.mssql.DATETIMEOFFSET.
     (‘sqlalchemy.dialects.mssql.base._DateTimeBase’, see
     sqlalchemy.types.DateTime)

      -- Method: sqlalchemy.dialects.mssql.DATETIMEOFFSET..
               __init__ (precision=None, **kw)

          Initialize self.  See help(type(self)) for accurate signature.

 -- Class: sqlalchemy.dialects.mssql.IMAGE (length=None)

     `Class signature'

     class sqlalchemy.dialects.mssql.IMAGE. (see
     sqlalchemy.types.LargeBinary)

      -- Method: sqlalchemy.dialects.mssql.IMAGE..__init__
               (length=None)

          `inherited from the' ‘sqlalchemy.types.LargeBinary.__init__’
          `method of' LargeBinary.

          Construct a LargeBinary type.

          Parameters: ‘length’ – optional, a length for the column for
          use in DDL statements, for those binary types that accept a
          length, such as the MySQL BLOB type.

 -- Class: sqlalchemy.dialects.mssql.JSON (none_as_null=False)

     MSSQL JSON type.

     MSSQL supports JSON-formatted data as of SQL Server 2016.

     The JSON datatype at the DDL level will represent the
     datatype as ‘NVARCHAR(max)’, but provides for JSON-level comparison
     functions as well as Python coercion behavior.

     JSON is used automatically whenever the base
     JSON datatype is used against a SQL Server backend.

     See also
     ........

     See JSON. - main documentation for the generic
     cross-platform JSON datatype.

     The JSON type supports persistence of JSON values as
     well as the core index operations provided by JSON
     datatype, by adapting the operations to render the ‘JSON_VALUE’ or
     ‘JSON_QUERY’ functions at the database level.

     The SQL Server JSON type necessarily makes use of the
     ‘JSON_QUERY’ and ‘JSON_VALUE’ functions when querying for elements
     of a JSON object.  These two functions have a major restriction in
     that they are `mutually exclusive' based on the type of object to
     be returned.  The ‘JSON_QUERY’ function `only' returns a JSON
     dictionary or list, but not an individual string, numeric, or
     boolean element; the ‘JSON_VALUE’ function `only' returns an
     individual string, numeric, or boolean element.  `both functions
     either return NULL or raise an error if they are not used against
     the correct expected value'.

     To handle this awkward requirement, indexed access rules are as
     follows:

       1. When extracting a sub element from a JSON that is itself a
          JSON dictionary or list, the Comparator.as_json()
          accessor should be used:

               stmt = select(
                   data_table.c.data["some key"].as_json()
               ).where(
                   data_table.c.data["some key"].as_json() == {"sub": "structure"}
               )

       2. When extracting a sub element from a JSON that is a plain
          boolean, string, integer, or float, use the appropriate method
          among Comparator.as_boolean(),
          Comparator.as_string(), Comparator.as_integer(),
          see Comparator.as_float():

               stmt = select(
                   data_table.c.data["some key"].as_string()
               ).where(
                   data_table.c.data["some key"].as_string() == "some string"
               )

     New in version 1.4.

     `Class signature'

     class sqlalchemy.dialects.mssql.JSON. (see
     sqlalchemy.types.JSON)

      -- Method: sqlalchemy.dialects.mssql.JSON..__init__
               (none_as_null=False)

          `inherited from the' ‘sqlalchemy.types.JSON.__init__’ `method
          of' JSON.

          Construct a JSON type.

          Parameters: ‘none_as_null=False’ – if True, persist the value
          ‘None’ as a SQL NULL value, not the JSON encoding of ‘null’.
          Note that when this flag is False, the null()
          construct can still be used to persist a NULL value:

               from sqlalchemy import null
               conn.execute(table.insert(), data=null())

               Note: JSON.none_as_null does `not' apply to
               the values passed to Column.default and
               Column.server_default; a value of ‘None’ passed for
               these parameters means “no default present”.

          See also
          ........

          See JSON.NULL.

 -- Class: sqlalchemy.dialects.mssql.MONEY

     `Class signature'

     class sqlalchemy.dialects.mssql.MONEY. (see
     sqlalchemy.types.TypeEngine)

      -- Method: sqlalchemy.dialects.mssql.MONEY..__init__
               ()

          `inherited from the' ‘builtins.object.__init__’ `method of'
          ‘builtins.object’

          Initialize self.  See help(type(self)) for accurate signature.

 -- Class: sqlalchemy.dialects.mssql.NCHAR (length=None, **kwargs)

     The SQL NCHAR type.

     `Class signature'

     class sqlalchemy.dialects.mssql.NCHAR. (see
     sqlalchemy.types.Unicode)

      -- Method: sqlalchemy.dialects.mssql.NCHAR..__init__
               (length=None, **kwargs)

          `inherited from the' ‘sqlalchemy.types.Unicode.__init__’
          `method of' Unicode.

          Create a Unicode object.

          Parameters are the same as that of String, with the
          exception that ‘convert_unicode’ defaults to ‘True’.

 -- Class: sqlalchemy.dialects.mssql.NTEXT (length=None, **kwargs)

     MSSQL NTEXT type, for variable-length unicode text up to 2^30
     characters.

     `Class signature'

     class sqlalchemy.dialects.mssql.NTEXT. (see
     sqlalchemy.types.UnicodeText)

      -- Method: sqlalchemy.dialects.mssql.NTEXT..__init__
               (length=None, **kwargs)

          `inherited from the' ‘sqlalchemy.types.UnicodeText.__init__’
          `method of' UnicodeText.

          Create a Unicode-converting Text type.

          Parameters are the same as that of TextClause, with
          the exception that ‘convert_unicode’ defaults to ‘True’.

 -- Class: sqlalchemy.dialects.mssql.NVARCHAR (length=None, **kwargs)

     The SQL NVARCHAR type.

     `Class signature'

     class sqlalchemy.dialects.mssql.NVARCHAR. (see
     sqlalchemy.types.Unicode)

      -- Method: sqlalchemy.dialects.mssql.NVARCHAR..
               __init__ (length=None, **kwargs)

          `inherited from the' ‘sqlalchemy.types.Unicode.__init__’
          `method of' Unicode.

          Create a Unicode object.

          Parameters are the same as that of String, with the
          exception that ‘convert_unicode’ defaults to ‘True’.

 -- Class: sqlalchemy.dialects.mssql.REAL (**kw)

     `Class signature'

     class sqlalchemy.dialects.mssql.REAL. (see
     sqlalchemy.types.REAL)

      -- Method: sqlalchemy.dialects.mssql.REAL..__init__
               (**kw)

          Construct a Float.

          Parameters:

             * ‘precision’ – the numeric precision for use in DDL
               ‘CREATE TABLE’.

             * ‘asdecimal’ – the same flag as that of Numeric,
               but defaults to ‘False’.  Note that setting this
               flag to ‘True’ results in floating point conversion.

             * ‘decimal_return_scale’ – Default scale to use when
               converting from floats to Python decimals.  Floating
               point values will typically be much longer due to decimal
               inaccuracy, and most floating point database types don’t
               have a notion of “scale”, so by default the float type
               looks for the first ten decimal places when converting.
               Specifying this value will override that length.  Note
               that the MySQL float types, which do include “scale”,
               will use “scale” as the default for decimal_return_scale,
               if not otherwise specified.

               New in version 0.9.0.

 -- Class: sqlalchemy.dialects.mssql.ROWVERSION (convert_int=False)

     Implement the SQL Server ROWVERSION type.

     The ROWVERSION datatype is a SQL Server synonym for the TIMESTAMP
     datatype, however current SQL Server documentation suggests using
     ROWVERSION for new datatypes going forward.

     The ROWVERSION datatype does `not' reflect (e.g.  introspect) from
     the database as itself; the returned datatype will be
     TIMESTAMP.

     This is a read-only datatype that does not support INSERT of
     values.

     New in version 1.2.

     See also
     ........

     See TIMESTAMP.

     `Class signature'

     class sqlalchemy.dialects.mssql.ROWVERSION.
     (‘sqlalchemy.dialects.mssql.base.TIMESTAMP’)

      -- Method: sqlalchemy.dialects.mssql.ROWVERSION..
               __init__ (convert_int=False)

          `inherited from the'
          ‘sqlalchemy.dialects.mssql.base.TIMESTAMP.__init__’ `method
          of' ‘TIMESTAMP’

          Construct a TIMESTAMP or ROWVERSION type.

          Parameters: ‘convert_int’ – if True, binary integer values
          will be converted to integers on read.

          New in version 1.2.

 -- Class: sqlalchemy.dialects.mssql.SMALLDATETIME (timezone=False)

     `Class signature'

     class sqlalchemy.dialects.mssql.SMALLDATETIME.
     (‘sqlalchemy.dialects.mssql.base._DateTimeBase’, see
     sqlalchemy.types.DateTime)

      -- Method: sqlalchemy.dialects.mssql.SMALLDATETIME..
               __init__ (timezone=False)

          `inherited from the' ‘sqlalchemy.types.DateTime.__init__’
          `method of' DateTime.

          Construct a new DateTime.

          Parameters: ‘timezone’ – boolean.  Indicates that the datetime
          type should enable timezone support, if available on the `base
          date/time-holding type only'.  It is recommended to make use
          of the TIMESTAMP datatype directly when using this
          flag, as some databases include separate generic
          date/time-holding types distinct from the timezone-capable
          TIMESTAMP datatype, such as Oracle.

 -- Class: sqlalchemy.dialects.mssql.SMALLMONEY

     `Class signature'

     class sqlalchemy.dialects.mssql.SMALLMONEY. (see
     sqlalchemy.types.TypeEngine)

      -- Method: sqlalchemy.dialects.mssql.SMALLMONEY..
               __init__ ()

          `inherited from the' ‘builtins.object.__init__’ `method of'
          ‘builtins.object’

          Initialize self.  See help(type(self)) for accurate signature.

 -- Class: sqlalchemy.dialects.mssql.SQL_VARIANT

     `Class signature'

     class sqlalchemy.dialects.mssql.SQL_VARIANT. (see
     sqlalchemy.types.TypeEngine)

      -- Method: sqlalchemy.dialects.mssql.SQL_VARIANT..
               __init__ ()

          `inherited from the' ‘builtins.object.__init__’ `method of'
          ‘builtins.object’

          Initialize self.  See help(type(self)) for accurate signature.

 -- Class: sqlalchemy.dialects.mssql.TEXT (length=None, collation=None,
          convert_unicode=False, unicode_error=None,
          _warn_on_bytestring=False, _expect_unicode=False)

     The SQL TEXT type.

     `Class signature'

     class sqlalchemy.dialects.mssql.TEXT. (see
     sqlalchemy.types.Text)

      -- Method: sqlalchemy.dialects.mssql.TEXT..__init__
               (length=None, collation=None, convert_unicode=False,
               unicode_error=None, _warn_on_bytestring=False,
               _expect_unicode=False)

          `inherited from the' ‘sqlalchemy.types.String.__init__’
          `method of' String.

          Create a string-holding type.

          Parameters:

             * ‘length’ – optional, a length for the column for use in
               DDL and CAST expressions.  May be safely omitted if no
               ‘CREATE TABLE’ will be issued.  Certain databases may
               require a ‘length’ for use in DDL, and will raise an
               exception when the ‘CREATE TABLE’ DDL is issued if a
               ‘VARCHAR’ with no length is included.  Whether the value
               is interpreted as bytes or characters is database
               specific.

             * ‘collation’ – Optional, a column-level collation for use
               in DDL and CAST expressions.  Renders using the COLLATE
               keyword supported by SQLite, MySQL, and PostgreSQL. E.g.:

                    >>> from sqlalchemy import cast, select, String
                    >>> print(select(cast('some string', String(collation='utf8'))))
                    SELECT CAST(:param_1 AS VARCHAR COLLATE utf8) AS anon_1

             * ‘convert_unicode’ – When set to ‘True’, the String
               type will assume that input is to be passed as Python
               Unicode objects under Python 2, and results returned as
               Python Unicode objects.  In the rare circumstance that
               the DBAPI does not support Python unicode under Python 2,
               SQLAlchemy will use its own encoder/decoder functionality
               on strings, referring to the value of the
               create_engine.encoding parameter parameter passed
               to create_engine() as the encoding.

               Deprecated since version 1.3: The
               String.convert_unicode parameter is deprecated and
               will be removed in a future release.  All modern DBAPIs
               now support Python Unicode directly and this parameter is
               unnecessary.

               For the extremely rare case that Python Unicode is to be
               encoded/decoded by SQLAlchemy on a backend that `does'
               natively support Python Unicode, the string value
               ‘"force"’ can be passed here which will cause
               SQLAlchemy’s encode/decode services to be used
               unconditionally.

                    Note: SQLAlchemy’s unicode-conversion flags and
                    features only apply to Python 2; in Python 3, all
                    string objects are Unicode objects.  For this
                    reason, as well as the fact that virtually all
                    modern DBAPIs now support Unicode natively even
                    under Python 2, the String.convert_unicode
                    flag is inherently a legacy feature.

                    Note: In the vast majority of cases, the
                    Unicode or UnicodeText datatypes
                    should be used for a Column that expects
                    to store non-ascii data.  These datatypes will
                    ensure that the correct types are used on the
                    database side as well as set up the correct Unicode
                    behaviors under Python 2.

               See also
               ........

               See create_engine.convert_unicode. - see
               Engine.-wide parameter

             * ‘unicode_error’ – Optional, a method to use to handle
               Unicode conversion errors.  Behaves like the ‘errors’
               keyword argument to the standard library’s
               ‘string.decode()’ functions, requires that
               String.convert_unicode is set to ‘"force"’

               Deprecated since version 1.3: The
               String.unicode_errors parameter is deprecated and
               will be removed in a future release.  This parameter is
               unnecessary for modern Python DBAPIs and degrades
               performance significantly.

 -- Class: sqlalchemy.dialects.mssql.TIME (precision=None, **kwargs)

     `Class signature'

     class sqlalchemy.dialects.mssql.TIME. (see
     sqlalchemy.types.TIME)

      -- Method: sqlalchemy.dialects.mssql.TIME..__init__
               (precision=None, **kwargs)

          Initialize self.  See help(type(self)) for accurate signature.

 -- Class: sqlalchemy.dialects.mssql.TIMESTAMP (convert_int=False)

     Implement the SQL Server TIMESTAMP type.

     Note this is `completely different' than the SQL Standard TIMESTAMP
     type, which is not supported by SQL Server.  It is a read-only
     datatype that does not support INSERT of values.

     New in version 1.2.

     See also
     ........

     See ROWVERSION.

     `Class signature'

     class sqlalchemy.dialects.mssql.TIMESTAMP.
     (‘sqlalchemy.types._Binary’)

      -- Method: sqlalchemy.dialects.mssql.TIMESTAMP..
               __init__ (convert_int=False)

          Construct a TIMESTAMP or ROWVERSION type.

          Parameters: ‘convert_int’ – if True, binary integer values
          will be converted to integers on read.

          New in version 1.2.

 -- Class: sqlalchemy.dialects.mssql.TINYINT

     `Class signature'

     class sqlalchemy.dialects.mssql.TINYINT. (see
     sqlalchemy.types.Integer)

      -- Method: sqlalchemy.dialects.mssql.TINYINT..__init__
               ()

          `inherited from the' ‘builtins.object.__init__’ `method of'
          ‘builtins.object’

          Initialize self.  See help(type(self)) for accurate signature.

 -- Class: sqlalchemy.dialects.mssql.UNIQUEIDENTIFIER

     `Class signature'

     class sqlalchemy.dialects.mssql.UNIQUEIDENTIFIER.
     (see sqlalchemy.types.TypeEngine)

      -- Method: sqlalchemy.dialects.mssql.UNIQUEIDENTIFIER..
               __init__ ()

          `inherited from the' ‘builtins.object.__init__’ `method of'
          ‘builtins.object’

          Initialize self.  See help(type(self)) for accurate signature.

 -- Class: sqlalchemy.dialects.mssql.VARCHAR (length=None,
          collation=None, convert_unicode=False, unicode_error=None,
          _warn_on_bytestring=False, _expect_unicode=False)

     The SQL VARCHAR type.

     `Class signature'

     class sqlalchemy.dialects.mssql.VARCHAR. (see
     sqlalchemy.types.String)

      -- Method: sqlalchemy.dialects.mssql.VARCHAR..__init__
               (length=None, collation=None, convert_unicode=False,
               unicode_error=None, _warn_on_bytestring=False,
               _expect_unicode=False)

          `inherited from the' ‘sqlalchemy.types.String.__init__’
          `method of' String.

          Create a string-holding type.

          Parameters:

             * ‘length’ – optional, a length for the column for use in
               DDL and CAST expressions.  May be safely omitted if no
               ‘CREATE TABLE’ will be issued.  Certain databases may
               require a ‘length’ for use in DDL, and will raise an
               exception when the ‘CREATE TABLE’ DDL is issued if a
               ‘VARCHAR’ with no length is included.  Whether the value
               is interpreted as bytes or characters is database
               specific.

             * ‘collation’ – Optional, a column-level collation for use
               in DDL and CAST expressions.  Renders using the COLLATE
               keyword supported by SQLite, MySQL, and PostgreSQL. E.g.:

                    >>> from sqlalchemy import cast, select, String
                    >>> print(select(cast('some string', String(collation='utf8'))))
                    SELECT CAST(:param_1 AS VARCHAR COLLATE utf8) AS anon_1

             * ‘convert_unicode’ – When set to ‘True’, the String
               type will assume that input is to be passed as Python
               Unicode objects under Python 2, and results returned as
               Python Unicode objects.  In the rare circumstance that
               the DBAPI does not support Python unicode under Python 2,
               SQLAlchemy will use its own encoder/decoder functionality
               on strings, referring to the value of the
               create_engine.encoding parameter parameter passed
               to create_engine() as the encoding.

               Deprecated since version 1.3: The
               String.convert_unicode parameter is deprecated and
               will be removed in a future release.  All modern DBAPIs
               now support Python Unicode directly and this parameter is
               unnecessary.

               For the extremely rare case that Python Unicode is to be
               encoded/decoded by SQLAlchemy on a backend that `does'
               natively support Python Unicode, the string value
               ‘"force"’ can be passed here which will cause
               SQLAlchemy’s encode/decode services to be used
               unconditionally.

                    Note: SQLAlchemy’s unicode-conversion flags and
                    features only apply to Python 2; in Python 3, all
                    string objects are Unicode objects.  For this
                    reason, as well as the fact that virtually all
                    modern DBAPIs now support Unicode natively even
                    under Python 2, the String.convert_unicode
                    flag is inherently a legacy feature.

                    Note: In the vast majority of cases, the
                    Unicode or UnicodeText datatypes
                    should be used for a Column that expects
                    to store non-ascii data.  These datatypes will
                    ensure that the correct types are used on the
                    database side as well as set up the correct Unicode
                    behaviors under Python 2.

               See also
               ........

               See create_engine.convert_unicode. - see
               Engine.-wide parameter

             * ‘unicode_error’ – Optional, a method to use to handle
               Unicode conversion errors.  Behaves like the ‘errors’
               keyword argument to the standard library’s
               ‘string.decode()’ functions, requires that
               String.convert_unicode is set to ‘"force"’

               Deprecated since version 1.3: The
               String.unicode_errors parameter is deprecated and
               will be removed in a future release.  This parameter is
               unnecessary for modern Python DBAPIs and degrades
               performance significantly.

 -- Class: sqlalchemy.dialects.mssql.XML (length=None, collation=None,
          convert_unicode=False, unicode_error=None,
          _warn_on_bytestring=False, _expect_unicode=False)

     MSSQL XML type.

     This is a placeholder type for reflection purposes that does not
     include any Python-side datatype support.  It also does not
     currently support additional arguments, such as “CONTENT”,
     “DOCUMENT”, “xml_schema_collection”.

     New in version 1.1.11.

     `Class signature'

     class sqlalchemy.dialects.mssql.XML. (see
     sqlalchemy.types.Text)

      -- Method: sqlalchemy.dialects.mssql.XML..__init__
               (length=None, collation=None, convert_unicode=False,
               unicode_error=None, _warn_on_bytestring=False,
               _expect_unicode=False)

          `inherited from the' ‘sqlalchemy.types.String.__init__’
          `method of' String.

          Create a string-holding type.

          Parameters:

             * ‘length’ – optional, a length for the column for use in
               DDL and CAST expressions.  May be safely omitted if no
               ‘CREATE TABLE’ will be issued.  Certain databases may
               require a ‘length’ for use in DDL, and will raise an
               exception when the ‘CREATE TABLE’ DDL is issued if a
               ‘VARCHAR’ with no length is included.  Whether the value
               is interpreted as bytes or characters is database
               specific.

             * ‘collation’ – Optional, a column-level collation for use
               in DDL and CAST expressions.  Renders using the COLLATE
               keyword supported by SQLite, MySQL, and PostgreSQL. E.g.:

                    >>> from sqlalchemy import cast, select, String
                    >>> print(select(cast('some string', String(collation='utf8'))))
                    SELECT CAST(:param_1 AS VARCHAR COLLATE utf8) AS anon_1

             * ‘convert_unicode’ – When set to ‘True’, the String
               type will assume that input is to be passed as Python
               Unicode objects under Python 2, and results returned as
               Python Unicode objects.  In the rare circumstance that
               the DBAPI does not support Python unicode under Python 2,
               SQLAlchemy will use its own encoder/decoder functionality
               on strings, referring to the value of the
               create_engine.encoding parameter parameter passed
               to create_engine() as the encoding.

               Deprecated since version 1.3: The
               String.convert_unicode parameter is deprecated and
               will be removed in a future release.  All modern DBAPIs
               now support Python Unicode directly and this parameter is
               unnecessary.

               For the extremely rare case that Python Unicode is to be
               encoded/decoded by SQLAlchemy on a backend that `does'
               natively support Python Unicode, the string value
               ‘"force"’ can be passed here which will cause
               SQLAlchemy’s encode/decode services to be used
               unconditionally.

                    Note: SQLAlchemy’s unicode-conversion flags and
                    features only apply to Python 2; in Python 3, all
                    string objects are Unicode objects.  For this
                    reason, as well as the fact that virtually all
                    modern DBAPIs now support Unicode natively even
                    under Python 2, the String.convert_unicode
                    flag is inherently a legacy feature.

                    Note: In the vast majority of cases, the
                    Unicode or UnicodeText datatypes
                    should be used for a Column that expects
                    to store non-ascii data.  These datatypes will
                    ensure that the correct types are used on the
                    database side as well as set up the correct Unicode
                    behaviors under Python 2.

               See also
               ........

               See create_engine.convert_unicode. - see
               Engine.-wide parameter

             * ‘unicode_error’ – Optional, a method to use to handle
               Unicode conversion errors.  Behaves like the ‘errors’
               keyword argument to the standard library’s
               ‘string.decode()’ functions, requires that
               String.convert_unicode is set to ‘"force"’

               Deprecated since version 1.3: The
               String.unicode_errors parameter is deprecated and
               will be removed in a future release.  This parameter is
               unnecessary for modern Python DBAPIs and degrades
               performance significantly.

5.1.5.27 PyODBC
...............

Support for the Microsoft SQL Server database via the PyODBC driver.

5.1.5.28 DBAPI
..............

Documentation and download information (if applicable) for PyODBC is
available at: ‘http://pypi.python.org/pypi/pyodbc/’

5.1.5.29 Connecting
...................

Connect String:
     mssql+pyodbc://<username>:<password>@<dsnname>

5.1.5.30 Connecting to PyODBC
.............................

The URL here is to be translated to PyODBC connection strings, as
detailed in ConnectionStrings(1).

   ---------- Footnotes ----------

   (1) https://code.google.com/p/pyodbc/wiki/ConnectionStrings

5.1.5.31 DSN Connections
........................

A DSN connection in ODBC means that a pre-existing ODBC datasource is
configured on the client machine.  The application then specifies the
name of this datasource, which encompasses details such as the specific
ODBC driver in use as well as the network address of the database.
Assuming a datasource is configured on the client, a basic DSN-based
connection looks like:

     engine = create_engine("mssql+pyodbc://scott:tiger@some_dsn")

Which above, will pass the following connection string to PyODBC:

     dsn=mydsn;UID=user;PWD=pass

If the username and password are omitted, the DSN form will also add the
‘Trusted_Connection=yes’ directive to the ODBC string.

5.1.5.32 Hostname Connections
.............................

Hostname-based connections are also supported by pyodbc.  These are
often easier to use than a DSN and have the additional advantage that
the specific database name to connect towards may be specified locally
in the URL, rather than it being fixed as part of a datasource
configuration.

When using a hostname connection, the driver name must also be specified
in the query parameters of the URL. As these names usually have spaces
in them, the name must be URL encoded which means using plus signs for
spaces:

     engine = create_engine("mssql+pyodbc://scott:tiger@myhost:port/databasename?driver=SQL+Server+Native+Client+10.0")

Other keywords interpreted by the Pyodbc dialect to be passed to
‘pyodbc.connect()’ in both the DSN and hostname cases include:
‘odbc_autotranslate’, ‘ansi’, ‘unicode_results’, ‘autocommit’,
‘authentication’.  Note that in order for the dialect to recognize these
keywords (including the ‘driver’ keyword above) they must be all
lowercase.  Multiple additional keyword arguments must be separated by
an ampersand (‘&’), not a semicolon:

     engine = create_engine(
         "mssql+pyodbc://scott:tiger@myhost:port/databasename"
         "?driver=ODBC+Driver+17+for+SQL+Server"
         "&authentication=ActiveDirectoryIntegrated"
     )

5.1.5.33 Pass through exact Pyodbc string
.........................................

A PyODBC connection string can also be sent in pyodbc’s format directly,
as specified in the PyODBC documentation(1), using the parameter
‘odbc_connect’.  A URL object can help make this easier:

     from sqlalchemy.engine import URL
     connection_string = "DRIVER={SQL Server Native Client 10.0};SERVER=dagger;DATABASE=test;UID=user;PWD=password"
     connection_url = URL.create("mssql+pyodbc", query={"odbc_connect": connection_string})

     engine = create_engine(connection_url)

   ---------- Footnotes ----------

   (1)
https://github.com/mkleehammer/pyodbc/wiki/Connecting-to-databases

5.1.5.34 Connecting to databases with access tokens
...................................................

Some database servers are set up to only accept access tokens for login.
For example, SQL Server allows the use of Azure Active Directory tokens
to connect to databases.  This requires creating a credential object
using the ‘azure-identity’ library.  More information about the
authentication step can be found in Microsoft’s documentation(1).

After getting an engine, the credentials need to be sent to
‘pyodbc.connect’ each time a connection is requested.  One way to do
this is to set up an event listener on the engine that adds the
credential token to the dialect’s connect call.  This is discussed more
generally in Generating dynamic authentication tokens.  For
SQL Server in particular, this is passed as an ODBC connection attribute
with a data structure described by Microsoft(2).

The following code snippet will create an engine that connects to an
Azure SQL database using Azure credentials:

     import struct
     from sqlalchemy import create_engine, event
     from sqlalchemy.engine.url import URL
     from azure import identity

     SQL_COPT_SS_ACCESS_TOKEN = 1256  # Connection option for access tokens, as defined in msodbcsql.h
     TOKEN_URL = "https://database.windows.net/"  # The token URL for any Azure SQL database

     connection_string = "mssql+pyodbc://@my-server.database.windows.net/myDb?driver=ODBC+Driver+17+for+SQL+Server"

     engine = create_engine(connection_string)

     azure_credentials = identity.DefaultAzureCredential()

     @event.listens_for(engine, "do_connect")
     def provide_token(dialect, conn_rec, cargs, cparams):
         # remove the "Trusted_Connection" parameter that SQLAlchemy adds
         cargs[0] = cargs[0].replace(";Trusted_Connection=Yes", "")

         # create token credential
         raw_token = azure_credentials.get_token(TOKEN_URL).token.encode("utf-16-le")
         token_struct = struct.pack(f"<I{len(raw_token)}s", len(raw_token), token)

         # apply it to keyword arguments
         cparams["attrs_before"] = {SQL_COPT_SS_ACCESS_TOKEN: token_struct}

     Tip: The ‘Trusted_Connection’ token is currently added by the
     SQLAlchemy pyodbc dialect when no username or password is present.
     This needs to be removed per Microsoft’s documentation for Azure
     access tokens(3), stating that a connection string when using an
     access token must not contain ‘UID’, ‘PWD’, ‘Authentication’ or
     ‘Trusted_Connection’ parameters.

   ---------- Footnotes ----------

   (1)
https://docs.microsoft.com/en-us/azure/developer/python/azure-sdk-authenticate?tabs=bash

   (2)
https://docs.microsoft.com/en-us/sql/connect/odbc/using-azure-active-directory#authenticating-with-an-access-token

   (3)
https://docs.microsoft.com/en-us/sql/connect/odbc/using-azure-active-directory#authenticating-with-an-access-token

5.1.5.35 Pyodbc Pooling / connection close behavior
...................................................

PyODBC uses internal pooling(1) by default, which means connections will
be longer lived than they are within SQLAlchemy itself.  As SQLAlchemy
has its own pooling behavior, it is often preferable to disable this
behavior.  This behavior can only be disabled globally at the PyODBC
module level, `before' any connections are made:

     import pyodbc

     pyodbc.pooling = False

     # don't use the engine before pooling is set to False
     engine = create_engine("mssql+pyodbc://user:pass@dsn")

If this variable is left at its default value of ‘True’, `the
application will continue to maintain active database connections', even
when the SQLAlchemy engine itself fully discards a connection or if the
engine is disposed.

See also
........

pooling(2) - in the PyODBC documentation.

   ---------- Footnotes ----------

   (1)
https://github.com/mkleehammer/pyodbc/wiki/The-pyodbc-Module#pooling

   (2)
https://github.com/mkleehammer/pyodbc/wiki/The-pyodbc-Module#pooling

5.1.5.36 Driver / Unicode Support
.................................

PyODBC works best with Microsoft ODBC drivers, particularly in the area
of Unicode support on both Python 2 and Python 3.

Using the FreeTDS ODBC drivers on Linux or OSX with PyODBC is `not'
recommended; there have been historically many Unicode-related issues in
this area, including before Microsoft offered ODBC drivers for Linux and
OSX. Now that Microsoft offers drivers for all platforms, for PyODBC
support these are recommended.  FreeTDS remains relevant for non-ODBC
drivers such as pymssql where it works very well.

5.1.5.37 Rowcount Support
.........................

Pyodbc only has partial support for rowcount.  See the notes at
Rowcount Support / ORM Versioning for important notes when using
ORM versioning.

5.1.5.38 Fast Executemany Mode
..............................

The Pyodbc driver has added support for a “fast executemany” mode of
execution which greatly reduces round trips for a DBAPI ‘executemany()’
call when using Microsoft ODBC drivers, for `limited size batches that
fit in memory'.  The feature is enabled by setting the flag
‘.fast_executemany’ on the DBAPI cursor when an executemany call is to
be used.  The SQLAlchemy pyodbc SQL Server dialect supports setting this
flag automatically when the ‘.fast_executemany’ flag is passed to
create_engine(). ; note that the ODBC driver must be the Microsoft
driver in order to use this flag:

     engine = create_engine(
         "mssql+pyodbc://scott:tiger@mssql2017:1433/test?driver=ODBC+Driver+13+for+SQL+Server",
         fast_executemany=True)

     Warning: The pyodbc fast_executemany mode `buffers all rows in
     memory' and is not compatible with very large batches of data.  A
     future version of SQLAlchemy may support this flag as a
     per-execution option instead.

New in version 1.3.

See also
........

fast executemany(1) - on github

   ---------- Footnotes ----------

   (1)
https://github.com/mkleehammer/pyodbc/wiki/Features-beyond-the-DB-API#fast_executemany

5.1.5.39 Setinputsizes Support
..............................

The pyodbc ‘cursor.setinputsizes()’ method can be used if necessary.  To
enable this hook, pass ‘use_setinputsizes=True’ to
create_engine():

     engine = create_engine("mssql+pyodbc://...", use_setinputsizes=True)

The behavior of the hook can then be customized, as may be necessary
particularly if fast_executemany is in use, via the
DialectEvents.do_setinputsizes() hook.  See that method for usage
examples.

Changed in version 1.4.1: The pyodbc dialects will not use setinputsizes
unless ‘use_setinputsizes=True’ is passed.

5.1.5.40 mxODBC
...............

Support for the Microsoft SQL Server database via the mxODBC driver.

5.1.5.41 DBAPI
..............

Documentation and download information (if applicable) for mxODBC is
available at: ‘http://www.egenix.com/’

5.1.5.42 Connecting
...................

Connect String:
     mssql+mxodbc://<username>:<password>@<dsnname>

Deprecated since version 1.4: The mxODBC DBAPI is deprecated and will be
removed in a future version.  Please use one of the supported DBAPIs to
connect to mssql.

5.1.5.43 Execution Modes
........................

mxODBC features two styles of statement execution, using the
‘cursor.execute()’ and ‘cursor.executedirect()’ methods (the second
being an extension to the DBAPI specification).  The former makes use of
a particular API call specific to the SQL Server Native Client ODBC
driver known SQLDescribeParam, while the latter does not.

mxODBC apparently only makes repeated use of a single prepared statement
when SQLDescribeParam is used.  The advantage to prepared statement
reuse is one of performance.  The disadvantage is that SQLDescribeParam
has a limited set of scenarios in which bind parameters are understood,
including that they cannot be placed within the argument lists of
function calls, anywhere outside the FROM, or even within subqueries
within the FROM clause - making the usage of bind parameters within
SELECT statements impossible for all but the most simplistic statements.

For this reason, the mxODBC dialect uses the “native” mode by default
only for INSERT, UPDATE, and DELETE statements, and uses the escaped
string mode for all other statements.

This behavior can be controlled via
Executable.execution_options() using the ‘native_odbc_execute’
flag with a value of ‘True’ or ‘False’, where a value of ‘True’ will
unconditionally use native bind parameters and a value of ‘False’ will
unconditionally use string-escaped parameters.

5.1.5.44 pymssql
................

Support for the Microsoft SQL Server database via the pymssql driver.

5.1.5.45 Connecting
...................

Connect String:
     mssql+pymssql://<username>:<password>@<freetds_name>/?charset=utf8

pymssql is a Python module that provides a Python DBAPI interface around
FreeTDS(1).

     Note: pymssql is currently not included in SQLAlchemy’s continuous
     integration (CI) testing.

Modern versions of this driver worked very well with SQL Server and
FreeTDS from Linux and were highly recommended.  However, pymssql is
currently unmaintained and has fallen behind the progress of the
Microsoft ODBC driver in its support for newer features of SQL Server.
The latest official release of pymssql at the time of this document is
version 2.1.4 (August, 2018) and it lacks support for:

  1. table-valued parameters (TVPs),

  2. ‘datetimeoffset’ columns using timezone-aware ‘datetime’ objects
     (values are sent and retrieved as strings), and

  3. encrypted connections (e.g., to Azure SQL), when pymssql is
     installed from the pre-built wheels.  Support for encrypted
     connections requires building pymssql from source, which can be a
     nuisance, especially under Windows.

The above features are all supported by mssql+pyodbc when using
Microsoft’s ODBC Driver for SQL Server (msodbcsql), which is now
available for Windows, (several flavors of) Linux, and macOS.

   ---------- Footnotes ----------

   (1) http://www.freetds.org/

5.1.6 Support Levels for Included Dialects
------------------------------------------

The following table summarizes the support level for each included
dialect.  `Supported database versions for included dialects'

Database                      Fully tested in CI.See Normal support.  See Best effort.

------------------------------------------------------------------------------------------------------------------------

`Microsoft SQL Server'        2017                          2012+                         2005+

`MySQL / MariaDB'             5.6, 5.7, 8.0 / 10.4, 10.5    5.6+ / 10+                    5.0.2+ / 5.0.2+

`Oracle'                      11.2, 18c                     11+                           8+

`PostgreSQL'                  9.6, 10, 11, 12               9.6+                          8+

`SQLite'                      3.21, 3.28+                   3.12+                         3.7.16+

5.1.7 Support Definitions
-------------------------

Fully tested in CI

     `Fully tested in CI' indicates a version that is tested in the
     sqlalchemy CI system and passes all the tests in the test suite.

Normal support

     `Normal support' indicates that most features should work, but not
     all versions are tested in the ci configuration so there may be
     some not supported edge cases.  We will try to fix issues that
     affect these versions.

Best effort

     `Best effort' indicates that we try to support basic features on
     them, but most likely there will be unsupported features or errors
     in some use cases.  Pull requests with associated issues may be
     accepted to continue supporting older versions, which are reviewed
     on a case-by-case basis.

5.2 Deprecated, no longer supported dialects
============================================

The following dialects have implementations within SQLAlchemy, but they
are not part of continuous integration testing nor are they actively
developed.  These dialects are deprecated and will be removed in future
major releases.

5.2.1 Firebird
--------------

Support for the Firebird database.

The following table summarizes current support levels for database
release versions.

5.2.1.1 DBAPI Support
.....................

The following dialect/DBAPI options are available.  Please refer to
individual DBAPI sections for connect information.

   * fdb.

   * kinterbasdb.

     Note: The Firebird dialect within SQLAlchemy `is not currently
     supported'.  It is not tested within continuous integration and is
     likely to have many issues and caveats not currently handled.
     Consider using the external dialect(1) instead.

Deprecated since version 1.4: The internal Firebird dialect is
deprecated and will be removed in a future version.  Use the external
dialect.

   ---------- Footnotes ----------

   (1) https://github.com/pauldex/sqlalchemy-firebird

5.2.1.2 Firebird Dialects
.........................

Firebird offers two distinct dialects(1) (not to be confused with a
SQLAlchemy ‘Dialect’):

dialect 1

     This is the old syntax and behaviour, inherited from Interbase
     pre-6.0.

dialect 3

     This is the newer and supported syntax, introduced in Interbase
     6.0.

The SQLAlchemy Firebird dialect detects these versions and adjusts its
representation of SQL accordingly.  However, support for dialect 1 is
not well tested and probably has incompatibilities.

   ---------- Footnotes ----------

   (1) http://mc-computing.com/Databases/Firebird/SQL_Dialect.html

5.2.1.3 Locking Behavior
........................

Firebird locks tables aggressively.  For this reason, a DROP TABLE may
hang until other transactions are released.  SQLAlchemy does its best to
release transactions as quickly as possible.  The most common cause of
hanging transactions is a non-fully consumed result set, i.e.:

     result = engine.execute(text("select * from table"))
     row = result.fetchone()
     return

Where above, the ‘CursorResult’ has not been fully consumed.  The
connection will be returned to the pool and the transactional state
rolled back once the Python garbage collector reclaims the objects which
hold onto the connection, which often occurs asynchronously.  The above
use case can be alleviated by calling ‘first()’ on the ‘CursorResult’
which will fetch the first row and immediately close all remaining
cursor/connection resources.

5.2.1.4 RETURNING support
.........................

Firebird 2.0 supports returning a result set from inserts, and 2.1
extends that to deletes and updates.  This is generically exposed by the
SQLAlchemy ‘returning()’ method, such as:

     # INSERT..RETURNING
     result = table.insert().returning(table.c.col1, table.c.col2).\
                    values(name='foo')
     print(result.fetchall())

     # UPDATE..RETURNING
     raises = empl.update().returning(empl.c.id, empl.c.salary).\
                   where(empl.c.sales>100).\
                   values(dict(salary=empl.c.salary * 1.1))
     print(raises.fetchall())

5.2.1.5 fdb
...........

Support for the Firebird database via the fdb driver.  fdb is a
kinterbasdb compatible DBAPI for Firebird.

Changed in version 0.9: - The fdb dialect is now the default dialect
under the ‘firebird://’ URL space, as ‘fdb’ is now the official Python
driver for Firebird.

5.2.1.6 DBAPI
.............

Documentation and download information (if applicable) for fdb is
available at: ‘http://pypi.python.org/pypi/fdb/’

5.2.1.7 Connecting
..................

Connect String:
     firebird+fdb://user:password@host:port/path/to/db[?key=value&key=value...]

5.2.1.8 Arguments
.................

The ‘fdb’ dialect is based on the
sqlalchemy.dialects.firebird.kinterbasdb dialect, however does not
accept every argument that Kinterbasdb does.

   * ‘enable_rowcount’ - True by default, setting this to False disables
     the usage of “cursor.rowcount” with the Kinterbasdb dialect, which
     SQLAlchemy ordinarily calls upon automatically after any UPDATE or
     DELETE statement.  When disabled, SQLAlchemy’s CursorResult will
     return -1 for result.rowcount.  The rationale here is that
     Kinterbasdb requires a second round trip to the database when
     .rowcount is called - since SQLA’s resultproxy automatically closes
     the cursor after a non-result-returning statement, rowcount must be
     called, if at all, before the result object is returned.
     Additionally, cursor.rowcount may not return correct results with
     older versions of Firebird, and setting this flag to False will
     also cause the SQLAlchemy ORM to ignore its usage.  The behavior
     can also be controlled on a per-execution basis using the
     ‘enable_rowcount’ option with Connection.execution_options():

          conn = engine.connect().execution_options(enable_rowcount=True)
          r = conn.execute(stmt)
          print(r.rowcount)

   * ‘retaining’ - False by default.  Setting this to True will pass the
     ‘retaining=True’ keyword argument to the ‘.commit()’ and
     ‘.rollback()’ methods of the DBAPI connection, which can improve
     performance in some situations, but apparently with significant
     caveats.  Please read the fdb and/or kinterbasdb DBAPI
     documentation in order to understand the implications of this flag.

     Changed in version 0.9.0: - the ‘retaining’ flag defaults to
     ‘False’.  In 0.8 it defaulted to ‘True’.

     See also
     ........

     ‘http://pythonhosted.org/fdb/usage-guide.html#retaining-transactions’
     - information on the “retaining” flag.

5.2.1.9 kinterbasdb
...................

Support for the Firebird database via the kinterbasdb driver.

5.2.1.10 DBAPI
..............

Documentation and download information (if applicable) for kinterbasdb
is available at: ‘http://firebirdsql.org/index.php?op=devel&sub=python’

5.2.1.11 Connecting
...................

Connect String:
     firebird+kinterbasdb://user:password@host:port/path/to/db[?key=value&key=value...]

5.2.1.12 Arguments
..................

The Kinterbasdb backend accepts the ‘enable_rowcount’ and ‘retaining’
arguments accepted by the sqlalchemy.dialects.firebird.fdb
dialect.  In addition, it also accepts the following:

   * ‘type_conv’ - select the kind of mapping done on the types: by
     default SQLAlchemy uses 200 with Unicode, datetime and decimal
     support.  See the linked documents below for further information.

   * ‘concurrency_level’ - set the backend policy with regards to
     threading issues: by default SQLAlchemy uses policy 1.  See the
     linked documents below for further information.

See also
........

‘http://sourceforge.net/projects/kinterbasdb’

‘http://kinterbasdb.sourceforge.net/dist_docs/usage.html#adv_param_conv_dynamic_type_translation’

‘http://kinterbasdb.sourceforge.net/dist_docs/usage.html#special_issue_concurrency’

5.2.2 Sybase
------------

Support for the Sybase database.

The following table summarizes current support levels for database
release versions.

5.2.2.1 DBAPI Support
.....................

The following dialect/DBAPI options are available.  Please refer to
individual DBAPI sections for connect information.

   * Python-Sybase.

   * PyODBC.

   * mxODBC.

     Note: The Sybase dialect within SQLAlchemy `is not currently
     supported'.  It is not tested within continuous integration and is
     likely to have many issues and caveats not currently handled.
     Consider using the external dialect(1) instead.

Deprecated since version 1.4: The internal Sybase dialect is deprecated
and will be removed in a future version.  Use the external dialect.

   ---------- Footnotes ----------

   (1) https://github.com/gordthompson/sqlalchemy-sybase

5.2.2.2 python-sybase
.....................

Support for the Sybase database via the Python-Sybase driver.

5.2.2.3 DBAPI
.............

Documentation and download information (if applicable) for Python-Sybase
is available at: ‘http://python-sybase.sourceforge.net/’

5.2.2.4 Connecting
..................

Connect String:
     sybase+pysybase://<username>:<password>@<dsn>/[database name]

5.2.2.5 Unicode Support
.......................

The python-sybase driver does not appear to support non-ASCII strings of
any kind at this time.

5.2.2.6 pyodbc
..............

Support for the Sybase database via the PyODBC driver.

5.2.2.7 DBAPI
.............

Documentation and download information (if applicable) for PyODBC is
available at: ‘http://pypi.python.org/pypi/pyodbc/’

5.2.2.8 Connecting
..................

Connect String:
     sybase+pyodbc://<username>:<password>@<dsnname>[/<database>]

5.2.2.9 Unicode Support
.......................

The pyodbc driver currently supports usage of these Sybase types with
Unicode or multibyte strings:

     CHAR
     NCHAR
     NVARCHAR
     TEXT
     VARCHAR

Currently `not' supported are:

     UNICHAR
     UNITEXT
     UNIVARCHAR

5.2.2.10 mxodbc
...............

Support for the Sybase database via the mxODBC driver.

5.2.2.11 DBAPI
..............

Documentation and download information (if applicable) for mxODBC is
available at: ‘http://www.egenix.com/’

5.2.2.12 Connecting
...................

Connect String:
     sybase+mxodbc://<username>:<password>@<dsnname>

     Note: This dialect is a stub only and is likely non functional at
     this time.

5.3 External Dialects
=====================

Currently maintained external dialect projects for SQLAlchemy include:

Database                                    Dialect

----------------------------------------------------------------------------------------

Amazon Redshift (via psycopg2)              sqlalchemy-redshift(1)

Apache Drill                                sqlalchemy-drill(2)

Apache Druid                                pydruid(3)

Apache Hive and Presto                      PyHive(4)

Apache Solr                                 sqlalchemy-solr(5)

CockroachDB                                 sqlalchemy-cockroachdb(6)

CrateDB                                     crate-python(7)

EXASolution                                 sqlalchemy_exasol(8)

Elasticsearch (readonly)                    elasticsearch-dbapi(9)

Firebird                                    sqlalchemy-firebird(10)

Google BigQuery                             pybigquery(11)

Google Sheets                               gsheets(12)

IBM DB2 and Informix                        ibm-db-sa(13)

Microsoft Access (via pyodbc)               sqlalchemy-access(14)

Microsoft SQL Server (via python-tds)       sqlalchemy-tds(15)

Microsoft SQL Server (via turbodbc)         sqlalchemy-turbodbc(16)

MonetDB                                     sqlalchemy-monetdb(17)

SAP Hana                                    sqlalchemy-hana(18)

SAP Sybase SQL Anywhere                     sqlalchemy-sqlany(19)

Snowflake                                   snowflake-sqlalchemy(20)

Teradata Vantage                            teradatasqlalchemy(21)

   ---------- Footnotes ----------

   (1) https://pypi.python.org/pypi/sqlalchemy-redshift

   (2) https://github.com/JohnOmernik/sqlalchemy-drill

   (3) https://github.com/druid-io/pydruid

   (4) https://github.com/dropbox/PyHive#sqlalchemy

   (5) https://github.com/aadel/sqlalchemy-solr

   (6) https://github.com/cockroachdb/sqlalchemy-cockroachdb

   (7) https://github.com/crate/crate-python

   (8) https://github.com/blue-yonder/sqlalchemy_exasol

   (9) https://github.com/preset-io/elasticsearch-dbapi/

   (10) https://github.com/pauldex/sqlalchemy-firebird

   (11) https://github.com/mxmzdlv/pybigquery/

   (12) https://github.com/betodealmeida/gsheets-db-api

   (13) https://pypi.org/project/ibm-db-sa/

   (14) https://pypi.org/project/sqlalchemy-access/

   (15) https://github.com/m32/sqlalchemy-tds

   (16) https://pypi.org/project/sqlalchemy-turbodbc/

   (17) https://github.com/gijzelaerr/sqlalchemy-monetdb

   (18) https://github.com/SAP/sqlalchemy-hana

   (19) https://github.com/sqlanywhere/sqlalchemy-sqlany

   (20) https://github.com/snowflakedb/snowflake-sqlalchemy

   (21) https://pypi.org/project/teradatasqlalchemy/

6 Frequently Asked Questions
****************************

The Frequently Asked Questions section is a growing collection of
commonly observed questions to well-known issues.

6.1 Connections / Engines
=========================

6.1.1 How do I configure logging?
---------------------------------

See Configuring Logging.

6.1.2 How do I pool database connections? Are my connections pooled?
--------------------------------------------------------------------

SQLAlchemy performs application-level connection pooling automatically
in most cases.  With the exception of SQLite, a Engine
object refers to a QueuePool as a source of connectivity.

For more detail, see Engine Configuration and
Connection Pooling.

6.1.3 How do I pass custom connect arguments to my database API?
----------------------------------------------------------------

The create_engine() call accepts additional arguments either
directly via the ‘connect_args’ keyword argument:

     e = create_engine("mysql://scott:tiger@localhost/test",
                         connect_args={"encoding": "utf8"})

Or for basic string and integer arguments, they can usually be specified
in the query string of the URL:

     e = create_engine("mysql://scott:tiger@localhost/test?encoding=utf8")

See also
........

See Custom DBAPI connect() arguments / on-connect routines.

6.1.4 “MySQL Server has gone away”
----------------------------------

The primary cause of this error is that the MySQL connection has timed
out and has been closed by the server.  The MySQL server closes
connections which have been idle a period of time which defaults to
eight hours.  To accommodate this, the immediate setting is to enable
the create_engine.pool_recycle setting, which will ensure
that a connection which is older than a set amount of seconds will be
discarded and replaced with a new connection when it is next checked
out.

For the more general case of accommodating database restarts and other
temporary loss of connectivity due to network issues, connections that
are in the pool may be recycled in response to more generalized
disconnect detection techniques.  The section Dealing with Disconnects
provides background on both “pessimistic” (e.g.
pre-ping) and “optimistic” (e.g.  graceful recovery) techniques.  Modern
SQLAlchemy tends to favor the “pessimistic” approach.

See also
........

See Dealing with Disconnects.

6.1.5 “Commands out of sync; you can’t run this command now” / “This result object does not return rows. It has been closed automatically”
------------------------------------------------------------------------------------------------------------------------------------------

The MySQL drivers have a fairly wide class of failure modes whereby the
state of the connection to the server is in an invalid state.
Typically, when the connection is used again, one of these two error
messages will occur.  The reason is because the state of the server has
been changed to one in which the client library does not expect, such
that when the client library emits a new statement on the connection,
the server does not respond as expected.

In SQLAlchemy, because database connections are pooled, the issue of the
messaging being out of sync on a connection becomes more important,
since when an operation fails, if the connection itself is in an
unusable state, if it goes back into the connection pool, it will
malfunction when checked out again.  The mitigation for this issue is
that the connection is `invalidated' when such a failure mode occurs so
that the underlying database connection to MySQL is discarded.  This
invalidation occurs automatically for many known failure modes and can
also be called explicitly via the Connection.invalidate()
method.

There is also a second class of failure modes within this category where
a context manager such as ‘with session.begin_nested():’ wants to “roll
back” the transaction when an error occurs; however within some failure
modes of the connection, the rollback itself (which can also be a
RELEASE SAVEPOINT operation) also fails, causing misleading stack
traces.

Originally, the cause of this error used to be fairly simple, it meant
that a multithreaded program was invoking commands on a single
connection from more than one thread.  This applied to the original
“MySQLdb” native-C driver that was pretty much the only driver in use.
However, with the introduction of pure Python drivers like PyMySQL and
MySQL-connector-Python, as well as increased use of tools such as
gevent/eventlet, multiprocessing (often with Celery), and others, there
is a whole series of factors that has been known to cause this problem,
some of which have been improved across SQLAlchemy versions but others
which are unavoidable:

   * `Sharing a connection among threads' - This is the original reason
     these kinds of errors occurred.  A program used the same connection
     in two or more threads at the same time, meaning multiple sets of
     messages got mixed up on the connection, putting the server-side
     session into a state that the client no longer knows how to
     interpret.  However, other causes are usually more likely today.

   * `Sharing the filehandle for the connection among processes' - This
     usually occurs when a program uses ‘os.fork()’ to spawn a new
     process, and a TCP connection that is present in th parent process
     gets shared into one or more child processes.  As multiple
     processes are now emitting messages to essentially the same
     filehandle, the server receives interleaved messages and breaks the
     state of the connection.

     This scenario can occur very easily if a program uses Python’s
     “multiprocessing” module and makes use of an Engine
     that was created in the parent process.  It’s common that
     “multiprocessing” is in use when using tools like Celery.  The
     correct approach should be either that a new Engine is
     produced when a child process first starts, discarding any
     Engine that came down from the parent process; or, the
     Engine that’s inherited from the parent process can have it’s
     internal pool of connections disposed by calling
     Engine.dispose().

   * `Greenlet Monkeypatching w/ Exits' - When using a library like
     gevent or eventlet that monkeypatches the Python networking API,
     libraries like PyMySQL are now working in an asynchronous mode of
     operation, even though they are not developed explicitly against
     this model.  A common issue is that a greenthread is interrupted,
     often due to timeout logic in the application.  This results in the
     ‘GreenletExit’ exception being raised, and the pure-Python MySQL
     driver is interrupted from its work, which may have been that it
     was receiving a response from the server or preparing to otherwise
     reset the state of the connection.  When the exception cuts all
     that work short, the conversation between client and server is now
     out of sync and subsequent usage of the connection may fail.
     SQLAlchemy as of version 1.1.0 knows how to guard against this, as
     if a database operation is interrupted by a so-called “exit
     exception”, which includes ‘GreenletExit’ and any other subclass of
     Python ‘BaseException’ that is not also a subclass of ‘Exception’,
     the connection is invalidated.

   * `Rollbacks / SAVEPOINT releases failing' - Some classes of error
     cause the connection to be unusable within the context of a
     transaction, as well as when operating in a “SAVEPOINT” block.  In
     these cases, the failure on the connection has rendered any
     SAVEPOINT as no longer existing, yet when SQLAlchemy, or the
     application, attempts to “roll back” this savepoint, the “RELEASE
     SAVEPOINT” operation fails, typically with a message like
     “savepoint does not exist”.  In this case, under Python 3 there
     will be a chain of exceptions output, where the ultimate “cause” of
     the error will be displayed as well.  Under Python 2, there are no
     “chained” exceptions, however recent versions of SQLAlchemy will
     attempt to emit a warning illustrating the original failure cause,
     while still throwing the immediate error which is the failure of
     the ROLLBACK.

6.1.6 How Do I “Retry” a Statement Execution Automatically?
-----------------------------------------------------------

The documentation section Dealing with Disconnects
discusses the strategies available for pooled connections that have been
disconnected since the last time a particular connection was checked
out.  The most modern feature in this regard is the
create_engine.pre_ping parameter, which allows that a “ping” is
emitted on a database connection when it’s retrieved from the pool,
reconnecting if the current connection has been disconnected.

It’s important to note that this “ping” is only emitted `before' the
connection is actually used for an operation.  Once the connection is
delivered to the caller, per the Python DBAPI specification it is now
subject to an `autobegin' operation, which means it will automatically
BEGIN a new transaction when it is first used that remains in effect for
subsequent statements, until the DBAPI-level ‘connection.commit()’ or
‘connection.rollback()’ method is invoked.

As discussed at Library Level (e.g. emulated) Autocommit,
there is a library level “autocommit” feature which is deprecated in 1.4
that causes DML and DDL executions to commit automatically after
individual statements are executed; however, outside of this deprecated
case, modern use of SQLAlchemy works with this transaction in all cases
and does not commit any data unless explicitly told to commit.

At the ORM level, a similar situation where the ORM Session
object also presents a legacy “autocommit” operation is present; however
even if this legacy mode of operation is used, the Session
still makes use of transactions internally, particularly within the
Session.flush() process.

The implication that this has for the notion of “retrying” a statement
is that in the default case, when a connection is lost, `the entire
transaction is lost'.  There is no useful way that the database can
“reconnect and retry” and continue where it left off, since data is
already lost.  For this reason, SQLAlchemy does not have a transparent
“reconnection” feature that works mid-transaction, for the case when the
database connection has disconnected while being used.  The canonical
approach to dealing with mid-operation disconnects is to `retry the
entire operation from the start of the transaction', often by using a
Python “retry” decorator, or to otherwise architect the application in
such a way that it is resilient against transactions that are dropped.

There is also the notion of extensions that can keep track of all of the
statements that have proceeded within a transaction and then replay them
all in a new transaction in order to approximate a “retry” operation.
SQLAlchemy’s event system does allow such a system to be
constructed, however this approach is also not generally useful as there
is no way to guarantee that those DML statements will be working against
the same state, as once a transaction has ended the state of the
database in a new transaction may be totally different.  Architecting
“retry” explicitly into the application at the points at which
transactional operations begin and commit remains the better approach
since the application-level transactional methods are the ones that know
best how to re-run their steps.

Otherwise, if SQLAlchemy were to provide a feature that transparently
and silently “reconnected” a connection mid-transaction, the effect
would be that data is silently lost.  By trying to hide the problem,
SQLAlchemy would make the situation much worse.

However, if we are `not' using transactions, then there are more options
available, as the next section describes.

6.1.6.1 Using DBAPI Autocommit Allows for a Readonly Version of Transparent Reconnect
.....................................................................................

With the rationale for not having a transparent reconnection mechanism
stated, the preceding section rests upon the assumption that the
application is in fact using DBAPI-level transactions.  As most DBAPIs
now offer native “autocommit” settings, we can make use of
these features to provide a limited form of transparent reconnect for
`read only, autocommit only operations'.  A transparent statement retry
may be applied to the ‘cursor.execute()’ method of the DBAPI, however it
is still not safe to apply to the ‘cursor.executemany()’ method of the
DBAPI, as the statement may have consumed any portion of the arguments
given.

     Warning: The following recipe should `not' be used for operations
     that write data.  Users should carefully read and understand how
     the recipe works and test failure modes very carefully against the
     specifically targeted DBAPI driver before making production use of
     this recipe.  The retry mechanism does not guarantee prevention of
     disconnection errors in all cases.

A simple retry mechanism may be applied to the DBAPI level
‘cursor.execute()’ method by making use of the
DialectEvents.do_execute() and
DialectEvents.do_execute_no_params() hooks, which will be able to
intercept disconnections during statement executions.  It will `not'
intercept connection failures during result set fetch operations, for
those DBAPIs that don’t fully buffer result sets.  The recipe requires
that the database support DBAPI level autocommit and is `not guaranteed'
for particular backends.  A single function ‘reconnecting_engine()’ is
presented which applies the event hooks to a given Engine
object, returning an always-autocommit version that enables DBAPI-level
autocommit.  A connection will transparently reconnect for
single-parameter and no-parameter statement executions:

     import time

     from sqlalchemy import event

     def reconnecting_engine(engine, num_retries, retry_interval):
         def _run_with_retries(fn, context, cursor, statement, *arg, **kw):
             for retry in range(num_retries + 1):
                 try:
                     fn(cursor, statement, context=context, *arg)
                 except engine.dialect.dbapi.Error as raw_dbapi_err:
                     connection = context.root_connection
                     if engine.dialect.is_disconnect(
                         raw_dbapi_err, connection, cursor
                     ):
                         if retry > num_retries:
                             raise
                         engine.logger.error(
                             "disconnection error, retrying operation",
                             exc_info=True,
                         )
                         connection.invalidate()

                         # use SQLAlchemy 2.0 API if available
                         if hasattr(connection, "rollback"):
                             connection.rollback()
                         else:
                             trans = connection.get_transaction()
                             if trans:
                                 trans.rollback()

                         time.sleep(retry_interval)
                         context.cursor = cursor = connection.connection.cursor()
                     else:
                         raise
                 else:
                     return True

         e = engine.execution_options(isolation_level="AUTOCOMMIT")

         @event.listens_for(e, "do_execute_no_params")
         def do_execute_no_params(cursor, statement, context):
             return _run_with_retries(
                 context.dialect.do_execute_no_params, context, cursor, statement
             )

         @event.listens_for(e, "do_execute")
         def do_execute(cursor, statement, parameters, context):
             return _run_with_retries(
                 context.dialect.do_execute, context, cursor, statement, parameters
             )

         return e

Given the above recipe, a reconnection mid-transaction may be
demonstrated using the following proof of concept script.  Once run, it
will emit a ‘SELECT 1’ statement to the database every five seconds:

     from sqlalchemy import create_engine
     from sqlalchemy import select

     if __name__ == "__main__":

         engine = create_engine("mysql://scott:tiger@localhost/test", echo_pool=True)

         def do_a_thing(engine):
             with engine.begin() as conn:
                 while True:
                     print("ping: %s" % conn.execute(select([1])).scalar())
                     time.sleep(5)

         e = reconnecting_engine(
             create_engine(
                 "mysql://scott:tiger@localhost/test", echo_pool=True
             ),
             num_retries=5,
             retry_interval=2,
         )

         do_a_thing(e)

Restart the database while the script runs to demonstrate the
transparent reconnect operation:

     $ python reconnect_test.py
     ping: 1
     ping: 1
     disconnection error, retrying operation
     Traceback (most recent call last):
       ...
     MySQLdb._exceptions.OperationalError: (2006, 'MySQL server has gone away')
     2020-10-19 16:16:22,624 INFO sqlalchemy.pool.impl.QueuePool Invalidate connection <_mysql.connection open to 'localhost' at 0xf59240>
     ping: 1
     ping: 1
     ...

The above recipe is tested for SQLAlchemy 1.4.

6.1.7 Why does SQLAlchemy issue so many ROLLBACKs?
--------------------------------------------------

SQLAlchemy currently assumes DBAPI connections are in “non-autocommit”
mode - this is the default behavior of the Python database API, meaning
it must be assumed that a transaction is always in progress.  The
connection pool issues ‘connection.rollback()’ when a connection is
returned.  This is so that any transactional resources remaining on the
connection are released.  On a database like PostgreSQL or MSSQL where
table resources are aggressively locked, this is critical so that rows
and tables don’t remain locked within connections that are no longer in
use.  An application can otherwise hang.  It’s not just for locks,
however, and is equally critical on any database that has any kind of
transaction isolation, including MySQL with InnoDB. Any connection that
is still inside an old transaction will return stale data, if that data
was already queried on that connection within isolation.  For background
on why you might see stale data even on MySQL, see
‘http://dev.mysql.com/doc/refman/5.1/en/innodb-transaction-model.html’

6.1.7.1 I’m on MyISAM - how do I turn it off?
.............................................

The behavior of the connection pool’s connection return behavior can be
configured using ‘reset_on_return’:

     from sqlalchemy import create_engine
     from sqlalchemy.pool import QueuePool

     engine = create_engine('mysql://scott:tiger@localhost/myisam_database', pool=QueuePool(reset_on_return=False))

6.1.7.2 I’m on SQL Server - how do I turn those ROLLBACKs into COMMITs?
.......................................................................

‘reset_on_return’ accepts the values ‘commit’, ‘rollback’ in addition to
‘True’, ‘False’, and ‘None’.  Setting to ‘commit’ will cause a COMMIT as
any connection is returned to the pool:

     engine = create_engine('mssql://scott:tiger@mydsn', pool=QueuePool(reset_on_return='commit'))

6.1.8 I am using multiple connections with a SQLite database (typically to test transaction operation), and my test program is not working!
-------------------------------------------------------------------------------------------------------------------------------------------

If using a SQLite ‘:memory:’ database, or a version of SQLAlchemy prior
to version 0.7, the default connection pool is the
SingletonThreadPool, which maintains exactly one SQLite connection
per thread.  So two connections in use in the same thread will actually
be the same SQLite connection.  Make sure you’re not using a :memory:
database and use NullPool, which is the default for
non-memory databases in current SQLAlchemy versions.

See also
........

See Threading/Pooling Behavior. - info on PySQLite’s behavior.

6.1.9 How do I get at the raw DBAPI connection when using an Engine?
--------------------------------------------------------------------

With a regular SA engine-level Connection, you can get at a pool-proxied
version of the DBAPI connection via the Connection.connection
attribute on Connection, and for the really-real DBAPI
connection you can call the ‘ConnectionFairy.connection’ attribute on
that - but there should never be any need to access the non-pool-proxied
DBAPI connection, as all methods are proxied through:

     engine = create_engine(...)
     conn = engine.connect()
     conn.connection.<do DBAPI things>
     cursor = conn.connection.cursor(<DBAPI specific arguments..>)

You must ensure that you revert any isolation level settings or other
operation-specific settings on the connection back to normal before
returning it to the pool.

As an alternative to reverting settings, you can call the
Connection.detach() method on either Connection or
the proxied connection, which will de-associate the connection from the
pool such that it will be closed and discarded when
Connection.close() is called:

     conn = engine.connect()
     conn.detach()  # detaches the DBAPI connection from the connection pool
     conn.connection.<go nuts>
     conn.close()  # connection is closed for real, the pool replaces it with a new connection

6.1.10 How do I use engines / connections / sessions with Python multiprocessing, or os.fork()?
-----------------------------------------------------------------------------------------------

This is covered in the section Using Connection Pools with Multiprocessing or os.fork().

6.2 MetaData / Schema
=====================

6.2.1 My program is hanging when I say ‘table.drop()’ / ‘metadata.drop_all()’
-----------------------------------------------------------------------------

This usually corresponds to two conditions: 1.  using PostgreSQL, which
is really strict about table locks, and 2.  you have a connection still
open which contains locks on the table and is distinct from the
connection being used for the DROP statement.  Heres the most minimal
version of the pattern:

     connection = engine.connect()
     result = connection.execute(mytable.select())

     mytable.drop(engine)

Above, a connection pool connection is still checked out; furthermore,
the result object above also maintains a link to this connection.  If
“implicit execution” is used, the result will hold this connection
opened until the result object is closed or all rows are exhausted.

The call to ‘mytable.drop(engine)’ attempts to emit DROP TABLE on a
second connection procured from the Engine which will lock.

The solution is to close out all connections before emitting DROP TABLE:

     connection = engine.connect()
     result = connection.execute(mytable.select())

     # fully read result sets
     result.fetchall()

     # close connections
     connection.close()

     # now locks are removed
     mytable.drop(engine)

6.2.2 Does SQLAlchemy support ALTER TABLE, CREATE VIEW, CREATE TRIGGER, Schema Upgrade Functionality?
-----------------------------------------------------------------------------------------------------

General ALTER support isn’t present in SQLAlchemy directly.  For special
DDL on an ad-hoc basis, the DDL and related constructs can
be used.  See Customizing DDL for a discussion on this
subject.

A more comprehensive option is to use schema migration tools, such as
Alembic or SQLAlchemy-Migrate; see Altering Database Objects through Migrations
for discussion on this.

6.2.3 How can I sort Table objects in order of their dependency?
----------------------------------------------------------------

This is available via the MetaData.sorted_tables function:

     metadata = MetaData()
     # ... add Table objects to metadata
     ti = metadata.sorted_tables:
     for t in ti:
         print(t)

6.2.4 How can I get the CREATE TABLE/ DROP TABLE output as a string?
--------------------------------------------------------------------

Modern SQLAlchemy has clause constructs which represent DDL operations.
These can be rendered to strings like any other SQL expression:

     from sqlalchemy.schema import CreateTable

     print(CreateTable(mytable))

To get the string specific to a certain engine:

     print(CreateTable(mytable).compile(engine))

There’s also a special form of Engine available via
create_mock_engine() that allows one to dump an entire metadata
creation sequence as a string, using this recipe:

     from sqlalchemy import create_mock_engine

     def dump(sql, *multiparams, **params):
         print(sql.compile(dialect=engine.dialect))
     engine = create_mock_engine('postgresql://', dump)
     metadata.create_all(engine, checkfirst=False)

The Alembic(1) tool also supports an “offline” SQL generation mode that
renders database migrations as SQL scripts.

   ---------- Footnotes ----------

   (1) https://alembic.sqlalchemy.org

6.2.5 How can I subclass Table/Column to provide certain behaviors/configurations?
----------------------------------------------------------------------------------

Table and Column are not good targets for direct
subclassing.  However, there are simple ways to get on-construction
behaviors using creation functions, and behaviors related to the
linkages between schema objects such as constraint conventions or naming
conventions using attachment events.  An example of many of these
techniques can be seen at Naming Conventions(1).

   ---------- Footnotes ----------

   (1)
http://www.sqlalchemy.org/trac/wiki/UsageRecipes/NamingConventions

6.3 SQL Expressions
===================

6.3.1 How do I render SQL expressions as strings, possibly with bound parameters inlined?
-----------------------------------------------------------------------------------------

The “stringification” of a SQLAlchemy Core statement object or
expression fragment, as well as that of an ORM Query object,
in the majority of simple cases is as simple as using the ‘str()’
builtin function, as below when use it with the ‘print’ function (note
the Python ‘print’ function also calls ‘str()’ automatically if we don’t
use it explicitly):

     >>> from sqlalchemy import table, column, select
     >>> t = table('my_table', column('x'))
     >>> statement = select(t)
     >>> print(str(statement))
     SELECT my_table.x
     FROM my_table

The ‘str()’ builtin, or an equivalent, can be invoked on ORM
Query object as well as any statement such as that of
select(), insert() etc.  and also any expression
fragment, such as:

     >>> from sqlalchemy import column
     >>> print(column('x') == 'some value')
     x = :x_1

6.3.1.1 Stringifying for Specific Databases
...........................................

A complication arises when the statement or fragment we are stringifying
contains elements that have a database-specific string format, or when
it contains elements that are only available within a certain kind of
database.  In these cases, we might get a stringified statement that is
not in the correct syntax for the database we are targeting, or the
operation may raise a UnsupportedCompilationError
exception.  In these cases, it is necessary that we stringify the
statement using the ClauseElement.compile() method, while
passing along an Engine or Dialect object that
represents the target database.  Such as below, if we have a MySQL
database engine, we can stringify a statement in terms of the MySQL
dialect:

     from sqlalchemy import create_engine

     engine = create_engine("mysql+pymysql://scott:tiger@localhost/test")
     print(statement.compile(engine))

More directly, without building up an Engine object we can
instantiate a Dialect object directly, as below where we
use a PostgreSQL dialect:

     from sqlalchemy.dialects import postgresql
     print(statement.compile(dialect=postgresql.dialect()))

When given an ORM ‘Query’ object, in order to get at the
ClauseElement.compile() method we only need access the
‘Query.statement’ accessor first:

     statement = query.statement
     print(statement.compile(someengine))

6.3.1.2 Rendering Bound Parameters Inline
.........................................

     Warning: `Never' use this technique with string content received
     from untrusted input, such as from web forms or other user-input
     applications.  SQLAlchemy’s facilities to coerce Python values into
     direct SQL string values are `not secure against untrusted input
     and do not validate the type of data being passed'.  Always use
     bound parameters when programmatically invoking non-DDL SQL
     statements against a relational database.

The above forms will render the SQL statement as it is passed to the
Python DBAPI, which includes that bound parameters are not rendered
inline.  SQLAlchemy normally does not stringify bound parameters, as
this is handled appropriately by the Python DBAPI, not to mention
bypassing bound parameters is probably the most widely exploited
security hole in modern web applications.  SQLAlchemy has limited
ability to do this stringification in certain circumstances such as that
of emitting DDL. In order to access this functionality one can use the
‘literal_binds’ flag, passed to ‘compile_kwargs’:

     from sqlalchemy.sql import table, column, select

     t = table('t', column('x'))

     s = select(t).where(t.c.x == 5)

     # **do not use** with untrusted input!!!
     print(s.compile(compile_kwargs={"literal_binds": True}))

The above approach has the caveats that it is only supported for basic
types, such as ints and strings, and furthermore if a bindparam()
without a pre-set value is used directly, it won’t be able to
stringify that either.

This functionality is provided mainly for logging or debugging purposes,
where having the raw sql string of a query may prove useful.  Note that
the ‘dialect’ parameter should also passed to the
ClauseElement.compile() method to render the query that will be
sent to the database.

To support inline literal rendering for types not supported, implement a
TypeDecorator for the target type which includes a
TypeDecorator.process_literal_param() method:

     from sqlalchemy import TypeDecorator, Integer

     class MyFancyType(TypeDecorator):
         impl = Integer

         def process_literal_param(self, value, dialect):
             return "my_fancy_formatting(%s)" % value

     from sqlalchemy import Table, Column, MetaData

     tab = Table('mytable', MetaData(), Column('x', MyFancyType()))

     stmt = tab.select().where(tab.c.x > 5)
     print(stmt.compile(compile_kwargs={"literal_binds": True}))

producing output like:

     SELECT mytable.x
     FROM mytable
     WHERE mytable.x > my_fancy_formatting(5)

6.3.2 Why are percent signs being doubled up when stringifying SQL statements?
------------------------------------------------------------------------------

Many DBAPI implementations make use of the ‘pyformat’ or ‘format’
paramstyle(1), which necessarily involve percent signs in their syntax.
Most DBAPIs that do this expect percent signs used for other reasons to
be doubled up (i.e.  escaped) in the string form of the statements used,
e.g.:

     SELECT a, b FROM some_table WHERE a = %s AND c = %s AND num %% modulus = 0

When SQL statements are passed to the underlying DBAPI by SQLAlchemy,
substitution of bound parameters works in the same way as the Python
string interpolation operator ‘%’, and in many cases the DBAPI actually
uses this operator directly.  Above, the substitution of bound
parameters would then look like:

     SELECT a, b FROM some_table WHERE a = 5 AND c = 10 AND num % modulus = 0

The default compilers for databases like PostgreSQL (default DBAPI is
psycopg2) and MySQL (default DBAPI is mysqlclient) will have this
percent sign escaping behavior:

     >>> from sqlalchemy import table, column
     >>> from sqlalchemy.dialects import postgresql
     >>> t = table("my_table", column("value % one"), column("value % two"))
     >>> print(t.select().compile(dialect=postgresql.dialect()))
     SELECT my_table."value %% one", my_table."value %% two"
     FROM my_table

When such a dialect is being used, if non-DBAPI statements are desired
that don’t include bound parameter symbols, one quick way to remove the
percent signs is to simply substitute in an empty set of parameters
using Python’s ‘%’ operator directly:

     >>> strstmt = str(t.select().compile(dialect=postgresql.dialect()))
     >>> print(strstmt % ())
     SELECT my_table."value % one", my_table."value % two"
     FROM my_table

The other is to set a different parameter style on the dialect being
used; all Dialect implementations accept a parameter
‘paramstyle’ which will cause the compiler for that dialect to use the
given parameter style.  Below, the very common ‘named’ parameter style
is set within the dialect used for the compilation so that percent signs
are no longer significant in the compiled form of SQL, and will no
longer be escaped:

     >>> print(t.select().compile(dialect=postgresql.dialect(paramstyle="named")))
     SELECT my_table."value % one", my_table."value % two"
     FROM my_table

   ---------- Footnotes ----------

   (1) https://www.python.org/dev/peps/pep-0249/#paramstyle

6.3.3 I’m using op() to generate a custom operator and my parenthesis are not coming out correctly
--------------------------------------------------------------------------------------------------

The Operators.op() method allows one to create a custom
database operator otherwise not known by SQLAlchemy:

     >>> print(column('q').op('->')(column('p')))
     q -> p

However, when using it on the right side of a compound expression, it
doesn’t generate parenthesis as we expect:

     >>> print((column('q1') + column('q2')).op('->')(column('p')))
     q1 + q2 -> p

Where above, we probably want ‘(q1 + q2) -> p’.

The solution to this case is to set the precedence of the operator,
using the Operators.op.precedence parameter, to a high
number, where 100 is the maximum value, and the highest number used by
any SQLAlchemy operator is currently 15:

     >>> print((column('q1') + column('q2')).op('->', precedence=100)(column('p')))
     (q1 + q2) -> p

We can also usually force parenthesization around a binary expression
(e.g.  an expression that has left/right operands and an operator) using
the ColumnElement.self_group() method:

     >>> print((column('q1') + column('q2')).self_group().op('->')(column('p')))
     (q1 + q2) -> p

6.3.3.1 Why are the parentheses rules like this?
................................................

A lot of databases barf when there are excessive parenthesis or when
parenthesis are in unusual places they doesn’t expect, so SQLAlchemy
does not generate parenthesis based on groupings, it uses operator
precedence and if the operator is known to be associative, so that
parenthesis are generated minimally.  Otherwise, an expression like:

     column('a') & column('b') & column('c') & column('d')

would produce:

     (((a AND b) AND c) AND d)

which is fine but would probably annoy people (and be reported as a
bug).  In other cases, it leads to things that are more likely to
confuse databases or at the very least readability, such as:

     column('q', ARRAY(Integer, dimensions=2))[5][6]

would produce:

     ((q[5])[6])

There are also some edge cases where we get things like ‘"(x) = 7"’ and
databases really don’t like that either.  So parenthesization doesn’t
naively parenthesize, it uses operator precedence and associativity to
determine groupings.

For Operators.op(), the value of precedence defaults to zero.

What if we defaulted the value of Operators.op.precedence to
100, e.g.  the highest?  Then this expression makes more parenthesis,
but is otherwise OK, that is, these two are equivalent:

     >>> print((column('q') - column('y')).op('+', precedence=100)(column('z')))
     (q - y) + z
     >>> print((column('q') - column('y')).op('+')(column('z')))
     q - y + z

but these two are not:

     >>> print(column('q') - column('y').op('+', precedence=100)(column('z')))
     q - y + z
     >>> print(column('q') - column('y').op('+')(column('z')))
     q - (y + z)

For now, it’s not clear that as long as we are doing parenthesization
based on operator precedence and associativity, if there is really a way
to parenthesize automatically for a generic operator with no precedence
given that is going to work in all cases, because sometimes you want a
custom op to have a lower precedence than the other operators and
sometimes you want it to be higher.

It is possible that maybe if the “binary” expression above forced the
use of the ‘self_group()’ method when ‘op()’ is called, making the
assumption that a compound expression on the left side can always be
parenthesized harmlessly.  Perhaps this change can be made at some
point, however for the time being keeping the parenthesization rules
more internally consistent seems to be the safer approach.

6.4 ORM Configuration
=====================

6.4.1 How do I map a table that has no primary key?
---------------------------------------------------

The SQLAlchemy ORM, in order to map to a particular table, needs there
to be at least one column denoted as a primary key column;
multiple-column, i.e.  composite, primary keys are of course entirely
feasible as well.  These columns do `not' need to be actually known to
the database as primary key columns, though it’s a good idea that they
are.  It’s only necessary that the columns `behave' as a primary key
does, e.g.  as a unique and not nullable identifier for a row.

Most ORMs require that objects have some kind of primary key defined
because the object in memory must correspond to a uniquely identifiable
row in the database table; at the very least, this allows the object can
be targeted for UPDATE and DELETE statements which will affect only that
object’s row and no other.  However, the importance of the primary key
goes far beyond that.  In SQLAlchemy, all ORM-mapped objects are at all
times linked uniquely within a Session to their specific
database row using a pattern called the identity map, a pattern that’s
central to the unit of work system employed by SQLAlchemy, and is also
key to the most common (and not-so-common) patterns of ORM usage.

     Note: It’s important to note that we’re only talking about the
     SQLAlchemy ORM; an application which builds on Core and deals only
     with Table objects, see select() constructs and
     the like, `does not' need any primary key to be present on or
     associated with a table in any way (though again, in SQL, all
     tables should really have some kind of primary key, lest you need
     to actually update or delete specific rows).

In almost all cases, a table does have a so-called candidate key, which
is a column or series of columns that uniquely identify a row.  If a
table truly doesn’t have this, and has actual fully duplicate rows, the
table is not corresponding to first normal form(1) and cannot be mapped.
Otherwise, whatever columns comprise the best candidate key can be
applied directly to the mapper:

     class SomeClass(Base):
         __table__ = some_table_with_no_pk
         __mapper_args__ = {
             'primary_key':[some_table_with_no_pk.c.uid, some_table_with_no_pk.c.bar]
         }

Better yet is when using fully declared table metadata, use the
‘primary_key=True’ flag on those columns:

     class SomeClass(Base):
         __tablename__ = "some_table_with_no_pk"

         uid = Column(Integer, primary_key=True)
         bar = Column(String, primary_key=True)

All tables in a relational database should have primary keys.  Even a
many-to-many association table - the primary key would be the composite
of the two association columns:

     CREATE TABLE my_association (
       user_id INTEGER REFERENCES user(id),
       account_id INTEGER REFERENCES account(id),
       PRIMARY KEY (user_id, account_id)
     )

   ---------- Footnotes ----------

   (1) http://en.wikipedia.org/wiki/First_normal_form

6.4.2 How do I configure a Column that is a Python reserved word or similar?
----------------------------------------------------------------------------

Column-based attributes can be given any name desired in the mapping.
See Naming Columns Distinctly from Attribute Names.

6.4.3 How do I get a list of all columns, relationships, mapped attributes, etc. given a mapped class?
------------------------------------------------------------------------------------------------------

This information is all available from the Mapper object.

To get at the Mapper for a particular mapped class, call the
inspect() function on it:

     from sqlalchemy import inspect

     mapper = inspect(MyClass)

From there, all information about the class can be accessed through
properties such as:

   * Mapper.attrs. - a namespace of all mapped attributes.
     The attributes themselves are instances of MapperProperty,
     which contain additional attributes that can lead to the
     mapped SQL expression or column, if applicable.

   * Mapper.column_attrs. - the mapped attribute namespace
     limited to column and SQL expression attributes.  You might want to
     use Mapper.columns to get at the Column
     objects directly.

   * Mapper.relationships. - namespace of all
     RelationshipProperty attributes.

   * Mapper.all_orm_descriptors. - namespace of all mapped
     attributes, plus user-defined attributes defined using systems such
     as hybrid_property, AssociationProxy and
     others.

   * Mapper.columns. - A namespace of Column.
     objects and other named SQL expressions associated with the
     mapping.

   * Mapper.mapped_table. - The Table or other
     selectable to which this mapper is mapped.

   * Mapper.local_table. - The Table that is
     “local” to this mapper; this differs from
     Mapper.mapped_table in the case of a mapper mapped using
     inheritance to a composed selectable.

6.4.4 I’m getting a warning or error about “Implicitly combining column X under attribute Y”
--------------------------------------------------------------------------------------------

This condition refers to when a mapping contains two columns that are
being mapped under the same attribute name due to their name, but
there’s no indication that this is intentional.  A mapped class needs to
have explicit names for every attribute that is to store an independent
value; when two columns have the same name and aren’t disambiguated,
they fall under the same attribute and the effect is that the value from
one column is `copied' into the other, based on which column was
assigned to the attribute first.

This behavior is often desirable and is allowed without warning in the
case where the two columns are linked together via a foreign key
relationship within an inheritance mapping.  When the warning or
exception occurs, the issue can be resolved by either assigning the
columns to differently-named attributes, or if combining them together
is desired, by using column_property() to make this
explicit.

Given the example as follows:

     from sqlalchemy import Integer, Column, ForeignKey
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class A(Base):
         __tablename__ = 'a'

         id = Column(Integer, primary_key=True)

     class B(A):
         __tablename__ = 'b'

         id = Column(Integer, primary_key=True)
         a_id = Column(Integer, ForeignKey('a.id'))

As of SQLAlchemy version 0.9.5, the above condition is detected, and
will warn that the ‘id’ column of ‘A’ and ‘B’ is being combined under
the same-named attribute ‘id’, which above is a serious issue since it
means that a ‘B’ object’s primary key will always mirror that of its
‘A’.

A mapping which resolves this is as follows:

     class A(Base):
         __tablename__ = 'a'

         id = Column(Integer, primary_key=True)

     class B(A):
         __tablename__ = 'b'

         b_id = Column('id', Integer, primary_key=True)
         a_id = Column(Integer, ForeignKey('a.id'))

Suppose we did want ‘A.id’ and ‘B.id’ to be mirrors of each other,
despite the fact that ‘B.a_id’ is where ‘A.id’ is related.  We could
combine them together using column_property():

     class A(Base):
         __tablename__ = 'a'

         id = Column(Integer, primary_key=True)

     class B(A):
         __tablename__ = 'b'

         # probably not what you want, but this is a demonstration
         id = column_property(Column(Integer, primary_key=True), A.id)
         a_id = Column(Integer, ForeignKey('a.id'))

6.4.5 I’m using Declarative and setting primaryjoin/secondaryjoin using an ‘and_()’ or ‘or_()’, and I am getting an error message about foreign keys.
-----------------------------------------------------------------------------------------------------------------------------------------------------

Are you doing this?:

     class MyClass(Base):
         # ....

         foo = relationship("Dest", primaryjoin=and_("MyClass.id==Dest.foo_id", "MyClass.foo==Dest.bar"))

That’s an ‘and_()’ of two string expressions, which SQLAlchemy cannot
apply any mapping towards.  Declarative allows relationship()
arguments to be specified as strings, which are converted into
expression objects using ‘eval()’.  But this doesn’t occur inside of an
‘and_()’ expression - it’s a special operation declarative applies only
to the `entirety' of what’s passed to primaryjoin or other arguments as
a string:

     class MyClass(Base):
         # ....

         foo = relationship("Dest", primaryjoin="and_(MyClass.id==Dest.foo_id, MyClass.foo==Dest.bar)")

Or if the objects you need are already available, skip the strings:

     class MyClass(Base):
         # ....

         foo = relationship(Dest, primaryjoin=and_(MyClass.id==Dest.foo_id, MyClass.foo==Dest.bar))

The same idea applies to all the other arguments, such as
‘foreign_keys’:

     # wrong !
     foo = relationship(Dest, foreign_keys=["Dest.foo_id", "Dest.bar_id"])

     # correct !
     foo = relationship(Dest, foreign_keys="[Dest.foo_id, Dest.bar_id]")

     # also correct !
     foo = relationship(Dest, foreign_keys=[Dest.foo_id, Dest.bar_id])

     # if you're using columns from the class that you're inside of, just use the column objects !
     class MyClass(Base):
         foo_id = Column(...)
         bar_id = Column(...)
         # ...

         foo = relationship(Dest, foreign_keys=[foo_id, bar_id])

6.4.6 Why is ‘ORDER BY’ required with ‘LIMIT’ (especially with ‘subqueryload()’)?
---------------------------------------------------------------------------------

A relational database can return rows in any arbitrary order, when an
explicit ordering is not set.  While this ordering very often
corresponds to the natural order of rows within a table, this is not the
case for all databases and all queries.  The consequence of this is that
any query that limits rows using ‘LIMIT’ or ‘OFFSET’ should `always'
specify an ‘ORDER BY’.  Otherwise, it is not deterministic which rows
will actually be returned.

When we use a SQLAlchemy method like Query.first(), we are in
fact applying a ‘LIMIT’ of one to the query, so without an explicit
ordering it is not deterministic what row we actually get back.  While
we may not notice this for simple queries on databases that usually
returns rows in their natural order, it becomes much more of an issue if
we also use subqueryload() to load related collections, and
we may not be loading the collections as intended.

SQLAlchemy implements subqueryload() by issuing a separate
query, the results of which are matched up to the results from the first
query.  We see two queries emitted like this:

     >>> session.query(User).options(subqueryload(User.addresses)).all()
     {opensql}-- the "main" query
     SELECT users.id AS users_id
     FROM users
     {stop}
     {opensql}-- the "load" query issued by subqueryload
     SELECT addresses.id AS addresses_id,
            addresses.user_id AS addresses_user_id,
            anon_1.users_id AS anon_1_users_id
     FROM (SELECT users.id AS users_id FROM users) AS anon_1
     JOIN addresses ON anon_1.users_id = addresses.user_id
     ORDER BY anon_1.users_id

The second query embeds the first query as a source of rows.  When the
inner query uses ‘OFFSET’ and/or ‘LIMIT’ without ordering, the two
queries may not see the same results:

     >>> user = session.query(User).options(subqueryload(User.addresses)).first()
     {opensql}-- the "main" query
     SELECT users.id AS users_id
     FROM users
      LIMIT 1
     {stop}
     {opensql}-- the "load" query issued by subqueryload
     SELECT addresses.id AS addresses_id,
            addresses.user_id AS addresses_user_id,
            anon_1.users_id AS anon_1_users_id
     FROM (SELECT users.id AS users_id FROM users LIMIT 1) AS anon_1
     JOIN addresses ON anon_1.users_id = addresses.user_id
     ORDER BY anon_1.users_id

Depending on database specifics, there is a chance we may get a result
like the following for the two queries:

     -- query #1
     +--------+
     |users_id|
     +--------+
     |       1|
     +--------+

     -- query #2
     +------------+-----------------+---------------+
     |addresses_id|addresses_user_id|anon_1_users_id|
     +------------+-----------------+---------------+
     |           3|                2|              2|
     +------------+-----------------+---------------+
     |           4|                2|              2|
     +------------+-----------------+---------------+

Above, we receive two ‘addresses’ rows for ‘user.id’ of 2, and none for
1.  We’ve wasted two rows and failed to actually load the collection.
This is an insidious error because without looking at the SQL and the
results, the ORM will not show that there’s any issue; if we access the
‘addresses’ for the ‘User’ we have, it will emit a lazy load for the
collection and we won’t see that anything actually went wrong.

The solution to this problem is to always specify a deterministic sort
order, so that the main query always returns the same set of rows.  This
generally means that you should Query.order_by() on a unique
column on the table.  The primary key is a good choice for this:

     session.query(User).options(subqueryload(User.addresses)).order_by(User.id).first()

Note that the joinedload() eager loader strategy does not
suffer from the same problem because only one query is ever issued, so
the load query cannot be different from the main query.  Similarly, the
selectinload() eager loader strategy also does not have this
issue as it links its collection loads directly to primary key values
just loaded.

See also
........

See The Importance of Ordering.

6.5 Performance
===============

6.5.1 How can I profile a SQLAlchemy powered application?
---------------------------------------------------------

Looking for performance issues typically involves two strategies.  One
is query profiling, and the other is code profiling.

6.5.1.1 Query Profiling
.......................

Sometimes just plain SQL logging (enabled via python’s logging module or
via the ‘echo=True’ argument on create_engine()) can give an
idea how long things are taking.  For example, if you log something
right after a SQL operation, you’d see something like this in your log:

     17:37:48,325 INFO  [sqlalchemy.engine.base.Engine.0x...048c] SELECT ...
     17:37:48,326 INFO  [sqlalchemy.engine.base.Engine.0x...048c] {<params>}
     17:37:48,660 DEBUG [myapp.somemessage]

if you logged ‘myapp.somemessage’ right after the operation, you know it
took 334ms to complete the SQL part of things.

Logging SQL will also illustrate if dozens/hundreds of queries are being
issued which could be better organized into much fewer queries.  When
using the SQLAlchemy ORM, the “eager loading” feature is provided to
partially (see contains_eager()) or fully (see joinedload(),
see subqueryload()) automate this activity, but without the
ORM “eager loading” typically means to use joins so that results across
multiple tables can be loaded in one result set instead of multiplying
numbers of queries as more depth is added (i.e.  ‘r + r*r2 + r*r2*r3’ …)

For more long-term profiling of queries, or to implement an
application-side “slow query” monitor, events can be used to intercept
cursor executions, using a recipe like the following:

     from sqlalchemy import event
     from sqlalchemy.engine import Engine
     import time
     import logging

     logging.basicConfig()
     logger = logging.getLogger("myapp.sqltime")
     logger.setLevel(logging.DEBUG)

     @event.listens_for(Engine, "before_cursor_execute")
     def before_cursor_execute(conn, cursor, statement,
                             parameters, context, executemany):
         conn.info.setdefault('query_start_time', []).append(time.time())
         logger.debug("Start Query: %s", statement)

     @event.listens_for(Engine, "after_cursor_execute")
     def after_cursor_execute(conn, cursor, statement,
                             parameters, context, executemany):
         total = time.time() - conn.info['query_start_time'].pop(-1)
         logger.debug("Query Complete!")
         logger.debug("Total Time: %f", total)

Above, we use the ConnectionEvents.before_cursor_execute()
and ConnectionEvents.after_cursor_execute() events to
establish an interception point around when a statement is executed.  We
attach a timer onto the connection using the ‘info’ dictionary; we use a
stack here for the occasional case where the cursor execute events may
be nested.

6.5.1.2 Code Profiling
......................

If logging reveals that individual queries are taking too long, you’d
need a breakdown of how much time was spent within the database
processing the query, sending results over the network, being handled by
the DBAPI, and finally being received by SQLAlchemy’s result set and/or
ORM layer.  Each of these stages can present their own individual
bottlenecks, depending on specifics.

For that you need to use the Python Profiling Module(1).  Below is a
simple recipe which works profiling into a context manager:

     import cProfile
     import io
     import pstats
     import contextlib

     @contextlib.contextmanager
     def profiled():
         pr = cProfile.Profile()
         pr.enable()
         yield
         pr.disable()
         s = io.StringIO()
         ps = pstats.Stats(pr, stream=s).sort_stats('cumulative')
         ps.print_stats()
         # uncomment this to see who's calling what
         # ps.print_callers()
         print(s.getvalue())

To profile a section of code:

     with profiled():
         Session.query(FooClass).filter(FooClass.somevalue==8).all()

The output of profiling can be used to give an idea where time is being
spent.  A section of profiling output looks like this:

     13726 function calls (13042 primitive calls) in 0.014 seconds

     Ordered by: cumulative time

     ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     222/21    0.001    0.000    0.011    0.001 lib/sqlalchemy/orm/loading.py:26(instances)
     220/20    0.002    0.000    0.010    0.001 lib/sqlalchemy/orm/loading.py:327(_instance)
     220/20    0.000    0.000    0.010    0.000 lib/sqlalchemy/orm/loading.py:284(populate_state)
        20    0.000    0.000    0.010    0.000 lib/sqlalchemy/orm/strategies.py:987(load_collection_from_subq)
        20    0.000    0.000    0.009    0.000 lib/sqlalchemy/orm/strategies.py:935(get)
         1    0.000    0.000    0.009    0.009 lib/sqlalchemy/orm/strategies.py:940(_load)
        21    0.000    0.000    0.008    0.000 lib/sqlalchemy/orm/strategies.py:942(<genexpr>)
         2    0.000    0.000    0.004    0.002 lib/sqlalchemy/orm/query.py:2400(__iter__)
         2    0.000    0.000    0.002    0.001 lib/sqlalchemy/orm/query.py:2414(_execute_and_instances)
         2    0.000    0.000    0.002    0.001 lib/sqlalchemy/engine/base.py:659(execute)
         2    0.000    0.000    0.002    0.001 lib/sqlalchemy/sql/elements.py:321(_execute_on_connection)
         2    0.000    0.000    0.002    0.001 lib/sqlalchemy/engine/base.py:788(_execute_clauseelement)

     ...

Above, we can see that the ‘instances()’ SQLAlchemy function was called
222 times (recursively, and 21 times from the outside), taking a total
of .011 seconds for all calls combined.

   ---------- Footnotes ----------

   (1) https://docs.python.org/2/library/profile.html

6.5.1.3 Execution Slowness
..........................

The specifics of these calls can tell us where the time is being spent.
If for example, you see time being spent within ‘cursor.execute()’, e.g.
against the DBAPI:

     2    0.102    0.102    0.204    0.102 {method 'execute' of 'sqlite3.Cursor' objects}

this would indicate that the database is taking a long time to start
returning results, and it means your query should be optimized, either
by adding indexes or restructuring the query and/or underlying schema.
For that task, analysis of the query plan is warranted, using a system
such as EXPLAIN, SHOW PLAN, etc.  as is provided by the database
backend.

6.5.1.4 Result Fetching Slowness - Core
.......................................

If on the other hand you see many thousands of calls related to fetching
rows, or very long calls to ‘fetchall()’, it may mean your query is
returning more rows than expected, or that the fetching of rows itself
is slow.  The ORM itself typically uses ‘fetchall()’ to fetch rows (or
‘fetchmany()’ if the Query.yield_per() option is used).

An inordinately large number of rows would be indicated by a very slow
call to ‘fetchall()’ at the DBAPI level:

     2    0.300    0.600    0.300    0.600 {method 'fetchall' of 'sqlite3.Cursor' objects}

An unexpectedly large number of rows, even if the ultimate result
doesn’t seem to have many rows, can be the result of a cartesian product
- when multiple sets of rows are combined together without appropriately
joining the tables together.  It’s often easy to produce this behavior
with SQLAlchemy Core or ORM query if the wrong Column objects
are used in a complex query, pulling in additional FROM clauses that are
unexpected.

On the other hand, a fast call to ‘fetchall()’ at the DBAPI level, but
then slowness when SQLAlchemy’s CursorResult is asked to do
a ‘fetchall()’, may indicate slowness in processing of datatypes, such
as unicode conversions and similar:

     # the DBAPI cursor is fast...
     2    0.020    0.040    0.020    0.040 {method 'fetchall' of 'sqlite3.Cursor' objects}

     ...

     # but SQLAlchemy's result proxy is slow, this is type-level processing
     2    0.100    0.200    0.100    0.200 lib/sqlalchemy/engine/result.py:778(fetchall)

In some cases, a backend might be doing type-level processing that isn’t
needed.  More specifically, seeing calls within the type API that are
slow are better indicators - below is what it looks like when we use a
type like this:

     from sqlalchemy import TypeDecorator
     import time

     class Foo(TypeDecorator):
         impl = String

         def process_result_value(self, value, thing):
             # intentionally add slowness for illustration purposes
             time.sleep(.001)
             return value

the profiling output of this intentionally slow operation can be seen
like this:

     200    0.001    0.000    0.237    0.001 lib/sqlalchemy/sql/type_api.py:911(process)
     200    0.001    0.000    0.236    0.001 test.py:28(process_result_value)
     200    0.235    0.001    0.235    0.001 {time.sleep}

that is, we see many expensive calls within the ‘type_api’ system, and
the actual time consuming thing is the ‘time.sleep()’ call.

Make sure to check the Dialect documentation for notes on
known performance tuning suggestions at this level, especially for
databases like Oracle.  There may be systems related to ensuring numeric
accuracy or string processing that may not be needed in all cases.

There also may be even more low-level points at which row-fetching
performance is suffering; for example, if time spent seems to focus on a
call like ‘socket.receive()’, that could indicate that everything is
fast except for the actual network connection, and too much time is
spent with data moving over the network.

6.5.1.5 Result Fetching Slowness - ORM
......................................

To detect slowness in ORM fetching of rows (which is the most common
area of performance concern), calls like ‘populate_state()’ and
‘_instance()’ will illustrate individual ORM object populations:

     # the ORM calls _instance for each ORM-loaded row it sees, and
     # populate_state for each ORM-loaded row that results in the population
     # of an object's attributes
     220/20    0.001    0.000    0.010    0.000 lib/sqlalchemy/orm/loading.py:327(_instance)
     220/20    0.000    0.000    0.009    0.000 lib/sqlalchemy/orm/loading.py:284(populate_state)

The ORM’s slowness in turning rows into ORM-mapped objects is a product
of the complexity of this operation combined with the overhead of
cPython.  Common strategies to mitigate this include:

   * fetch individual columns instead of full entities, that is:

          session.query(User.id, User.name)

     instead of:

          session.query(User)

   * Use Bundle objects to organize column-based results:

          u_b = Bundle('user', User.id, User.name)
          a_b = Bundle('address', Address.id, Address.email)

          for user, address in session.query(u_b, a_b).join(User.addresses):
              # ...

   * Use result caching - see Dogpile Caching for an
     in-depth example of this.

   * Consider a faster interpreter like that of PyPy.

The output of a profile can be a little daunting but after some practice
they are very easy to read.

See also
........

See Performance. - a suite of performance demonstrations with
bundled profiling capabilities.

6.5.2 I’m inserting 400,000 rows with the ORM and it’s really slow!
-------------------------------------------------------------------

The SQLAlchemy ORM uses the unit of work pattern when synchronizing
changes to the database.  This pattern goes far beyond simple “inserts”
of data.  It includes that attributes which are assigned on objects are
received using an attribute instrumentation system which tracks changes
on objects as they are made, includes that all rows inserted are tracked
in an identity map which has the effect that for each row SQLAlchemy
must retrieve its “last inserted id” if not already given, and also
involves that rows to be inserted are scanned and sorted for
dependencies as needed.  Objects are also subject to a fair degree of
bookkeeping in order to keep all of this running, which for a very large
number of rows at once can create an inordinate amount of time spent
with large data structures, hence it’s best to chunk these.

Basically, unit of work is a large degree of automation in order to
automate the task of persisting a complex object graph into a relational
database with no explicit persistence code, and this automation has a
price.

ORMs are basically not intended for high-performance bulk inserts - this
is the whole reason SQLAlchemy offers the Core in addition to the ORM as
a first-class component.

For the use case of fast bulk inserts, the SQL generation and execution
system that the ORM builds on top of is part of the Core.
Using this system directly, we can produce an INSERT that is competitive
with using the raw database API directly.

     Note: When using the psycopg2 dialect, consider making use of the
     batch execution helpers feature of psycopg2, now
     supported directly by the SQLAlchemy psycopg2 dialect.

Alternatively, the SQLAlchemy ORM offers the Bulk Operations
suite of methods, which provide hooks into subsections of the unit of
work process in order to emit Core-level INSERT and UPDATE constructs
with a small degree of ORM-based automation.

The example below illustrates time-based tests for several different
methods of inserting rows, going from the most automated to the least.
With cPython 2.7, runtimes observed:

     SQLAlchemy ORM: Total time for 100000 records 6.89754080772 secs
     SQLAlchemy ORM pk given: Total time for 100000 records 4.09481811523 secs
     SQLAlchemy ORM bulk_save_objects(): Total time for 100000 records 1.65821218491 secs
     SQLAlchemy ORM bulk_insert_mappings(): Total time for 100000 records 0.466513156891 secs
     SQLAlchemy Core: Total time for 100000 records 0.21024107933 secs
     sqlite3: Total time for 100000 records 0.137335062027 sec

We can reduce the time by a factor of nearly three using recent versions
of PyPy(1):

     SQLAlchemy ORM: Total time for 100000 records 2.39429616928 secs
     SQLAlchemy ORM pk given: Total time for 100000 records 1.51412987709 secs
     SQLAlchemy ORM bulk_save_objects(): Total time for 100000 records 0.568987131119 secs
     SQLAlchemy ORM bulk_insert_mappings(): Total time for 100000 records 0.320806980133 secs
     SQLAlchemy Core: Total time for 100000 records 0.206904888153 secs
     sqlite3: Total time for 100000 records 0.165791988373 sec

Script:

     import time
     import sqlite3

     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy import Column, Integer, String,  create_engine
     from sqlalchemy.orm import scoped_session, sessionmaker

     Base = declarative_base()
     DBSession = scoped_session(sessionmaker())
     engine = None

     class Customer(Base):
         __tablename__ = "customer"
         id = Column(Integer, primary_key=True)
         name = Column(String(255))

     def init_sqlalchemy(dbname='sqlite:///sqlalchemy.db'):
         global engine
         engine = create_engine(dbname, echo=False)
         DBSession.remove()
         DBSession.configure(bind=engine, autoflush=False, expire_on_commit=False)
         Base.metadata.drop_all(engine)
         Base.metadata.create_all(engine)

     def test_sqlalchemy_orm(n=100000):
         init_sqlalchemy()
         t0 = time.time()
         for i in xrange(n):
             customer = Customer()
             customer.name = 'NAME ' + str(i)
             DBSession.add(customer)
             if i % 1000 == 0:
                 DBSession.flush()
         DBSession.commit()
         print(
             "SQLAlchemy ORM: Total time for " + str(n) +
             " records " + str(time.time() - t0) + " secs")

     def test_sqlalchemy_orm_pk_given(n=100000):
         init_sqlalchemy()
         t0 = time.time()
         for i in xrange(n):
             customer = Customer(id=i + 1, name="NAME " + str(i))
             DBSession.add(customer)
             if i % 1000 == 0:
                 DBSession.flush()
         DBSession.commit()
         print(
             "SQLAlchemy ORM pk given: Total time for " + str(n) +
             " records " + str(time.time() - t0) + " secs")

     def test_sqlalchemy_orm_bulk_save_objects(n=100000):
         init_sqlalchemy()
         t0 = time.time()
         for chunk in range(0, n, 10000):
             DBSession.bulk_save_objects(
                 [
                     Customer(name="NAME " + str(i))
                     for i in xrange(chunk, min(chunk + 10000, n))
                 ]
             )
         DBSession.commit()
         print(
             "SQLAlchemy ORM bulk_save_objects(): Total time for " + str(n) +
             " records " + str(time.time() - t0) + " secs")

     def test_sqlalchemy_orm_bulk_insert(n=100000):
         init_sqlalchemy()
         t0 = time.time()
         for chunk in range(0, n, 10000):
             DBSession.bulk_insert_mappings(
                 Customer,
                 [
                     dict(name="NAME " + str(i))
                     for i in xrange(chunk, min(chunk + 10000, n))
                 ]
             )
         DBSession.commit()
         print(
             "SQLAlchemy ORM bulk_insert_mappings(): Total time for " + str(n) +
             " records " + str(time.time() - t0) + " secs")

     def test_sqlalchemy_core(n=100000):
         init_sqlalchemy()
         t0 = time.time()
         engine.execute(
             Customer.__table__.insert(),
             [{"name": 'NAME ' + str(i)} for i in xrange(n)]
         )
         print(
             "SQLAlchemy Core: Total time for " + str(n) +
             " records " + str(time.time() - t0) + " secs")

     def init_sqlite3(dbname):
         conn = sqlite3.connect(dbname)
         c = conn.cursor()
         c.execute("DROP TABLE IF EXISTS customer")
         c.execute(
             "CREATE TABLE customer (id INTEGER NOT NULL, "
             "name VARCHAR(255), PRIMARY KEY(id))")
         conn.commit()
         return conn

     def test_sqlite3(n=100000, dbname='sqlite3.db'):
         conn = init_sqlite3(dbname)
         c = conn.cursor()
         t0 = time.time()
         for i in xrange(n):
             row = ('NAME ' + str(i),)
             c.execute("INSERT INTO customer (name) VALUES (?)", row)
         conn.commit()
         print(
             "sqlite3: Total time for " + str(n) +
             " records " + str(time.time() - t0) + " sec")

     if __name__ == '__main__':
         test_sqlalchemy_orm(100000)
         test_sqlalchemy_orm_pk_given(100000)
         test_sqlalchemy_orm_bulk_save_objects(100000)
         test_sqlalchemy_orm_bulk_insert(100000)
         test_sqlalchemy_core(100000)
         test_sqlite3(100000)

   ---------- Footnotes ----------

   (1) http://pypy.org/

6.6 Sessions / Queries
======================

6.6.1 I’m re-loading data with my Session but it isn’t seeing changes that I committed elsewhere
------------------------------------------------------------------------------------------------

The main issue regarding this behavior is that the session acts as
though the transaction is in the `serializable' isolation state, even if
it’s not (and it usually is not).  In practical terms, this means that
the session does not alter any data that it’s already read within the
scope of a transaction.

If the term “isolation level” is unfamiliar, then you first need to read
this link:

Isolation Level(1)

In short, serializable isolation level generally means that once you
SELECT a series of rows in a transaction, you will get `the identical
data' back each time you re-emit that SELECT. If you are in the
next-lower isolation level, “repeatable read”, you’ll see newly added
rows (and no longer see deleted rows), but for rows that you’ve
`already' loaded, you won’t see any change.  Only if you are in a lower
isolation level, e.g.  “read committed”, does it become possible to see
a row of data change its value.

For information on controlling the isolation level when using the
SQLAlchemy ORM, see Setting Transaction Isolation Levels / DBAPI AUTOCOMMIT.

To simplify things dramatically, the Session itself works in
terms of a completely isolated transaction, and doesn’t overwrite any
mapped attributes it’s already read unless you tell it to.  The use case
of trying to re-read data you’ve already loaded in an ongoing
transaction is an `uncommon' use case that in many cases has no effect,
so this is considered to be the exception, not the norm; to work within
this exception, several methods are provided to allow specific data to
be reloaded within the context of an ongoing transaction.

To understand what we mean by “the transaction” when we talk about the
Session, your Session is intended to only work
within a transaction.  An overview of this is at Managing Transactions.

Once we’ve figured out what our isolation level is, and we think that
our isolation level is set at a low enough level so that if we re-SELECT
a row, we should see new data in our Session, how do we see
it?

Three ways, from most common to least:

  1. We simply end our transaction and start a new one on next access
     with our Session by calling Session.commit().
     (note that if the Session is in the lesser-used
     “autocommit” mode, there would be a call to Session.begin()
     as well).  The vast majority of applications and use cases do
     not have any issues with not being able to “see” data in other
     transactions because they stick to this pattern, which is at the
     core of the best practice of `short lived transactions'.  See
     When do I construct a Session, when do I commit it, and when do I close it?
     for some thoughts on this.

  2. We tell our Session to re-read rows that it has already
     read, either when we next query for them using
     Session.expire_all() or Session.expire(), or
     immediately on an object using ‘refresh’.  See Refreshing / Expiring
     for detail on this.

  3. We can run whole queries while setting them to definitely overwrite
     already-loaded objects as they read rows by using “populate
     existing”.  This is an exection option described at Populate Existing.

But remember, `the ORM cannot see changes in rows if our isolation level
is repeatable read or higher, unless we start a new transaction'.

   ---------- Footnotes ----------

   (1) https://en.wikipedia.org/wiki/Isolation_%28database_systems%29

6.6.2 “This Session’s transaction has been rolled back due to a previous exception during flush.” (or similar)
--------------------------------------------------------------------------------------------------------------

This is an error that occurs when a Session.flush() raises
an exception, rolls back the transaction, but further commands upon the
Session are called without an explicit call to
Session.rollback() or Session.close().

It usually corresponds to an application that catches an exception upon
Session.flush() or Session.commit() and does not
properly handle the exception.  For example:

     from sqlalchemy import create_engine, Column, Integer
     from sqlalchemy.orm import sessionmaker
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base(create_engine('sqlite://'))

     class Foo(Base):
         __tablename__ = 'foo'
         id = Column(Integer, primary_key=True)

     Base.metadata.create_all()

     session = sessionmaker()()

     # constraint violation
     session.add_all([Foo(id=1), Foo(id=1)])

     try:
         session.commit()
     except:
         # ignore error
         pass

     # continue using session without rolling back
     session.commit()

The usage of the Session should fit within a structure
similar to this:

     try:
         <use session>
         session.commit()
     except:
        session.rollback()
        raise
     finally:
        session.close()  # optional, depends on use case

Many things can cause a failure within the try/except besides flushes.
Applications should ensure some system of “framing” is applied to
ORM-oriented processes so that connection and transaction resources have
a definitive boundary, and so that transactions can be explicitly rolled
back if any failure conditions occur.

This does not mean there should be try/except blocks throughout an
application, which would not be a scalable architecture.  Instead, a
typical approach is that when ORM-oriented methods and functions are
first called, the process that’s calling the functions from the very top
would be within a block that commits transactions at the successful
completion of a series of operations, as well as rolls transactions back
if operations fail for any reason, including failed flushes.  There are
also approaches using function decorators or context managers to achieve
similar results.  The kind of approach taken depends very much on the
kind of application being written.

For a detailed discussion on how to organize usage of the Session,
please see When do I construct a Session, when do I commit it, and when do I close it?.

6.6.2.1 But why does flush() insist on issuing a ROLLBACK?
..........................................................

It would be great if Session.flush() could partially
complete and then not roll back, however this is beyond its current
capabilities since its internal bookkeeping would have to be modified
such that it can be halted at any time and be exactly consistent with
what’s been flushed to the database.  While this is theoretically
possible, the usefulness of the enhancement is greatly decreased by the
fact that many database operations require a ROLLBACK in any case.
Postgres in particular has operations which, once failed, the
transaction is not allowed to continue:

     test=> create table foo(id integer primary key);
     NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
     CREATE TABLE
     test=> begin;
     BEGIN
     test=> insert into foo values(1);
     INSERT 0 1
     test=> commit;
     COMMIT
     test=> begin;
     BEGIN
     test=> insert into foo values(1);
     ERROR:  duplicate key value violates unique constraint "foo_pkey"
     test=> insert into foo values(2);
     ERROR:  current transaction is aborted, commands ignored until end of transaction block

What SQLAlchemy offers that solves both issues is support of SAVEPOINT,
via Session.begin_nested().  Using
Session.begin_nested(), you can frame an operation that may
potentially fail within a transaction, and then “roll back” to the point
before its failure while maintaining the enclosing transaction.

6.6.2.2 But why isn’t the one automatic call to ROLLBACK enough? Why must I ROLLBACK again?
...........................................................................................

The rollback that’s caused by the flush() is not the end of the complete
transaction block; while it ends the database transaction in play, from
the Session point of view there is still a transaction that
is now in an inactive state.

Given a block such as:

     sess = Session()   # begins a logical transaction
     try:
         sess.flush()

         sess.commit()
     except:
         sess.rollback()

Above, when a Session is first created, assuming “autocommit
mode” isn’t used, a logical transaction is established within the
Session.  This transaction is “logical” in that it does not actually
use any database resources until a SQL statement is invoked, at which
point a connection-level and DBAPI-level transaction is started.
However, whether or not database-level transactions are part of its
state, the logical transaction will stay in place until it is ended
using Session.commit(), Session.rollback(), or
Session.close().

When the ‘flush()’ above fails, the code is still within the transaction
framed by the try/commit/except/rollback block.  If ‘flush()’ were to
fully roll back the logical transaction, it would mean that when we then
reach the ‘except:’ block the Session would be in a clean
state, ready to emit new SQL on an all new transaction, and the call to
Session.rollback() would be out of sequence.  In particular,
the Session would have begun a new transaction by this point,
which the Session.rollback() would be acting upon
erroneously.  Rather than allowing SQL operations to proceed on a new
transaction in this place where normal usage dictates a rollback is
about to take place, the Session instead refuses to continue
until the explicit rollback actually occurs.

In other words, it is expected that the calling code will `always' call
Session.commit(), Session.rollback(), or
Session.close() to correspond to the current transaction block.
‘flush()’ keeps the Session within this transaction block so
that the behavior of the above code is predictable and consistent.

6.6.3 How do I make a Query that always adds a certain filter to every query?
-----------------------------------------------------------------------------

See the recipe at FilteredQuery(1).

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/wiki/UsageRecipes/FilteredQuery

6.6.4 My Query does not return the same number of objects as query.count() tells me - why?
------------------------------------------------------------------------------------------

The Query object, when asked to return a list of ORM-mapped
objects, will `deduplicate the objects based on primary key'.  That is,
if we for example use the ‘User’ mapping described at Object Relational Tutorial (1.x API),
and we had a SQL query like the
following:

     q = session.query(User).outerjoin(User.addresses).filter(User.name == 'jack')

Above, the sample data used in the tutorial has two rows in the
‘addresses’ table for the ‘users’ row with the name ‘'jack'’, primary
key value 5.  If we ask the above query for a Query.count(),
we will get the answer `2':

     >>> q.count()
     2

However, if we run Query.all() or iterate over the query, we
get back `one element':

     >>> q.all()
     [User(id=5, name='jack', ...)]

This is because when the Query object returns full entities,
they are `deduplicated'.  This does not occur if we instead request
individual columns back:

     >>> session.query(User.id, User.name).outerjoin(User.addresses).filter(User.name == 'jack').all()
     [(5, 'jack'), (5, 'jack')]

There are two main reasons the Query will deduplicate:

   * `To allow joined eager loading to work correctly' - see Joined Eager Loading
     works by querying rows using joins against
     related tables, where it then routes rows from those joins into
     collections upon the lead objects.  In order to do this, it has to
     fetch rows where the lead object primary key is repeated for each
     sub-entry.  This pattern can then continue into further
     sub-collections such that a multiple of rows may be processed for a
     single lead object, such as ‘User(id=5)’.  The dedpulication allows
     us to receive objects in the way they were queried, e.g.  all the
     ‘User()’ objects whose name is ‘'jack'’ which for us is one object,
     with the ‘User.addresses’ collection eagerly loaded as was
     indicated either by ‘lazy='joined'’ on the relationship()
     or via the joinedload() option.  For consistency,
     the deduplication is still applied whether or not the joinedload is
     established, as the key philosophy behind eager loading is that
     these options never affect the result.

   * `To eliminate confusion regarding the identity map' - this is
     admittedly the less critical reason.  As the Session
     makes use of an identity map, even though our SQL result set has
     two rows with primary key 5, there is only one ‘User(id=5)’ object
     inside the Session which must be maintained uniquely on
     its identity, that is, its primary key / class combination.  It
     doesn’t actually make much sense, if one is querying for ‘User()’
     objects, to get the same object multiple times in the list.  An
     ordered set would potentially be a better representation of what
     Query seeks to return when it returns full objects.

The issue of Query deduplication remains problematic, mostly
for the single reason that the Query.count() method is
inconsistent, and the current status is that joined eager loading has in
recent releases been superseded first by the “subquery eager loading”
strategy and more recently the “select IN eager loading” strategy, both
of which are generally more appropriate for collection eager loading.
As this evolution continues, SQLAlchemy may alter this behavior on
Query, which may also involve new APIs in order to more directly
control this behavior, and may also alter the behavior of joined eager
loading in order to create a more consistent usage pattern.

6.6.5 I’ve created a mapping against an Outer Join, and while the query returns rows, no objects are returned. Why not?
-----------------------------------------------------------------------------------------------------------------------

Rows returned by an outer join may contain NULL for part of the primary
key, as the primary key is the composite of both tables.  The
Query object ignores incoming rows that don’t have an acceptable
primary key.  Based on the setting of the ‘allow_partial_pks’ flag on
mapper(), a primary key is accepted if the value has at least
one non-NULL value, or alternatively if the value has no NULL values.
See ‘allow_partial_pks’ at mapper().

6.6.6 I’m using ‘joinedload()’ or ‘lazy=False’ to create a JOIN/OUTER JOIN and SQLAlchemy is not constructing the correct query when I try to add a WHERE, ORDER BY, LIMIT, etc. (which relies upon the (OUTER) JOIN)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

The joins generated by joined eager loading are only used to fully load
related collections, and are designed to have no impact on the primary
results of the query.  Since they are anonymously aliased, they cannot
be referenced directly.

For detail on this behavior, see The Zen of Joined Eager Loading.

6.6.7 Query has no ‘__len__()’, why not?
----------------------------------------

The Python ‘__len__()’ magic method applied to an object allows the
‘len()’ builtin to be used to determine the length of the collection.
It’s intuitive that a SQL query object would link ‘__len__()’ to the
Query.count() method, which emits a ‘SELECT COUNT’. The
reason this is not possible is because evaluating the query as a list
would incur two SQL calls instead of one:

     class Iterates(object):
         def __len__(self):
             print("LEN!")
             return 5

         def __iter__(self):
             print("ITER!")
             return iter([1, 2, 3, 4, 5])

     list(Iterates())

output:

     ITER!
     LEN!

6.6.8 How Do I use Textual SQL with ORM Queries?
------------------------------------------------

See:

   * Using Textual SQL. - Ad-hoc textual blocks with
     Query.

   * Using SQL Expressions with Sessions. - Using
     Session with textual SQL directly.

6.6.9 I’m calling ‘Session.delete(myobject)’ and it isn’t removed from the parent collection!
---------------------------------------------------------------------------------------------

See Notes on Delete - Deleting Objects Referenced from Collections and Scalar Relationships
for a description of this behavior.

6.6.10 why isn’t my ‘__init__()’ called when I load objects?
------------------------------------------------------------

See Constructors and Object Initialization for a description
of this behavior.

6.6.11 how do I use ON DELETE CASCADE with SA’s ORM?
----------------------------------------------------

SQLAlchemy will always issue UPDATE or DELETE statements for dependent
rows which are currently loaded in the Session.  For rows
which are not loaded, it will by default issue SELECT statements to load
those rows and update/delete those as well; in other words it assumes
there is no ON DELETE CASCADE configured.  To configure SQLAlchemy to
cooperate with ON DELETE CASCADE, see Using foreign key ON DELETE cascade with ORM relationships.

6.6.12 I set the “foo_id” attribute on my instance to “7”, but the “foo” attribute is still ‘None’ - shouldn’t it have loaded Foo with id #7?
---------------------------------------------------------------------------------------------------------------------------------------------

The ORM is not constructed in such a way as to support immediate
population of relationships driven from foreign key attribute changes -
instead, it is designed to work the other way around - foreign key
attributes are handled by the ORM behind the scenes, the end user sets
up object relationships naturally.  Therefore, the recommended way to
set ‘o.foo’ is to do just that - set it!:

     foo = Session.query(Foo).get(7)
     o.foo = foo
     Session.commit()

Manipulation of foreign key attributes is of course entirely legal.
However, setting a foreign-key attribute to a new value currently does
not trigger an “expire” event of the relationship() in which
it’s involved.  This means that for the following sequence:

     o = Session.query(SomeClass).first()
     assert o.foo is None  # accessing an un-set attribute sets it to None
     o.foo_id = 7

‘o.foo’ is initialized to ‘None’ when we first accessed it.  Setting
‘o.foo_id = 7’ will have the value of “7” as pending, but no flush has
occurred - so ‘o.foo’ is still ‘None’:

     # attribute is already set to None, has not been
     # reconciled with o.foo_id = 7 yet
     assert o.foo is None

For ‘o.foo’ to load based on the foreign key mutation is usually
achieved naturally after the commit, which both flushes the new foreign
key value and expires all state:

     Session.commit()  # expires all attributes

     foo_7 = Session.query(Foo).get(7)

     assert o.foo is foo_7  # o.foo lazyloads on access

A more minimal operation is to expire the attribute individually - this
can be performed for any persistent object using Session.expire():

     o = Session.query(SomeClass).first()
     o.foo_id = 7
     Session.expire(o, ['foo'])  # object must be persistent for this

     foo_7 = Session.query(Foo).get(7)

     assert o.foo is foo_7  # o.foo lazyloads on access

Note that if the object is not persistent but present in the
Session, it’s known as pending.  This means the row for the object
has not been INSERTed into the database yet.  For such an object,
setting ‘foo_id’ does not have meaning until the row is inserted;
otherwise there is no row yet:

     new_obj = SomeClass()
     new_obj.foo_id = 7

     Session.add(new_obj)

     # accessing an un-set attribute sets it to None
     assert new_obj.foo is None

     Session.flush()  # emits INSERT

     # expire this because we already set .foo to None
     Session.expire(o, ['foo'])

     assert new_obj.foo is foo_7  # now it loads

Attribute loading for non-persistent objects
............................................

One variant on the “pending” behavior above is if we use the flag
‘load_on_pending’ on relationship().  When this flag is set,
the lazy loader will emit for ‘new_obj.foo’ before the INSERT proceeds;
another variant of this is to use the
Session.enable_relationship_loading() method, which can “attach”
an object to a Session in such a way that many-to-one
relationships load as according to foreign key attributes regardless of
the object being in any particular state.  Both techniques are `not
recommended for general use'; they were added to suit specific
programming scenarios encountered by users which involve the repurposing
of the ORM’s usual object states.

The recipe ExpireRelationshipOnFKChange(1) features an example using
SQLAlchemy events in order to coordinate the setting of foreign key
attributes with many-to-one relationships.

   ---------- Footnotes ----------

   (1)
http://www.sqlalchemy.org/trac/wiki/UsageRecipes/ExpireRelationshipOnFKChange

6.6.13 How do I walk all objects that are related to a given object?
--------------------------------------------------------------------

An object that has other objects related to it will correspond to the
relationship() constructs set up between mappers.  This code
fragment will iterate all the objects, correcting for cycles as well:

     from sqlalchemy import inspect

     def walk(obj):
         deque = [obj]

         seen = set()

         while deque:
             obj = deque.pop(0)
             if obj in seen:
                 continue
             else:
                 seen.add(obj)
                 yield obj
             insp = inspect(obj)
             for relationship in insp.mapper.relationships:
                 related = getattr(obj, relationship.key)
                 if relationship.uselist:
                     deque.extend(related)
                 elif related is not None:
                     deque.append(related)

The function can be demonstrated as follows:

     Base = declarative_base()

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)
         bs = relationship("B", backref="a")

     class B(Base):
         __tablename__ = 'b'
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey('a.id'))
         c_id = Column(ForeignKey('c.id'))
         c = relationship("C", backref="bs")

     class C(Base):
         __tablename__ = 'c'
         id = Column(Integer, primary_key=True)

     a1 = A(bs=[B(), B(c=C())])

     for obj in walk(a1):
         print(obj)

Output:

     <__main__.A object at 0x10303b190>
     <__main__.B object at 0x103025210>
     <__main__.B object at 0x10303b0d0>
     <__main__.C object at 0x103025490>

6.6.14 Is there a way to automagically have only unique keywords (or other kinds of objects) without doing a query for the keyword and getting a reference to the row containing that keyword?
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

When people read the many-to-many example in the docs, they get hit with
the fact that if you create the same ‘Keyword’ twice, it gets put in the
DB twice.  Which is somewhat inconvenient.

This UniqueObject(1) recipe was created to address this issue.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/wiki/UsageRecipes/UniqueObject

6.6.15 Why does post_update emit UPDATE in addition to the first UPDATE?
------------------------------------------------------------------------

The post_update feature, documented at Rows that point to themselves / Mutually Dependent Rows,
involves that an UPDATE
statement is emitted in response to changes to a particular
relationship-bound foreign key, in addition to the INSERT/UPDATE/DELETE
that would normally be emitted for the target row.  While the primary
purpose of this UPDATE statement is that it pairs up with an INSERT or
DELETE of that row, so that it can post-set or pre-unset a foreign key
reference in order to break a cycle with a mutually dependent foreign
key, it currently is also bundled as a second UPDATE that emits when the
target row itself is subject to an UPDATE. In this case, the UPDATE
emitted by post_update is `usually' unnecessary and will often appear
wasteful.

However, some research into trying to remove this “UPDATE / UPDATE”
behavior reveals that major changes to the unit of work process would
need to occur not just throughout the post_update implementation, but
also in areas that aren’t related to post_update for this to work, in
that the order of operations would need to be reversed on the
non-post_update side in some cases, which in turn can impact other
cases, such as correctly handling an UPDATE of a referenced primary key
value (see #1063(1) for a proof of concept).

The answer is that “post_update” is used to break a cycle between two
mutually dependent foreign keys, and to have this cycle breaking be
limited to just INSERT/DELETE of the target table implies that the
ordering of UPDATE statements elsewhere would need to be liberalized,
leading to breakage in other edge cases.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1063

6.7 Third Party Integration Issues
==================================

6.7.1 I’m getting errors related to “‘numpy.int64’”, “‘numpy.bool_’”, etc.
--------------------------------------------------------------------------

The numpy(1) package has its own numeric datatypes that extend from
Python’s numeric types, but contain some behaviors that in some cases
make them impossible to reconcile with some of SQLAlchemy’s behaviors,
as well as in some cases with those of the underlying DBAPI driver in
use.

Two errors which can occur are ‘ProgrammingError: can't adapt type
'numpy.int64'’ on a backend such as psycopg2, and ‘ArgumentError: SQL
expression object expected, got object of type <class 'numpy.bool_'>
instead’; in more recent versions of SQLAlchemy this may be
‘ArgumentError: SQL expression for WHERE/HAVING role expected, got
True’.

In the first case, the issue is due to psycopg2 not having an
appropriate lookup entry for the ‘int64’ datatype such that it is not
accepted directly by queries.  This may be illustrated from code based
on the following:

     import numpy

     class A(Base):
         __tablename__ = "a"

         id = Column(Integer, primary_key=True)
         data = Column(Integer)

     # .. later
     session.add(A(data=numpy.int64(10)))
     session.commit()

In the latter case, the issue is due to the ‘numpy.int64’ datatype
overriding the ‘__eq__()’ method and enforcing that the return type of
an expression is ‘numpy.True’ or ‘numpy.False’, which breaks
SQLAlchemy’s expression language behavior that expects to return
ColumnElement expressions from Python equality comparisons:

     >>> import numpy
     >>> from sqlalchemy import column, Integer
     >>> print(column('x', Integer) == numpy.int64(10))  # works
     x = :x_1
     >>> print(numpy.int64(10) == column('x', Integer))  # breaks
     False

These errors are both solved in the same way, which is that special
numpy datatypes need to be replaced with regular Python values.
Examples include applying the Python ‘int()’ function to types like
‘numpy.int32’ and ‘numpy.int64’ and the Python ‘float()’ function to
‘numpy.float32’:

     data = numpy.int64(10)

     session.add(A(data=int(data)))

     result = session.execute(
         select(A.data).where(int(data) == A.data)
     )

     session.commit()

   ---------- Footnotes ----------

   (1) https://numpy.org

6.7.2 SQL expression for WHERE/HAVING role expected, got True
-------------------------------------------------------------

See I’m getting errors related to “numpy.int64”, “numpy.bool_”, etc..

7 Error Messages
****************

This section lists descriptions and background for common error messages
and warnings raised or emitted by SQLAlchemy.

SQLAlchemy normally raises errors within the context of a
SQLAlchemy-specific exception class.  For details on these classes, see
Core Exceptions and ORM Exceptions.

SQLAlchemy errors can roughly be separated into two categories, the
`programming-time error' and the `runtime error'.  Programming-time
errors are raised as a result of functions or methods being called with
incorrect arguments, or from other configuration-oriented methods such
as mapper configurations that can’t be resolved.  The programming-time
error is typically immediate and deterministic.  The runtime error on
the other hand represents a failure that occurs as a program runs in
response to some condition that occurs arbitrarily, such as database
connections being exhausted or some data-related issue occurring.
Runtime errors are more likely to be seen in the logs of a running
application as the program encounters these states in response to load
and data being encountered.

Since runtime errors are not as easy to reproduce and often occur in
response to some arbitrary condition as the program runs, they are more
difficult to debug and also affect programs that have already been put
into production.

Within this section, the goal is to try to provide background on some of
the most common runtime errors as well as programming time errors.

7.1 Legacy API Features
=======================

7.1.1 select() construct created in “legacy” mode; keyword arguments, etc.
--------------------------------------------------------------------------

The select() construct has been updated as of SQLAlchemy 1.4
to support the newer calling style that will be standard in
SQLAlchemy 2.0.  For backwards compatibility in the interm, the
construct accepts arguments in both the “legacy” style as well as the
“new” style.

The “new” style features that column and table expressions are passed
positionally to the select() construct only; any other
modifiers to the object must be passed using subsequent method chaining:

     # this is the way to do it going forward
     stmt = select(table1.c.myid).where(table1.c.myid == table2.c.otherid)

For comparison, a select() in legacy forms of SQLAlchemy,
before methods like Select.where() were even added, would
like:

     # this is how it was documented in original SQLAlchemy versions
     # many years ago
     stmt = select([table1.c.myid], whereclause=table1.c.myid == table2.c.otherid)

Or even that the “whereclause” would be passed positionally:

     # this is also how it was documented in original SQLAlchemy versions
     # many years ago
     stmt = select([table1.c.myid], table1.c.myid == table2.c.otherid)

For some years now, the additional “whereclause” and other arguments
that are accepted have been removed from most narrative documentation,
leading to a calling style that is most familiar as the list of column
arguments passed as a list, but no further arguments:

     # this is how it's been documented since around version 1.0 or so
     stmt = select([table1.c.myid]).where(table1.c.myid == table2.c.otherid)

The document at select() no longer accepts varied constructor arguments, columns are passed positionally
describes this change
in terms of 2.0 Migration.

See also
........

See select() no longer accepts varied constructor arguments, columns are passed positionally.

See Migrating to SQLAlchemy 2.0.

7.1.2 The <some function> in SQLAlchemy 2.0 will no longer <something>
----------------------------------------------------------------------

SQLAlchemy 2.0 is expected to be a major shift for a wide variety of key
SQLAlchemy usage patterns in both the Core and ORM components.  The goal
of this release is to make a slight readjustment in some of the most
fundamental assumptions of SQLAlchemy since its early beginnings, and to
deliver a newly streamlined usage model that is hoped to be
significantly more minimalist and consistent between the Core and ORM
components, as well as more capable.

Introduced at Migrating to SQLAlchemy 2.0, the SQLAlchemy 2.0
project includes a comprehensive future compatibility system that is to
be integrated into the 1.4 series of SQLAlchemy, such that applications
will have a clear, unambiguous, and incremental upgrade path in order to
migrate applications to being fully 2.0 compatible.  The
RemovedIn20Warning deprecation warning is at the base of this
system to provide guidance on what behaviors in an existing codebase
will need to be modified.  An overview of how to enable this warning is
at SQLAlchemy 2.0 Deprecations Mode.

See also
........

See Migrating to SQLAlchemy 2.0. - An overview of the upgrade
process from the 1.x series, as well as the current goals and progress
of SQLAlchemy 2.0.

See SQLAlchemy 2.0 Deprecations Mode. - specific guidelines on
how to use “2.0 deprecations mode” in SQLAlchemy 1.4.

7.1.3 A bind was located via legacy bound metadata, but since future=True is set on this Session, this bind is ignored.
-----------------------------------------------------------------------------------------------------------------------

The concept of “bound metadata” is being removed in SQLAlchemy 2.0.
This refers to the MetaData.bind parameter on the
MetaData object that in turn allows objects like the ORM
Session to associate a particular mapped class with an ‘Engine’.
In SQLAlchemy 2.0, the Session must be linked to each
‘Engine’ directly.  That is, instead of instantiating the Session
or sessionmaker without any arguments, and associating
the Engine with the MetaData:

     engine = create_engine("sqlite://")
     Session = sessionmaker()
     metadata = MetaData(bind=engine)
     Base = declarative_base(metadata=metadata)

     class MyClass(Base):
         # ...

     session = Session()
     session.add(MyClass())
     session.commit()

The Engine must instead be associated directly with the
sessionmaker or Session.  The MetaData
object should no longer be associated with any engine:

     engine = create_engine("sqlite://")
     Session = sessionmaker(engine)
     Base = declarative_base()

     class MyClass(Base):
         # ...

     session = Session()
     session.add(MyClass())
     session.commit()

In SQLAlchemy 1.4, this 2.0 style behavior is enabled when the
Session.future flag is set on sessionmaker or
Session.

7.2 Connections and Transactions
================================

7.2.1 QueuePool limit of size <x> overflow <y> reached, connection timed out, timeout <z>
-----------------------------------------------------------------------------------------

This is possibly the most common runtime error experienced, as it
directly involves the work load of the application surpassing a
configured limit, one which typically applies to nearly all SQLAlchemy
applications.

The following points summarize what this error means, beginning with the
most fundamental points that most SQLAlchemy users should already be
familiar with.

   * `The SQLAlchemy Engine object uses a pool of connections by
     default' - What this means is that when one makes use of a SQL
     database connection resource of an Engine object, and
     then releases that resource, the database connection itself remains
     connected to the database and is returned to an internal queue
     where it can be used again.  Even though the code may appear to be
     ending its conversation with the database, in many cases the
     application will still maintain a fixed number of database
     connections that persist until the application ends or the pool is
     explicitly disposed.

   * Because of the pool, when an application makes use of a SQL
     database connection, most typically from either making use of
     Engine.connect() or when making queries using an ORM
     Session, this activity does not necessarily establish a new
     connection to the database at the moment the connection object is
     acquired; it instead consults the connection pool for a connection,
     which will often retrieve an existing connection from the pool to
     be re-used.  If no connections are available, the pool will create
     a new database connection, but only if the pool has not surpassed a
     configured capacity.

   * The default pool used in most cases is called QueuePool.
     When you ask this pool to give you a connection and none are
     available, it will create a new connection `if the total number of
     connections in play are less than a configured value'.  This value
     is equal to the `pool size plus the max overflow'.  That means if
     you have configured your engine as:

          engine = create_engine("mysql://u:p@host/db", pool_size=10, max_overflow=20)

     The above Engine will allow `at most 30 connections' to
     be in play at any time, not including connections that were
     detached from the engine or invalidated.  If a request for a new
     connection arrives and 30 connections are already in use by other
     parts of the application, the connection pool will block for a
     fixed period of time, before timing out and raising this error
     message.

     In order to allow for a higher number of connections be in use at
     once, the pool can be adjusted using the
     create_engine.pool_size and
     create_engine.max_overflow parameters as passed to the
     create_engine() function.  The timeout to wait for a
     connection to be available is configured using the
     create_engine.pool_timeout parameter.

   * The pool can be configured to have unlimited overflow by setting
     create_engine.max_overflow to the value “-1”.  With
     this setting, the pool will still maintain a fixed pool of
     connections, however it will never block upon a new connection
     being requested; it will instead unconditionally make a new
     connection if none are available.

     However, when running in this way, if the application has an issue
     where it is using up all available connectivity resources, it will
     eventually hit the configured limit of available connections on the
     database itself, which will again return an error.  More seriously,
     when the application exhausts the database of connections, it
     usually will have caused a great amount of resources to be used up
     before failing, and can also interfere with other applications and
     database status mechanisms that rely upon being able to connect to
     the database.

     Given the above, the connection pool can be looked at as a `safety
     valve for connection use', providing a critical layer of protection
     against a rogue application causing the entire database to become
     unavailable to all other applications.  When receiving this error
     message, it is vastly preferable to repair the issue using up too
     many connections and/or configure the limits appropriately, rather
     than allowing for unlimited overflow which does not actually solve
     the underlying issue.

What causes an application to use up all the connections that it has
available?

   * `The application is fielding too many concurrent requests to do
     work based on the configured value for the pool' - This is the most
     straightforward cause.  If you have an application that runs in a
     thread pool that allows for 30 concurrent threads, with one
     connection in use per thread, if your pool is not configured to
     allow at least 30 connections checked out at once, you will get
     this error once your application receives enough concurrent
     requests.  Solution is to raise the limits on the pool or lower the
     number of concurrent threads.

   * `The application is not returning connections to the pool' - This
     is the next most common reason, which is that the application is
     making use of the connection pool, but the program is failing to
     release these connections and is instead leaving them open.  The
     connection pool as well as the ORM Session do have logic
     such that when the session and/or connection object is garbage
     collected, it results in the underlying connection resources being
     released, however this behavior cannot be relied upon to release
     resources in a timely manner.

     A common reason this can occur is that the application uses ORM
     sessions and does not call Session.close() upon them
     one the work involving that session is complete.  Solution is to
     make sure ORM sessions if using the ORM, or engine-bound
     Connection objects if using Core, are explicitly closed at
     the end of the work being done, either via the appropriate
     ‘.close()’ method, or by using one of the available context
     managers (e.g.  “with:” statement) to properly release the
     resource.

   * `The application is attempting to run long-running transactions' -
     A database transaction is a very expensive resource, and should
     `never be left idle waiting for some event to occur'.  If an
     application is waiting for a user to push a button, or a result to
     come off of a long running job queue, or is holding a persistent
     connection open to a browser, `don’t keep a database transaction
     open for the whole time'.  As the application needs to work with
     the database and interact with an event, open a short-lived
     transaction at that point and then close it.

   * `The application is deadlocking' - Also a common cause of this
     error and more difficult to grasp, if an application is not able to
     complete its use of a connection either due to an application-side
     or database-side deadlock, the application can use up all the
     available connections which then leads to additional requests
     receiving this error.  Reasons for deadlocks include:

        * Using an implicit async system such as gevent or eventlet
          without properly monkeypatching all socket libraries and
          drivers, or which has bugs in not fully covering for all
          monkeypatched driver methods, or less commonly when the async
          system is being used against CPU-bound workloads and greenlets
          making use of database resources are simply waiting too long
          to attend to them.  Neither implicit nor explicit async
          programming frameworks are typically necessary or appropriate
          for the vast majority of relational database operations; if an
          application must use an async system for some area of
          functionality, it’s best that database-oriented business
          methods run within traditional threads that pass messages to
          the async part of the application.

        * A database side deadlock, e.g.  rows are mutually deadlocked

        * Threading errors, such as mutexes in a mutual deadlock, or
          calling upon an already locked mutex in the same thread

Keep in mind an alternative to using pooling is to turn off pooling
entirely.  See the section Switching Pool Implementations
for background on this.  However, note that when this error message is
occurring, it is `always' due to a bigger problem in the application
itself; the pool just helps to reveal the problem sooner.

See also
........

See Connection Pooling.

See Working with Engines and Connections.

7.2.2 Can’t reconnect until invalid transaction is rolled back
--------------------------------------------------------------

This error condition refers to the case where a Connection
was invalidated, either due to a database disconnect detection or due to
an explicit call to Connection.invalidate(), but there is
still a transaction present that was initiated by the
Connection.begin() method.  When a connection is invalidated, any
Transaction that was in progress is now in an invalid state,
and must be explicitly rolled back in order to remove it from the
Connection.

7.2.3 This connection is on an inactive transaction. Please rollback() fully before proceeding
----------------------------------------------------------------------------------------------

This error condition was added to SQLAlchemy as of version 1.4.  The
error refers to the state where a Connection is placed into
a transaction using a method like Connection.begin(), and
then a further “marker” transaction is created within that scope; the
“marker” transaction is then rolled back using
Transaction.rollback() or closed using Transaction.close(),
however the outer transaction is still present in an “inactive”
state and must be rolled back.

The pattern looks like:

     engine = create_engine(...)

     connection = engine.connect()
     transaction1 = connection.begin()

     # this is a "sub" or "marker" transaction, a logical nesting
     # structure based on "real" transaction transaction1
     transaction2 = connection.begin()
     transaction2.rollback()

     # transaction1 is still present and needs explicit rollback,
     # so this will raise
     connection.execute(text("select 1"))

Above, ‘transaction2’ is a “marker” transaction, which indicates a
logical nesting of transactions within an outer one; while the inner
transaction can roll back the whole transaction via its rollback()
method, its commit() method has no effect except to close the scope of
the “marker” transaction itself.  The call to ‘transaction2.rollback()’
has the effect of `deactivating' transaction1 which means it is
essentially rolled back at the database level, however is still present
in order to accommodate a consistent nesting pattern of transactions.

The correct resolution is to ensure the outer transaction is also rolled
back:

     transaction1.rollback()

This pattern is not commonly used in Core.  Within the ORM, a similar
issue can occur which is the product of the ORM’s “logical” transaction
structure; this is described in the FAQ entry at *note “This Session’s
transaction has been rolled back due to a previous exception during
flush.” (or similar): 612.

The “subtransaction” pattern is to be removed in SQLAlchemy 2.0 so that
this particular programming pattern will no longer be available and this
error message will no longer occur in Core.

7.3 DBAPI Errors
================

The Python database API, or DBAPI, is a specification for database
drivers which can be located at Pep-249(1).  This API specifies a set of
exception classes that accommodate the full range of failure modes of
the database.

SQLAlchemy does not generate these exceptions directly.  Instead, they
are intercepted from the database driver and wrapped by the
SQLAlchemy-provided exception DBAPIError, however the
messaging within the exception is `generated by the driver, not
SQLAlchemy'.

   ---------- Footnotes ----------

   (1) https://www.python.org/dev/peps/pep-0249/

7.3.1 InterfaceError
--------------------

Exception raised for errors that are related to the database interface
rather than the database itself.

This error is a DBAPI Error and originates from the
database driver (DBAPI), not SQLAlchemy itself.

The ‘InterfaceError’ is sometimes raised by drivers in the context of
the database connection being dropped, or not being able to connect to
the database.  For tips on how to deal with this, see the section
Dealing with Disconnects.

7.3.2 DatabaseError
-------------------

Exception raised for errors that are related to the database itself, and
not the interface or data being passed.

This error is a DBAPI Error and originates from the
database driver (DBAPI), not SQLAlchemy itself.

7.3.3 DataError
---------------

Exception raised for errors that are due to problems with the processed
data like division by zero, numeric value out of range, etc.

This error is a DBAPI Error and originates from the
database driver (DBAPI), not SQLAlchemy itself.

7.3.4 OperationalError
----------------------

Exception raised for errors that are related to the database’s operation
and not necessarily under the control of the programmer, e.g.  an
unexpected disconnect occurs, the data source name is not found, a
transaction could not be processed, a memory allocation error occurred
during processing, etc.

This error is a DBAPI Error and originates from the
database driver (DBAPI), not SQLAlchemy itself.

The ‘OperationalError’ is the most common (but not the only) error class
used by drivers in the context of the database connection being dropped,
or not being able to connect to the database.  For tips on how to deal
with this, see the section Dealing with Disconnects.

7.3.5 IntegrityError
--------------------

Exception raised when the relational integrity of the database is
affected, e.g.  a foreign key check fails.

This error is a DBAPI Error and originates from the
database driver (DBAPI), not SQLAlchemy itself.

7.3.6 InternalError
-------------------

Exception raised when the database encounters an internal error, e.g.
the cursor is not valid anymore, the transaction is out of sync, etc.

This error is a DBAPI Error and originates from the
database driver (DBAPI), not SQLAlchemy itself.

The ‘InternalError’ is sometimes raised by drivers in the context of the
database connection being dropped, or not being able to connect to the
database.  For tips on how to deal with this, see the section
Dealing with Disconnects.

7.3.7 ProgrammingError
----------------------

Exception raised for programming errors, e.g.  table not found or
already exists, syntax error in the SQL statement, wrong number of
parameters specified, etc.

This error is a DBAPI Error and originates from the
database driver (DBAPI), not SQLAlchemy itself.

The ‘ProgrammingError’ is sometimes raised by drivers in the context of
the database connection being dropped, or not being able to connect to
the database.  For tips on how to deal with this, see the section
Dealing with Disconnects.

7.3.8 NotSupportedError
-----------------------

Exception raised in case a method or database API was used which is not
supported by the database, e.g.  requesting a .rollback() on a
connection that does not support transaction or has transactions turned
off.

This error is a DBAPI Error and originates from the
database driver (DBAPI), not SQLAlchemy itself.

7.4 SQL Expression Language
===========================

7.4.1 Compiler StrSQLCompiler can’t render element of type <element type>
-------------------------------------------------------------------------

This error usually occurs when attempting to stringify a SQL expression
construct that includes elements which are not part of the default
compilation; in this case, the error will be against the
StrSQLCompiler class.  In less common cases, it can also occur
when the wrong kind of SQL expression is used with a particular type of
database backend; in those cases, other kinds of SQL compiler classes
will be named, such as ‘SQLCompiler’ or
‘sqlalchemy.dialects.postgresql.PGCompiler’.  The guidance below is more
specific to the “stringification” use case but describes the general
background as well.

Normally, a Core SQL construct or ORM Query object can be
stringified directly, such as when we use ‘print()’:

     >>> from sqlalchemy import column
     >>> print(column('x') == 5)
     x = :x_1

When the above SQL expression is stringified, the StrSQLCompiler
compiler class is used, which is a special statement compiler that
is invoked when a construct is stringified without any dialect-specific
information.

However, there are many constructs that are specific to some particular
kind of database dialect, for which the StrSQLCompiler
doesn’t know how to turn into a string, such as the PostgreSQL "insert
on conflict"(1) construct:

     >>> from sqlalchemy.dialects.postgresql import insert
     >>> from sqlalchemy import table, column
     >>> my_table = table('my_table', column('x'), column('y'))
     >>> insert_stmt = insert(my_table).values(x='foo')
     >>> insert_stmt = insert_stmt.on_conflict_do_nothing(
     ...     index_elements=['y']
     ... )
     >>> print(insert_stmt)
     Traceback (most recent call last):

     ...

     sqlalchemy.exc.UnsupportedCompilationError:
     Compiler <sqlalchemy.sql.compiler.StrSQLCompiler object at 0x7f04fc17e320>
     can't render element of type
     <class 'sqlalchemy.dialects.postgresql.dml.OnConflictDoNothing'>

In order to stringify constructs that are specific to particular
backend, the ClauseElement.compile() method must be used,
passing either an Engine or a Dialect object
which will invoke the correct compiler.  Below we use a PostgreSQL
dialect:

     >>> from sqlalchemy.dialects import postgresql
     >>> print(insert_stmt.compile(dialect=postgresql.dialect()))
     INSERT INTO my_table (x) VALUES (%(x)s) ON CONFLICT (y) DO NOTHING

For an ORM Query object, the statement can be accessed using
the ‘Query.statement’ accessor:

     statement = query.statement
     print(statement.compile(dialect=postgresql.dialect()))

See the FAQ link below for additional detail on direct stringification /
compilation of SQL elements.

See also
........

See How do I render SQL expressions as strings, possibly with bound parameters inlined?.

   ---------- Footnotes ----------

   (1) postgresql_insert_on_conflict

7.4.2 TypeError: <operator> not supported between instances of ‘ColumnProperty’ and <something>
-----------------------------------------------------------------------------------------------

This often occurs when attempting to use a column_property()
or deferred() object in the context of a SQL expression,
usually within declarative such as:

     class Bar(Base):
         __tablename__ = 'bar'

         id = Column(Integer, primary_key=True)
         cprop = deferred(Column(Integer))

         __table_args__ = (
             CheckConstraint(cprop > 5),
         )

Above, the ‘cprop’ attribute is used inline before it has been mapped,
however this ‘cprop’ attribute is not a Column, it’s a
ColumnProperty, which is an interim object and therefore does not
have the full functionality of either the Column object or
the InstrumentedAttribute object that will be mapped onto
the ‘Bar’ class once the declarative process is complete.

While the ColumnProperty does have a ‘__clause_element__()’
method, which allows it to work in some column-oriented contexts, it
can’t work in an open-ended comparison context as illustrated above,
since it has no Python ‘__eq__()’ method that would allow it to
interpret the comparison to the number “5” as a SQL expression and not a
regular Python comparison.

The solution is to access the Column directly using the
ColumnProperty.expression attribute:

     class Bar(Base):
         __tablename__ = 'bar'

         id = Column(Integer, primary_key=True)
         cprop = deferred(Column(Integer))

         __table_args__ = (
             CheckConstraint(cprop.expression > 5),
         )

7.4.3 This Compiled object is not bound to any Engine or Connection
-------------------------------------------------------------------

This error refers to the concept of “bound metadata”, described at
Connectionless Execution, Implicit Execution.  The issue occurs
when one invokes the Executable.execute() method directly
off of a Core expression object that is not associated with any
Engine:

     metadata = MetaData()
     table = Table('t', metadata, Column('q', Integer))

     stmt = select(table)
     result = stmt.execute()   # <--- raises

What the logic is expecting is that the MetaData object has
been `bound' to a Engine:

     engine = create_engine("mysql+pymysql://user:pass@host/db")
     metadata = MetaData(bind=engine)

Where above, any statement that derives from a Table which in
turn derives from that MetaData will implicitly make use of
the given Engine in order to invoke the statement.

Note that the concept of bound metadata is a `legacy pattern' and in
most cases is `highly discouraged'.  The best way to invoke the
statement is to pass it to the Connection.execute() method
of a Connection:

     with engine.connect() as conn:
       result = conn.execute(stmt)

When using the ORM, a similar facility is available via the
Session:

     result = session.execute(stmt)

See also
........

See Connectionless Execution, Implicit Execution.

7.4.4 A value is required for bind parameter <x> (in parameter group <y>)
-------------------------------------------------------------------------

This error occurs when a statement makes use of bindparam()
either implicitly or explicitly and does not provide a value when the
statement is executed:

     stmt = select(table.c.column).where(table.c.id == bindparam('my_param'))

     result = conn.execute(stmt)

Above, no value has been provided for the parameter “my_param”.  The
correct approach is to provide a value:

     result = conn.execute(stmt, my_param=12)

When the message takes the form “a value is required for bind parameter
<x> in parameter group <y>”, the message is referring to the
“executemany” style of execution.  In this case, the statement is
typically an INSERT, UPDATE, or DELETE and a list of parameters is being
passed.  In this format, the statement may be generated dynamically to
include parameter positions for every parameter given in the argument
list, where it will use the `first set of parameters' to determine what
these should be.

For example, the statement below is calculated based on the first
parameter set to require the parameters, “a”, “b”, and “c” - these names
determine the final string format of the statement which will be used
for each set of parameters in the list.  As the second entry does not
contain “b”, this error is generated:

     m = MetaData()
     t = Table(
         't', m,
         Column('a', Integer),
         Column('b', Integer),
         Column('c', Integer)
     )

     e.execute(
         t.insert(), [
             {"a": 1, "b": 2, "c": 3},
             {"a": 2, "c": 4},
             {"a": 3, "b": 4, "c": 5},
         ]
     )

     sqlalchemy.exc.StatementError: (sqlalchemy.exc.InvalidRequestError)
     A value is required for bind parameter 'b', in parameter group 1
     [SQL: u'INSERT INTO t (a, b, c) VALUES (?, ?, ?)']
     [parameters: [{'a': 1, 'c': 3, 'b': 2}, {'a': 2, 'c': 4}, {'a': 3, 'c': 5, 'b': 4}]]

Since “b” is required, pass it as ‘None’ so that the INSERT may proceed:

     e.execute(
         t.insert(), [
             {"a": 1, "b": 2, "c": 3},
             {"a": 2, "b": None, "c": 4},
             {"a": 3, "b": 4, "c": 5},
         ]
     )

See also
........

See Bind Parameter Objects.

See Executing Multiple Statements.

7.4.5 Expected FROM clause, got Select. To create a FROM clause, use the .subquery() method
-------------------------------------------------------------------------------------------

This refers to a change made as of SQLAlchemy 1.4 where a SELECT
statement as generated by a function such as select(), but
also including things like unions and textual SELECT expressions are no
longer considered to be FromClause objects and can’t be
placed directly in the FROM clause of another SELECT statement without
them being wrapped in a Subquery first.  This is a major
conceptual change in the Core and the full rationale is discussed at
A SELECT statement is no longer implicitly considered to be a FROM clause.

Given an example as:

     m = MetaData()
     t = Table(
        't', m,
        Column('a', Integer),
        Column('b', Integer),
        Column('c', Integer)
     )
     stmt = select(t)

Above, ‘stmt’ represents a SELECT statement.  The error is produced when
we want to use ‘stmt’ directly as a FROM clause in another SELECT, such
as if we attempted to select from it:

     new_stmt_1 = select(stmt)

Or if we wanted to use it in a FROM clause such as in a JOIN:

     new_stmt_2 = select(some_table).select_from(some_table.join(stmt))

In previous versions of SQLAlchemy, using a SELECT inside of another
SELECT would produce a parenthesized, unnamed subquery.  In most cases,
this form of SQL is not very useful as databases like MySQL and
PostgreSQL require that subqueries in FROM clauses have named aliases,
which means using the SelectBase.alias() method or as of 1.4
using the SelectBase.subquery() method to produce this.  On
other databases, it is still much clearer for the subquery to have a
name to resolve any ambiguity on future references to column names
inside the subquery.

Beyond the above practical reasons, there are a lot of other
SQLAlchemy-oriented reasons the change is being made.  The correct form
of the above two statements therefore requires that
SelectBase.subquery() is used:

     subq = stmt.subquery()

     new_stmt_1 = select(subq)

     new_stmt_2 = select(some_table).select_from(some_table.join(subq))

See also
........

See A SELECT statement is no longer implicitly considered to be a FROM clause.

7.5 Object Relational Mapping
=============================

7.5.1 Parent instance <x> is not bound to a Session; (lazy load/deferred load/refresh/etc.) operation cannot proceed
--------------------------------------------------------------------------------------------------------------------

This is likely the most common error message when dealing with the ORM,
and it occurs as a result of the nature of a technique the ORM makes
wide use of known as lazy loading.  Lazy loading is a common
object-relational pattern whereby an object that’s persisted by the ORM
maintains a proxy to the database itself, such that when various
attributes upon the object are accessed, their value may be retrieved
from the database `lazily'.  The advantage to this approach is that
objects can be retrieved from the database without having to load all of
their attributes or related data at once, and instead only that data
which is requested can be delivered at that time.  The major
disadvantage is basically a mirror image of the advantage, which is that
if lots of objects are being loaded which are known to require a certain
set of data in all cases, it is wasteful to load that additional data
piecemeal.

Another caveat of lazy loading beyond the usual efficiency concerns is
that in order for lazy loading to proceed, the object has to `remain
associated with a Session' in order to be able to retrieve its state.
This error message means that an object has become de-associated with
its Session and is being asked to lazy load data from the
database.

The most common reason that objects become detached from their
Session is that the session itself was closed, typically via the
Session.close() method.  The objects will then live on to be
accessed further, very often within web applications where they are
delivered to a server-side templating engine and are asked for further
attributes which they cannot load.

Mitigation of this error is via two general techniques:

   * `Don’t close the session prematurely' - Often, applications will
     close out a transaction before passing off related objects to some
     other system which then fails due to this error.  Sometimes the
     transaction doesn’t need to be closed so soon; an example is the
     web application closes out the transaction before the view is
     rendered.  This is often done in the name of “correctness”, but may
     be seen as a mis-application of “encapsulation”, as this term
     refers to code organization, not actual actions.  The template that
     uses an ORM object is making use of the proxy pattern(1) which
     keeps database logic encapsulated from the caller.  If the
     Session can be held open until the lifespan of the objects are
     done, this is the best approach.

   * `Load everything that’s needed up front' - It is very often
     impossible to keep the transaction open, especially in more complex
     applications that need to pass objects off to other systems that
     can’t run in the same context even though they’re in the same
     process.  In this case, the application should try to make
     appropriate use of eager loading to ensure that objects have what
     they need up front.

     When using this approach, it is usually necessary that the
     Session.expire_on_commit parameter be set to ‘False’, so that
     after a Session.commit() operation, the objects within
     the session aren’t expired, which would incur a lazy load if their
     attributes were subsequently accessed.  Additionally, the
     Session.rollback() method unconditionally expires all
     contents in the Session and should also be avoided in
     non-error scenarios.

     See also
     ........

     See Relationship Loading Techniques. - detailed
     documentation on eager loading and other relationship-oriented
     loading techniques

     See Committing. - background on session commit

     See Refreshing / Expiring. - background on attribute expiry

   ---------- Footnotes ----------

   (1) https://en.wikipedia.org/wiki/Proxy_pattern

7.5.2 This Session’s transaction has been rolled back due to a previous exception during flush
----------------------------------------------------------------------------------------------

The flush process of the Session, described at Flushing,
will roll back the database transaction if an error is encountered,
in order to maintain internal consistency.  However, once this occurs,
the session’s transaction is now “inactive” and must be explicitly
rolled back by the calling application, in the same way that it would
otherwise need to be explicitly committed if a failure had not occurred.

This is a common error when using the ORM and typically applies to an
application that doesn’t yet have correct “framing” around its
Session operations.  Further detail is described in the FAQ at
“This Session’s transaction has been rolled back due to a previous exception during flush.” (or similar).

7.5.3 For relationship <relationship>, delete-orphan cascade is normally configured only on the “one” side of a one-to-many relationship, and not on the “many” side of a many-to-one or many-to-many relationship.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

This error arises when the “delete-orphan” cascade is set on
a many-to-one or many-to-many relationship, such as:

     class A(Base):
         __tablename__ = "a"

         id = Column(Integer, primary_key=True)

         bs = relationship("B", back_populates="a")

     class B(Base):
         __tablename__ = "b"
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey("a.id"))

         # this will emit the error message when the mapper
         # configuration step occurs
         a = relationship("A", back_populates="bs", cascade="all, delete-orphan")

     configure_mappers()

Above, the “delete-orphan” setting on ‘B.a’ indicates the intent that
when every ‘B’ object that refers to a particular ‘A’ is deleted, that
the ‘A’ should then be deleted as well.  That is, it expresses that the
“orphan” which is being deleted would be an ‘A’ object, and it becomes
an “orphan” when every ‘B’ that refers to it is deleted.

The “delete-orphan” cascade model does not support this functionality.
The “orphan” consideration is only made in terms of the deletion of a
single object which would then refer to zero or more objects that are
now “orphaned” by this single deletion, which would result in those
objects being deleted as well.  In other words, it is designed only to
track the creation of “orphans” based on the removal of one and only one
“parent” object per orphan, which is the natural case in a one-to-many
relationship where a deletion of the object on the “one” side results in
the subsequent deletion of the related items on the “many” side.

The above mapping in support of this functionality would instead place
the cascade setting on the one-to-many side, which looks like:

     class A(Base):
         __tablename__ = "a"

         id = Column(Integer, primary_key=True)

         bs = relationship("B", back_populates="a", cascade="all, delete-orphan")

     class B(Base):
         __tablename__ = "b"
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey("a.id"))

         a = relationship("A", back_populates="bs")

Where the intent is expressed that when an ‘A’ is deleted, all of the
‘B’ objects to which it refers are also deleted.

The error message then goes on to suggest the usage of the
relationship.single_parent flag.  This flag may be used to enforce
that a relationship which is capable of having many objects refer to a
particular object will in fact have only `one' object referring to it at
a time.  It is used for legacy or other less ideal database schemas
where the foreign key relationships suggest a “many” collection, however
in practice only one object would actually refer to a given target
object at at time.  This uncommon scenario can be demonstrated in terms
of the above example as follows:

     class A(Base):
         __tablename__ = "a"

         id = Column(Integer, primary_key=True)

         bs = relationship("B", back_populates="a")

     class B(Base):
         __tablename__ = "b"
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey("a.id"))

         a = relationship(
             "A",
             back_populates="bs",
             single_parent=True,
             cascade="all, delete-orphan",
         )

The above configuration will then install a validator which will enforce
that only one ‘B’ may be associated with an ‘A’ at at time, within the
scope of the ‘B.a’ relationship:

     >>> b1 = B()
     >>> b2 = B()
     >>> a1 = A()
     >>> b1.a = a1
     >>> b2.a = a1
     sqlalchemy.exc.InvalidRequestError: Instance <A at 0x7eff44359350> is
     already associated with an instance of <class '__main__.B'> via its
     B.a attribute, and is only allowed a single parent.

Note that this validator is of limited scope and will not prevent
multiple “parents” from being created via the other direction.  For
example, it will not detect the same setting in terms of ‘A.bs’:

     >>> a1.bs = [b1, b2]
     >>> session.add_all([a1, b1, b2])
     >>> session.commit()
     {opensql}
     INSERT INTO a DEFAULT VALUES
     ()
     INSERT INTO b (a_id) VALUES (?)
     (1,)
     INSERT INTO b (a_id) VALUES (?)
     (1,)

However, things will not go as expected later on, as the “delete-orphan”
cascade will continue to work in terms of a `single' lead object,
meaning if we delete `either' of the ‘B’ objects, the ‘A’ is deleted.
The other ‘B’ stays around, where the ORM will usually be smart enough
to set the foreign key attribute to NULL, but this is usually not what’s
desired:

     >>> session.delete(b1)
     >>> session.commit()
     {opensql}
     UPDATE b SET a_id=? WHERE b.id = ?
     (None, 2)
     DELETE FROM b WHERE b.id = ?
     (1,)
     DELETE FROM a WHERE a.id = ?
     (1,)
     COMMIT

For all the above examples, similar logic applies to the calculus of a
many-to-many relationship; if a many-to-many relationship sets
single_parent=True on one side, that side can use the “delete-orphan”
cascade, however this is very unlikely to be what someone actually wants
as the point of a many-to-many relationship is so that there can be many
objects referring to an object in either direction.

Overall, “delete-orphan” cascade is usually applied on the “one” side of
a one-to-many relationship so that it deletes objects in the “many”
side, and not the other way around.

Changed in version 1.3.18: The text of the “delete-orphan” error message
when used on a many-to-one or many-to-many relationship has been updated
to be more descriptive.

See also
........

See Cascades.

See delete-orphan.

*note Instance <instance> is already associated with an instance of
<instance> via its <attribute> attribute, and is only allowed a single
parent.: 1b01.

7.5.4 Instance <instance> is already associated with an instance of <instance> via its <attribute> attribute, and is only allowed a single parent.
--------------------------------------------------------------------------------------------------------------------------------------------------

This error is emitted when the relationship.single_parent
flag is used, and more than one object is assigned as the “parent” of an
object at once.

Given the following mapping:

     class A(Base):
         __tablename__ = "a"

         id = Column(Integer, primary_key=True)

     class B(Base):
         __tablename__ = "b"
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey("a.id"))

         a = relationship(
             "A",
             single_parent=True,
             cascade="all, delete-orphan",
         )

The intent indicates that no more than a single ‘B’ object may refer to
a particular ‘A’ object at once:

     >>> b1 = B()
     >>> b2 = B()
     >>> a1 = A()
     >>> b1.a = a1
     >>> b2.a = a1
     sqlalchemy.exc.InvalidRequestError: Instance <A at 0x7eff44359350> is
     already associated with an instance of <class '__main__.B'> via its
     B.a attribute, and is only allowed a single parent.

When this error occurs unexpectedly, it is usually because the
relationship.single_parent flag was applied in response to the
error message described at *note For relationship <relationship>,
delete-orphan cascade is normally configured only on the “one” side of a
one-to-many relationship, and not on the “many” side of a many-to-one or
many-to-many relationship.: 647, and the issue is in fact a
misunderstanding of the “delete-orphan” cascade setting.  See that
message for details.

See also
........

*note For relationship <relationship>, delete-orphan cascade is normally
configured only on the “one” side of a one-to-many relationship, and not
on the “many” side of a many-to-one or many-to-many relationship.: 647.

7.6 AsyncIO Exceptions
======================

7.6.1 AwaitRequired
-------------------

The SQLAlchemy async mode requires an async driver to be used to connect
to the db.  This error is usually raised when trying to use the async
version of SQLAlchemy with a non compatible DBAPI.

See also
........

See Asynchronous I/O (asyncio).

7.6.2 MissingGreenlet
---------------------

A call to the async DBAPI was initiated outside the greenlet spawn
context usually setup by the SQLAlchemy AsyncIO proxy classes.  Usually
this error happens when an IO was attempted in an unexpected place,
without using the provided async api.  When using the ORM this may be
due to a lazy loading attempt, which is unsupported when using
SQLAlchemy with AsyncIO dialects.

See also
........

_session_run_sync

7.7 Core Exception Classes
==========================

See Core Exceptions for Core exception classes.

7.8 ORM Exception Classes
=========================

See ORM Exceptions for ORM exception classes.

8 Changes and Migration
***********************

SQLAlchemy changelogs and migration guides are now integrated within the
main documentation.

8.1 Current Migration Guide
===========================

8.1.1 What’s New in SQLAlchemy 1.4?
-----------------------------------

     About this Document: This document describes changes between
     SQLAlchemy version 1.3 and SQLAlchemy version 1.4.

     Version 1.4 is taking on a different focus than other SQLAlchemy
     releases in that it is in many ways attempting to serve as a
     potential migration point for a more dramatic series of API changes
     currently planned for release 2.0 of SQLAlchemy.  The focus of
     SQLAlchemy 2.0 is a modernized and slimmed down API that removes
     lots of usage patterns that have long been discouraged, as well as
     mainstreams the best ideas in SQLAlchemy as first class API
     features, with the goal being that there is much less ambiguity in
     how the API is to be used, as well as that a series of implicit
     behaviors and rarely-used API flags that complicate the internals
     and hinder performance will be removed.

     For the current status of SQLAlchemy 2.0, see Migrating to SQLAlchemy 2.0.

8.1.1.1 Major API changes and features - General
................................................

8.1.1.2 Python 3.6 is the minimum Python 3 version; Python 2.7 still supported
..............................................................................

As Python 3.5 reached EOL in September of 2020, SQLAlchemy 1.4 now
places version 3.6 as the minimum Python 3 version.  Python 2.7 is still
supported, however the SQLAlchemy 1.4 series will be the last series to
support Python 2.

8.1.1.3 ORM Query is internally unified with select, update, delete; 2.0 style execution available
..................................................................................................

The biggest conceptual change to SQLAlchemy for version 2.0 and
essentially in 1.4 as well is that the great separation between the
Select construct in Core and the Query object in
the ORM has been removed, as well as between the Query.update()
and Query.delete() methods in how they relate to
Update and Delete.

With regards to Select and Query, these two
objects have for many versions had similar, largely overlapping APIs and
even some ability to change between one and the other, while remaining
very different in their usage patterns and behaviors.  The historical
background for this was that the Query object was introduced
to overcome shortcomings in the Select object which used to
be at the core of how ORM objects were queried, except that they had to
be queried in terms of Table metadata only.  However
Query had only a simplistic interface for loading objects, and
only over the course of many major releases did it eventually gain most
of the flexibility of the Select object, which then led to
the ongoing awkwardness that these two objects became highly similar yet
still largely incompatible with each other.

In version 1.4, all Core and ORM SELECT statements are rendered from a
Select object directly; when the Query object is
used, at statement invocation time it copies its state to a
Select which is then invoked internally using 2.0 style execution.
Going forward, the Query object will become legacy only, and
applications will be encouraged to move to 2.0 style execution which
allows Core constructs to be used freely against ORM entities:

     with Session(engine, future=True) as sess:

         stmt = select(User).where(
             User.name == 'sandy'
         ).join(User.addresses).where(Address.email_address.like("%gmail%"))

         result = sess.execute(stmt)

         for user in result.scalars():
             print(user)

Things to note about the above example:

   * The Session and sessionmaker objects now
     feature full context manager (i.e.  the ‘with:’ statement)
     capability; see the revised documentation at Opening and Closing a Session
     for an example.

   * Within the 1.4 series, all 2.0 style ORM invocation uses a
     Session that includes the Session.future flag set
     to ‘True’; this flag indicates the Session should have
     2.0-style behaviors, which include that ORM queries can be invoked
     from execute as well as some changes in transactional
     features.  In version 2.0 this flag will always be ‘True’.

   * The select() construct no longer needs brackets around
     the columns clause; see select(), case() now accept positional expressions
     for background on this improvement.

   * The select(). / see Select object has a
     Select.join() method that acts like that of the Query
     and even accommodates an ORM relationship attribute (without
     breaking the separation between Core and ORM!) - see
     select().join() and outerjoin() add JOIN criteria to the current query, rather than creating a subquery
     for background on
     this.

   * Statements that work with ORM entities and are expected to return
     ORM results are invoked using Session.execute().  See
     Querying (2.0 style) for a primer.

   * a Result object is returned, rather than a plain list,
     which itself is a much more sophisticated version of the previous
     ‘ResultProxy’ object; this object is now used both for Core and ORM
     results.  See New Result object, *note RowProxy is no
     longer a “proxy”; is now called Row and behaves like an enhanced
     named tuple: c98, and The “KeyedTuple” object returned by Query is replaced by Row
     for information on this.

Throughout SQLAlchemy’s documentation, there will be many references to
1.x style and 2.0 style execution.  This is to distinguish between the
two querying styles and to attempt to forwards-document the new calling
style going forward.  In SQLAlchemy 2.0, while the Query
object may remain as a legacy construct, it will no longer be featured
in most documentation.

Similar adjustments have been made to “bulk updates and deletes” such
that Core update() and delete() can be used for
bulk operations.  A bulk update like the following:

     session.query(User).filter(User.name == 'sandy').update({"password": "foobar"}, synchronize_session="fetch")

can now be achieved in 2.0 style (and indeed the above runs internally
in this way) as follows:

     with Session(engine, future=True) as sess:
         stmt = update(User).where(
             User.name == 'sandy'
         ).values(password="foobar").execution_options(
             synchronize_session="fetch"
         )

         sess.execute(stmt)

Note the use of the Executable.execution_options() method to
pass ORM-related options.  The use of “execution options” is now much
more prevalent within both Core and ORM, and many ORM-related methods
from Query are now implemented as execution options (see
Query.execution_options() for some examples).

See also
........

See Migrating to SQLAlchemy 2.0.

#5159(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5159

8.1.1.4 Transparent SQL Compilation Caching added to All DQL, DML Statements in Core, ORM
.........................................................................................

One of the most broadly encompassing changes to ever land in a single
SQLAlchemy version, a many-month reorganization and refactoring of all
querying systems from the base of Core all the way through ORM now
allows the majority of Python computation involved producing SQL strings
and related statement metadata from a user-constructed statement to be
cached in memory, such that subsequent invocations of an identical
statement construct will use 35-60% fewer CPU resources.

This caching goes beyond the construction of the SQL string to also
include the construction of result fetching structures that link the SQL
construct to the result set, and in the ORM it includes the
accommodation of ORM-enabled attribute loaders, relationship eager
loaders and other options, and object construction routines that must be
built up each time an ORM query seeks to run and construct ORM objects
from result sets.

To introduce the general idea of the feature, given code from the
Performance suite as follows, which will invoke a very simple
query “n” times, for a default value of n=10000.  The query returns only
a single row, as the overhead we are looking to decrease is that of
`many small queries'.  The optimization is not as significant for
queries that return many rows:

     session = Session(bind=engine)
     for id_ in random.sample(ids, n):
         result = session.query(Customer).filter(Customer.id == id_).one()

This example in the 1.3 release of SQLAlchemy on a Dell XPS13 running
Linux completes as follows:

     test_orm_query : (10000 iterations); total time 3.440652 sec

In 1.4, the code above without modification completes:

     test_orm_query : (10000 iterations); total time 2.367934 sec

This first test indicates that regular ORM queries when using caching
can run over many iterations in the range of `30% faster'.

A second variant of the feature is the optional use of Python lambdas to
defer the construction of the query itself.  This is a more
sophisticated variant of the approach used by the “Baked Query”
extension, which was introduced in version 1.0.0.  The “lambda” feature
may be used in a style very similar to that of baked queries, except
that it is available in an ad-hoc way for any SQL construct.  It
additionally includes the ability to scan each invocation of the lambda
for bound literal values that change on every invocation, as well as
changes to other constructs, such as querying from a different entity or
column each time, while still not having to run the actual code each
time.

Using this API looks as follows:

     session = Session(bind=engine)
     for id_ in random.sample(ids, n):
         stmt = lambda_stmt(lambda: future_select(Customer))
         stmt += lambda s: s.where(Customer.id == id_)
         session.execute(stmt).scalar_one()

The code above completes:

     test_orm_query_newstyle_w_lambdas : (10000 iterations); total time 1.247092 sec

This test indicates that using the newer “select()” style of ORM
querying, in conjunction with a full “baked” style invocation that
caches the entire construction, can run over many iterations in the
range of `60% faster' and grants performance about the same as the baked
query system which is now superseded by the native caching system.

The new system makes use of the existing
Connection.execution_options.compiled_cache execution option and
also adds a cache to the Engine directly, which is
configured using the Engine.query_cache_size parameter.

A significant portion of API and behavioral changes throughout 1.4 were
driven in order to support this new feature.

See also
........

See SQL Compilation Caching.

#4639(1) #5380(2) #4645(3) #4808(4) #5004(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4639

   (2) http://www.sqlalchemy.org/trac/ticket/5380

   (3) http://www.sqlalchemy.org/trac/ticket/4645

   (4) http://www.sqlalchemy.org/trac/ticket/4808

   (5) http://www.sqlalchemy.org/trac/ticket/5004

8.1.1.5 Declarative is now integrated into the ORM with new features
....................................................................

After ten years or so of popularity, the ‘sqlalchemy.ext.declarative’
package is now integrated into the ‘sqlalchemy.orm’ namespace, with the
exception of the declarative “extension” classes which remain as
Declarative extensions.

The new classes added to ‘sqlalchemy.orm’ include:

   * registry. - a new class that supersedes the role of the
     “declarative base” class, serving as a registry of mapped classes
     which can be referenced via string name within
     relationship() calls and is agnostic of the style in which any
     particular class was mapped.

   * declarative_base(). - this is the same declarative base
     class that has been in use throughout the span of the declarative
     system, except it now references a registry object
     internally and is implemented by the
     registry.generate_base() method which can be invoked from a
     registry directly.  The declarative_base()
     function creates this registry automatically so there is no impact
     on existing code.  The
     ‘sqlalchemy.ext.declarative.declarative_base’ name is still
     present, emitting a 2.0 deprecation warning when 2.0 deprecations mode
     is enabled.

   * declared_attr(). - the same “declared attr” function
     call now part of ‘sqlalchemy.orm’.  The
     ‘sqlalchemy.ext.declarative.declared_attr’ name is still present,
     emitting a 2.0 deprecation warning when 2.0 deprecations mode
     is enabled.

   * Other names moved into ‘sqlalchemy.orm’ include
     has_inherited_table(), synonym_for(),
     ‘DeclarativeMeta’, see as_declarative().

In addition, The ‘instrument_declarative()’ function is deprecated,
superseded by registry.map_declaratively().  The
ConcreteBase, AbstractConcreteBase, and
DeferredReflection classes remain as extensions in the
Declarative Extensions package.

Mapping styles have now been organized such that they all extend from
the registry object, and fall into these categories:

   *
     Declarative Mapping.

             *
               Using declarative_base(). Base class w/ metaclass

                       * Declarative Table.

                       * Imperative Table (a.k.a. “hybrid table”).

             *
               Using registry.mapped(). Declarative Decorator

                       * Declarative Table

                       *
                         Imperative Table (Hybrid)

                                 * Declarative Mapping with Dataclasses and Attrs.

   *
     Imperative (a.k.a. “classical” mapping).

             *
               Using registry.map_imperatively().

                       * Imperative Mapping with Dataclasses and Attrs.

The existing classical mapping function mapper() remains,
however it is deprecated to call upon mapper() directly; the
new registry.map_imperatively() method now routes the
request through the sqlalchemy.orm.registry() so that it
integrates with other declarative mappings unambiguously.

The new approach interoperates with 3rd party class instrumentation
systems which necessarily must take place on the class before the
mapping process does, allowing declarative mapping to work via a
decorator instead of a declarative base so that packages like
dataclasses(1) and attrs(2) can be used with declarative mappings, in
addition to working with classical mappings.

Declarative documentation has now been fully integrated into the ORM
mapper configuration documentation and includes examples for all styles
of mappings organized into one place.  See the section Mapping Python Classes
for the start of the newly reorganized
documentation.

See also
........

See Mapping Python Classes.

See Python Dataclasses, attrs Supported w/ Declarative, Imperative Mappings.

#5508(3)

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/dataclasses.html

   (2) https://pypi.org/project/attrs/

   (3) http://www.sqlalchemy.org/trac/ticket/5508

8.1.1.6 Python Dataclasses, attrs Supported w/ Declarative, Imperative Mappings
...............................................................................

Along with the new declarative decorator styles introduced in
Declarative is now integrated into the ORM with new features, the
Mapper is now explicitly aware of the Python ‘dataclasses’
module and will recognize attributes that are configured in this way,
and proceed to map them without skipping them as was the case
previously.  In the case of the ‘attrs’ module, ‘attrs’ already removes
its own attributes from the class so was already compatible with
SQLAlchemy classical mappings.  With the addition of the
registry.mapped() decorator, both attribute systems can now
interoperate with Declarative mappings as well.

See also
........

See Declarative Mapping with Dataclasses and Attrs.

See Imperative Mapping with Dataclasses and Attrs.

#5027(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5027

8.1.1.7 Asynchronous IO Support for Core and ORM
................................................

SQLAlchemy now supports Python ‘asyncio’-compatible database drivers
using an all-new asyncio front-end interface to Connection
for Core usage as well as Session for ORM use, using the
AsyncConnection and AsyncSession objects.

     Note: The new asyncio feature should be considered `alpha level'
     for the initial releases of SQLAlchemy 1.4.  This is super new
     stuff that uses some previously unfamiliar programming techniques.

The initial database API supported is the asyncpg asyncio
driver for PostgreSQL.

The internal features of SQLAlchemy are fully integrated by making use
of the greenlet(1) library in order to adapt the flow of execution
within SQLAlchemy’s internals to propagate asyncio ‘await’ keywords
outwards from the database driver to the end-user API, which features
‘async’ methods.  Using this approach, the asyncpg driver is fully
operational within SQLAlchemy’s own test suite and features
compatibility with most psycopg2 features.  The approach was vetted and
improved upon by developers of the greenlet project for which SQLAlchemy
is appreciative.

greenlets are good
..................

Don’t confuse the greenlet(2) library with event-based IO libraries that
build on top of it such as ‘gevent’ and ‘eventlet’; while the use of
these libraries with SQLAlchemy is common, SQLAlchemy’s asyncio
integration `does not' make use of these event based systems in any way.
The asyncio API integrates with the user-provided event loop, typically
Python’s own asyncio event loop, without the use of additional threads
or event systems.  The approach involves a single greenlet context
switch per ‘await’ call, and the extension which makes it possible is
less than 20 lines of code.

The user facing ‘async’ API itself is focused around IO-oriented methods
such as AsyncEngine.connect() and
AsyncConnection.execute().  The new Core constructs strictly
support 2.0 style usage only; which means all statements must be invoked
given a connection object, in this case AsyncConnection.

Within the ORM, 2.0 style query execution is supported, using
select() constructs in conjunction with
AsyncSession.execute(); the legacy Query object itself
is not supported by the AsyncSession class.

ORM features such as lazy loading of related attributes as well as
unexpiry of expired attributes are by definition disallowed in the
traditional asyncio programming model, as they indicate IO operations
that would run implicitly within the scope of a Python ‘getattr()’
operation.  To overcome this, the `traditional' asyncio application
should make judicious use of eager loading techniques as
well as forego the use of features such as expire on commit
so that such loads are not needed.

For the asyncio application developer who `chooses to break' with
tradition, the new API provides a `strictly optional feature' such that
applications that wish to make use of such ORM features can opt to
organize database-related code into functions which can then be run
within greenlets using the AsyncSession.run_sync() method.
See the ‘greenlet_orm.py’ example at Asyncio Integration for
a demonstration.

Support for asynchronous cursors is also provided using new methods
AsyncConnection.stream() and AsyncSession.stream(),
which support a new AsyncResult object that itself
provides awaitable versions of common methods like
AsyncResult.all() and AsyncResult.fetchmany().  Both
Core and ORM are integrated with the feature which corresponds to the
use of “server side cursors” in traditional SQLAlchemy.

See also
........

See Asynchronous I/O (asyncio).

See Asyncio Integration.

#3414(3)

   ---------- Footnotes ----------

   (1) https://greenlet.readthedocs.io/en/latest/

   (2) https://greenlet.readthedocs.io/en/latest/

   (3) http://www.sqlalchemy.org/trac/ticket/3414

8.1.1.8 Many Core and ORM statement objects now perform much of their construction and validation in the compile phase
......................................................................................................................

A major initiative in the 1.4 series is to approach the model of both
Core SQL statements as well as the ORM Query to allow for an efficient,
cacheable model of statement creation and compilation, where the
compilation step would be cached, based on a cache key generated by the
created statement object, which itself is newly created for each use.
Towards this goal, much of the Python computation which occurs within
the construction of statements, particularly that of the ORM
Query as well as the select() construct when used to
invoke ORM queries, is being moved to occur within the compilation phase
of the statement which only occurs after the statement has been invoked,
and only if the statement’s compiled form was not yet cached.

From an end-user perspective, this means that some of the error messages
which can arise based on arguments passed to the object will no longer
be raised immediately, and instead will occur only when the statement is
invoked for the first time.  These conditions are always structural and
not data driven, so there is no risk of such a condition being missed
due to a cached statement.

Error conditions which fall under this category include:

   * when a ‘_selectable.CompoundSelect’ is constructed (e.g.  a UNION,
     EXCEPT, etc.)  and the SELECT statements passed do not have the
     same number of columns, a CompileError is now raised to
     this effect; previously, an ArgumentError would be
     raised immediately upon statement construction.

   * Various error conditions which may arise when calling upon
     Query.join() will be evaluated at statement compilation time
     rather than when the method is first called.

See also
........

See Transparent SQL Compilation Caching added to All DQL, DML Statements in Core, ORM.

8.1.1.9 Repaired internal importing conventions such that code linters may work correctly
.........................................................................................

SQLAlchemy has for a long time used a parameter-injecting decorator to
help resolve mutually-dependent module imports, like this:

     @util.dependency_for("sqlalchemy.sql.dml")
     def insert(self, dml, *args, **kw):

Where the above function would be rewritten to no longer have the ‘dml’
parameter on the outside.  This would confuse code-linting tools into
seeing a missing parameter to functions.  A new approach has been
implemented internally such that the function’s signature is no longer
modified and the module object is procured inside the function instead.

#4656(1)

#4689(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4656

   (2) http://www.sqlalchemy.org/trac/ticket/4689

8.1.1.10 Support for SQL Regular Expression operators
.....................................................

A long awaited feature to add rudimentary support for database regular
expression operators, to complement the ColumnOperators.like()
and ColumnOperators.match() suites of operations.  The
new features include ColumnOperators.regexp_match()
implementing a regular expression match like function, and
ColumnOperators.regexp_replace() implementing a regular expression
string replace function.

Supported backends include SQLite, PostgreSQL, MySQL / MariaDB, and
Oracle.  The SQLite backend only supports “regexp_match” but not
“regexp_replace”.

The regular expression syntaxes and flags are `not backend agnostic'.  A
future feature will allow multiple regular expression syntaxes to be
specified at once to switch between different backends on the fly.

For SQLite, Python’s ‘re.search()’ function with no additional arguments
is established as the implementation.

See also
........

See ColumnOperators.regexp_match().

See ColumnOperators.regexp_replace().

See Regular Expression Support. - SQLite implementation notes

#1390(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1390

8.1.1.11 SQLAlchemy 2.0 Deprecations Mode
.........................................

One of the primary goals of the 1.4 release is to provide a
“transitional” release so that applications may migrate to SQLAlchemy
2.0 gradually.  Towards this end, a primary feature in release 1.4 is
“2.0 deprecations mode”, which is a series of deprecation warnings that
emit against every detectable API pattern which will work differently in
version 2.0.  The warnings all make use of the RemovedIn20Warning
class.  As these warnings affect foundational patterns including
the select() and Engine constructs, even simple
applications can generate a lot of warnings until appropriate API
changes are made.  The warning mode is therefore turned off by default
until the developer enables the environment variable
‘SQLALCHEMY_WARN_20=1’.

For a full walkthrough of using 2.0 Deprecations mode, see
Migration to 2.0 Step Two - Turn on RemovedIn20Warnings.

See also
........

See Migrating to SQLAlchemy 2.0.

See Migration to 2.0 Step Two - Turn on RemovedIn20Warnings.

8.1.1.12 API and Behavioral Changes - Core
..........................................

8.1.1.13 A SELECT statement is no longer implicitly considered to be a FROM clause
..................................................................................

This change is one of the larger conceptual changes in SQLAlchemy in
many years, however it is hoped that the end user impact is relatively
small, as the change more closely matches what databases like MySQL and
PostgreSQL require in any case.

The most immediate noticeable impact is that a select() can
no longer be embedded inside of another select() directly,
without explicitly turning the inner select() into a subquery
first.  This is historically performed by using the
SelectBase.alias() method, which remains, however is more
explicitly suited by using a new method SelectBase.subquery();
both methods do the same thing.  The object returned is now
Subquery, which is very similar to the Alias object and
shares a common base AliasedReturnsRows.

That is, this will now raise:

     stmt1 = select(user.c.id, user.c.name)
     stmt2 = select(addresses, stmt1).select_from(addresses.join(stmt1))

Raising:

     sqlalchemy.exc.ArgumentError: Column expression or FROM clause expected,
     got <...Select object ...>. To create a FROM clause from a <class
     'sqlalchemy.sql.selectable.Select'> object, use the .subquery() method.

The correct calling form is instead (noting also that brackets are no longer required for select()):

     sq1 = select(user.c.id, user.c.name).subquery()
     stmt2 = select(addresses, sq1).select_from(addresses.join(sq1))

Noting above that the SelectBase.subquery() method is
essentially equivalent to using the SelectBase.alias()
method.

The rationale for this change is based on the following:

   * In order to support the unification of Select with
     Query, the Select object needs to have
     Select.join() and Select.outerjoin() methods that
     actually add JOIN criteria to the existing FROM clause, as is what
     users have always expected it to do in any case.  The previous
     behavior, having to align with what a FromClause would
     do, was that it would generate an unnamed subquery and then JOIN to
     it, which was a completely useless feature that only confused those
     users unfortunate enough to try this.  This change is discussed at
     select().join() and outerjoin() add JOIN criteria to the current query, rather than creating a subquery.

   * The behavior of including a SELECT in the FROM clause of another
     SELECT without first creating an alias or subquery would be that it
     creates an unnamed subquery.  While standard SQL does support this
     syntax, in practice it is rejected by most databases.  For example,
     both the MySQL and PostgreSQL outright reject the usage of unnamed
     subqueries:

          # MySQL / MariaDB:

          MariaDB [(none)]> select * from (select 1);
          ERROR 1248 (42000): Every derived table must have its own alias

          # PostgreSQL:

          test=> select * from (select 1);
          ERROR:  subquery in FROM must have an alias
          LINE 1: select * from (select 1);
                                ^
          HINT:  For example, FROM (SELECT ...) [AS] foo.

     A database like SQLite accepts them, however it is still often the
     case that the names produced from such a subquery are too ambiguous
     to be useful:

          sqlite> CREATE TABLE a(id integer);
          sqlite> CREATE TABLE b(id integer);
          sqlite> SELECT * FROM a JOIN (SELECT * FROM b) ON a.id=id;
          Error: ambiguous column name: id
          sqlite> SELECT * FROM a JOIN (SELECT * FROM b) ON a.id=b.id;
          Error: no such column: b.id

          # use a name
          sqlite> SELECT * FROM a JOIN (SELECT * FROM b) AS anon_1 ON a.id=anon_1.id;

As SelectBase objects are no longer FromClause
objects, attributes like the ‘.c’ attribute as well as methods like
‘.select()’ is now deprecated, as they imply implicit production of a
subquery.  The ‘.join()’ and ‘.outerjoin()’ methods are now
repurposed to append JOIN criteria to the existing query in a
similar way as that of Query.join(), which is what users have
always expected these methods to do in any case.

In place of the ‘.c’ attribute, a new attribute
SelectBase.selected_columns is added.  This attribute resolves to
a column collection that is what most people hope that ‘.c’ does (but
does not), which is to reference the columns that are in the columns
clause of the SELECT statement.  A common beginner mistake is code such
as the following:

     stmt = select(users)
     stmt = stmt.where(stmt.c.name == 'foo')

The above code appears intuitive and that it would generate “SELECT *
FROM users WHERE name=’foo’”, however veteran SQLAlchemy users will
recognize that it in fact generates a useless subquery resembling
“SELECT * FROM (SELECT * FROM users) WHERE name=’foo’”.

The new SelectBase.selected_columns attribute however `does'
suit the use case above, as in a case like the above it links directly
to the columns present in the ‘users.c’ collection:

     stmt = select(users)
     stmt = stmt.where(stmt.selected_columns.name == 'foo')

#4617(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4617

8.1.1.14 select().join() and outerjoin() add JOIN criteria to the current query, rather than creating a subquery
................................................................................................................

Towards the goal of unifying Query and Select,
particularly for 2.0 style use of Select, it was critical that
there be a working Select.join() method that behaves like
the Query.join() method, adding additional entries to the
FROM clause of the existing SELECT and then returning the new
Select object for further modification, instead of wrapping the
object inside of an unnamed subquery and returning a JOIN from that
subquery, a behavior that has always been virtually useless and
completely misleading to users.

To allow this to be the case, see A SELECT statement is no longer implicitly considered to be a FROM clause
was first implemented
which splits off Select from having to be a FromClause;
this removed the requirement that Select.join() would
need to return a Join object rather than a new version of
that Select object that includes a new JOIN in its FROM
clause.

From that point on, as the Select.join() and
Select.outerjoin() did have an existing behavior, the original
plan was that these methods would be deprecated, and the new “useful”
version of the methods would be available on an alternate, “future”
Select object available as a separate import.

However, after some time working with this particular codebase, it was
decided that having two different kinds of Select objects
floating around, each with 95% the same behavior except for some subtle
difference in how some of the methods behave was going to be more
misleading and inconvenient than simply making a hard change in how
these two methods behave, given that the existing behavior of
Select.join() and Select.outerjoin() is essentially
never used and only causes confusion.

So it was decided, given how very useless the current behavior is, and
how extremely useful and important and useful the new behavior would be,
to make a `hard behavioral change' in this one area, rather than waiting
another year and having a more awkward API in the interim.  SQLAlchemy
developers do not take it lightly to make a completely breaking change
like this, however this is a very special case and it is extremely
unlikely that the previous implementation of these methods was being
used; as noted in A SELECT statement is no longer implicitly considered to be a FROM clause,
major databases such as MySQL and
PostgreSQL don’t allow for unnamed subqueries in any case and from a
syntactical point of view it’s nearly impossible for a JOIN from an
unnamed subquery to be useful since it’s very difficult to refer to the
columns within it unambiguously.

With the new implementation, see Select.join() and
Select.outerjoin() now behave very similarly to that of
Query.join(), adding JOIN criteria to the existing statement by
matching to the left entity:

     stmt = select(user_table).join(addresses_table, user_table.c.id == addresses_table.c.user_id)

producing:

     SELECT user.id, user.name FROM user JOIN address ON user.id=address.user_id

As is the case for Join, the ON clause is automatically
determined if feasible:

     stmt = select(user_table).join(addresses_table)

When ORM entities are used in the statement, this is essentially how ORM
queries are built up using 2.0 style invocation.  ORM entities will
assign a “plugin” to the statement internally such that ORM-related
compilation rules will take place when the statement is compiled into a
SQL string.  More directly, the Select.join() method can
accommodate ORM relationships, without breaking the hard separation
between Core and ORM internals:

     stmt = select(User).join(User.addresses)

Another new method Select.join_from() is also added, which
allows easier specification of the left and right side of a join at
once:

     stmt = select(Address.email_address, User.name).join_from(User, Address)

producing:

     SELECT address.email_address, user.name FROM user JOIN address ON user.id == address.user_id

8.1.1.15 The URL object is now immutable
........................................

The URL object has been formalized such that it now
presents itself as a ‘namedtuple’ with a fixed number of fields that are
immutable.  In addition, the dictionary represented by the
URL.query attribute is also an immutable mapping.  Mutation of
the URL object was not a formally supported or documented
use case which led to some open-ended use cases that made it very
difficult to intercept incorrect usages, most commonly mutation of the
URL.query dictionary to include non-string elements.  It
also led to all the common problems of allowing mutability in a
fundamental data object, namely unwanted mutations elsewhere leaking
into code that didn’t expect the URL to change.  Finally, the namedtuple
design is inspired by that of Python’s ‘urllib.parse.urlparse()’ which
returns the parsed object as a named tuple.

The decision to change the API outright is based on a calculus weighing
the infeasibility of a deprecation path (which would involve changing
the URL.query dictionary to be a special dictionary that
emits deprecation warnings when any kind of standard library mutation
methods are invoked, in addition that when the dictionary would hold any
kind of list of elements, the list would also have to emit deprecation
warnings on mutation) against the unlikely use case of projects already
mutating URL objects in the first place, as well as that
small changes such as that of #5341(1) were creating
backwards-incompatibility in any case.  The primary case for mutation of
a URL object is that of parsing plugin arguments within the
CreateEnginePlugin extension point, itself a fairly recent
addition that based on Github code search is in use by two repositories,
neither of which are actually mutating the URL object.

The URL object now provides a rich interface inspecting and
generating new URL objects.  The existing mechanism to
create a URL object, the make_url() function,
remains unchanged:

     >>> from sqlalchemy.engine import make_url
     >>> url = make_url("postgresql+psycopg2://user:pass@host/dbname")

For programmatic construction, code that may have been using the
URL constructor or ‘__init__’ method directly will receive a
deprecation warning if arguments are passed as keyword arguments and not
an exact 7-tuple.  The keyword-style constructor is now available via
the URL.create() method:

     >>> from sqlalchemy.engine import URL
     >>> url = URL.create("postgresql", "user", "pass", host="host", database="dbname")
     >>> str(url)
     'postgresql://user:pass@host/dbname'

Fields can be altered typically using the URL.set() method,
which returns a new URL object with changes applied:

     >>> mysql_url = url.set(drivername="mysql+pymysql")
     >>> str(mysql_url)
     'mysql+pymysql://user:pass@host/dbname'

To alter the contents of the URL.query dictionary, methods
such as URL.update_query_dict() may be used:

     >>> url.update_query_dict({"sslcert": '/path/to/crt'})
     postgresql://user:***@host/dbname?sslcert=%2Fpath%2Fto%2Fcrt

To upgrade code that is mutating these fields directly, a `backwards and
forwards compatible approach' is to use a duck-typing, as in the
following style:

     def set_url_drivername(some_url, some_drivername):
         # check for 1.4
         if hasattr(some_url, "set"):
             return some_url.set(drivername=some_drivername)
         else:
             # SQLAlchemy 1.3 or earlier, mutate in place
             some_url.drivername = some_drivername
             return some_url

     def set_ssl_cert(some_url, ssl_cert):
         # check for 1.4
         if hasattr(some_url, "update_query_dict"):
             return some_url.update_query_dict({"sslcert": ssl_cert})
         else:
             # SQLAlchemy 1.3 or earlier, mutate in place
             some_url.query["sslcert"] = ssl_cert
             return some_url

The query string retains its existing format as a dictionary of strings
to strings, using sequences of strings to represent multiple parameters.
For example:

     >>> from sqlalchemy.engine import make_url
     >>> url = make_url("postgresql://user:pass@host/dbname?alt_host=host1&alt_host=host2&sslcert=%2Fpath%2Fto%2Fcrt")
     >>> url.query
     immutabledict({'alt_host': ('host1', 'host2'), 'sslcert': '/path/to/crt'})

To work with the contents of the URL.query attribute such
that all values are normalized into sequences, use the
URL.normalized_query attribute:

     >>> url.normalized_query
     immutabledict({'alt_host': ('host1', 'host2'), 'sslcert': ('/path/to/crt',)})

The query string can be appended to via methods such as
URL.update_query_dict(), URL.update_query_pairs(),
URL.update_query_string():

     >>> url.update_query_dict({"alt_host": "host3"}, append=True)
     postgresql://user:***@host/dbname?alt_host=host1&alt_host=host2&alt_host=host3&sslcert=%2Fpath%2Fto%2Fcrt

See also
........

See URL.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5341

8.1.1.16 Changes to CreateEnginePlugin
......................................

The CreateEnginePlugin is also impacted by this change, as
the documentation for custom plugins indicated that the ‘dict.pop()’
method should be used to remove consumed arguments from the URL object.
This should now be achieved using the
CreateEnginePlugin.update_url() method.  A backwards compatible
approach would look like:

     from sqlalchemy.engine import CreateEnginePlugin

     class MyPlugin(CreateEnginePlugin):
         def __init__(self, url, kwargs):
             # check for 1.4 style
             if hasattr(CreateEnginePlugin, "update_url"):
                 self.my_argument_one = url.query['my_argument_one']
                 self.my_argument_two = url.query['my_argument_two']
             else:
                 # legacy
                 self.my_argument_one = url.query.pop('my_argument_one')
                 self.my_argument_two = url.query.pop('my_argument_two')

             self.my_argument_three = kwargs.pop('my_argument_three', None)

         def update_url(self, url):
             # this method runs in 1.4 only and should be used to consume
             # plugin-specific arguments
             return url.difference_update_query(
                 ["my_argument_one", "my_argument_two"]
             )

See the docstring at CreateEnginePlugin for complete
details on how this class is used.

#5526(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5526

8.1.1.17 select(), case() now accept positional expressions
...........................................................

As it may be seen elsewhere in this document, the select()
construct will now accept “columns clause” arguments positionally,
rather than requiring they be passed as a list:

     # new way, supports 2.0
     stmt = select(table.c.col1, table.c.col2, ...)

When sending the arguments positionally, no other keyword arguments are
permitted.  In SQLAlchemy 2.0, the above calling style will be the only
calling style supported.

For the duration of 1.4, the previous calling style will still continue
to function, which passes the list of columns or other expressions as a
list:

     # old way, still works in 1.4
     stmt = select([table.c.col1, table.c.col2, ...])

The above legacy calling style also accepts the old keyword arguments
that have since been removed from most narrative documentation.  The
existence of these keyword arguments is why the columns clause was
passed as a list in the first place:

     # very much the old way, but still works in 1.4
     stmt = select([table.c.col1, table.c.col2, ...], whereclause=table.c.col1 == 5)

The detection between the two styles is based on whether or not the
first positional argument is a list.  There are unfortunately still
likely some usages that look like the following, where the keyword for
the “whereclause” is omitted:

     # very much the old way, but still works in 1.4
     stmt = select([table.c.col1, table.c.col2, ...], table.c.col1 == 5)

As part of this change, the Select construct also gains the
2.0-style “future” API which includes an updated Select.join()
method as well as methods like Select.filter_by() and
Select.join_from().

In a related change, the case() construct has also been
modified to accept its list of WHEN clauses positionally, with a similar
deprecation track for the old calling style:

     stmt = select(users_table).where(
         case(
             (users_table.c.name == 'wendy', 'W'),
             (users_table.c.name == 'jack', 'J'),
             else_='E'
         )
     )

The convention for SQLAlchemy constructs accepting ‘*args’ vs.  a list
of values, as is the latter case for a construct like
ColumnOperators.in_(), is that `positional arguments are used for
structural specification, lists are used for data specification'.

See also
........

See select() no longer accepts varied constructor arguments, columns are passed positionally.

See select() construct created in “legacy” mode; keyword arguments, etc..

#5284(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5284

8.1.1.18 All IN expressions render parameters for each value in the list on the fly (e.g. expanding parameters)
...............................................................................................................

The “expanding IN” feature, first introduced in Late-expanded IN parameter sets allow IN expressions with cached statements,
has
matured enough such that it is clearly superior to the previous method
of rendering IN expressions.  As the approach was improved to handle
empty lists of values, it is now the only means that Core / ORM will use
to render lists of IN parameters.

The previous approach which has been present in SQLAlchemy since its
first release was that when a list of values were passed to the
ColumnOperators.in_() method, the list would be expanded into a
series of individual BindParameter objects at statement
construction time.  This suffered from the limitation that it was not
possible to vary the parameter list at statement execution time based on
the parameter dictionary, which meant that string SQL statements could
not be cached independently of their parameters, nor could the parameter
dictionary be fully used for statements that included IN expressions
generally.

In order to service the “baked query” feature described at Baked Queries,
a cacheable version of IN was needed, which is what
brought about the “expanding IN” feature.  In contrast to the existing
behavior whereby the parameter list is expanded at statement
construction time into individual BindParameter objects, the
feature instead uses a single BindParameter that stores the
list of values at once; when the statement is executed by the
Engine, it is “expanded” on the fly into individual bound parameter
positions based on the parameters passed to the call to
Connection.execute(), and the existing SQL string which may have
been retrieved from a previous execution is modified using a regular
expression to suit the current parameter set.  This allows for the same
Compiled object, which stores the rendered string statement,
to be invoked multiple times against different parameter sets that
modify the list contents passed to IN expressions, while still
maintaining the behavior of individual scalar parameters being passed to
the DBAPI. While some DBAPIs do support this functionality directly, it
is not generally available; the “expanding IN” feature now supports the
behavior consistently for all backends.

As a major focus of 1.4 is to allow for true statement caching in Core
and ORM without the awkwardness of the “baked” system, and since the
“expanding IN” feature represents a simpler approach to building
expressions in any case, it’s now invoked automatically whenever a list
of values is passed to an IN expression:

     stmt = select(A.id, A.data).where(A.id.in_([1, 2, 3]))

The pre-execution string representation is:

     >>> print(stmt)
     SELECT a.id, a.data
     FROM a
     WHERE a.id IN ([POSTCOMPILE_id_1])

To render the values directly, use ‘literal_binds’ as was the case
previously:

     >>> print(stmt.compile(compile_kwargs={"literal_binds": True}))
     SELECT a.id, a.data
     FROM a
     WHERE a.id IN (1, 2, 3)

A new flag, “render_postcompile”, is added as a helper to allow the
current bound value to be rendered as it would be passed to the
database:

     >>> print(stmt.compile(compile_kwargs={"render_postcompile": True}))
     SELECT a.id, a.data
     FROM a
     WHERE a.id IN (:id_1_1, :id_1_2, :id_1_3)

Engine logging output shows the ultimate rendered statement as well:

     INFO sqlalchemy.engine.base.Engine SELECT a.id, a.data
     FROM a
     WHERE a.id IN (?, ?, ?)
     INFO sqlalchemy.engine.base.Engine (1, 2, 3)

As part of this change, the behavior of “empty IN” expressions, where
the list parameter is empty, is now standardized on use of the IN
operator against a so-called “empty set”.  As there is no standard SQL
syntax for empty sets, a SELECT that returns no rows is used, tailored
in specific ways for each backend so that the database treats it as an
empty set; this feature was first introduced in version 1.3 and is
described at Expanding IN feature now supports empty lists.
The create_engine.empty_in_strategy parameter, introduced in
version 1.2 as a means for migrating for how this case was treated for
the previous IN system, is now deprecated and this flag no longer has an
effect; as described in The IN / NOT IN operator’s empty collection behavior is now configurable; default expression simplified,
this flag allowed a dialect to switch between the original system
of comparing a column against itself, which turned out to be a huge
performance issue, and a newer system of comparing “1 != 1” in order to
produce a “false” expression.  The 1.3 introduced behavior which now
takes place in all cases is more correct than both approaches as the IN
operator is still used, and does not have the performance issue of the
original system.

In addition, the “expanding” parameter system has been generalized so
that it also services other dialect-specific use cases where a parameter
cannot be accommodated by the DBAPI or backing database; see *note New
“post compile” bound parameters used for LIMIT/OFFSET in Oracle, SQL
Server: d0e. for details.

See also
........

See New “post compile” bound parameters used for LIMIT/OFFSET in Oracle, SQL Server.

See Expanding IN feature now supports empty lists.

See BindParameter.

#4645(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4645

8.1.1.19 Built-in FROM linting will warn for any potential cartesian products in a SELECT statement
...................................................................................................

As the Core expression language as well as the ORM are built on an
“implicit FROMs” model where a particular FROM clause is automatically
added if any part of the query refers to it, a common issue is the case
where a SELECT statement, either a top level statement or an embedded
subquery, contains FROM elements that are not joined to the rest of the
FROM elements in the query, causing what’s referred to as a “cartesian
product” in the result set, i.e.  every possible combination of rows
from each FROM element not otherwise joined.  In relational databases,
this is nearly always an undesirable outcome as it produces an enormous
result set full of duplicated, uncorrelated data.

SQLAlchemy, for all of its great features, is particularly prone to this
sort of issue happening as a SELECT statement will have elements added
to its FROM clause automatically from any table seen in the other
clauses.  A typical scenario looks like the following, where two tables
are JOINed together, however an additional entry in the WHERE clause
that perhaps inadvertently does not line up with these two tables will
create an additional FROM entry:

     address_alias = aliased(Address)

     q = session.query(User).\
         join(address_alias, User.addresses).\
         filter(Address.email_address == 'foo')

The above query selects from a JOIN of ‘User’ and ‘address_alias’, the
latter of which is an alias of the ‘Address’ entity.  However, the
‘Address’ entity is used within the WHERE clause directly, so the above
would result in the SQL:

     SELECT
         users.id AS users_id, users.name AS users_name,
         users.fullname AS users_fullname,
         users.nickname AS users_nickname
     FROM addresses, users JOIN addresses AS addresses_1 ON users.id = addresses_1.user_id
     WHERE addresses.email_address = :email_address_1

In the above SQL, we can see what SQLAlchemy developers term “the
dreaded comma”, as we see “FROM addresses, users JOIN addresses” in the
FROM clause which is the classic sign of a cartesian product; where a
query is making use of JOIN in order to join FROM clauses together,
however because one of them is not joined, it uses a comma.  The above
query will return a full set of rows that join the “user” and
“addresses” table together on the “id / user_id” column, and will then
apply all those rows into a cartesian product against every row in the
“addresses” table directly.  That is, if there are ten user rows and 100
rows in addresses, the above query will return its expected result rows,
likely to be 100 as all address rows would be selected, multiplied by
100 again, so that the total result size would be 10000 rows.

The “table1, table2 JOIN table3” pattern is one that also occurs quite
frequently within the SQLAlchemy ORM due to either subtle
mis-application of ORM features particularly those related to joined
eager loading or joined table inheritance, as well as a result of
SQLAlchemy ORM bugs within those same systems.  Similar issues apply to
SELECT statements that use “implicit joins”, where the JOIN keyword is
not used and instead each FROM element is linked with another one via
the WHERE clause.

For some years there has been a recipe on the Wiki that applies a graph
algorithm to a select() construct at query execution time and
inspects the structure of the query for these un-linked FROM clauses,
parsing through the WHERE clause and all JOIN clauses to determine how
FROM elements are linked together and ensuring that all the FROM
elements are connected in a single graph.  This recipe has now been
adapted to be part of the SQLCompiler itself where it now
optionally emits a warning for a statement if this condition is
detected.  The warning is enabled using the
create_engine.enable_from_linting flag and is enabled by default.
The computational overhead of the linter is very low, and additionally
it only occurs during statement compilation which means for a cached SQL
statement it only occurs once.

Using this feature, our ORM query above will emit a warning:

     >>> q.all()
     SAWarning: SELECT statement has a cartesian product between FROM
     element(s) "addresses_1", "users" and FROM element "addresses".
     Apply join condition(s) between each element to resolve.

The linter feature accommodates not just for tables linked together
through the JOIN clauses but also through the WHERE clause Above, we can
add a WHERE clause to link the new ‘Address’ entity with the previous
‘address_alias’ entity and that will remove the warning:

     q = session.query(User).\
         join(address_alias, User.addresses).\
         filter(Address.email_address == 'foo').\
         filter(Address.id == address_alias.id)  # resolve cartesian products,
                                                 # will no longer warn

The cartesian product warning considers `any' kind of link between two
FROM clauses to be a resolution, even if the end result set is still
wasteful, as the linter is intended only to detect the common case of a
FROM clause that is completely unexpected.  If the FROM clause is
referred to explicitly elsewhere and linked to the other FROMs, no
warning is emitted:

     q = session.query(User).\
         join(address_alias, User.addresses).\
         filter(Address.email_address == 'foo').\
         filter(Address.id > address_alias.id)  # will generate a lot of rows,
                                                # but no warning

Full cartesian products are also allowed if they are explicitly stated;
if we wanted for example the cartesian product of ‘User’ and ‘Address’,
we can JOIN on true() so that every row will match with
every other; the following query will return all rows and produce no
warnings:

     from sqlalchemy import true

     # intentional cartesian product
     q = session.query(User).join(Address, true())  # intentional cartesian product

The warning is only generated by default when the statement is compiled
by the Connection for execution; calling the
ClauseElement.compile() method will not emit a warning unless the
linting flag is supplied:

     >>> from sqlalchemy.sql import FROM_LINTING
     >>> print(q.statement.compile(linting=FROM_LINTING))
     SAWarning: SELECT statement has a cartesian product between FROM element(s) "addresses" and FROM element "users".  Apply join condition(s) between each element to resolve.
     SELECT users.id, users.name, users.fullname, users.nickname
     FROM addresses, users JOIN addresses AS addresses_1 ON users.id = addresses_1.user_id
     WHERE addresses.email_address = :email_address_1

#4737(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4737

8.1.1.20 New Result object
..........................

A major goal of SQLAlchemy 2.0 is to unify how “results” are handled
between the ORM and Core.  Towards this goal, version 1.4 introduces new
versions of both the ‘ResultProxy’ and ‘RowProxy’ objects that have been
part of SQLAlchemy since the beginning.

The new objects are documented at Result and Row,
and are used not only for Core result sets but for 2.0 style results
within the ORM as well.

This result object is fully compatible with ‘ResultProxy’ and includes
many new features, that are now applied to both Core and ORM results
equally, including methods such as:

Result.one(). - returns exactly a single row, or raises:

     with engine.connect() as conn:
         row = conn.execute(table.select().where(table.c.id == 5)).one()

See Result.one_or_none(). - same, but also returns None for no
rows

See Result.all(). - returns all rows

See Result.partitions(). - fetches rows in chunks:

     with engine.connect() as conn:
         result = conn.execute(
             table.select().order_by(table.c.id),
             execution_options={"stream_results": True}
         )
         for chunk in result.partitions(500):
             # process up to 500 records

See Result.columns(). - allows slicing and reorganizing of rows:

     with engine.connect() as conn:
        # requests x, y, z
        result = conn.execute(select(table.c.x, table.c.y, table.c.z))

        # iterate rows as y, x
        for y, x in result.columns("y", "x"):
            print("Y: %s  X: %s" % (y, x))

See Result.scalars(). - returns lists of scalar objects, from the
first column by default but can also be selected:

     result = session.execute(select(User).order_by(User.id))
     for user_obj in result.scalars():
         # ...

See Result.mappings(). - instead of named-tuple rows, returns
dictionaries:

     with engine.connect() as conn:
        result = conn.execute(select(table.c.x, table.c.y, table.c.z))

        for map_ in result.mappings():
            print("Y: %(y)s  X: %(x)s" % map_)

When using Core, the object returned by Connection.execute()
is an instance of CursorResult, which continues to feature
the same API features as ‘ResultProxy’ regarding inserted primary keys,
defaults, rowcounts, etc.  For ORM, a Result subclass will be
returned that performs translation of Core rows into ORM rows, and then
allows all the same operations to take place.

See also
........

See ORM Query Unified with Core Select. - in the 2.0 migration
documentation

#5087(1)

#4395(2)

#4959(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5087

   (2) http://www.sqlalchemy.org/trac/ticket/4395

   (3) http://www.sqlalchemy.org/trac/ticket/4959

8.1.1.21 RowProxy is no longer a “proxy”; is now called Row and behaves like an enhanced named tuple
....................................................................................................

The ‘RowProxy’ class, which represents individual database result rows
in a Core result set, is now called Row and is no longer a
“proxy” object; what this means is that when the Row object
is returned, the row is a simple tuple that contains the data in its
final form, already having been processed by result-row handling
functions associated with datatypes (examples include turning a date
string from the database into a ‘datetime’ object, a JSON string into a
Python ‘json.loads()’ result, etc.).

The immediate rationale for this is so that the row can act more like a
Python named tuple, rather than a mapping, where the values in the tuple
are the subject of the ‘__contains__’ operator on the tuple, rather than
the keys.  With Row acting like a named tuple, it is then
suitable for use as as replacement for the ORM’s ‘KeyedTuple’ object,
leading to an eventual API where both the ORM and Core deliver result
sets that behave identically.  Unification of major patterns within ORM
and Core is a major goal of SQLAlchemy 2.0, and release 1.4 aims to have
most or all of the underlying architectural patterns in place in order
to support this process.  The note in The “KeyedTuple” object returned by Query is replaced by Row
describes the ORM’s use of
the Row class.

For release 1.4, the Row class provides an additional
subclass LegacyRow, which is used by Core and provides a
backwards-compatible version of ‘RowProxy’ while emitting deprecation
warnings for those API features and behaviors that will be moved.  ORM
Query now makes use of Row directly as a
replacement for ‘KeyedTuple’.

The LegacyRow class is a transitional class where the
‘__contains__’ method is still testing against the keys, not the values,
while emitting a deprecation warning when the operation succeeds.
Additionally, all the other mapping-like methods on the previous
‘RowProxy’ are deprecated, including ‘LegacyRow.keys()’, see
LegacyRow.items(), etc.  For mapping-like behaviors from a
Row object, including support for these methods as well as a
key-oriented ‘__contains__’ operator, the API going forward will be to
first access a special attribute Row._mapping, which will
then provide a complete mapping interface to the row, rather than a
tuple interface.

8.1.1.22 Rationale: To behave more like a named tuple rather than a mapping
...........................................................................

The difference between a named tuple and a mapping as far as boolean
operators can be summarized.  Given a “named tuple” in pseudo code as:

     row = (id: 5,  name: 'some name')

The biggest cross-incompatible difference is the behavior of
‘__contains__’:

     "id" in row          # True for a mapping, False for a named tuple
     "some name" in row   # False for a mapping, True for a named tuple

In 1.4, when a LegacyRow is returned by a Core result set,
the above ‘"id" in row’ comparison will continue to succeed, however a
deprecation warning will be emitted.  To use the “in” operator as a
mapping, use the Row._mapping attribute:

     "id" in row._mapping

SQLAlchemy 2.0’s result object will feature a ‘.mappings()’ modifier so
that these mappings can be received directly:

     # using sqlalchemy.future package
     for row in result.mappings():
         row["id"]

8.1.1.23 Proxying behavior goes away, was also unnecessary in modern usage
..........................................................................

The refactor of Row to behave like a tuple requires that all
data values be fully available up front.  This is an internal behavior
change from that of ‘RowProxy’, where result-row processing functions
would be invoked at the point of accessing an element of the row,
instead of when the row was first fetched.  This means for example when
retrieving a datetime value from SQLite, the data for the row as present
in the ‘RowProxy’ object would previously have looked like:

     row_proxy = (1, '2019-12-31 19:56:58.272106')

and then upon access via ‘__getitem__’, the ‘datetime.strptime()’
function would be used on the fly to convert the above string date into
a ‘datetime’ object.  With the new architecture, the ‘datetime()’ object
is present in the tuple when it is returned, the ‘datetime.strptime()’
function having been called just once up front:

     row = (1, datetime.datetime(2019, 12, 31, 19, 56, 58, 272106))

The ‘RowProxy’ and Row objects in SQLAlchemy are where the
majority of SQLAlchemy’s C extension code takes place.  This code has
been highly refactored to provide the new behavior in an efficient
manner, and overall performance has been improved as the design of
Row is now considerably simpler.

The rationale behind the previous behavior assumed a usage model where a
result row might have dozens or hundreds of columns present, where most
of those columns would not be accessed, and for which a majority of
those columns would require some result-value processing function.  By
invoking the processing function only when needed, the goal was that
lots of result processing functions would not be necessary, thus
increasing performance.

There are many reasons why the above assumptions do not hold:

  1. the vast majority of row-processing functions called were to
     Unicode decode a bytestring into a Python Unicode string under
     Python 2.  This was right as Python Unicode was beginning to see
     use and before Python 3 existed.  Once Python 3 was introduced,
     within a few years, all Python DBAPIs took on the proper role of
     supporting the delivering of Python Unicode objects directly, under
     both Python 2 and Python 3, as an option in the former case and as
     the only way forward in the latter case.  Eventually, in most cases
     it became the default for Python 2 as well.  SQLAlchemy’s Python 2
     support still enables explicit string-to-Unicode conversion for
     some DBAPIs such as cx_Oracle, however it is now performed at the
     DBAPI level rather than as a standard SQLAlchemy result row
     processing function.

  2. The above string conversion, when it is used, was made to be
     extremely performant via the C extensions, so much so that even in
     1.4, SQLAlchemy’s byte-to-Unicode codec hook is plugged into
     cx_Oracle where it has been observed to be more performant than
     cx_Oracle’s own hook; this meant that the overhead for converting
     all strings in a row was not as significant as it originally was in
     any case.

  3. Row processing functions are not used in most other cases; the
     exceptions are SQLite’s datetime support, JSON support for some
     backends, some numeric handlers such as string to ‘Decimal’.  In
     the case of ‘Decimal’, Python 3 also standardized on the highly
     performant ‘cdecimal’ implementation, which is not the case in
     Python 2 which continues to use the much less performant pure
     Python version.

  4. Fetching full rows where only a few columns are needed is not
     common within real-world use cases In the early days of SQLAlchemy,
     database code from other languages of the form “row = fetch(‘SELECT
     * FROM table’)” was common; using SQLAlchemy’s expression language
     however, code observed in the wild typically makes use of the
     specific columns needed.

See also
........

See The “KeyedTuple” object returned by Query is replaced by Row.

#4710(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4710

8.1.1.24 SELECT objects and derived FROM clauses allow for duplicate columns and column labels
..............................................................................................

This change allows that the select() construct now allows for
duplicate column labels as well as duplicate column objects themselves,
so that result tuples are organized and ordered in the identical way in
that the columns were selected.  The ORM Query already works
this way, so this change allows for greater cross-compatibility between
the two, which is a key goal of the 2.0 transition:

     >>> from sqlalchemy import column, select
     >>> c1, c2, c3, c4 = column('c1'), column('c2'), column('c3'), column('c4')
     >>> stmt = select(c1, c2, c3.label('c2'), c2, c4)
     >>> print(stmt)
     SELECT c1, c2, c3 AS c2, c2, c4

To support this change, the ColumnCollection used by
SelectBase as well as for derived FROM clauses such as subqueries
also support duplicate columns; this includes the new
SelectBase.selected_columns attribute, the deprecated
‘SelectBase.c’ attribute, as well as the FromClause.c
attribute seen on constructs such as Subquery and
Alias:

     >>> list(stmt.selected_columns)
     [
         <sqlalchemy.sql.elements.ColumnClause at 0x7fa540bcca20; c1>,
         <sqlalchemy.sql.elements.ColumnClause at 0x7fa540bcc9e8; c2>,
         <sqlalchemy.sql.elements.Label object at 0x7fa540b3e2e8>,
         <sqlalchemy.sql.elements.ColumnClause at 0x7fa540bcc9e8; c2>,
         <sqlalchemy.sql.elements.ColumnClause at 0x7fa540897048; c4>
     ]

     >>> print(stmt.subquery().select())
     SELECT anon_1.c1, anon_1.c2, anon_1.c2, anon_1.c2, anon_1.c4
     FROM (SELECT c1, c2, c3 AS c2, c2, c4) AS anon_1

ColumnCollection also allows access by integer index to
support when the string “key” is ambiguous:

     >>> stmt.selected_columns[2]
     <sqlalchemy.sql.elements.Label object at 0x7fa540b3e2e8>

To suit the use of ColumnCollection in objects such as
Table and PrimaryKeyConstraint, the old “deduplicating”
behavior which is more critical for these objects is preserved in a new
class ‘DedupeColumnCollection’.

The change includes that the familiar warning ‘"Column %r on table %r
being replaced by %r, which has the same key. Consider use_labels for
select() statements."’ is `removed'; the Select.apply_labels()
is still available and is still used by the ORM for all SELECT
operations, however it does not imply deduplication of column objects,
although it does imply deduplication of implicitly generated labels:

     >>> from sqlalchemy import table
     >>> user = table('user', column('id'), column('name'))
     >>> stmt = select(user.c.id, user.c.name, user.c.id).apply_labels()
     >>> print(stmt)
     SELECT "user".id AS user_id, "user".name AS user_name, "user".id AS id_1
     FROM "user"

Finally, the change makes it easier to create UNION and other
‘_selectable.CompoundSelect’ objects, by ensuring that the number and
position of columns in a SELECT statement mirrors what was given, in a
use case such as:

     >>> s1 = select(user, user.c.id)
     >>> s2 = select(c1, c2, c3)
     >>> from sqlalchemy import union
     >>> u = union(s1, s2)
     >>> print(u)
     SELECT "user".id, "user".name, "user".id
     FROM "user" UNION SELECT c1, c2, c3

#4753(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4753

8.1.1.25 Improved column labeling for simple column expressions using CAST or similar
.....................................................................................

A user pointed out that the PostgreSQL database has a convenient
behavior when using functions like CAST against a named column, in that
the result column name is named the same as the inner expression:

     test=> SELECT CAST(data AS VARCHAR) FROM foo;

     data
     ------
      5
     (1 row)

This allows one to apply CAST to table columns while not losing the
column name (above using the name ‘"data"’) in the result row.  Compare
to databases such as MySQL/MariaDB, as well as most others, where the
column name is taken from the full SQL expression and is not very
portable:

     MariaDB [test]> SELECT CAST(data AS CHAR) FROM foo;
     +--------------------+
     | CAST(data AS CHAR) |
     +--------------------+
     | 5                  |
     +--------------------+
     1 row in set (0.003 sec)

In SQLAlchemy Core expressions, we never deal with a raw generated name
like the above, as SQLAlchemy applies auto-labeling to expressions like
these, which are up until now always a so-called “anonymous” expression:

     >>> print(select(cast(foo.c.data, String)))
     SELECT CAST(foo.data AS VARCHAR) AS anon_1     # old behavior
     FROM foo

These anonymous expressions were necessary as SQLAlchemy’s ‘ResultProxy’
made heavy use of result column names in order to match up datatypes,
such as the String datatype which used to have
result-row-processing behavior, to the correct column, so most
importantly the names had to be both easy to determine in a
database-agnostic manner as well as unique in all cases.  In SQLAlchemy
1.0 as part of #918(1), this reliance on named columns in result rows
(specifically the ‘cursor.description’ element of the PEP-249 cursor)
was scaled back to not be necessary for most Core SELECT constructs; in
release 1.4, the system overall is becoming more comfortable with SELECT
statements that have duplicate column or label names such as in
SELECT objects and derived FROM clauses allow for duplicate columns and column labels.
So we now emulate PostgreSQL’s reasonable behavior
for simple modifications to a single column, most prominently with CAST:

     >>> print(select(cast(foo.c.data, String)))
     SELECT CAST(foo.data AS VARCHAR) AS data
     FROM foo

For CAST against expressions that don’t have a name, the previous logic
is used to generate the usual “anonymous” labels:

     >>> print(select(cast('hi there,' + foo.c.data, String)))
     SELECT CAST(:data_1 + foo.data AS VARCHAR) AS anon_1
     FROM foo

A cast() against a Label, despite having to omit
the label expression as these don’t render inside of a CAST, will
nonetheless make use of the given name:

     >>> print(select(cast(('hi there,' + foo.c.data).label('hello_data'), String)))
     SELECT CAST(:data_1 + foo.data AS VARCHAR) AS hello_data
     FROM foo

And of course as was always the case, see Label can be applied
to the expression on the outside to apply an “AS <name>” label directly:

     >>> print(select(cast(('hi there,' + foo.c.data), String).label('hello_data')))
     SELECT CAST(:data_1 + foo.data AS VARCHAR) AS hello_data
     FROM foo

#4449(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/918

   (2) http://www.sqlalchemy.org/trac/ticket/4449

8.1.1.26 New “post compile” bound parameters used for LIMIT/OFFSET in Oracle, SQL Server
........................................................................................

A major goal of the 1.4 series is to establish that all Core SQL
constructs are completely cacheable, meaning that a particular
Compiled structure will produce an identical SQL string regardless
of any SQL parameters used with it, which notably includes those used to
specify the LIMIT and OFFSET values, typically used for pagination and
“top N” style results.

While SQLAlchemy has used bound parameters for LIMIT/OFFSET schemes for
many years, a few outliers remained where such parameters were not
allowed, including a SQL Server “TOP N” statement, such as:

     SELECT TOP 5 mytable.id, mytable.data FROM mytable

as well as with Oracle, where the FIRST_ROWS() hint (which SQLAlchemy
will use if the ‘optimize_limits=True’ parameter is passed to
create_engine() with an Oracle URL) does not allow them, but also
that using bound parameters with ROWNUM comparisons has been reported as
producing slower query plans:

     SELECT anon_1.id, anon_1.data FROM (
         SELECT /*+ FIRST_ROWS(5) */
         anon_2.id AS id,
         anon_2.data AS data,
         ROWNUM AS ora_rn FROM (
             SELECT mytable.id, mytable.data FROM mytable
         ) anon_2
         WHERE ROWNUM <= :param_1
     ) anon_1 WHERE ora_rn > :param_2

In order to allow for all statements to be unconditionally cacheable at
the compilation level, a new form of bound parameter called a “post
compile” parameter has been added, which makes use of the same mechanism
as that of “expanding IN parameters”.  This is a bindparam()
that behaves identically to any other bound parameter except that
parameter value will be rendered literally into the SQL string before
sending it to the DBAPI ‘cursor.execute()’ method.  The new parameter is
used internally by the SQL Server and Oracle dialects, so that the
drivers receive the literal rendered value but the rest of SQLAlchemy
can still consider this as a bound parameter.  The above two statements
when stringified using ‘str(statement.compile(dialect=<dialect>))’ now
look like:

     SELECT TOP [POSTCOMPILE_param_1] mytable.id, mytable.data FROM mytable

and:

     SELECT anon_1.id, anon_1.data FROM (
         SELECT /*+ FIRST_ROWS([POSTCOMPILE__ora_frow_1]) */
         anon_2.id AS id,
         anon_2.data AS data,
         ROWNUM AS ora_rn FROM (
             SELECT mytable.id, mytable.data FROM mytable
         ) anon_2
         WHERE ROWNUM <= [POSTCOMPILE_param_1]
     ) anon_1 WHERE ora_rn > [POSTCOMPILE_param_2]

The ‘[POSTCOMPILE_<param>]’ format is also what is seen when an
“expanding IN” is used.

When viewing the SQL logging output, the final form of the statement
will be seen:

     SELECT anon_1.id, anon_1.data FROM (
         SELECT /*+ FIRST_ROWS(5) */
         anon_2.id AS id,
         anon_2.data AS data,
         ROWNUM AS ora_rn FROM (
             SELECT mytable.id AS id, mytable.data AS data FROM mytable
         ) anon_2
         WHERE ROWNUM <= 8
     ) anon_1 WHERE ora_rn > 3

The “post compile parameter” feature is exposed as public API through
the bindparam.literal_execute parameter, however is
currently not intended for general use.  The literal values are rendered
using the TypeEngine.literal_processor() of the underlying
datatype, which in SQLAlchemy has `extremely limited' scope, supporting
only integers and simple string values.

#4808(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4808

8.1.1.27 Connection-level transactions can now be inactive based on subtransaction
..................................................................................

A Connection now includes the behavior where a
Transaction can be made inactive due to a rollback on an inner
transaction, however the Transaction will not clear until it
is itself rolled back.

This is essentially a new error condition which will disallow statement
executions to proceed on a Connection if an inner “sub”
transaction has been rolled back.  The behavior works very similarly to
that of the ORM Session, where if an outer transaction has
been begun, it needs to be rolled back to clear the invalid transaction;
this behavior is described in “This Session’s transaction has been rolled back due to a previous exception during flush.” (or similar).

While the Connection has had a less strict behavioral
pattern than the Session, this change was made as it helps to
identify when a subtransaction has rolled back the DBAPI transaction,
however the external code isn’t aware of this and attempts to continue
proceeding, which in fact runs operations on a new transaction.  The
“test harness” pattern described at Joining a Session into an External Transaction (such as for test suites)
is the common place
for this to occur.

The “subtransaction” feature of Core and ORM is itself deprecated and
will no longer be present in version 2.0.  As a result, this new error
condition is itself temporary as it will no longer apply once
subtransactions are removed.

In order to work with the 2.0 style behavior that does not include
subtransactions, use the create_engine.future parameter on
create_engine().

The error message is described in the errors page at *note This
connection is on an inactive transaction.  Please rollback() fully
before proceeding: 1ade.

8.1.1.28 Enum and Boolean datatypes no longer default to “create constraint”
............................................................................

The Enum.create_constraint and
Boolean.create_constraint parameters now default to False,
indicating when a so-called “non-native” version of these two datatypes
is created, a CHECK constraint will `not' be generated by default.
These CHECK constraints present schema-management maintenance
complexities that should be opted in to, rather than being turned on by
default.

To ensure that a CREATE CONSTRAINT is emitted for these types, set these
flags to ‘True’:

     class Spam(Base):
         __tablename__ = "spam"
         id = Column(Integer, primary_key=True)
         boolean = Column(Boolean(create_constraint=True))
         enum = Column(Enum("a", "b", "c", create_constraint=True))

#5367(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5367

8.1.1.29 New Features - ORM
...........................

8.1.1.30 Raiseload for Columns
..............................

The “raiseload” feature, which raises InvalidRequestError
when an unloaded attribute is accessed, is now available for
column-oriented attributes using the defer.raiseload
parameter of defer().  This works in the same manner as that
of the raiseload() option used by relationship loading:

     book = session.query(Book).options(defer(Book.summary, raiseload=True)).first()

     # would raise an exception
     book.summary

To configure column-level raiseload on a mapping, the
deferred.raiseload parameter of deferred() may be
used.  The undefer() option may then be used at query time
to eagerly load the attribute:

     class Book(Base):
         __tablename__ = 'book'

         book_id = Column(Integer, primary_key=True)
         title = Column(String(200), nullable=False)
         summary = deferred(Column(String(2000)), raiseload=True)
         excerpt = deferred(Column(Text), raiseload=True)

     book_w_excerpt = session.query(Book).options(undefer(Book.excerpt)).first()

It was originally considered that the existing raiseload()
option that works for relationship() attributes be expanded
to also support column-oriented attributes.  However, this would break
the “wildcard” behavior of raiseload(), which is documented
as allowing one to prevent all relationships from loading:

     session.query(Order).options(
         joinedload(Order.items), raiseload('*'))

Above, if we had expanded raiseload() to accommodate for
columns as well, the wildcard would also prevent columns from loading
and thus be a backwards incompatible change; additionally, it’s not
clear if raiseload() covered both column expressions and
relationships, how one would achieve the effect above of only blocking
relationship loads, without new API being added.  So to keep things
simple, the option for columns remains on defer():

     raiseload(). - query option to raise for relationship
     loads

     See defer.raiseload. - query option to raise for column
     expression loads

As part of this change, the behavior of “deferred” in conjunction with
attribute expiration has changed.  Previously, when an object would be
marked as expired, and then unexpired via the access of one of the
expired attributes, attributes which were mapped as “deferred” at the
mapper level would also load.  This has been changed such that an
attribute that is deferred in the mapping will never “unexpire”, it only
loads when accessed as part of the deferral loader.

An attribute that is not mapped as “deferred”, however was deferred at
query time via the defer() option, will be reset when the
object or attribute is expired; that is, the deferred option is removed.
This is the same behavior as was present previously.

See also
........

See Raiseload for Deferred Columns.

#4826(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4826

8.1.1.31 ORM Batch inserts with psycopg2 now batch statements with RETURNING in most cases
..........................................................................................

The change in psycopg2 dialect features “execute_values” with RETURNING for INSERT statements by default
adds support for
“executemany” + “RETURNING” at the same time in Core, which is now
enabled for the psycopg2 dialect by default using the psycopg2
‘execute_values()’ extension.  The ORM flush process now makes use of
this feature such that the retrieval of newly generated primary key
values and server defaults can be achieved while not losing the
performance benefits of being able to batch INSERT statements together.
Additionally, psycopg2’s ‘execute_values()’ extension itself provides a
five-fold performance improvement over psycopg2’s default “executemany”
implementation, by rewriting an INSERT statement to include many
“VALUES” expressions all in one statement rather than invoking the same
statement repeatedly, as psycopg2 lacks the ability to PREPARE the
statement ahead of time as would normally be expected for this approach
to be performant.

SQLAlchemy includes a performance suite within its examples,
where we can compare the times generated for the “batch_inserts” runner
against 1.3 and 1.4, revealing a 3x-5x speedup for most flavors of batch
insert:

     # 1.3
     $ python -m examples.performance bulk_inserts --dburl postgresql://scott:tiger@localhost/test
     test_flush_no_pk : (100000 iterations); total time 14.051527 sec
     test_bulk_save_return_pks : (100000 iterations); total time 15.002470 sec
     test_flush_pk_given : (100000 iterations); total time 7.863680 sec
     test_bulk_save : (100000 iterations); total time 6.780378 sec
     test_bulk_insert_mappings :  (100000 iterations); total time 5.363070 sec
     test_core_insert : (100000 iterations); total time 5.362647 sec

     # 1.4 with enhancement
     $ python -m examples.performance bulk_inserts --dburl postgresql://scott:tiger@localhost/test
     test_flush_no_pk : (100000 iterations); total time 3.820807 sec
     test_bulk_save_return_pks : (100000 iterations); total time 3.176378 sec
     test_flush_pk_given : (100000 iterations); total time 4.037789 sec
     test_bulk_save : (100000 iterations); total time 2.604446 sec
     test_bulk_insert_mappings : (100000 iterations); total time 1.204897 sec
     test_core_insert : (100000 iterations); total time 0.958976 sec

Note that the ‘execute_values()’ extension modifies the INSERT statement
in the psycopg2 layer, `after' it’s been logged by SQLAlchemy.  So with
SQL logging, one will see the parameter sets batched together, but the
joining of multiple “values” will not be visible on the application
side:

     2020-06-27 19:08:18,166 INFO sqlalchemy.engine.Engine INSERT INTO a (data) VALUES (%(data)s) RETURNING a.id
     2020-06-27 19:08:18,166 INFO sqlalchemy.engine.Engine [generated in 0.00698s] ({'data': 'data 1'}, {'data': 'data 2'}, {'data': 'data 3'}, {'data': 'data 4'}, {'data': 'data 5'}, {'data': 'data 6'}, {'data': 'data 7'}, {'data': 'data 8'}  ... displaying 10 of 4999 total bound parameter sets ...  {'data': 'data 4998'}, {'data': 'data 4999'})
     2020-06-27 19:08:18,254 INFO sqlalchemy.engine.Engine COMMIT

The ultimate INSERT statement can be seen by enabling statement logging
on the PostgreSQL side:

     2020-06-27 19:08:18.169 EDT [26960] LOG:  statement: INSERT INTO a (data)
     VALUES ('data 1'),('data 2'),('data 3'),('data 4'),('data 5'),('data 6'),('data
     7'),('data 8'),('data 9'),('data 10'),('data 11'),('data 12'),
     ... ('data 999'),('data 1000') RETURNING a.id

     2020-06-27 19:08:18.175 EDT
     [26960] LOG:  statement: INSERT INTO a (data) VALUES ('data 1001'),('data
     1002'),('data 1003'),('data 1004'),('data 1005 '),('data 1006'),('data
     1007'),('data 1008'),('data 1009'),('data 1010'),('data 1011'), ...

The feature batches rows into groups of 1000 by default which can be
affected using the ‘executemany_values_page_size’ argument documented at
Psycopg2 Fast Execution Helpers.

#5263(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5263

8.1.1.32 ORM Bulk Update and Delete use RETURNING for “fetch” strategy when available
.....................................................................................

An ORM bulk update or delete that uses the “fetch” strategy:

     sess.query(User).filter(User.age > 29).update(
         {"age": User.age - 10}, synchronize_session="fetch"
     )

Will now use RETURNING if the backend database supports it; this
currently includes PostgreSQL and SQL Server (the Oracle dialect does
not support RETURNING of multiple rows):

     UPDATE users SET age_int=(users.age_int - %(age_int_1)s) WHERE users.age_int > %(age_int_2)s RETURNING users.id
     [generated in 0.00060s] {'age_int_1': 10, 'age_int_2': 29}
     Col ('id',)
     Row (2,)
     Row (4,)

For backends that do not support RETURNING of multiple rows, the
previous approach of emitting SELECT for the primary keys beforehand is
still used:

     SELECT users.id FROM users WHERE users.age_int > %(age_int_1)s
     [generated in 0.00043s] {'age_int_1': 29}
     Col ('id',)
     Row (2,)
     Row (4,)
     UPDATE users SET age_int=(users.age_int - %(age_int_1)s) WHERE users.age_int > %(age_int_2)s
     [generated in 0.00102s] {'age_int_1': 10, 'age_int_2': 29}

One of the intricate challenges of this change is to support cases such
as the horizontal sharding extension, where a single bulk update or
delete may be multiplexed among backends some of which support RETURNING
and some don’t.  The new 1.4 execution architecture supports this case
so that the “fetch” strategy can be left intact with a graceful degrade
to using a SELECT, rather than having to add a new “returning” strategy
that would not be backend-agnostic.

As part of this change, the “fetch” strategy is also made much more
efficient in that it will no longer expire the objects located which
match the rows, for Python expressions used in the SET clause which can
be evaluated in Python; these are instead assigned directly onto the
object in the same way as the “evaluate” strategy.  Only for SQL
expressions that can’t be evaluated does it fall back to expiring the
attributes.  The “evaluate” strategy has also been enhanced to fall back
to “expire” for a value that cannot be evaluated.

8.1.1.33 Behavioral Changes - ORM
.................................

8.1.1.34 The “KeyedTuple” object returned by Query is replaced by Row
.....................................................................

As discussed at RowProxy is no longer a “proxy”; is now called Row and behaves like an enhanced named tuple,
the Core ‘RowProxy’
object is now replaced by a class called Row.  The base
Row object now behaves more fully like a named tuple, and as such
it is now used as the basis for tuple-like results returned by the
Query object, rather than the previous “KeyedTuple” class.

The rationale is so that by SQLAlchemy 2.0, both Core and ORM SELECT
statements will return result rows using the same Row object
which behaves like a named tuple.  Dictionary-like functionality is
available from Row via the Row._mapping
attribute.  In the interim, Core result sets will make use of a
Row subclass LegacyRow which maintains the previous
dict/tuple hybrid behavior for backwards compatibility while the
Row class will be used directly for ORM tuple results returned by
the Query object.

Effort has been made to get most of the featureset of Row to
be available within the ORM, meaning that access by string name as well
as entity / column should work:

     row = s.query(User, Address).join(User.addresses).first()

     row._mapping[User]  # same as row[0]
     row._mapping[Address]  # same as row[1]
     row._mapping["User"]  # same as row[0]
     row._mapping["Address"]  # same as row[1]

     u1 = aliased(User)
     row = s.query(u1).only_return_tuples(True).first()
     row._mapping[u1]  # same as row[0]

     row = (
         s.query(User.id, Address.email_address)
         .join(User.addresses)
         .first()
     )

     row._mapping[User.id]  # same as row[0]
     row._mapping["id"]  # same as row[0]
     row._mapping[users.c.id]  # same as row[0]

See also
........

See RowProxy is no longer a “proxy”; is now called Row and behaves like an enhanced named tuple.

#4710(1).

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4710

8.1.1.35 Session features new “autobegin” behavior
..................................................

The Session object’s default behavior of ‘autocommit=False’
historically has meant that there is always a SessionTransaction
object in play, associated with the Session via the
Session.transaction attribute.  When the given
SessionTransaction was complete, due to a commit, rollback, or
close, it was immediately replaced with a new one.  The
SessionTransaction by itself does not imply the usage of any
connection-oriented resources, so this long-standing behavior has a
particular elegance to it in that the state of
Session.transaction is always predictable as non-None.

However, as part of the initiative in #5056(1) to greatly reduce
reference cycles, this assumption means that calling upon
Session.close() results in a Session object that still
has reference cycles and is more expensive to clean up, not to mention
that there is a small overhead in constructing the
SessionTransaction object, which meant that there would be
unnecessary overhead created for a Session that for example
invoked Session.commit() and then Session.close().

As such, it was decided that Session.close() should leave
the internal state of ‘self.transaction’, now referred to internally as
‘self._transaction’, as None, and that a new SessionTransaction
should only be created when needed.  For consistency and code
coverage, this behavior was also expanded to include all the points at
which “autobegin” is expected, not just when Session.close()
were called.

In particular, this causes a behavioral change for applications which
subscribe to the SessionEvents.after_transaction_create()
event hook; previously, this event would be emitted when the
Session were first constructed, as well as for most actions that
closed the previous transaction and would emit
SessionEvents.after_transaction_end().  The new behavior is that
SessionEvents.after_transaction_create() is emitted on
demand, when the Session has not yet created a new
SessionTransaction object and mapped objects are associated with
the Session through methods like Session.add()
and Session.delete(), when the Session.transaction
attribute is called upon, when the Session.flush()
method has tasks to complete, etc.

Besides the change in when the
SessionEvents.after_transaction_create() event is emitted, the
change should have no other user-visible impact on the Session
object’s behavior; the Session will continue to have the
behavior that it remains usable for new operations after
Session.close() is called, and the sequencing of how the
Session interacts with the Engine and the database
itself should also remain unaffected, since these operations were
already operating in an on-demand fashion.

#5074(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5056

   (2) http://www.sqlalchemy.org/trac/ticket/5074

8.1.1.36 Viewonly relationships don’t synchronize backrefs
..........................................................

In #5149(1) in 1.3.14, SQLAlchemy began emitting a warning when the
relationship.backref or relationship.back_populates
keywords would be used at the same time as the
relationship.viewonly flag on the target relationship.  This was
because a “viewonly” relationship does not actually persist changes made
to it, which could cause some misleading behaviors to occur.  However,
in #5237(2), we sought to refine this behavior as there are legitimate
use cases to have backrefs set up on viewonly relationships, including
that back populates attributes are used in some cases by the
relationship lazy loaders to determine that an additional eager load in
the other direction is not necessary, as well as that back populates can
be used for mapper introspection and that backref() can be a
convenient way to set up bi-directional relationships.

The solution then was to make the “mutation” that occurs from a backref
an optional thing, using the relationship.sync_backref flag.
In 1.4 the value of relationship.sync_backref defaults to
False for a relationship target that also sets
relationship.viewonly.  This indicates that any changes made to a
relationship with viewonly will not impact the state of the other side
or of the Session in any way:

     class User(Base):
         # ...

         addresses = relationship(Address, backref=backref("user", viewonly=True))

     class Address(Base):
         # ...

     u1 = session.query(User).filter_by(name="x").first()

     a1 = Address()
     a1.user = u1

Above, the ‘a1’ object will `not' be added to the ‘u1.addresses’
collection, nor will the ‘a1’ object be added to the session.
Previously, both of these things would be true.  The warning that
relationship.sync_backref should be set to ‘False’ when
relationship.viewonly is ‘False’ is no longer emitted as this is
now the default behavior.

#5237(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5149

   (2) http://www.sqlalchemy.org/trac/ticket/5237

   (3) http://www.sqlalchemy.org/trac/ticket/5237

8.1.1.37 cascade_backrefs behavior deprecated for removal in 2.0
................................................................

SQLAlchemy has long had a behavior of cascading objects into the
Session based on backref assignment.  Given ‘User’ below already in
a Session, assigning it to the ‘Address.user’ attribute of an
‘Address’ object, assuming a bidirectional relationship is set up, would
mean that the ‘Address’ also gets put into the Session at
that point:

     u1 = User()
     session.add(u1)

     a1 = Address()
     a1.user = u1  # <--- adds "a1" to the Session

The above behavior was an unintended side effect of backref behavior, in
that since ‘a1.user’ implies ‘u1.addresses.append(a1)’, ‘a1’ would get
cascaded into the Session.  This remains the default behavior
throughout 1.4.  At some point, a new flag
relationship.cascade_backrefs was added to disable to above
behavior, as it can be surprising and also gets in the way of some
operations where the object would be placed in the Session
too early and get prematurely flushed.

In 2.0, the default behavior will be that “cascade_backrefs” is False,
and additionally there will be no “True” behavior as this is not
generally a desirable behavior.  When 2.0 deprecation warnings are
enabled, a warning will be emitted when a “backref cascade” actually
takes place.  To get the new behavior, either set
relationship.cascade_backrefs to ‘False’ on the target
relationship, as is already supported in 1.3 and earlier, or
alternatively make use of the Session.future flag to
2.0-style mode:

     Session = sessionmaker(engine, future=True)

     with Session() as session:
       u1 = User()
       session.add(u1)

       a1 = Address()
       a1.user = u1  # <--- will not add "a1" to the Session

#5150(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5150

8.1.1.38 Eager loaders emit during unexpire operations
......................................................

A long sought behavior was that when an expired object is accessed,
configured eager loaders will run in order to eagerly load relationships
on the expired object when the object is refreshed or otherwise
unexpired.  This behavior has now been added, so that joinedloaders will
add inline JOINs as usual, and selectin/subquery loaders will run an
“immediateload” operation for a given relationship, when an expired
object is unexpired or an object is refreshed:

     >>> a1 = session.query(A).options(joinedload(A.bs)).first()
     >>> a1.data = 'new data'
     >>> session.commit()

Above, the ‘A’ object was loaded with a ‘joinedload()’ option associated
with it in order to eagerly load the ‘bs’ collection.  After the
‘session.commit()’, the state of the object is expired.  Upon accessing
the ‘.data’ column attribute, the object is refreshed and this will now
include the joinedload operation as well:

     >>> a1.data
     SELECT a.id AS a_id, a.data AS a_data, b_1.id AS b_1_id, b_1.a_id AS b_1_a_id
     FROM a LEFT OUTER JOIN b AS b_1 ON a.id = b_1.a_id
     WHERE a.id = ?

The behavior applies both to loader strategies applied to the
relationship() directly, as well as with options used with
Query.options(), provided that the object was originally loaded by
that query.

For the “secondary” eager loaders “selectinload” and “subqueryload”, the
SQL strategy for these loaders is not necessary in order to eagerly load
attributes on a single object; so they will instead invoke the
“immediateload” strategy in a refresh scenario, which resembles the
query emitted by “lazyload”, emitted as an additional query:

     >>> a1 = session.query(A).options(selectinload(A.bs)).first()
     >>> a1.data = 'new data'
     >>> session.commit()
     >>> a1.data
     SELECT a.id AS a_id, a.data AS a_data
     FROM a
     WHERE a.id = ?
     (1,)
     SELECT b.id AS b_id, b.a_id AS b_a_id
     FROM b
     WHERE ? = b.a_id
     (1,)

Note that a loader option does not apply to an object that was
introduced into the Session in a different way.  That is, if
the ‘a1’ object were just persisted in this Session, or was
loaded with a different query before the eager option had been applied,
then the object doesn’t have an eager load option associated with it.
This is not a new concept, however users who are looking for the
eagerload on refresh behavior may find this to be more noticeable.

#1763(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1763

8.1.1.39 Accessing an uninitialized collection attribute on a transient object no longer mutates __dict__
.........................................................................................................

It has always been SQLAlchemy’s behavior that accessing mapped
attributes on a newly created object returns an implicitly generated
value, rather than raising ‘AttributeError’, such as ‘None’ for scalar
attributes or ‘[]’ for a list-holding relationship:

     >>> u1 = User()
     >>> u1.name
     None
     >>> u1.addresses
     []

The rationale for the above behavior was originally to make ORM objects
easier to work with.  Since an ORM object represents an empty row when
first created without any state, it is intuitive that its un-accessed
attributes would resolve to ‘None’ (or SQL NULL) for scalars and to
empty collections for relationships.  In particular, it makes possible
an extremely common pattern of being able to mutate the new collection
without manually creating and assigning an empty collection first:

     >>> u1 = User()
     >>> u1.addresses.append(Address())  # no need to assign u1.addresses = []

Up until version 1.0 of SQLAlchemy, the behavior of this initialization
system for both scalar attributes as well as collections would be that
the ‘None’ or empty collection would be `populated' into the object’s
state, e.g.  ‘__dict__’.  This meant that the following two operations
were equivalent:

     >>> u1 = User()
     >>> u1.name = None  # explicit assignment

     >>> u2 = User()
     >>> u2.name  # implicit assignment just by accessing it
     None

Where above, both ‘u1’ and ‘u2’ would have the value ‘None’ populated in
the value of the ‘name’ attribute.  Since this is a SQL NULL, the ORM
would skip including these values within an INSERT so that SQL-level
defaults take place, if any, else the value defaults to NULL on the
database side.

In version 1.0 as part of Changes to attribute events and other operations regarding attributes that have no pre-existing value,
this behavior was refined so that the ‘None’ value was no longer
populated into ‘__dict__’, only returned.  Besides removing the mutating
side effect of a getter operation, this change also made it possible to
set columns that did have server defaults to the value NULL by actually
assigning ‘None’, which was now distinguished from just reading it.

The change however did not accommodate for collections, where returning
an empty collection that is not assigned meant that this mutable
collection would be different each time and also would not be able to
correctly accommodate for mutating operations (e.g.  append, add, etc.)
called upon it.  While the behavior continued to generally not get in
anyone’s way, an edge case was eventually identified in #4519(1) where
this empty collection could be harmful, which is when the object is
merged into a session:

     >>> u1 = User(id=1)  # create an empty User to merge with id=1 in the database
     >>> merged1 = session.merge(u1)  # value of merged1.addresses is unchanged from that of the DB

     >>> u2 = User(id=2) # create an empty User to merge with id=2 in the database
     >>> u2.addresses
     []
     >>> merged2 = session.merge(u2)  # value of merged2.addresses has been emptied in the DB

Above, the ‘.addresses’ collection on ‘merged1’ will contain all the
‘Address()’ objects that were already in the database.  ‘merged2’ will
not; because it has an empty list implicitly assigned, the ‘.addresses’
collection will be erased.  This is an example of where this mutating
side effect can actually mutate the database itself.

While it was considered that perhaps the attribute system should begin
using strict “plain Python” behavior, raising ‘AttributeError’ in all
cases for non-existent attributes on non-persistent objects and
requiring that all collections be explicitly assigned, such a change
would likely be too extreme for the vast number of applications that
have relied upon this behavior for many years, leading to a complex
rollout / backwards compatibility problem as well as the likelihood that
workarounds to restore the old behavior would become prevalent, thus
rendering the whole change ineffective in any case.

The change then is to keep the default producing behavior, but to
finally make the non-mutating behavior of scalars a reality for
collections as well, via the addition of additional mechanics in the
collection system.  When accessing the empty attribute, the new
collection is created and associated with the state, however is not
added to ‘__dict__’ until it is actually mutated:

     >>> u1 = User()
     >>> l1 = u1.addresses  # new list is created, associated with the state
     >>> assert u1.addresses is l1  # you get the same list each time you access it
     >>> assert "addresses" not in u1.__dict__  # but it won't go into __dict__ until it's mutated
     >>> from sqlalchemy import inspect
     >>> inspect(u1).attrs.addresses.history
     History(added=None, unchanged=None, deleted=None)

When the list is changed, then it becomes part of the tracked changes to
be persisted to the database:

     >>> l1.append(Address())
     >>> assert "addresses" in u1.__dict__
     >>> inspect(u1).attrs.addresses.history
     History(added=[<__main__.Address object at 0x7f49b725eda0>], unchanged=[], deleted=[])

This change is expected to have `nearly' no impact on existing
applications in any way, except that it has been observed that some
applications may be relying upon the implicit assignment of this
collection, such as to assert that the object contains certain values
based on its ‘__dict__’:

     >>> u1 = User()
     >>> u1.addresses
     []
     # this will now fail, would pass before
     >>> assert {k: v for k, v in u1.__dict__.items() if not k.startswith("_")} == {"addresses": []}

or to ensure that the collection won’t require a lazy load to proceed,
the (admittedly awkward) code below will now also fail:

     >>> u1 = User()
     >>> u1.addresses
     []
     >>> s.add(u1)
     >>> s.flush()
     >>> s.close()
     >>> u1.addresses  # <-- will fail, .addresses is not loaded and object is detached

Applications that rely upon the implicit mutating behavior of
collections will need to be changed so that they assign the desired
collection explicitly:

     >>> u1.addresses = []

#4519(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4519

   (2) http://www.sqlalchemy.org/trac/ticket/4519

8.1.1.40 The “New instance conflicts with existing identity” error is now a warning
...................................................................................

SQLAlchemy has always had logic to detect when an object in the
Session to be inserted has the same primary key as an object that
is already present:

     class Product(Base):
         __tablename__ = 'product'

         id = Column(Integer, primary_key=True)

     session = Session(engine)

     # add Product with primary key 1
     session.add(Product(id=1))
     session.flush()

     # add another Product with same primary key
     session.add(Product(id=1))
     s.commit()  # <-- will raise FlushError

The change is that the FlushError is altered to be only a
warning:

     sqlalchemy/orm/persistence.py:408: SAWarning: New instance <Product at 0x7f1ff65e0ba8> with identity key (<class '__main__.Product'>, (1,), None) conflicts with persistent instance <Product at 0x7f1ff60a4550>

Subsequent to that, the condition will attempt to insert the row into
the database which will emit IntegrityError, which is the
same error that would be raised if the primary key identity was not
already present in the Session:

     sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: product.id

The rationale is to allow code that is using IntegrityError
to catch duplicates to function regardless of the existing state of the
Session, as is often done using savepoints:

     # add another Product with same primary key
     try:
         with session.begin_nested():
             session.add(Product(id=1))
     except exc.IntegrityError:
         print("row already exists")

The above logic was not fully feasible earlier, as in the case that the
‘Product’ object with the existing identity were already in the
Session, the code would also have to catch FlushError,
which additionally is not filtered for the specific condition of
integrity issues.  With the change, the above block behaves consistently
with the exception of the warning also being emitted.

Since the logic in question deals with the primary key, all databases
emit an integrity error in the case of primary key conflicts on INSERT.
The case where an error would not be raised, that would have earlier, is
the extremely unusual scenario of a mapping that defines a primary key
on the mapped selectable that is more restrictive than what is actually
configured in the database schema, such as when mapping to joins of
tables or when defining additional columns as part of a composite
primary key that is not actually constrained in the database schema.
However, these situations also work more consistently in that the INSERT
would theoretically proceed whether or not the existing identity were
still in the database.  The warning can also be configured to raise an
exception using the Python warnings filter.

#4662(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4662

8.1.1.41 Persistence-related cascade operations disallowed with viewonly=True
.............................................................................

When a relationship() is set as ‘viewonly=True’ using the
relationship.viewonly flag, it indicates this relationship
should only be used to load data from the database, and should not be
mutated or involved in a persistence operation.  In order to ensure this
contract works successfully, the relationship can no longer specify
relationship.cascade settings that make no sense in terms of
“viewonly”.

The primary targets here are the “delete, delete-orphan” cascades, which
through 1.3 continued to impact persistence even if viewonly were True,
which is a bug; even if viewonly were True, an object would still
cascade these two operations onto the related object if the parent were
deleted or the object were detached.  Rather than modify the cascade
operations to check for viewonly, the configuration of both of these
together is simply disallowed:

     class User(Base):
         # ...

         # this is now an error
         addresses = relationship(
             "Address", viewonly=True, cascade="all, delete-orphan")

The above will raise:

     sqlalchemy.exc.ArgumentError: Cascade settings
     "delete, delete-orphan, merge, save-update" apply to persistence
     operations and should not be combined with a viewonly=True relationship.

Applications that have this issue should be emitting a warning as of
SQLAlchemy 1.3.12, and for the above error the solution is to remove the
cascade settings for a viewonly relationship.

#4993(1) #4994(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4993

   (2) http://www.sqlalchemy.org/trac/ticket/4994

8.1.1.42 Stricter behavior when querying inheritance mappings using custom queries
..................................................................................

This change applies to the scenario where a joined- or single- table
inheritance subclass entity is being queried, given a completed SELECT
subquery to select from.  If the given subquery returns rows that do not
correspond to the requested polymorphic identity or identities, an error
is raised.  Previously, this condition would pass silently under joined
table inheritance, returning an invalid subclass, and under single table
inheritance, the Query would be adding additional criteria
against the subquery to limit the results which could inappropriately
interfere with the intent of the query.

Given the example mapping of ‘Employee’, ‘Engineer(Employee)’,
‘Manager(Employee)’, in the 1.3 series if we were to emit the following
query against a joined inheritance mapping:

     s = Session(e)

     s.add_all([Engineer(), Manager()])

     s.commit()

     print(
         s.query(Manager).select_entity_from(s.query(Employee).subquery()).all()
     )

The subquery selects both the ‘Engineer’ and the ‘Manager’ rows, and
even though the outer query is against ‘Manager’, we get a non ‘Manager’
object back:

     SELECT anon_1.type AS anon_1_type, anon_1.id AS anon_1_id
     FROM (SELECT employee.type AS type, employee.id AS id
     FROM employee) AS anon_1
     2020-01-29 18:04:13,524 INFO sqlalchemy.engine.base.Engine ()
     [<__main__.Engineer object at 0x7f7f5b9a9810>, <__main__.Manager object at 0x7f7f5b9a9750>]

The new behavior is that this condition raises an error:

     sqlalchemy.exc.InvalidRequestError: Row with identity key
     (<class '__main__.Employee'>, (1,), None) can't be loaded into an object;
     the polymorphic discriminator column '%(140205120401296 anon)s.type'
     refers to mapped class Engineer->engineer, which is not a sub-mapper of
     the requested mapped class Manager->manager

The above error only raises if the primary key columns of that entity
are non-NULL. If there’s no primary key for a given entity in a row, no
attempt to construct an entity is made.

In the case of single inheritance mapping, the change in behavior is
slightly more involved; if ‘Engineer’ and ‘Manager’ above are mapped
with single table inheritance, in 1.3 the following query would be
emitted and only a ‘Manager’ object is returned:

     SELECT anon_1.type AS anon_1_type, anon_1.id AS anon_1_id
     FROM (SELECT employee.type AS type, employee.id AS id
     FROM employee) AS anon_1
     WHERE anon_1.type IN (?)
     2020-01-29 18:08:32,975 INFO sqlalchemy.engine.base.Engine ('manager',)
     [<__main__.Manager object at 0x7ff1b0200d50>]

The Query added the “single table inheritance” criteria to
the subquery, editorializing on the intent that was originally set up by
it.  This behavior was added in version 1.0 in #3891(1), and creates a
behavioral inconsistency between “joined” and “single” table
inheritance, and additionally modifies the intent of the given query,
which may intend to return additional rows where the columns that
correspond to the inheriting entity are NULL, which is a valid use case.
The behavior is now equivalent to that of joined table inheritance,
where it is assumed that the subquery returns the correct rows and an
error is raised if an unexpected polymorphic identity is encountered:

     SELECT anon_1.type AS anon_1_type, anon_1.id AS anon_1_id
     FROM (SELECT employee.type AS type, employee.id AS id
     FROM employee) AS anon_1
     2020-01-29 18:13:10,554 INFO sqlalchemy.engine.base.Engine ()
     Traceback (most recent call last):
     # ...
     sqlalchemy.exc.InvalidRequestError: Row with identity key
     (<class '__main__.Employee'>, (1,), None) can't be loaded into an object;
     the polymorphic discriminator column '%(140700085268432 anon)s.type'
     refers to mapped class Engineer->employee, which is not a sub-mapper of
     the requested mapped class Manager->employee

The correct adjustment to the situation as presented above which worked
on 1.3 is to adjust the given subquery to correctly filter the rows
based on the discriminator column:

     print(
         s.query(Manager).select_entity_from(
             s.query(Employee).filter(Employee.discriminator == 'manager').
             subquery()).all()
     )

     SELECT anon_1.type AS anon_1_type, anon_1.id AS anon_1_id
     FROM (SELECT employee.type AS type, employee.id AS id
     FROM employee
     WHERE employee.type = ?) AS anon_1
     2020-01-29 18:14:49,770 INFO sqlalchemy.engine.base.Engine ('manager',)
     [<__main__.Manager object at 0x7f70e13fca90>]

#5122(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3891

   (2) http://www.sqlalchemy.org/trac/ticket/5122

8.1.1.43 Dialect Changes
........................

8.1.1.44 psycopg2 version 2.7 or higher is required for the PostgreSQL psycopg2 dialect
.......................................................................................

The psycopg2 dialect relies upon many features of psycopg2 released in
the past few years.  To simplify the dialect, version 2.7, released in
March, 2017 is now the minimum version required.

8.1.1.45 psycopg2 dialect no longer has limitations regarding bound parameter names
...................................................................................

SQLAlchemy 1.3 was not able to accommodate bound parameter names that
included percent signs or parenthesis under the psycopg2 dialect.  This
in turn meant that column names which included these characters were
also problematic as INSERT and other DML statements would generate
parameter names that matched that of the column, which would then cause
failures.  The workaround was to make use of the Column.key
parameter so that an alternate name that would be used to generate the
parameter, or otherwise the parameter style of the dialect had to be
changed at the create_engine() level.  As of SQLAlchemy
1.4.0beta3 all naming limitations have been removed and parameters are
fully escaped in all scenarios, so these workarounds are no longer
necessary.

#5941(1)

#5653(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5941

   (2) http://www.sqlalchemy.org/trac/ticket/5653

8.1.1.46 psycopg2 dialect features “execute_values” with RETURNING for INSERT statements by default
...................................................................................................

The first half of a significant performance enhancement for PostgreSQL
when using both Core and ORM, the psycopg2 dialect now uses
‘psycopg2.extras.execute_values()’ by default for compiled INSERT
statements and also implements RETURNING support in this mode.  The
other half of this change is ORM Batch inserts with psycopg2 now batch statements with RETURNING in most cases
which allows the
ORM to take advantage of RETURNING with executemany (i.e.  batching of
INSERT statements) so that ORM bulk inserts with psycopg2 are up to 400%
faster depending on specifics.

This extension method allows many rows to be INSERTed within a single
statement, using an extended VALUES clause for the statement.  While
SQLAlchemy’s insert() construct already supports this syntax
via the Insert.values() method, the extension method allows
the construction of the VALUES clause to occur dynamically when the
statement is executed as an “executemany” execution, which is what
occurs when one passes a list of parameter dictionaries to
Connection.execute().  It also occurs beyond the cache boundary so
that the INSERT statement may be cached before the VALUES are rendered.

A quick test of the ‘execute_values()’ approach using the
‘bulk_inserts.py’ script in the Performance example suite
reveals an approximate `fivefold performance increase':

     $ python -m examples.performance bulk_inserts --test test_core_insert --num 100000 --dburl postgresql://scott:tiger@localhost/test

     # 1.3
     test_core_insert : A single Core INSERT construct inserting mappings in bulk. (100000 iterations); total time 5.229326 sec

     # 1.4
     test_core_insert : A single Core INSERT construct inserting mappings in bulk. (100000 iterations); total time 0.944007 sec

Support for the “batch” extension was added in version 1.2 in
Support for Batch Mode / Fast Execution Helpers, and enhanced to
include support for the ‘execute_values’ extension in 1.3 in #4623(1).
In 1.4 the ‘execute_values’ extension is now being turned on by default
for INSERT statements; the “batch” extension for UPDATE and DELETE
remains off by default.

In addition, the ‘execute_values’ extension function supports returning
the rows that are generated by RETURNING as an aggregated list.  The
psycopg2 dialect will now retrieve this list if the given
insert() construct requests returning via the
Insert.returning() method or similar methods intended to return
generated defaults; the rows are then installed in the result so that
they are retrieved as though they came from the cursor directly.  This
allows tools like the ORM to use batched inserts in all cases, which is
expected to provide a dramatic performance improvement.

The ‘executemany_mode’ feature of the psycopg2 dialect has been revised
with the following changes:

   * A new mode ‘"values_only"’ is added.  This mode uses the very
     performant ‘psycopg2.extras.execute_values()’ extension method for
     compiled INSERT statements run with executemany(), but does not use
     ‘execute_batch()’ for UPDATE and DELETE statements.  This new mode
     is now the default setting for the psycopg2 dialect.

   * The existing ‘"values"’ mode is now named ‘"values_plus_batch"’.
     This mode will use ‘execute_values’ for INSERT statements and
     ‘execute_batch’ for UPDATE and DELETE statements.  The mode is not
     enabled by default because it disables the proper functioning of
     ‘cursor.rowcount’ with UPDATE and DELETE statements executed with
     ‘executemany()’.

   * RETURNING support is enabled for ‘"values_only"’ and ‘"values"’ for
     INSERT statements.  The psycopg2 dialect will receive the rows back
     from psycopg2 using the fetch=True flag and install them into the
     result set as though they came directly from the cursor (which they
     ultimately did, however psycopg2’s extension function has
     aggregated multiple batches into one list).

   * The default “page_size” setting for ‘execute_values’ has been
     increased from 100 to 1000.  The default remains at 100 for the
     ‘execute_batch’ function.  These parameters may both be modified as
     was the case before.

   * The ‘use_batch_mode’ flag that was part of the 1.2 version of the
     feature is removed; the behavior remains controllable via the
     ‘executemany_mode’ flag added in 1.3.

   * The Core engine and dialect has been enhanced to support
     executemany plus returning mode, currently only available with
     psycopg2, by providing new
     CursorResult.inserted_primary_key_rows and
     ‘CursorResult.returned_default_rows’ accessors.

See also
........

See Psycopg2 Fast Execution Helpers.

#5401(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4623

   (2) http://www.sqlalchemy.org/trac/ticket/5401

8.1.1.47 Removed “join rewriting” logic from SQLite dialect; updated imports
............................................................................

Dropped support for right-nested join rewriting to support old SQLite
versions prior to 3.7.16, released in 2013.  It is not expected that any
modern Python versions rely upon this limitation.

The behavior was first introduced in 0.9 and was part of the larger
change of allowing for right nested joins as described at *note Many
JOIN and LEFT OUTER JOIN expressions will no longer be wrapped in
(SELECT * FROM ..)  AS ANON_1: 1b5d.  However the SQLite workaround
produced many regressions in the 2013-2014 period due to its complexity.
In 2016, the dialect was modified so that the join rewriting logic would
only occur for SQLite versions prior to 3.7.16 after bisection was used
to identify where SQLite fixed its support for this construct, and no
further issues were reported against the behavior (even though some bugs
were found internally).  It is now anticipated that there are little to
no Python builds for Python 2.7 or 3.5 and above (the supported Python
versions) which would include a SQLite version prior to 3.7.17, and the
behavior is only necessary only in more complex ORM joining scenarios.
A warning is now emitted if the installed SQLite version is older than
3.7.16.

In related changes, the module imports for SQLite no longer attempt to
import the “pysqlite2” driver on Python 3 as this driver does not exist
on Python 3; a very old warning for old pysqlite2 versions is also
dropped.

#4895(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4895

8.1.1.48 Added Sequence support for MariaDB 10.3
................................................

The MariaDB database as of 10.3 supports sequences.  SQLAlchemy’s MySQL
dialect now implements support for the Sequence object
against this database, meaning “CREATE SEQUENCE” DDL will be emitted for
a Sequence that is present in a Table or
MetaData collection in the same way as it works for backends such
as PostgreSQL, Oracle, when the dialect’s server version check has
confirmed the database is MariaDB 10.3 or greater.  Additionally, the
Sequence will act as a column default and primary key
generation object when used in these ways.

Since this change will impact the assumptions both for DDL as well as
the behavior of INSERT statements for an application that is currently
deployed against MariaDB 10.3 which also happens to make explicit use
the Sequence construct within its table definitions, it is
important to note that Sequence supports a flag
Sequence.optional which is used to limit the scenarios in which
the Sequence to take effect.  When “optional” is used on a
Sequence that is present in the integer primary key column
of a table:

     Table(
         "some_table", metadata,
         Column("id", Integer, Sequence("some_seq", optional=True), primary_key=True)
     )

The above Sequence is only used for DDL and INSERT
statements if the target database does not support any other means of
generating integer primary key values for the column.  That is, the
Oracle database above would use the sequence, however the PostgreSQL and
MariaDB 10.3 databases would not.  This may be important for an existing
application that is upgrading to SQLAlchemy 1.4 which may not have
emitted DDL for this Sequence against its backing database,
as an INSERT statement will fail if it seeks to use a sequence that was
not created.

See also
........

See Defining Sequences.

#4976(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4976

8.1.1.49 Added Sequence support distinct from IDENTITY to SQL Server
....................................................................

The Sequence construct is now fully functional with
Microsoft SQL Server.  When applied to a Column, the DDL for
the table will no longer include IDENTITY keywords and instead will rely
upon “CREATE SEQUENCE” to ensure a sequence is present which will then
be used for INSERT statements on the table.

The Sequence prior to version 1.3 was used to control
parameters for the IDENTITY column in SQL Server; this usage emitted
deprecation warnings throughout 1.3 and is now removed in 1.4.  For
control of parameters for an IDENTITY column, the ‘mssql_identity_start’
and ‘mssql_identity_increment’ parameters should be used; see the MSSQL
dialect documentation linked below.

See also
........

See Auto Increment Behavior / IDENTITY Columns.

#4235(1)

#4633(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4235

   (2) http://www.sqlalchemy.org/trac/ticket/4633

8.2 SQLAlchemy 2.0 Overview and Status
======================================

8.2.1 Migrating to SQLAlchemy 2.0
---------------------------------

     About this document: SQLAlchemy 2.0 presents a major shift for a
     wide variety of key SQLAlchemy usage patterns in both the Core and
     ORM components.  The goal of this release is to make a slight
     readjustment in some of the most fundamental assumptions of
     SQLAlchemy since its early beginnings, and to deliver a newly
     streamlined usage model that is hoped to be significantly more
     minimalist and consistent between the Core and ORM components, as
     well as more capable.  The move of Python to be Python 3 only as
     well as the emergence of gradual typing systems for Python 3 are
     the initial inspirations for this shift, as is the changing nature
     of the Python community which now includes not just hardcore
     database programmers but a vast new community of data scientists
     and students of many different disciplines.

     SQLAlchemy started with Python 2.3 which had no context managers,
     no function decorators, Unicode as a second class feature, and a
     variety of other shortcomings that would be unknown today.  The
     biggest changes in SQLAlchemy 2.0 are targeting the residual
     assumptions left over from this early period in SQLAlchemy’s
     development as well as the leftover artifacts resulting from the
     incremental introduction of key API features such as ‘Query’ and
     Declarative.  It also hopes standardize some newer capabilities
     that have proven to be very effective.

8.2.1.1 Overview
................

The SQLAlchemy 2.0 transition presents itself in the SQLAlchemy 1.4
release as a series of steps that allow an application of any size or
complexity to be migrated to SQLAlchemy 2.0 using a gradual, iterative
process.  Lessons learned from the Python 2 to Python 3 transition have
inspired a system that intends to as great a degree as possible to not
require any “breaking” changes, or any change that would need to be made
universally or not at all.

As a means of both proving the 2.0 architecture as well as allowing a
fully iterative transition environment, the entire scope of 2.0’s new
APIs and features are present and available within the 1.4 series; this
includes major new areas of functionality such as the SQL caching
system, the new ORM statement execution model, new transactional
paradigms for both ORM and Core, a new ORM declarative system that
unifies classical and declarative mapping, support for Python
dataclasses, and asyncio support for Core and ORM.

The steps to achieve 2.0 migration are in the following subsections;
overall, the general strategy is that once an application runs on 1.4 in
with all warning flags turned on and does not emit any 2.0-deprecation
warnings, it is now cross-compatible with SQLAlchemy 2.0.

8.2.1.2 First Prerequisite, step one - A Working 1.3 Application
................................................................

The first step is getting an existing application onto 1.4, in the case
of a typical non trivial application, is to ensure it runs on SQLAlchemy
1.3 with no deprecation warnings.  Release 1.4 does have a few changes
linked to conditions that warn in previous version, including some
warnings that were introduced in 1.3, in particular some changes to the
behavior of the relationship.viewonly and
relationship.sync_backref flags.

For best results, the application should be able to run, or pass all of
its tests, with the latest SQLAlchemy 1.3 release with no SQLAlchemy
deprecation warnings; these are warnings emitted for the
SADeprecationWarning class.

8.2.1.3 First Prerequisite, step two - A Working 1.4 Application
................................................................

Once the application is good to go on SQLAlchemy 1.3, the next step is
to get it running on SQLAlchemy 1.4.  In the vast majority of cases,
applications should run without problems from SQLAlchemy 1.3 to 1.4.
However, it’s always the case between any 1.x and 1.y release, APIs and
behaviors have changed either subtly or in some cases a little less
subtly, and the SQLAlchemy project always gets a good deal of regression
reports for the first few months.

The 1.x->1.y release process usually has a few changes around the
margins that are a little bit more dramatic and are based around use
cases that are expected to be very seldom if at all used.  For 1.4, the
changes identified as being in this realm are as follows:

   * The URL object is now immutable. - this impacts code
     that would be manipulating the URL object and may
     impact code that makes use of the CreateEnginePlugin
     extension point.  This is an uncommon case but may affect in
     particular some test suites that are making use of special database
     provisioning logic.  A github search for code that uses the
     relatively new and little-known CreateEnginePlugin
     class found two projects that were unaffected by the change.

   * A SELECT statement is no longer implicitly considered to be a FROM clause.
     - this change may impact code that was somehow
     relying upon behavior that was mostly unusable in the Select
     construct, where it would create unnamed subqueries that were
     usually confusing and non-working.  These subqueries would be
     rejected by most databases in any case as a name is usually
     required except on SQLite, however it is possible some applications
     will need to adjust some queries that are inadvertently relying
     upon this.

   * select().join() and outerjoin() add JOIN criteria to the current query, rather than creating a subquery.
     - somewhat
     related, the Select class featured ‘.join()’ and
     ‘.outerjoin()’ methods that implicitly created a subquery and then
     returned a Join construct, which again would be mostly
     useless and produced lots of confusion.  The decision was made to
     move forward with the vastly more useful 2.0-style join-building
     approach where these methods now work the same way as the ORM
     Query.join() method.

   * Many Core and ORM statement objects now perform much of their construction and validation in the compile phase.
     - some
     error messages related to construction of a Query or
     Select may not be emitted until compilation / execution,
     rather than at construction time.  This might impact some test
     suites that are testing against failure modes.

For the full overview of SQLAlchemy 1.4 changes, see the What’s New in SQLAlchemy 1.4?
document.

8.2.1.4 Migration to 2.0 Step One - Python 3 only (Python 3.6 minimum)
......................................................................

SQLAlchemy 2.0 was first inspired by the fact that Python 2’s EOL was in
2020.  SQLAlchemy is taking a longer period of time than other major
projects to drop Python 2.7 support, since it is not too much in the way
of things for the moment.  However, version 2.0 hopes to start embracing
PEP 484(1) and other new features to a great degree, so it is likely
that release 1.4 will be the last Python 2 supporting version, even if
there is a SQLAlchemy 1.5 (which is also unlikely at the moment).

In order to use SQLAlchemy 2.0, the application will need to be runnable
on at least `Python 3.6' as of this writing.  SQLAlchemy 1.4 now
supports Python 3.6 or newer within the Python 3 series; throughout the
1.4 series, the application can remain running on Python 2.7 or on at
least Python 3.6.

   ---------- Footnotes ----------

   (1) https://www.python.org/dev/peps/pep-0484

8.2.1.5 Migration to 2.0 Step Two - Turn on RemovedIn20Warnings
...............................................................

SQLAlchemy 1.4 features a conditional deprecation warning system
inspired by the Python “-3” flag that would indicate legacy patterns in
a running application.  For SQLAlchemy 1.4, the
RemovedIn20Warning deprecation class is emitted only when an
environment variable ‘SQLALCHEMY_WARN_20’ is set to either of ‘true’ or
‘1’.

Given the example program below:

     from sqlalchemy import column
     from sqlalchemy import create_engine
     from sqlalchemy import select
     from sqlalchemy import table

     engine = create_engine("sqlite://")

     engine.execute("CREATE TABLE foo (id integer)")
     engine.execute("INSERT INTO foo (id) VALUES (1)")

     foo = table("foo", column("id"))
     result = engine.execute(select([foo.c.id]))

     print(result.fetchall())

The above program uses several patterns that many users will already
identify as “legacy”, namely the use of the Engine.execute()
method that’s part of the connectionless execution system.
When we run the above program against 1.4, it returns a single line:

     $ python test3.py
     [(1,)]

To enable “2.0 deprecations mode”, we enable the ‘SQLALCHEMY_WARN_20=1’
variable, and additionally ensure that a warnings filter(1) that will
not suppress any warnings is selected:

     SQLALCHEMY_WARN_20=1 python -W always::DeprecationWarning test3.py

With warnings turned on, our program now has a lot to say:

     $ SQLALCHEMY_WARN_20=1 python2 -W always::DeprecationWarning test3.py
     test3.py:9: RemovedIn20Warning: The Engine.execute() function/method is considered legacy as of the 1.x series of SQLAlchemy and will be removed in 2.0. All statement execution in SQLAlchemy 2.0 is performed by the Connection.execute() method of Connection, or in the ORM by the Session.execute() method of Session. (Background on SQLAlchemy 2.0 at: http://sqlalche.me/e/b8d9) (Background on SQLAlchemy 2.0 at: http://sqlalche.me/e/b8d9)
       engine.execute("CREATE TABLE foo (id integer)")
     /home/classic/dev/sqlalchemy/lib/sqlalchemy/engine/base.py:2856: RemovedIn20Warning: Passing a string to Connection.execute() is deprecated and will be removed in version 2.0.  Use the text() construct, or the Connection.exec_driver_sql() method to invoke a driver-level SQL string. (Background on SQLAlchemy 2.0 at: http://sqlalche.me/e/b8d9)
       return connection.execute(statement, *multiparams, **params)
     /home/classic/dev/sqlalchemy/lib/sqlalchemy/engine/base.py:1639: RemovedIn20Warning: The current statement is being autocommitted using implicit autocommit.Implicit autocommit will be removed in SQLAlchemy 2.0.   Use the .begin() method of Engine or Connection in order to use an explicit transaction for DML and DDL statements. (Background on SQLAlchemy 2.0 at: http://sqlalche.me/e/b8d9)
       self._commit_impl(autocommit=True)
     test3.py:10: RemovedIn20Warning: The Engine.execute() function/method is considered legacy as of the 1.x series of SQLAlchemy and will be removed in 2.0. All statement execution in SQLAlchemy 2.0 is performed by the Connection.execute() method of Connection, or in the ORM by the Session.execute() method of Session. (Background on SQLAlchemy 2.0 at: http://sqlalche.me/e/b8d9) (Background on SQLAlchemy 2.0 at: http://sqlalche.me/e/b8d9)
       engine.execute("INSERT INTO foo (id) VALUES (1)")
     /home/classic/dev/sqlalchemy/lib/sqlalchemy/engine/base.py:2856: RemovedIn20Warning: Passing a string to Connection.execute() is deprecated and will be removed in version 2.0.  Use the text() construct, or the Connection.exec_driver_sql() method to invoke a driver-level SQL string. (Background on SQLAlchemy 2.0 at: http://sqlalche.me/e/b8d9)
       return connection.execute(statement, *multiparams, **params)
     /home/classic/dev/sqlalchemy/lib/sqlalchemy/engine/base.py:1639: RemovedIn20Warning: The current statement is being autocommitted using implicit autocommit.Implicit autocommit will be removed in SQLAlchemy 2.0.   Use the .begin() method of Engine or Connection in order to use an explicit transaction for DML and DDL statements. (Background on SQLAlchemy 2.0 at: http://sqlalche.me/e/b8d9)
       self._commit_impl(autocommit=True)
     /home/classic/dev/sqlalchemy/lib/sqlalchemy/sql/selectable.py:4271: RemovedIn20Warning: The legacy calling style of select() is deprecated and will be removed in SQLAlchemy 2.0.  Please use the new calling style described at select(). (Background on SQLAlchemy 2.0 at: http://sqlalche.me/e/b8d9) (Background on SQLAlchemy 2.0 at: http://sqlalche.me/e/b8d9)
       return cls.create_legacy_select(*args, **kw)
     test3.py:14: RemovedIn20Warning: The Engine.execute() function/method is considered legacy as of the 1.x series of SQLAlchemy and will be removed in 2.0. All statement execution in SQLAlchemy 2.0 is performed by the Connection.execute() method of Connection, or in the ORM by the Session.execute() method of Session. (Background on SQLAlchemy 2.0 at: http://sqlalche.me/e/b8d9) (Background on SQLAlchemy 2.0 at: http://sqlalche.me/e/b8d9)
       result = engine.execute(select([foo.c.id]))
     [(1,)]

With the above guidance, we can migrate our program to use 2.0 styles,
and as a bonus our program is much clearer:

     from sqlalchemy import column
     from sqlalchemy import create_engine
     from sqlalchemy import select
     from sqlalchemy import table
     from sqlalchemy import text

     engine = create_engine("sqlite://")

     # don't rely on autocommit for DML and DDL
     with engine.begin() as connection:
         # use connection.execute(), not engine.execute()
         # use the text() construct to execute textual SQL
         connection.execute(text("CREATE TABLE foo (id integer)"))
         connection.execute(text("INSERT INTO foo (id) VALUES (1)"))

     foo = table("foo", column("id"))

     with engine.connect() as connection:
         # use connection.execute(), not engine.execute()
         # select() now accepts column / table expressions positionally
         result = connection.execute(select(foo.c.id))

     print(result.fetchall())

The goal of “2.0 deprecations mode” is that a program which runs with no
RemovedIn20Warning warnings with “2.0 deprecations mode”
turned on is then ready to run in SQLAlchemy 2.0.

   ---------- Footnotes ----------

   (1)
https://docs.python.org/3/library/warnings.html#the-warnings-filter

8.2.1.6 Migration to 2.0 Step Three - Resolve all RemovedIn20Warnings
.....................................................................

Code can be developed iteratively to resolve these warnings.  Within the
SQLAlchemy project itself, the approach taken is as follows:

  1. enable the ‘SQLALCHEMY_WARN_20=1’ environment variable in the test
     suite, for SQLAlchemy this is in the tox.ini file

  2. Within the setup for the test suite, set up a series of warnings
     filters that will select for particular subsets of warnings to
     either raise an exception, or to be ignored (or logged).  Work with
     just one subgroup of warnings at a time.  Below, a warnings filter
     is configured for an application where the change to the Core level
     ‘.execute()’ calls will be needed in order for all tests to pass,
     but all other 2.0-style warnings will be suppressed:

          import warnings
          from sqlalchemy import exc

          # for warnings related to execute() / scalar(), raise
          for msg in [
              r"The (?:Executable|Engine)\.(?:execute|scalar)\(\) function",
              r"The current statement is being autocommitted using implicit "
              "autocommit,",
              r"The connection.execute\(\) method in SQLAlchemy 2.0 will accept "
              "parameters as a single dictionary or a single sequence of "
              "dictionaries only.",
              r"The Connection.connect\(\) function/method is considered legacy",
              r".*DefaultGenerator.execute\(\)",
          ]:
            warnings.filterwarnings(
                "error", message=msg, category=sa_exc.RemovedIn20Warning,
            )

          # for all other warnings, just log
          warnings.filterwarnings(
            "always", category=exc.RemovedIn20Warning
          )

  3. As each sub-category of warnings are resolved in the application,
     new warnings that are caught by the “always” filter can be added to
     the list of “errors” to be resolved.

  4. Once no more warnings are emitted, the filter can be removed.

8.2.1.7 Migration to 2.0 Step Four - Use the ‘future’ flag on Engine
....................................................................

The Engine object features an updated transaction-level API
in version 2.0.  In 1.4, this new API is available by passing the flag
‘future=True’ to the create_engine() function.

When the create_engine.future flag is used, the Engine
and Connection objects support the 2.0 API fully and not
at all any legacy features, including the new argument format for
Connection.execute(), the removal of “implicit autocommit”, string
statements require the text() construct unless the
‘Connection.exec_driver_sql()’ method is used, and connectionless
execution from the Engine is removed.

If all RemovedIn20Warning warnings have been resolved
regarding use of the Engine and Connection, then
the create_engine.future flag may be enabled and there should
be no errors raised.

The new engine is described at Engine which delivers a new
Connection object.  In addition to the above changes, the,
see Connection object features Connection.commit() and
Connection.rollback() methods, to support the new
“commit-as-you-go” mode of operation:

     from sqlalchemy import create_engine

     engine = create_engine("postgresql:///")

     with engine.connect() as conn:
         conn.execute(text("insert into table (x) values (:some_x)"), {"some_x": 10})

         conn.commit()  # commit as you go

8.2.1.8 Migration to 2.0 Step Four - Use the ‘future’ flag on Session
.....................................................................

The Session object also features an updated
transaction/connection level API in version 2.0.  This API is available
in 1.4 using the Session.future flag on Session
or on sessionmaker.

The Session object supports “future” mode in place, and
involves these changes:

  1. The Session no longer supports “bound metadata” when it
     resolves the engine to be used for connectivity.  This means that
     an Engine object `must' be passed to the constructor
     (this may be either a legacy or future style object).

  2. The Session.begin.subtransactions flag is no longer
     supported.

  3. The Session.commit() method always emits a COMMIT to the
     database, rather than attempting to reconcile “subtransactions”.

  4. The Session.rollback() method always rolls back the
     full stack of transactions at once, rather than attempting to keep
     “subtransactions” in place.

The Session also supports more flexible creational patterns
in 1.4 which are now closely matched to the patterns used by the
Connection object.  Highlights include that the Session
may be used as a context manager:

     from sqlalchemy.orm import Session
     with Session(engine) as session:
         session.add(MyObject())
         session.commit()

In addition, the sessionmaker object supports a
sessionmaker.begin() context manager that will create a
Session and begin /commit a transaction in one block:

     from sqlalchemy.orm import sessionmaker

     Session = sessionmaker(engine)

     with Session.begin() as session:
         session.add(MyObject())

See the section Session-level vs. Engine level transaction control
for a comparison of Session creational patterns
compared to those of Connection.

Once the application passes all tests/ runs with ‘SQLALCHEMY_WARN_20=1’
and all ‘exc.RemovedIn20Warning’ occurrences set to raise an error, `the
application is ready!'.

The sections that follow will detail the specific changes to make for
all major API modifications.

8.2.1.9 2.0 Migration - Core Connection / Transaction
.....................................................

8.2.1.10 Library-level (but not driver level) “Autocommit” removed from both Core and ORM
.........................................................................................

`Synopsis'

In SQLAlchemy 1.x, the following statements will automatically commit
the underlying DBAPI transaction, but in SQLAlchemy 2.0 this will not
occur:

     conn = engine.connect()

     # won't autocommit in 2.0
     conn.execute(some_table.insert().values(foo='bar'))

Nor will this autocommit:

     conn = engine.connect()

     # won't autocommit in 2.0
     conn.execute(text("INSERT INTO table (foo) VALUES ('bar')"))

The common workaround for custom DML that requires commit, the
“autocommit” execution option, will be removed:

     conn = engine.connect()

     # won't autocommit in 2.0
     conn.execute(
       text("EXEC my_procedural_thing()").execution_options(autocommit=True)
     )

`Migration to 2.0'

The method that is cross-compatible with 1.x style and 2.0 style
execution is to make use of the Connection.begin() method,
or the Engine.begin() context manager:

     with engine.begin() as conn:
         conn.execute(some_table.insert().values(foo='bar'))
         conn.execute(some_other_table.insert().values(bat='hoho'))

     with engine.connect() as conn:
         with conn.begin():
             conn.execute(some_table.insert().values(foo='bar'))
             conn.execute(some_other_table.insert().values(bat='hoho'))

     with engine.begin() as conn:
         conn.execute(text("EXEC my_procedural_thing()"))

When using 2.0 style with the create_engine.future flag,
“commit as you go” style may also be used, as the Connection
features `autobegin' behavior, which takes place when a statement is
first invoked in the absence of an explicit call to
Connection.begin():

     with engine.connect() as conn:
         conn.execute(some_table.insert().values(foo='bar'))
         conn.execute(some_other_table.insert().values(bat='hoho'))

         conn.commit()

When 2.0 deprecations mode is enabled, a warning will emit
when the deprecated “autocommit” feature takes place, indicating those
places where an explicit transaction should be noted.

`Discussion'

SQLAlchemy’s first releases were at odds with the spirit of the Python
DBAPI ( PEP 249(1)) in that it tried to hide PEP 249(2)’s emphasis on
“implicit begin” and “explicit commit” of transactions.  Fifteen years
later we now see this was essentially a mistake, as SQLAlchemy’s many
patterns that attempt to “hide” the presence of a transaction make for a
more complex API which works inconsistently and is extremely confusing
to especially those users who are new to relational databases and ACID
transactions in general.  SQLAlchemy 2.0 will do away with all attempts
to implicitly commit transactions, and usage patterns will always
require that the user demarcate the “beginning” and the “end” of a
transaction in some way, in the same way as reading or writing to a file
in Python has a “beginning” and an “end”.

In the case of autocommit for a pure textual statement, there is
actually a regular expression that parses every statement in order to
detect autocommit!  Not surprisingly, this regex is continuously failing
to accommodate for various kinds of statements and stored procedures
that imply a “write” to the database, leading to ongoing confusion as
some statements produce results in the database and others don’t.  By
preventing the user from being aware of the transactional concept, we
get a lot of bug reports on this one because users don’t understand that
databases always use a transaction, whether or not some layer is
autocommitting it.

SQLAlchemy 2.0 will require that all database actions at every level be
explicit as to how the transaction should be used.  For the vast
majority of Core use cases, it’s the pattern that is already
recommended:

     with engine.begin() as conn:
         conn.execute(some_table.insert().values(foo='bar'))

For “commit as you go, or rollback instead” usage, which resembles how
the Session is normally used today, the “future” version of
Connection, which is the one that is returned from an
Engine that was created using the create_engine.future
flag, includes new Connection.commit() and
Connection.rollback() methods, which act upon a transaction that
is now begun automatically when a statement is first invoked:

     # 1.4 / 2.0 code

     from sqlalchemy import create_engine

     engine = create_engine(..., future=True)

     with engine.connect() as conn:
         conn.execute(some_table.insert().values(foo='bar'))
         conn.commit()

         conn.execute(text("some other SQL"))
         conn.rollback()

Above, the ‘engine.connect()’ method will return a Connection
that features `autobegin', meaning the ‘begin()’ event is emitted
when the execute method is first used (note however that there is no
actual “BEGIN” in the Python DBAPI). “autobegin” is a new pattern in
SQLAlchemy 1.4 that is featured both by Connection as well as
the ORM Session object; autobegin allows that the
Connection.begin() method may be called explicitly when the object
is first acquired, for schemes that wish to demarcate the beginning of
the transaction, but if the method is not called, then it occurs
implicitly when work is first done on the object.

The removal of “autocommit” is closely related to the removal of
“connectionless” execution discussed at “Implicit” and “Connectionless” execution, “bound metadata” removed.
All of
these legacy patterns built up from the fact that Python did not have
context managers or decorators when SQLAlchemy was first created, so
there were no convenient idiomatic patterns for demarcating the use of a
resource.

   ---------- Footnotes ----------

   (1) https://www.python.org/dev/peps/pep-0249

   (2) https://www.python.org/dev/peps/pep-0249

8.2.1.11 Driver-level autocommit remains available
..................................................

True “autocommit” behavior is now widely available with most DBAPI
implementations, and is supported by SQLAlchemy via the
Connection.execution_options.isolation_level parameter as
discussed at Setting Transaction Isolation Levels including DBAPI Autocommit.
True autocommit is treated as an “isolation level” so
that the structure of application code does not change when autocommit
is used; the Connection.begin() context manager as well as
methods like Connection.commit() may still be used, they are
simply no-ops at the database driver level when DBAPI-level autocommit
is turned on.

8.2.1.12 “Implicit” and “Connectionless” execution, “bound metadata” removed
............................................................................

`Synopsis'

The ability to associate an Engine with a MetaData
object, which then makes available a range of so-called
“connectionless” execution patterns, is removed:

     from sqlalchemy import MetaData

     metadata = MetaData(bind=engine)  # no longer supported

     metadata.create_all()   # requires Engine or Connection

     metadata.reflect()  # requires Engine or Connection

     t = Table('t', metadata, autoload=True)  # use autoload_with=engine

     result = engine.execute(t.select())  # no longer supported

     result = t.select().execute()  # no longer supported

`Migration to 2.0'

For schema level patterns, explicit use of an Engine or
Connection is required.  The Engine may still be
used directly as the source of connectivity for a
MetaData.create_all() operation or autoload operation.  For
executing statements, only the Connection object has an
Connection.execute() method (in addition to the ORM-level
Session.execute() method):

     from sqlalchemy import MetaData

     metadata = MetaData()

     # engine level:

     # create tables
     metadata.create_all(engine)

     # reflect all tables
     metadata.reflect(engine)

     # reflect individual table
     t = Table('t', metadata, autoload_with=engine)

     # connection level:

     with engine.connect() as connection:
         # create tables, requires explicit begin and/or commit:
         with connection.begin():
             metadata.create_all(connection)

         # reflect all tables
         metadata.reflect(connection)

         # reflect individual table
         t = Table('t', metadata, autoload_with=connection)

         # execute SQL statements
         result = conn.execute(t.select())

`Discussion'

The Core documentation has already standardized on the desired pattern
here, so it is likely that most modern applications would not have to
change much in any case, however there are likely many applications that
still rely upon ‘engine.execute()’ calls that will need to be adjusted.

“Connectionless” execution refers to the still fairly popular pattern of
invoking ‘.execute()’ from the Engine:

     result = engine.execute(some_statement)

The above operation implicitly procures a Connection object,
and runs the ‘.execute()’ method on it.  While this appears to be a
simple convenience feature, it has been shown to give rise to several
issues:

   * Programs that feature extended strings of ‘engine.execute()’ calls
     have become prevalent, overusing a feature that was intended to be
     seldom used and leading to inefficient non-transactional
     applications.  New users are confused as to the difference between
     ‘engine.execute()’ and ‘connection.execute()’ and the nuance
     between these two approaches is often not understood.

   * The feature relies upon the “application level autocommit” feature
     in order to make sense, which itself is also being removed as it is
     also inefficient and misleading.

   * In order to handle result sets, ‘Engine.execute’ returns a result
     object with unconsumed cursor results.  This cursor result
     necessarily still links to the DBAPI connection which remains in an
     open transaction, all of which is released once the result set has
     fully consumed the rows waiting within the cursor.  This means that
     ‘Engine.execute’ does not actually close out the connection
     resources that it claims to be managing when the call is complete.
     SQLAlchemy’s “autoclose” behavior is well-tuned enough that users
     don’t generally report any negative effects from this system,
     however it remains an overly implicit and inefficient system left
     over from SQLAlchemy’s earliest releases.

The removal of “connectionless” execution then leads to the removal of
an even more legacy pattern, that of “implicit, connectionless”
execution:

     result = some_statement.execute()

The above pattern has all the issues of “connectionless” execution, plus
it relies upon the “bound metadata” pattern, which SQLAlchemy has tried
to de-emphasize for many years.  This was SQLAlchemy’s very first
advertised usage model in version 0.1, which became obsolete almost
immediately when the Connection object was introduced and
later Python context managers provided a better pattern for using
resources within a fixed scope.

With implicit execution removed, “bound metadata” itself also no longer
has a purpose within this system.  In modern use “bound metadata” tends
to still be somewhat convenient for working within
MetaData.create_all() calls as well as with Session
objects, however having these functions receive an Engine
explicitly provides for clearer application design.

8.2.1.13 Many Choices becomes One Choice
........................................

Overall, the above executional patterns were introduced in SQLAlchemy’s
very first 0.1 release before the Connection object even
existed.  After many years of de-emphasizing these patterns, “implicit,
connectionless” execution and “bound metadata” are no longer as widely
used so in 2.0 we seek to finally reduce the number of choices for how
to execute a statement in Core from “many choices”:

     # many choices

     # bound metadata?
     metadata = MetaData(engine)

     # or not?
     metadata = MetaData()

     # execute from engine?
     result = engine.execute(stmt)

     # or execute the statement itself (but only if you did
     # "bound metadata" above, which means you can't get rid of "bound" if any
     # part of your program uses this form)
     result = stmt.execute()

     # execute from connection, but it autocommits?
     conn = engine.connect()
     conn.execute(stmt)

     # execute from connection, but autocommit isn't working, so use the special
     # option?
     conn.execution_options(autocommit=True).execute(stmt)

     # or on the statement ?!
     conn.execute(stmt.execution_options(autocommit=True))

     # or execute from connection, and we use explicit transaction?
     with conn.begin():
         conn.execute(stmt)

to “one choice”, where by “one choice” we mean “explicit connection with
explicit transaction”; there are still a few ways to demarcate
transaction blocks depending on need.  The “one choice” is to procure a
Connection and then to explicitly demarcate the transaction,
in the case that the operation is a write operation:

     # one choice - work with explicit connection, explicit transaction
     # (there remain a few variants on how to demarcate the transaction)

     # "begin once" - one transaction only per checkout
     with engine.begin() as conn:
         result = conn.execute(stmt)

     # "commit as you go" - zero or more commits per checkout
     with engine.connect() as conn:
         result = conn.execute(stmt)
         conn.commit()

     # "commit as you go" but with a transaction block instead of autobegin
     with engine.connect() as conn:
         with conn.begin():
             result = conn.execute(stmt)

8.2.1.14 execute() method more strict, execution options are more prominent
...........................................................................

`Synopsis'

The argument patterns that may be used with the
sqlalchemy.engine.Connection() execute method in SQLAlchemy 2.0
are highly simplified, removing many previously available argument
patterns.  The new API in the 1.4 series is described at
sqlalchemy.future.Connection().  The examples below illustrate the
patterns that require modification:

     connection = engine.connect()

     # direct string SQL not supported; use text() or exec_driver_sql() method
     result = connection.execute("select * from table")

     # positional parameters no longer supported, only named
     # unless using exec_driver_sql()
     result = connection.execute(table.insert(), ('x', 'y', 'z'))

     # **kwargs no longer accepted, pass a single dictionary
     result = connection.execute(table.insert(), x=10, y=5)

     # multiple *args no longer accepted, pass a list
     result = connection.execute(
         table.insert(),
         {"x": 10, "y": 5}, {"x": 15, "y": 12}, {"x": 9, "y": 8}
     )

`Migration to 2.0'

The new Connection.execute() method now accepts a subset of
the argument styles that are accepted by the 1.x
Connection.execute() method, so the following code is
cross-compatible between 1.x and 2.0:

     connection = engine.connect()

     from sqlalchemy import text
     result = connection.execute(text("select * from table"))

     # pass a single dictionary for single statement execution
     result = connection.execute(table.insert(), {"x": 10, "y": 5})

     # pass a list of dictionaries for executemany
     result = connection.execute(
         table.insert(),
         [{"x": 10, "y": 5}, {"x": 15, "y": 12}, {"x": 9, "y": 8}]
     )

`Discussion'

The use of ‘*args’ and ‘**kwargs’ has been removed both to remove the
complexity of guessing what kind of arguments were passed to the method,
as well as to make room for other options, namely the
Connection.execute.execution_options dictionary that is now
available to provide options on a per statement basis.  The method is
also modified so that its use pattern matches that of the
Session.execute() method, which is a much more prominent API in 2.0
style.

The removal of direct string SQL is to resolve an inconsistency between
Connection.execute() and Session.execute(), where
in the former case the string is passed to the driver raw, and in the
latter case it is first converted to a text() construct.  By
allowing only text() this also limits the accepted parameter
format to “named” and not “positional”.  Finally, the string SQL use
case is becoming more subject to scrutiny from a security perspective,
and the text() construct has come to represent an explicit
boundary into the textual SQL realm where attention to untrusted user
input must be given.

8.2.1.15 Result rows act like named tuples
..........................................

`Synopsis'

Version 1.4 introduces an all new Result object that in
turn returns Row objects, which behave like named tuples when
using “future” mode:

     engine = create_engine(..., future=True)  # using future mode

     with engine.connect() as conn:
         result = conn.execute(text("select x, y from table"))

         row = result.first()  # suppose the row is (1, 2)

         "x" in row   # evaluates to False, in 1.x / future=False, this would be True

         1 in row  # evaluates to True, in 1.x / future=False, this would be False

`Migration to 2.0'

Application code or test suites that are testing for a particular key
being present in a row would need to test the ‘row.keys()’ collection
instead.  This is however an unusual use case as a result row is
typically used by code that already knows what columns are present
within it.

`Discussion'

Already part of 1.4, the previous ‘KeyedTuple’ class that was used when
selecting rows from the Query object has been replaced by
the Row class, which is the base of the same Row
that comes back with Core statement results when using the
create_engine.future flag with Engine. (when the
create_engine.future flag is not set, Core result sets use the
LegacyRow subclass, which maintains backwards-compatible
behaviors for the ‘__contains__()’ method; ORM exclusively uses the
Row class directly).

This Row behaves like a named tuple, in that it acts as a
sequence but also supports attribute name access, e.g.
‘row.some_column’.  However, it also provides the previous “mapping”
behavior via the special attribute ‘row._mapping’, which produces a
Python mapping such that keyed access such as ‘row["some_column"]’ can
be used.

In order to receive results as mappings up front, the ‘mappings()’
modifier on the result can be used:

     from sqlalchemy.future.orm import Session

     session = Session(some_engine)

     result = session.execute(stmt)
     for row in result.mappings():
         print("the user is: %s" % row["User"])

The Row class as used by the ORM also supports access via
entity or attribute:

     from sqlalchemy.future import select

     stmt = select(User, Address).join(User.addresses)

     for row in session.execute(stmt).mappings():
         print("the user is: %s  the address is: %s" % (
             row[User],
             row[Address]
         ))

See also
........

See RowProxy is no longer a “proxy”; is now called Row and behaves like an enhanced named tuple.

8.2.1.16 2.0 Migration - Core Usage
...................................

8.2.1.17 select() no longer accepts varied constructor arguments, columns are passed positionally
.................................................................................................

`synopsis'

The select() construct as well as the related method
FromClause.select() will no longer accept keyword arguments to
build up elements such as the WHERE clause, FROM list and ORDER BY. The
list of columns may now be sent positionally, rather as a list.
Additionally, the case() construct now accepts its WHEN
criteria positionally, rather than as a list:

     # select_from / order_by keywords no longer supported
     stmt = select([1], select_from=table, order_by=table.c.id)

     # whereclause parameter no longer supported
     stmt = select([table.c.x], table.c.id == 5)

     # whereclause parameter no longer supported
     stmt = table.select(table.c.id == 5)

     # list emits a deprecation warning
     stmt = select([table.c.x, table.c.y])

     # list emits a deprecation warning
     case_clause = case(
       [
         (table.c.x == 5, "five"),
         (table.c.x == 7, "seven")
       ],
       else_="neither five nor seven"
     )

`Migration to 2.0'

Only the “generative” style of select() will be supported.
The list of columns / tables to SELECT from should be passed
positionally.  The select() construct in SQLAlchemy 1.4
accepts both the legacy styles and the new styles using an
auto-detection scheme, so the code below is cross-compatible with 1.4
and 2.0:

     # use generative methods
     stmt = select(1).select_from(table).order_by(table.c.id)

     # use generative methods
     stmt = select(table).where(table.c.id == 5)

     # use generative methods
     stmt = table.select().where(table.c.id == 5)

     # pass columns clause expressions positionally
     stmt = select(table.c.x, table.c.y)

     # case conditions passed positionally
     case_clause = case(
       (table.c.x == 5, "five"),
       (table.c.x == 7, "seven"),
       else_="neither five nor seven"
     )

`Discussion'

SQLAlchemy has for many years developed a convention for SQL constructs
accepting an argument either as a list or as positional arguments.  This
convention states that `structural' elements, those that form the
structure of a SQL statement, should be passed `positionally'.
Conversely, `data' elements, those that form the parameterized data of a
SQL statement, should be passed `as lists'.  For many years, the
select() construct could not participate in this convention
smoothly because of the very legacy calling pattern where the “WHERE”
clause would be passed positionally.  SQLAlchemy 2.0 finally resolves
this by changing the select() construct to only accept the
“generative” style that has for many years been the only documented
style in the Core tutorial.

Examples of “structural” vs.  “data” elements are as follows:

     # table columns for CREATE TABLE - structural
     table = Table("table", metadata, Column('x', Integer), Column('y', Integer))

     # columns in a SELECT statement - structural
     stmt = select(table.c.x, table.c.y)

     # literal elements in an IN clause - data
     stmt = stmt.where(table.c.y.in_([1, 2, 3]))

See also
........

See select(), case() now accept positional expressions.

See select() construct created in “legacy” mode; keyword arguments, etc..

8.2.1.18 insert/update/delete DML no longer accept keyword constructor arguments
................................................................................

`Synopsis'

In a similar way as to the previous change to select(), the
constructor arguments to insert(), update() and
delete() other than the table argument are essentially
removed:

     # no longer supported
     stmt = insert(table, values={"x": 10, "y": 15}, inline=True)

     # no longer supported
     stmt = insert(table, values={"x": 10, "y": 15}, returning=[table.c.x])

     # no longer supported
     stmt = table.delete(table.c.x > 15)

     # no longer supported
     stmt = table.update(
         table.c.x < 15,
         preserve_parameter_order=True
     ).values(
         [(table.c.y, 20), (table.c.x, table.c.y + 10)]
     )

`Migration to 2.0'

The following examples illustrate generative method use for the above
examples:

     # use generative methods, **kwargs OK for values()
     stmt = insert(table).values(x=10, y=15).inline()

     # use generative methods, dictionary also still  OK for values()
     stmt = insert(table).values({"x": 10, "y": 15}).returning(table.c.x)

     # use generative methods
     stmt = table.delete().where(table.c.x > 15)

     # use generative methods, ordered_values() replaces preserve_parameter_order
     stmt = table.update().where(
         table.c.x < 15,
     ).ordered_values(
         (table.c.y, 20), (table.c.x, table.c.y + 10)
     )

`Discussion'

The API and internals is being simplified for the DML constructs in a
similar manner as that of the select() construct.

8.2.1.19 2.0 Migration - ORM Configuration
..........................................

8.2.1.20 Declarative becomes a first class API
..............................................

`Synopsis'

The ‘sqlalchemy.ext.declarative’ package is mostly, with some
exceptions, moved to the ‘sqlalchemy.orm’ package.  The
declarative_base() and declared_attr() functions are
present without any behavioral changes.  A new super-implementation of
declarative_base() known as registry now serves as
the top-level ORM configurational construct, which also provides for
decorator-based declarative and new support for classical mappings that
integrate with the declarative registry.

`Migration to 2.0'

Change imports:

     from sqlalchemy.ext import declarative_base, declared_attr

To:

     from sqlalchemy.orm import declarative_base, declared_attr

`Discussion'

After ten years or so of popularity, the ‘sqlalchemy.ext.declarative’
package is now integrated into the ‘sqlalchemy.orm’ namespace, with the
exception of the declarative “extension” classes which remain as
Declarative extensions.  The change is detailed further in the 1.4
migration guide at Declarative is now integrated into the ORM with new features.

See also
........

See Mapping Python Classes. - all new unified documentation for
Declarative, classical mapping, dataclasses, attrs, etc.

See Declarative is now integrated into the ORM with new features.

8.2.1.21 The original “mapper()” function now a core element of Declarative, renamed
....................................................................................

`Synopsis'

The mapper() function moves behind the scenes to be invoked
by higher level APIs.  The new version of this function is the method
registry.map_imperatively() taken from a registry
object.

`Migration to 2.0'

Code that works with classical mappings should change imports and code
from:

     from sqlalchemy.orm import mapper

     mapper(SomeClass, some_table, properties={
         "related": relationship(SomeRelatedClass)
     })

To work from a central registry object:

     from sqlalchemy.orm import registry

     mapper_reg = registry()

     mapper_reg.map_imperatively(SomeClass, some_table, properties={
         "related": relationship(SomeRelatedClass)
     })

The above registry is also the source for declarative
mappings, and classical mappings now have access to this registry
including string-based configuration on relationship():

     from sqlalchemy.orm import registry

     mapper_reg = registry()

     Base = mapper_reg.generate_base()

     class SomeRelatedClass(Base):
         __tablename__ = 'related'

         # ...

     mapper_reg.map_imperatively(SomeClass, some_table, properties={
         "related": relationship(
             "SomeRelatedClass",
             primaryjoin="SomeRelatedClass.related_id == SomeClass.id"
         )
     })

`Discussion'

By popular demand, “classical mapping” is staying around, however the
new form of it is based off of the registry object and is
available as registry.map_imperatively().

In addition, the primary rationale used for “classical mapping” is that
of keeping the Table setup distinct from the class.
Declarative has always allowed this style using so-called hybrid declarative.
However, to remove the base class requirement, a first
class decorator form has been added.

As yet another separate but related enhancement, support for
Python dataclasses is added as well to both declarative decorator
and classical mapping forms.

See also
........

See Mapping Python Classes. - all new unified documentation for
Declarative, classical mapping, dataclasses, attrs, etc.

8.2.1.22 2.0 Migration - ORM Usage
..................................

The biggest visible change in SQLAlchemy 2.0 is the use of
Session.execute() in conjunction with select() to run
ORM queries, instead of using Session.query().  As mentioned
elsewhere, there is no plan to actually remove the
Session.query(). API itself, as it is now implemented by using the
new API internally it will remain as a legacy API, and both APIs can be
used freely.

The table below provides an introduction to the general change in
calling form with links to documentation for each technique presented.
The individual migration notes are in the embedded sections following
the table, and may include additional notes not summarized here.
`Overview of Major ORM Querying Patterns'

1.x style form                        2.0 style form                        See Also

------------------------------------------------------------------------------------------------------------------

     session.query(User).get(42)           session.get(User, 42)            ORM Query - get() method moves to Session.

     session.query(User).all()             session.execute(                 see ORM Query Unified with Core Select.
                                               select(User)
                                           ).scalars().all()                Result.scalars().

     session.query(User).\                 session.execute(                 see ORM Query Unified with Core Select
     filter_by(name='some user').one()         select(User).
                                               filter_by(name="some user")  Result.scalar_one().
                                           ).scalar_one()

     session.query(User).options(          session.execute(                 see ORM Rows not uniquified by default.
         joinedload(User.addresses)            select(User).
     ).all()                                   options(
                                                 joinedload(User.addresses)
                                               )
                                           ).unique().all()

     session.query(User).\                 session.execute(                 see ORM Query Unified with Core Select.
         join(Address).\                       select(User).
         filter(Address.email == 'e@sa.us').\         join(Address).        Joins
         all()                                 where(Address.email == 'e@sa.us')
                                           ).scalars().all()

     session.query(User).from_statement(     session.execute(               see Getting ORM Results from Textual and Core Statements.
         text("select * from users")           select(User).
     ).all()                                   from_statement(
                                                   text("select * from users")
                                               )
                                           ).scalars().all()

     session.query(User).\                 session.execute(                 see ORM Execution Options.
         join(User.addresses).\                select(User).
         options(                              join(User.addresses).        See Populate Existing.
           contains_eager(User.addresses)         options(contains_eager(User.addresses)).
         ).\                                   execution_options(populate_existing=True)
         populate_existing().all()         ).scalars().all()

     session.query(User).\                 session.execute(                 see UPDATE and DELETE with arbitrary WHERE clause.
         filter(User.name == 'foo').\          update(User).
         update(                               where(User.name == 'foo').
             {"fullname": "Foo Bar"},          values(fullname="Foo Bar").
             synchronize_session="evaluate"         execution_options(synchronize_session="evaluate")
         )                                 )

8.2.1.23 ORM Query Unified with Core Select
...........................................

`Synopsis'

The Query object (as well as the BakedQuery and
ShardedQuery extensions) become long term legacy objects,
replaced by the direct usage of the select() construct in
conjunction with the Session.execute() method.  Results that
are returned from Query in the form of lists of objects or
tuples, or as scalar ORM objects are returned from
Session.execute() uniformly as Result objects, which
feature an interface consistent with that of Core execution.

Legacy code examples are illustrated below:

     session = Session(engine)

     # becomes legacy use case
     user = session.query(User).filter_by(name='some user').one()

     # becomes legacy use case
     user = session.query(User).get(5)

     # becomes legacy use case
     for user in session.query(User).join(User.addresses).filter(Address.email == 'some@email.com'):
         # ...

     # becomes legacy use case
     users = session.query(User).options(joinedload(User.addresses)).order_by(User.id).all()

     # becomes legacy use case
     users = session.query(User).from_statement(
         text("select * from users")
     ).all()

     # etc

`Migration to 2.0'

Because the vast majority of an ORM application is expected to make use
of Query objects as well as that the Query
interface being available does not impact the new interface, the object
will stay around in 2.0 but will no longer be part of documentation nor
will it be supported for the most part.  The select()
construct now suits both the Core and ORM use cases, which when invoked
via the Session.execute() method will return ORM-oriented
results, that is, ORM objects if that’s what was requested.

The Select() construct `adds many new methods' for
compatibility with Query, including Select.filter().
See Select.filter_by(), newly reworked Select.join()
and Select.outerjoin() methods, see Select.options(),
etc.  Other more supplemental methods of Query such as
Query.populate_existing() are implemented via execution
options.

Return results are in terms of a Result object, the new
version of the SQLAlchemy ‘ResultProxy’ object, which also adds many new
methods for compatibility with Query, including
Result.one(), Result.all(), Result.first(),
Result.one_or_none(), etc.

The Result object however does require some different calling
patterns, in that when first returned it will `always return tuples' and
it will `not deduplicate results in memory'.  In order to return single
ORM objects the way Query does, the Result.scalars()
modifier must be called first.  In order to return uniqued objects,
as is necessary when using joined eager loading, the
Result.unique() modifier must be called first.

Documentation for all new features of select() including
execution options, etc.  are at ORM Querying Guide.

Below are some examples of how to migrate to select():

     session = Session(engine)

     user = session.execute(
         select(User).filter_by(name="some user")
     ).scalar_one()

     # get() moves to the Session directly
     user = session.get(User, 5)

     for user in session.execute(
         select(User).join(User.addresses).filter(Address.email == "some@email.case")
     ).scalars():
         # ...

     # when using joinedload() against collections, use unique() on the result
     users = session.execute(
         select(User).options(joinedload(User.addresses)).order_by(User.id)
     ).unique().all()

     # select() has ORM-ish methods like from_statement() that only work
     # if the statement is against ORM entities
     users = session.execute(
         select(User).from_statement(text("select * from users"))
     ).scalars().all()

`Discussion'

The fact that SQLAlchemy has both a select() construct as
well as a separate Query object that features an extremely
similar, but fundamentally incompatible interface is likely the greatest
inconsistency in SQLAlchemy, one that arose as a result of small
incremental additions over time that added up to two major APIs that are
divergent.

In SQLAlchemy’s first releases, the Query object didn’t
exist at all.  The original idea was that the Mapper
construct itself would be able to select rows, and that Table
objects, not classes, would be used to create the various criteria in a
Core-style approach.  The Query came along some months /
years into SQLAlchemy’s history as a user proposal for a new,
“buildable” querying object originally called ‘SelectResults’ was
accepted.  Concepts like a ‘.where()’ method, which ‘SelectResults’
called ‘.filter()’, were not present in SQLAlchemy previously, and the
select() construct used only the “all-at-once” construction
style that’s now deprecated at select() no longer accepts varied constructor arguments, columns are passed positionally.

As the new approach took off, the object evolved into the Query
object as new features such as being able to select individual
columns, being able to select multiple entities at once, being able to
build subqueries from a Query object rather than from a
select object were added.  The goal became that Query
should have the full functionality of select in that it
could be composed to build SELECT statements fully with no explicit use
of select() needed.  At the same time, see select()
had also evolved “generative” methods like Select.where() and
Select.order_by().

In modern SQLAlchemy, this goal has been achieved and the two objects
are now completely overlapping in functionality.  The major challenge to
unifying these objects was that the select() object needed to
remain `completely agnostic of the ORM'. To achieve this, the vast
majority of logic from Query has been moved into the SQL
compile phase, where ORM-specific compiler plugins receive the
Select construct and interpret its contents in terms of an
ORM-style query, before passing off to the core-level compiler in order
to create a SQL string.  With the advent of the new ‘SQL compilation
caching system <change_4639>’, the majority of this ORM logic is also
cached.

See also
........

See ORM Query is internally unified with select, update, delete; 2.0 style execution available.

8.2.1.24 ORM Query - get() method moves to Session
..................................................

`Synopsis'

The Query.get() method remains for legacy purposes, but the
primary interface is now the Session.get() method:

     # legacy usage
     user_obj = session.query(User).get(5)

`Migration to 2.0'

In 1.4 / 2.0, the Session object adds a new
Session.get() method:

     # 1.4 / 2.0 cross-compatible use
     user_obj = session.get(User, 5)

`Discussion'

The Query object is to be a legacy object in 2.0, as ORM
queries are now available using the select() object.  As the
Query.get() method defines a special interaction with the
Session and does not necessarily even emit a query, it’s more
appropriate that it be part of Session, where it is similar to
other “identity” methods such as refresh and merge.

SQLAlchemy originally included “get()” to resemble the Hibernate
‘Session.load()’ method.  As is so often the case, we got it slightly
wrong as this method is really more about the Session than
with writing a SQL query.

8.2.1.25 ORM Query - Joining / loading on relationships uses attributes, not strings
....................................................................................

`Synopsis'

This refers to patterns such as that of Query.join() as well
as query options like joinedload() which currently accept a
mixture of string attribute names or actual class attributes.  The
string forms will all be removed in 2.0:

     # string use removed
     q = session.query(User).join("addresses")

     # string use removed
     q = session.query(User).options(joinedload("addresess"))

     # string use removed
     q = session.query(Address).filter(with_parent(u1, "addresses"))

`Migration to 2.0'

Modern SQLAlchemy 1.x versions support the recommended technique which
is to use mapped attributes:

     # compatible with all modern SQLAlchemy versions

     q = session.query(User).join(User.addresses)

     q = session.query(User).options(joinedload(User.addresess))

     q = session.query(Address).filter(with_parent(u1, User.addresses))

The same techniques apply to 2.0-style style use:

     # SQLAlchemy 1.4 / 2.0 cross compatible use

     stmt = select(User).join(User.addresses)
     result = session.execute(stmt)

     stmt = select(User).options(joinedload(User.addresess))
     result = session.execute(stmt)

     stmt = select(Address).where(with_parent(u1, User.addresses))
     result = session.execute(stmt)

`Discussion'

The string calling form is ambiguous and requires that the internals do
extra work to determine the appropriate path and retrieve the correct
mapped property.  By passing the ORM mapped attribute directly, not only
is the necessary information passed up front, the attribute is also
typed and is more potentially compatible with IDEs and pep-484
integrations.

8.2.1.26 ORM Query - Chaining using lists of attributes, rather than individual calls, removed
..............................................................................................

`Synopsis'

“Chained” forms of joining and loader options which accept multiple
mapped attributes in a list will be removed:

     # chaining removed
     q = session.query(User).join("orders", "items", "keywords")

`Migration to 2.0'

Use individual calls to Query.join() for 1.x /2.0 cross
compatible use:

     q = session.query(User).join(User.orders).join(Order.items).join(Item.keywords)

For 2.0-style use, see Select has the same behavior of
Select.join(), and also features a new Select.join_from()
method that allows an explicit left side:

     # 1.4 / 2.0 cross compatible

     stmt = select(User).join(User.orders).join(Order.items).join(Item.keywords)
     result = session.execute(stmt)

     # join_from can also be helpful
     stmt = select(User).join_from(User, Order).join_from(Order, Item, Order.items)
     result = session.execute(stmt)

`Discussion'

Removing the chaining of attributes is in line with simplifying the
calling interface of methods such as Select.join().

8.2.1.27 ORM Query - join(…, aliased=True), from_joinpoint removed
..................................................................

`Synopsis'

The ‘aliased=True’ option on Query.join() is removed, as is
the ‘from_joinpoint’ flag:

     # no longer supported
     q = session.query(Node).\
       join("children", aliased=True).filter(Node.name == "some sub child").
       join("children", from_joinpoint=True, aliased=True).\
       filter(Node.name == 'some sub sub child')

`Migration to 2.0'

Use explicit aliases instead:

     n1 = aliased(Node)
     n2 = aliased(Node)

     q = select(Node).join(Node.children.of_type(n1)).\
         where(n1.name == "some sub child").\
         join(n1.children.of_type(n2)).\
         where(n2.name == "some sub child")

`Discussion'

The ‘aliased=True’ option on Query.join() is another feature
that seems to be almost never used, based on extensive code searches to
find actual use of this feature.  The internal complexity that the
‘aliased=True’ flag requires is `enormous', and will be going away in
2.0.

Most users aren’t familiar with this flag, however it allows for
automatic aliasing of elements along a join, which then applies
automatic aliasing to filter conditions.  The original use case was to
assist in long chains of self-referential joins, as in the example shown
above.  However, the automatic adaption of the filter criteria that is
enormously complicated internally and almost never used in real world
applications.  The pattern also leads to issues such as if filter
criteria need to be added at each link in the chain; the pattern then
must use the ‘from_joinpoint’ flag which SQLAlchemy developers could
absolutely find no occurrence of this parameter ever being used in real
world applications.

The ‘aliased=True’ and ‘from_joinpoint’ parameters were developed at a
time when the Query object didn’t yet have good capabilities
regarding joining along relationship attributes, functions like
PropComparator.of_type() did not exist, and the aliased()
construct itself didn’t exist early on.

8.2.1.28 Using DISTINCT with additional columns, but only select the entity
...........................................................................

`Synopsis'

Query will automatically add columns in the ORDER BY when
distinct is used.  The following query will select from all User columns
as well as “address.email_address” but only return User objects:

     # 1.xx code

     result = session.query(User).join(User.addresses).\
         distinct().order_by(Address.email_address).all()

In version 2.0, the “email_address” column will not be automatically
added to the columns clause, and the above query will fail, since
relational databases won’t allow you to ORDER BY “address.email_address”
when using DISTINCT if it isn’t also in the columns clause.

`Migration to 2.0'

In 2.0, the column must be added explicitly.  To resolve the issue of
only returning the main entity object, and not the extra column, use the
Result.columns() method:

     # 1.4 / 2.0 code

     stmt = select(User, Address.email_address).join(User.addresses).\
         distinct().order_by(Address.email_address)

     result = session.execute(stmt).scalars(User).all()

`Discussion'

This case is an example of the limited flexibility of Query
leading to the case where implicit, “magical” behavior needed to be
added; the “email_address” column is implicitly added to the columns
clause, then additional internal logic would omit that column from the
actual results returned.

The new approach simplifies the interaction and makes what’s going on
explicit, while still making it possible to fulfill the original use
case without inconvenience.

8.2.1.29 Selecting from the query itself as a subquery, e.g. “from_self()”
..........................................................................

`Synopsis'

The Query.from_self() method will be removed from
Query:

     # from_self is removed
     q = session.query(User, Address.email_address).\
       join(User.addresses).\
       from_self(User).order_by(Address.email_address)

`Migration to 2.0'

The aliased() construct may be used to emit ORM queries
against an entity that is in terms of any arbitrary selectable.  It has
been enhanced in version 1.4 to smoothly accommodate being used multiple
times against the same subquery for different entities as well.  This
can be used in 1.x style with Query as below; note that
since the final query wants to query in terms of both the ‘User’ and
‘Address’ entities, two separate aliased() constructs are
created:

     from sqlalchemy.orm import aliased

     subq = session.query(User, Address.email_address).\
       join(User.addresses).subquery()

     ua = aliased(User, subq)

     aa = aliased(Address, subq)

     q = session.query(ua, aa).order_by(aa.email_address)

The same form may be used in 2.0 style:

     from sqlalchemy.orm import aliased

     subq = select(User, Address.email_address).\
       join(User.addresses).subquery()

     ua = aliased(User, subq)

     aa = aliased(Address, subq)

     stmt = select(ua, aa).order_by(aa.email_address)

     result = session.execute(stmt)

`Discussion'

The Query.from_self() method is a very complicated method
that is rarely used.  The purpose of this method is to convert a
Query into a subquery, then return a new Query which
SELECTs from that subquery.  The elaborate aspect of this method is that
the returned query applies automatic translation of ORM entities and
columns to be stated in the SELECT in terms of the subquery, as well as
that it allows the entities and columns to be SELECTed from to be
modified.

Because Query.from_self() packs an intense amount of
implicit translation into the SQL it produces, while it does allow a
certain kind of pattern to be executed very succinctly, real world use
of this method is infrequent as it is not simple to understand.

The new approach makes use of the aliased() construct so
that the ORM internals don’t need to guess which entities and columns
should be adapted and in what way; in the example above, the ‘ua’ and
‘aa’ objects, both of which are ‘AliasedClass’ instances, provide to the
internals an unambiguous marker as to where the subquery should be
referred towards as well as what entity column or relationship is being
considered for a given component of the query.

SQLAlchemy 1.4 also features an improved labeling style that no longer
requires the use of long labels that include the table name in order to
disambiguate columns of same names from different tables.  In the above
examples, even if our ‘User’ and ‘Address’ entities have overlapping
column names, we can select from both entities at once without having to
specify any particular labeling:

     # 1.4 / 2.0 code

     subq = select(User, Address).\
         join(User.addresses).subquery()

     ua = aliased(User, subq)
     aa = aliased(Address, subq)

     stmt = select(ua, aa).order_by(aa.email_address)
     result = session.execute(stmt)

The above query will disambiguate the ‘.id’ column of ‘User’ and
‘Address’, where ‘Address.id’ is rendered and tracked as ‘id_1’:

     SELECT anon_1.id AS anon_1_id, anon_1.id_1 AS anon_1_id_1,
            anon_1.user_id AS anon_1_user_id,
            anon_1.email_address AS anon_1_email_address
     FROM (
       SELECT "user".id AS id, address.id AS id_1,
       address.user_id AS user_id, address.email_address AS email_address
       FROM "user" JOIN address ON "user".id = address.user_id
     ) AS anon_1 ORDER BY anon_1.email_address

#5221(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5221

8.2.1.30 Selecting entities from alternative selectables; Query.select_entity_from()
....................................................................................

`Synopsis'

The Query.select_entity_from() method will be removed in
2.0:

     subquery = session.query(User).filter(User.id == 5).subquery()

     user = session.query(User).select_entity_from(subquery).first()

`Migration to 2.0'

As is the case described at Selecting from the query itself as a subquery, e.g. “from_self()”,
the aliased() object
provides a single place that operations like “select entity from a
subquery” may be achieved.  Using 1.x style:

     from sqlalchemy.orm import aliased

     subquery = session.query(User).filter(User.id == 5).subquery()

     ua = aliased(User, subquery)

     user = session.query(ua).first()

Using 2.0 style:

     from sqlalchemy.orm import aliased

     subquery = select(User).where(User.id == 5).subquery()

     ua = aliased(User, subquery)

     user = session.execute(select(ua)).scalars().first()

`Discussion'

The points here are basically the same as those discussed at
Selecting from the query itself as a subquery, e.g. “from_self()”.
The ‘Query.select_from_entity()’ method was another way to instruct the
query to load rows for a particular ORM mapped entity from an alternate
selectable, which involved having the ORM apply automatic aliasing to
that entity wherever it was used in the query later on, such as in the
WHERE clause or ORDER BY. This intensely complex feature is seldom used
in this way, where as was the case with Query.from_self(),
it’s much easier to follow what’s going on when using an explicit
aliased() object, both from a user point of view as well as how
the internals of the SQLAlchemy ORM must handle it.

8.2.1.31 ORM Rows not uniquified by default
...........................................

`Synopsis'

ORM rows returned by ‘session.execute(stmt)’ are no longer automatically
“uniqued”.  This will normally be a welcome change, except in the case
where the “joined eager loading” loader strategy is used with
collections:

     # In the legacy API, many rows each have the same User primary key, but
     # only one User per primary key is returned
     users = session.query(User).options(joinedload(User.addresses))

     # In the new API, uniquing is available but not implicitly
     # enabled
     result = session.execute(
         select(User).options(joinedload(User.addresses))
     )

     # this actually will raise an error to let the user know that
     # uniquing should be applied
     rows = result.all()

`Migrating to 2.0'

When using a joined load of a collection, it’s required that the
Result.unique() method is called.  The ORM will actually set a
default row handler that will raise an error if this is not done, to
ensure that a joined eager load collection does not return duplicate
rows while still maintaining explicitness:

     # 1.4 / 2.0 code

     stmt = select(User).options(joinedload(User.addresses))

     # statement will raise if unique() is not used, due to joinedload()
     # of a collection.  in all other cases, unique() is not needed.
     # By stating unique() explicitly, confusion over discrepancies between
     # number of objects/ rows returned vs. "SELECT COUNT(*)" is resolved
     rows = session.execute(stmt).unique().all()

`Discussion'

The situation here is a little bit unusual, in that SQLAlchemy is
requiring that a method be invoked that it is in fact entirely capable
of doing automatically.  The reason for requiring that the method be
called is to ensure the developer is “opting in” to the use of the
Result.unique() method, such that they will not be confused when a
straight count of rows does not conflict with the count of records in
the actual result set, which has been a long running source of user
confusion and bug reports for many years.  That the uniquifying is not
happening in any other case by default will improve performance and also
improve clarity in those cases where automatic uniquing was causing
confusing results.

To the degree that having to call Result.unique() when
joined eager load collections are used is inconvenient, in modern
SQLAlchemy the selectinload() strategy presents a
collection-oriented eager loader that is superior in most respects to
joinedload() and should be preferred.

8.2.1.32 Autocommit mode removed from Session; autobegin support added
......................................................................

`Synopsis'

The Session will no longer support “autocommit” mode, that
is, this pattern:

     from sqlalchemy.orm import Session

     sess = Session(engine, autocommit=True)

     # no transaction begun, but emits SQL, won't be supported
     obj = sess.query(Class).first()

     # session flushes in a transaction that it begins and
     # commits, won't be supported
     sess.flush()

`Migration to 2.0'

The main reason a Session is used in “autocommit” mode is so
that the Session.begin() method is available, so that
framework integrations and event hooks can control when this event
happens.  In 1.4, the Session now features autobegin behavior
which resolves this issue; the Session.begin()
method may now be called:

     from sqlalchemy.orm import Session

     sess = Session(engine)

     sess.begin()  # begin explicitly; if not called, will autobegin
                   # when database access is needed

     sess.add(obj)

     sess.commit()

`Discussion'

The “autocommit” mode is another holdover from the first versions of
SQLAlchemy.  The flag has stayed around mostly in support of allowing
explicit use of Session.begin(), which is now solved by 1.4,
as well as to allow the use of “subtransactions”, which are also removed
in 2.0.

8.2.1.33 Session “subtransaction” behavior removed
..................................................

TODO: more detail

See the section Migrating from the “subtransaction” pattern
for background on this change.

8.2.1.34 2.0 Migration - ORM Extension and Recipe Changes
.........................................................

8.2.1.35 Dogpile cache recipe and Horizontal Sharding uses new Session API
..........................................................................

TODO: more detail

As the Query object becomes legacy, these two recipes which
previously relied upon subclassing of the Query object now
make use of the SessionEvents.do_orm_execute() hook.  See
the section Re-Executing Statements for an example.

8.2.1.36 Baked Query Extension Superseded by built-in caching
.............................................................

TODO: more detail

The baked query extension is superseded by the built in caching system
and is no longer used by the ORM internals.

See SQL Compilation Caching for full background on the new
caching system.

8.2.1.37 Asyncio Support
........................

SQLAlchemy 1.4 includes asyncio support for both Core and ORM. The new
API exclusively makes use of the “future” patterns noted above.  See
Asynchronous IO Support for Core and ORM for background.

8.3 Change logs
===============

8.3.1 1.4 Changelog
-------------------

This document details individual issue-level changes made throughout 1.4
releases.  For a narrative overview of what’s new in 1.4, see
What’s New in SQLAlchemy 1.4?.

8.3.1.1 1.4.3
.............

no release date

8.3.1.2 1.4.2
.............

Released: March 19, 2021

8.3.1.3 orm
...........

   * `[orm] [usecase] [dataclasses]' ¶. Added support for
     the declared_attr object to work in the context of
     dataclass fields.

     See also
     ........

     See Using Declarative Mixins with Dataclasses.

     References: #6100(1)

   * `[orm] [bug] [dataclasses]' ¶. Fixed issue in new ORM
     dataclasses functionality where dataclass fields on an abstract
     base or mixin that contained column or other mapping constructs
     would not be mapped if they also included a “default” key within
     the dataclasses.field() object.

     References: #6093(2)

   * `[orm] [bug] [regression]' ¶. Fixed regression where
     the Query.selectable accessor, which is a synonym for
     ‘Query.__clause_element__()’, got removed, it’s now restored.

     References: #6088(3)

   * `[orm] [bug] [regression]' ¶. Fixed regression where
     use of an unnamed SQL expression such as a SQL function would raise
     a column targeting error if the query itself were using joinedload
     for an entity and was also being wrapped in a subquery by the
     joinedload eager loading process.

     References: #6086(4)

   * `[orm] [bug] [regression]' ¶. Fixed regression where
     the Query.filter_by() method would fail to locate the
     correct source entity if the Query.join() method had
     been used targeting an entity without any kind of ON clause.

     References: #6092(5)

   * `[orm] [bug] [regression]' ¶. Fixed regression where
     the SQL compilation of a Function would not work
     correctly if the object had been “annotated”, which is an internal
     memoization process used mostly by the ORM. In particular it could
     affect ORM lazy loads which make greater use of this feature in
     1.4.

     References: #6095(6)

   * `[orm] [bug]' ¶. Fixed regression where the
     ConcreteBase would fail to map at all when a mapped column
     name overlapped with the discriminator column name, producing an
     assertion error.  The use case here did not function correctly in
     1.3 as the polymorphic union would produce a query that ignored the
     discriminator column entirely, while emitting duplicate column
     warnings.  As 1.4’s architecture cannot easily reproduce this
     essentially broken behavior of 1.3 at the ‘select()’ level right
     now, the use case now raises an informative error message
     instructing the user to use the
     ‘.ConcreteBase._concrete_discriminator_name’ attribute to resolve
     the conflict.  To assist with this configuration,
     ‘.ConcreteBase._concrete_discriminator_name’ may be placed on the
     base class only where it will be automatically used by subclasses;
     previously this was not the case.

     References: #6090(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/6100

   (2) http://www.sqlalchemy.org/trac/ticket/6093

   (3) http://www.sqlalchemy.org/trac/ticket/6088

   (4) http://www.sqlalchemy.org/trac/ticket/6086

   (5) http://www.sqlalchemy.org/trac/ticket/6092

   (6) http://www.sqlalchemy.org/trac/ticket/6095

   (7) http://www.sqlalchemy.org/trac/ticket/6090

8.3.1.4 engine
..............

   * `[engine] [bug] [regression]' ¶. Restored top level
     import for ‘sqlalchemy.engine.reflection’.  This ensures that the
     base Inspector class is properly registered so that
     inspect() works for third party dialects that don’t
     otherwise import this package.

8.3.1.5 sql
...........

   * `[sql] [bug] [regression]' ¶. Fixed issue where using a
     ‘func’ that includes dotted packagenames would fail to be cacheable
     by the SQL caching system due to a Python list of names that needed
     to be a tuple.

     References: #6101(1)

   * `[sql] [bug] [regression]' ¶. Fixed regression in the
     case() construct, where the “dictionary” form of
     argument specification failed to work correctly if it were passed
     positionally, rather than as a “whens” keyword argument.

     References: #6097(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/6101

   (2) http://www.sqlalchemy.org/trac/ticket/6097

8.3.1.6 mypy
............

   * `[mypy] [bug]' ¶. Fixed issue in MyPy extension which
     crashed on detecting the type of a Column if the type
     were given with a module prefix like ‘sa.Integer()’.

     References: #sqlalchemy/sqlalchemy2-stubs/2(1)

   ---------- Footnotes ----------

   (1)
http://www.sqlalchemy.org/trac/ticket/sqlalchemy/sqlalchemy2-stubs/2

8.3.1.7 postgresql
..................

   * `[postgresql] [usecase]' ¶. Rename the column name used
     by a reflection query that used a reserved word in some postgresql
     compatible databases.

     References: #6982(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/6982

8.3.1.8 1.4.1
.............

Released: March 17, 2021

8.3.1.9 orm
...........

   * `[orm] [bug] [regression]' ¶. Fixed regression where
     producing a Core expression construct such as select()
     using ORM entities would eagerly configure the mappers, in an
     effort to maintain compatibility with the Query object
     which necessarily does this to support many backref-related legacy
     cases.  However, core select() constructs are also used
     in mapper configurations and such, and to that degree this eager
     configuration is more of an inconvenience, so eager configure has
     been disabled for the select() and other Core constructs
     in the absence of ORM loading types of functions such as
     Load.

     The change maintains the behavior of Query so that
     backwards compatibility is maintained.  However, when using a
     select() in conjunction with ORM entities, a “backref” that
     isn’t explicitly placed on one of the classes until mapper
     configure time won’t be available unless configure_mappers()
     or the newer configure() has been called
     elsewhere.  Prefer using relationship.back_populates
     for more explicit relationship configuration which does not have
     the eager configure requirement.

     References: #6066(1)

   * `[orm] [bug] [regression]' ¶. Fixed a critical
     regression in the relationship lazy loader where the SQL criteria
     used to fetch a related many-to-one object could go stale in
     relation to other memoized structures within the loader if the
     mapper had configuration changes, such as can occur when mappers
     are late configured or configured on demand, producing a comparison
     to None and returning no object.  Huge thanks to Alan Hamlett for
     their help tracking this down late into the night.

     References: #6055(2)

   * `[orm] [bug] [regression]' ¶. Fixed regression where
     the Query.exists() method would fail to create an
     expression if the entity list of the Query were an
     arbitrary SQL column expression.

     References: #6076(3)

   * `[orm] [bug] [regression]' ¶. Fixed regression where
     calling upon Query.count() in conjunction with a loader
     option such as joinedload() would fail to ignore the
     loader option.  This is a behavior that has always been very
     specific to the Query.count() method; an error is
     normally raised if a given Query has options that don’t
     apply to what it is returning.

     References: #6052(4)

   * `[orm] [bug] [regression]' ¶. Fixed regression in
     Session.identity_key(), including that the method and related
     methods were not covered by any unit test as well as that the
     method contained a typo preventing it from functioning correctly.

     References: #6067(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/6066

   (2) http://www.sqlalchemy.org/trac/ticket/6055

   (3) http://www.sqlalchemy.org/trac/ticket/6076

   (4) http://www.sqlalchemy.org/trac/ticket/6052

   (5) http://www.sqlalchemy.org/trac/ticket/6067

8.3.1.10 orm declarative
........................

   * `[orm] [declarative] [bug] [regression]' ¶. Fixed bug
     where user-mapped classes that contained an attribute named
     “registry” would cause conflicts with the new registry-based
     mapping system when using ‘DeclarativeMeta’.  While the attribute
     remains something that can be set explicitly on a declarative base
     to be consumed by the metaclass, once located it is placed under a
     private class variable so it does not conflict with future
     subclasses that use the same name for other purposes.

     References: #6054(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/6054

8.3.1.11 engine
...............

   * `[engine] [bug] [regression]' ¶. The Python
     ‘namedtuple()’ has the behavior such that the names ‘count’ and
     ‘index’ will be served as tuple values if the named tuple includes
     those names; if they are absent, then their behavior as methods of
     ‘collections.abc.Sequence’ is maintained.  Therefore the Row
     and LegacyRow classes have been fixed so that they
     work in this same way, maintaining the expected behavior for
     database rows that have columns named “index” or “count”.

     References: #6074(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/6074

8.3.1.12 mssql
..............

   * `[mssql] [bug] [regression]' ¶. Fixed regression where
     a new setinputsizes() API that’s available for pyodbc was enabled,
     which is apparently incompatible with pyodbc’s fast_executemany()
     mode in the absence of more accurate typing information, which as
     of yet is not fully implemented or tested.  The pyodbc dialect and
     connector has been modified so that setinputsizes() is not used at
     all unless the parameter ‘use_setinputsizes’ is passed to the
     dialect, e.g.  via create_engine(), at which point its
     behavior can be customized using the
     DialectEvents.do_setinputsizes() hook.

     See also
     ........

     See Setinputsizes Support.

     References: #6058(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/6058

8.3.1.13 misc
.............

   * `[bug] [regression]' ¶. Added back ‘items’ and ‘values’
     to ‘ColumnCollection’ class.  The regression was introduced while
     adding support for duplicate columns in from clauses and selectable
     in ticket #4753.

     References: #6068(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/6068

8.3.1.14 1.4.0
..............

Released: March 15, 2021

8.3.1.15 orm
............

   * `[orm] [bug]' ¶. Fixed issue where the process of
     joining two tables could fail if one of the tables had an
     unrelated, unresolvable foreign key constraint which would raise
     NoReferenceError within the join process, which
     nonetheless could be bypassed to allow the join to complete.  The
     logic which tested the exception for significance within the
     process would make assumptions about the construct which would
     fail.

     This change is also `backported' to: 1.3.24

     References: #5952(1)

   * `[orm] [bug]' ¶. Removed very old warning that states
     that passive_deletes is not intended for many-to-one relationships.
     While it is likely that in many cases placing this parameter on a
     many-to-one relationship is not what was intended, there are use
     cases where delete cascade may want to be disallowed following from
     such a relationship.

     This change is also `backported' to: 1.3.24

     References: #5983(2)

   * `[orm] [bug]' ¶. Fixed issue where the
     MutableComposite construct could be placed into an invalid
     state when the parent object was already loaded, and then covered
     by a subsequent query, due to the composite properties’ refresh
     handler replacing the object with a new one not handled by the
     mutable extension.

     This change is also `backported' to: 1.3.24

     References: #6001(3)

   * `[orm] [bug]' ¶. Fixed regression where the
     relationship.query_class parameter stopped being functional
     for “dynamic” relationships.  The ‘AppenderQuery’ remains dependent
     on the legacy Query class; users are encouraged to
     migrate from the use of “dynamic” relationships to using
     with_parent() instead.

     References: #5981(4)

   * `[orm] [bug] [regression]' ¶. Fixed regression where
     Query.join() would produce no effect if the query
     itself as well as the join target were against a Table
     object, rather than a mapped class.  This was part of a more
     systemic issue where the legacy ORM query compiler would not be
     correctly used from a Query if the statement produced
     had not ORM entities present within it.

     References: #6003(5)

   * `[orm] [bug] [asyncio]' ¶. The API for
     AsyncSession.delete() is now an awaitable; this method
     cascades along relationships which must be loaded in a similar
     manner as the AsyncSession.merge() method.

     References: #5998(6)

   * `[orm] [bug]' ¶. The unit of work process now turns off
     all “lazy=’raise’” behavior altogether when a flush is proceeding.
     While there are areas where the UOW is sometimes loading things
     that aren’t ultimately needed, the lazy=”raise” strategy is not
     helpful here as the user often does not have much control or
     visibility into the flush process.

     References: #5984(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5952

   (2) http://www.sqlalchemy.org/trac/ticket/5983

   (3) http://www.sqlalchemy.org/trac/ticket/6001

   (4) http://www.sqlalchemy.org/trac/ticket/5981

   (5) http://www.sqlalchemy.org/trac/ticket/6003

   (6) http://www.sqlalchemy.org/trac/ticket/5998

   (7) http://www.sqlalchemy.org/trac/ticket/5984

8.3.1.16 engine
...............

   * `[engine] [bug]' ¶. Fixed bug where the
     “schema_translate_map” feature failed to be taken into account for
     the use case of direct execution of DefaultGenerator
     objects such as sequences, which included the case where they were
     “pre-executed” in order to generate primary key values when
     implicit_returning was disabled.

     This change is also `backported' to: 1.3.24

     References: #5929(1)

   * `[engine] [bug]' ¶. Improved engine logging to note
     ROLLBACK and COMMIT which is logged while the DBAPI driver is in
     AUTOCOMMIT mode.  These ROLLBACK/COMMIT are library level and do
     not have any effect when AUTOCOMMIT is in effect, however it’s
     still worthwhile to log as these indicate where SQLAlchemy sees the
     “transaction” demarcation.

     References: #6002(2)

   * `[engine] [bug] [regression]' ¶. Fixed a regression
     where the “reset agent” of the connection pool wasn’t really being
     utilized by the Connection when it were closed, and
     also leading to a double-rollback scenario that was somewhat
     wasteful.  The newer architecture of the engine has been updated so
     that the connection pool “reset-on-return” logic will be skipped
     when the Connection explicitly closes out the
     transaction before returning the pool to the connection.

     References: #6004(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5929

   (2) http://www.sqlalchemy.org/trac/ticket/6002

   (3) http://www.sqlalchemy.org/trac/ticket/6004

8.3.1.17 sql
............

   * `[sql] [change]' ¶. Altered the compilation for the
     CTE construct so that a string is returned representing
     the inner SELECT statement if the CTE is stringified
     directly, outside of the context of an enclosing SELECT; This is
     the same behavior of FromClause.alias() and
     Select.subquery().  Previously, a blank string would be
     returned as the CTE is normally placed above a SELECT after that
     SELECT has been generated, which is generally misleading when
     debugging.

   * `[sql] [bug] [sqlite]' ¶. Fixed issue where the CHECK
     constraint generated by Boolean or Enum
     would fail to render the naming convention correctly after the
     first compilation, due to an unintended change of state within the
     name given to the constraint.  This issue was first introduced in
     0.9 in the fix for issue #3067, and the fix revises the approach
     taken at that time which appears to have been more involved than
     what was needed.

     This change is also `backported' to: 1.3.24

     References: #6007(1)

   * `[sql] [bug]' ¶. Fixed bug where the “percent escaping”
     feature that occurs with dialects that use the “format” or
     “pyformat” bound parameter styles was not enabled for the
     Operators.op() and custom_op constructs, for
     custom operators that use percent signs.  The percent sign will now
     be automatically doubled based on the paramstyle as necessary.

     References: #6016(2)

   * `[sql] [bug] [regression]' ¶. Fixed regression where
     the “unsupported compilation error” for unknown datatypes would
     fail to raise correctly.

     References: #5979(3)

   * `[sql] [bug] [regression]' ¶. Fixed regression where
     usage of the standalone distinct() used in the form of
     being directly SELECTed would fail to be locatable in the result
     set by column identity, which is how the ORM locates columns.
     While standalone distinct() is not oriented towards
     being directly SELECTed (use ‘select.distinct()’ for a regular
     ‘SELECT DISTINCT..’) , it was usable to a limited extent in this
     way previously (but wouldn’t work in subqueries, for example).  The
     column targeting for unary expressions such as “DISTINCT <col>” has
     been improved so that this case works again, and an additional
     improvement has been made so that usage of this form in a subquery
     at least generates valid SQL which was not the case previously.

     The change additionally enhances the ability to target elements in
     ‘row._mapping’ based on SQL expression objects in ORM-enabled
     SELECT statements, including whether the statement was invoked by
     ‘connection.execute()’ or ‘session.execute()’.

     References: #6008(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/6007

   (2) http://www.sqlalchemy.org/trac/ticket/6016

   (3) http://www.sqlalchemy.org/trac/ticket/5979

   (4) http://www.sqlalchemy.org/trac/ticket/6008

8.3.1.18 schema
...............

   * `[schema] [bug]' ¶. Repaired / implemented support for
     primary key constraint naming conventions that use column
     names/keys/etc as part of the convention.  In particular, this
     includes that the PrimaryKeyConstraint object that’s
     automatically associated with a Table will update its
     name as new primary key Column objects are added to the
     table and then to the constraint.  Internal failure modes related
     to this constraint construction process including no columns
     present, no name present or blank name present are now
     accommodated.

     This change is also `backported' to: 1.3.24

     References: #5919(1)

   * `[schema] [bug]' ¶. Deprecated all schema-level
     ‘.copy()’ methods and renamed to ‘_copy()’.  These are not standard
     Python “copy()” methods as they typically rely upon being
     instantiated within particular contexts which are passed to the
     method as optional keyword arguments.  The
     Table.tometadata() method is the public API that provides
     copying for Table objects.

     References: #5953(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5919

   (2) http://www.sqlalchemy.org/trac/ticket/5953

8.3.1.19 mypy
.............

   * `[mypy] [feature]' ¶. Rudimentary and experimental
     support for Mypy has been added in the form of a new plugin, which
     itself depends on new typing stubs for SQLAlchemy.  The plugin
     allows declarative mappings in their standard form to both be
     compatible with Mypy as well as to provide typing support for
     mapped classes and instances.

     See also
     ........

     See Mypy / Pep-484 Support for ORM Mappings.

     References: #4609(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4609

8.3.1.20 postgresql
...................

   * `[postgresql] [usecase] [asyncio] [mysql]' ¶. Added an
     ‘asyncio.Lock()’ within SQLAlchemy’s emulated DBAPI cursor, local
     to the connection, for the asyncpg and aiomysql dialects for the
     scope of the ‘cursor.execute()’ and ‘cursor.executemany()’ methods.
     The rationale is to prevent failures and corruption for the case
     where the connection is used in multiple awaitables at once.

     While this use case can also occur with threaded code and
     non-asyncio dialects, we anticipate this kind of use will be more
     common under asyncio, as the asyncio API is encouraging of such
     use.  It’s definitely better to use a distinct connection per
     concurrent awaitable however as concurrency will not be achieved
     otherwise.

     For the asyncpg dialect, this is so that the space between the call
     to ‘prepare()’ and ‘fetch()’ is prevented from allowing concurrent
     executions on the connection from causing interface error
     exceptions, as well as preventing race conditions when starting a
     new transaction.  Other PostgreSQL DBAPIs are threadsafe at the
     connection level so this intends to provide a similar behavior,
     outside the realm of server side cursors.

     For the aiomysql dialect, the mutex will provide safety such that
     the statement execution and the result set fetch, which are two
     distinct steps at the connection level, won’t get corrupted by
     concurrent executions on the same connection.

     References: #5967(1)

   * `[postgresql] [bug]' ¶. Fixed issue where using
     aggregate_order_by would return ARRAY(NullType) under
     certain conditions, interfering with the ability of the result
     object to return data correctly.

     This change is also `backported' to: 1.3.24

     References: #5989(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5967

   (2) http://www.sqlalchemy.org/trac/ticket/5989

8.3.1.21 mssql
..............

   * `[mssql] [bug]' ¶. Fix a reflection error for MSSQL
     2005 introduced by the reflection of filtered indexes.

     References: #5919(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5919

8.3.1.22 misc
.............

   * `[usecase] [ext]' ¶. Add new parameter
     AutomapBase.prepare.reflection_options to allow passing of
     MetaData.reflect() options like ‘only’ or
     dialect-specific reflection options like ‘oracle_resolve_synonyms’.

     References: #5942(1)

   * `[bug] [ext]' ¶. The ‘sqlalchemy.ext.mutable’ extension
     now tracks the “parents” collection using the InstanceState
     associated with objects, rather than the object itself.  The
     latter approach required that the object be hashable so that it can
     be inside of a ‘WeakKeyDictionary’, which goes against the
     behavioral contract of the ORM overall which is that ORM mapped
     objects do not need to provide any particular kind of ‘__hash__()’
     method and that unhashable objects are supported.

     References: #6020(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5942

   (2) http://www.sqlalchemy.org/trac/ticket/6020

8.3.1.23 1.4.0b3
................

Released: February 15, 2021

8.3.1.24 orm
............

   * `[orm] [feature]' ¶. The ORM used in 2.0 style can now
     return ORM objects from the rows returned by an UPDATE..RETURNING
     or INSERT..RETURNING statement, by supplying the construct to
     Select.from_statement() in an ORM context.

     See also
     ........

     See Selecting ORM Objects Inline with UPDATE.. RETURNING or INSERT..RETURNING.

   * `[orm] [bug]' ¶. Fixed issue in new 1.4/2.0 style ORM
     queries where a statement-level label style would not be preserved
     in the keys used by result rows; this has been applied to all
     combinations of Core/ORM columns / session vs.  connection etc.  so
     that the linkage from statement to result row is the same in all
     cases.  As part of this change, the labeling of column expressions
     in rows has been improved to retain the original name of the ORM
     attribute even if used in a subquery.

     References: #5933(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5933

8.3.1.25 engine
...............

   * `[engine] [bug] [postgresql]' ¶. Continued with the
     improvement made as part of #5653(1) to further support bound
     parameter names, including those generated against column names,
     for names that include colons, parenthesis, and question marks, as
     well as improved test support, so that bound parameter names even
     if they are auto-derived from column names should have no problem
     including for parenthesis in psycopg2’s “pyformat” style.

     As part of this change, the format used by the asyncpg DBAPI
     adapter (which is local to SQLAlchemy’s asyncpg dialect) has been
     changed from using “qmark” paramstyle to “format”, as there is a
     standard and internally supported SQL string escaping style for
     names that use percent signs with “format” style (i.e.  to double
     percent signs), as opposed to names that use question marks with
     “qmark” style (where an escaping system is not defined by pep-249
     or Python).

     See also
     ........

     See psycopg2 dialect no longer has limitations regarding bound parameter names.

     References: #5941(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5653

   (2) http://www.sqlalchemy.org/trac/ticket/5941

8.3.1.26 sql
............

   * `[sql] [usecase] [postgresql] [sqlite]' ¶. Enhance
     ‘set_’ keyword of ‘OnConflictDoUpdate’ to accept a
     ColumnCollection, such as the ‘.c.’ collection from a
     ‘Selectable’, or the ‘.excluded’ contextual object.

     References: #5939(1)

   * `[sql] [bug]' ¶. Fixed bug where the “cartesian
     product” assertion was not correctly accommodating for joins
     between tables that relied upon the use of LATERAL to connect from
     a subquery to another subquery in the enclosing context.

     References: #5924(2)

   * `[sql] [bug]' ¶. Fixed 1.4 regression where the
     ‘Function.in_()’ method was not covered by tests and failed to
     function properly in all cases.

     References: #5934(3)

   * `[sql] [bug]' ¶. Fixed regression where use of an
     arbitrary iterable with the select() function was not
     working, outside of plain lists.  The forwards/backwards
     compatibility logic here now checks for a wider range of incoming
     “iterable” types including that a ‘.c’ collection from a selectable
     can be passed directly.  Pull request compliments of Oliver Rice.

     References: #5935(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5939

   (2) http://www.sqlalchemy.org/trac/ticket/5924

   (3) http://www.sqlalchemy.org/trac/ticket/5934

   (4) http://www.sqlalchemy.org/trac/ticket/5935

8.3.1.27 1.4.0b2
................

Released: February 3, 2021

8.3.1.28 general
................

   * `[general] [bug]' ¶. Fixed a SQLite source file that
     had non-ascii characters inside of its docstring without a source
     encoding, introduced within the “INSERT..ON CONFLICT” feature,
     which would cause failures under Python 2.

8.3.1.29 platform
.................

   * `[platform] [performance]' ¶. Adjusted some elements
     related to internal class production at import time which added
     significant latency to the time spent to import the library vs.
     that of 1.3.  The time is now about 20-30% slower than 1.3 instead
     of 200%.

     References: #5681(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5681

8.3.1.30 orm
............

   * `[orm] [usecase]' ¶. Added
     ORMExecuteState.bind_mapper and
     ORMExecuteState.all_mappers accessors to
     ORMExecuteState event object, so that handlers can respond to
     the target mapper and/or mapped class or classes involved in an ORM
     statement execution.

   * `[orm] [usecase] [asyncio]' ¶. Added
     AsyncSession.scalar(), AsyncSession.get() as well
     as support for sessionmaker.begin() to work as an async
     context manager with AsyncSession.  Also added
     AsyncSession.in_transaction() accessor.

     References: #5796(1), #5797(2), #5802(3)

   * `[orm] [changed]' ¶. Mapper “configuration”, which
     occurs within the configure_mappers() function, is now
     organized to be on a per-registry basis.  This allows for example
     the mappers within a certain declarative base to be configured, but
     not those of another base that is also present in memory.  The goal
     is to provide a means of reducing application startup time by only
     running the “configure” process for sets of mappers that are
     needed.  This also adds the registry.configure() method
     that will run configure for the mappers local in a particular
     registry only.

     References: #5897(4)

   * `[orm] [bug]' ¶. Added a comprehensive check and an
     informative error message for the case where a mapped class, or a
     string mapped class name, is passed to
     relationship.secondary.  This is an extremely common error
     which warrants a clear message.

     Additionally, added a new rule to the class registry resolution
     such that with regards to the relationship.secondary
     parameter, if a mapped class and its table are of the identical
     string name, the Table will be favored when resolving
     this parameter.  In all other cases, the class continues to be
     favored if a class and table share the identical name.

     This change is also `backported' to: 1.3.21

     References: #5774(5)

   * `[orm] [bug]' ¶. Fixed bug involving the
     ‘restore_load_context’ option of ORM events such as
     ‘InstanceEvents.load()’ such that the flag would not be carried
     along to subclasses which were mapped after the event handler were
     first established.

     This change is also `backported' to: 1.3.21

     References: #5737(6)

   * `[orm] [bug] [regression]' ¶. Fixed issue in new
     Session similar to that of the Connection where
     the new “autobegin” logic could be tripped into a re-entrant
     (recursive) state if SQL were executed within the
     SessionEvents.after_transaction_create() event hook.

     References: #5845(7)

   * `[orm] [bug] [unitofwork]' ¶. Improved the unit of work
     topological sorting system such that the toplogical sort is now
     deterministic based on the sorting of the input set, which itself
     is now sorted at the level of mappers, so that the same inputs of
     affected mappers should produce the same output every time, among
     mappers / tables that don’t have any dependency on each other.
     This further reduces the chance of deadlocks as can be observed in
     a flush that UPDATEs among multiple, unrelated tables such that row
     locks are generated.

     References: #5735(8)

   * `[orm] [bug]' ¶. Fixed regression where the
     Bundle.single_entity flag would take effect for a
     Bundle even though it were not set.  Additionally, this flag
     is legacy as it only makes sense for the Query object
     and not 2.0 style execution.  a deprecation warning is emitted when
     used with new-style execution.

     References: #5702(9)

   * `[orm] [bug]' ¶. Fixed regression where creating an
     aliased construct against a plain selectable and
     including a name would raise an assertionerror.

     References: #5750(10)

   * `[orm] [bug]' ¶. Related to the fixes for the lambda
     criteria system within Core, within the ORM implemented a variety
     of fixes for the with_loader_criteria() feature as well
     as the SessionEvents.do_orm_execute() event handler
     that is often used in conjunction [ticket:5760]:

        * fixed issue where with_loader_criteria() function
          would fail if the given entity or base included non-mapped
          mixins in its descending class hierarchy [ticket:5766]

        * The with_loader_criteria() feature is now
          unconditionally disabled for the case of ORM “refresh”
          operations, including loads of deferred or expired column
          attributes as well as for explicit operations like
          Session.refresh().  These loads are necessarily based on
          primary key identity where addiional WHERE criteria is never
          appropriate.  [ticket:5762]

        * Added new attribute ORMExecuteState.is_column_load.
          to indicate that a SessionEvents.do_orm_execute()
          handler that a particular operation is a primary-key-directed
          column attribute load, where additional criteria should not be
          added.  The with_loader_criteria() function as
          above ignores these in any case now.  [ticket:5761]

        * Fixed issue where the
          ORMExecuteState.is_relationship_load attribute would not
          be set correctly for many lazy loads as well as all
          selectinloads.  The flag is essential in order to test if
          options should be added to statements or if they would already
          have been propagated via relationship loads.  [ticket:5764]

     References: #5760(11), #5761(12), #5762(13), #5764(14), #5766(15)

   * `[orm] [bug]' ¶. Fixed 1.4 regression where the use of
     Query.having() in conjunction with queries with
     internally adapted SQL elements (common in inheritance scenarios)
     would fail due to an incorrect function call.  Pull request
     courtesy esoh.

     References: #5781(16)

   * `[orm] [bug]' ¶. Fixed an issue where the API to create
     a custom executable SQL construct using the
     ‘sqlalchemy.ext.compiles’ extension according to the documentation
     that’s been up for many years would no longer function if only
     ‘Executable, ClauseElement’ were used as the base classes,
     additional classes were needed if wanting to use
     Session.execute().  This has been resolved so that those extra
     classes aren’t needed.

   * `[orm] [bug] [regression]' ¶. Fixed ORM unit of work
     regression where an errant “assert primary_key” statement
     interferes with primary key generation sequences that don’t
     actually consider the columns in the table to use a real primary
     key constraint, instead using mapper.primary_key to
     establish certain columns as “primary”.

     References: #5867(17)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5796

   (2) http://www.sqlalchemy.org/trac/ticket/5797

   (3) http://www.sqlalchemy.org/trac/ticket/5802

   (4) http://www.sqlalchemy.org/trac/ticket/5897

   (5) http://www.sqlalchemy.org/trac/ticket/5774

   (6) http://www.sqlalchemy.org/trac/ticket/5737

   (7) http://www.sqlalchemy.org/trac/ticket/5845

   (8) http://www.sqlalchemy.org/trac/ticket/5735

   (9) http://www.sqlalchemy.org/trac/ticket/5702

   (10) http://www.sqlalchemy.org/trac/ticket/5750

   (11) http://www.sqlalchemy.org/trac/ticket/5760

   (12) http://www.sqlalchemy.org/trac/ticket/5761

   (13) http://www.sqlalchemy.org/trac/ticket/5762

   (14) http://www.sqlalchemy.org/trac/ticket/5764

   (15) http://www.sqlalchemy.org/trac/ticket/5766

   (16) http://www.sqlalchemy.org/trac/ticket/5781

   (17) http://www.sqlalchemy.org/trac/ticket/5867

8.3.1.31 orm declarative
........................

   * `[orm] [declarative] [feature]' ¶. Added an alternate
     resolution scheme to Declarative that will extract the SQLAlchemy
     column or mapped property from the “metadata” dictionary of a
     dataclasses.Field object.  This allows full declarative mappings to
     be combined with dataclass fields.

     See also
     ........

     See Example Two - Dataclasses with Declarative Table.

     References: #5745(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5745

8.3.1.32 engine
...............

   * `[engine] [feature]' ¶. Dialect-specific constructs
     such as Insert.on_conflict_do_update() can now
     stringify in-place without the need to specify an explicit dialect
     object.  The constructs, when called upon for ‘str()’, ‘print()’,
     etc.  now have internal direction to call upon their appropriate
     dialect rather than the “default”dialect which doesn’t know how to
     stringify these.  The approach is also adapted to generic
     schema-level create/drop such as AddConstraint, which
     will adapt its stringify dialect to one indicated by the element
     within it, such as the ExcludeConstraint object.

   * `[engine] [feature]' ¶. Added new execution option
     Connection.execution_options.logging_token.  This
     option will add an additional per-message token to log messages
     generated by the Connection as it executes statements.
     This token is not part of the logger name itself (that part can be
     affected using the existing create_engine.logging_name
     parameter), so is appropriate for ad-hoc connection use without the
     side effect of creating many new loggers.  The option can be set at
     the level of Connection or Engine.

     See also
     ........

     See Setting Per-Connection / Sub-Engine Tokens.

     References: #5911(1)

   * `[engine] [bug] [sqlite]' ¶. Fixed bug in the 2.0
     “future” version of Engine where emitting SQL during
     the ‘EngineEvents.begin()’ event hook would cause a re-entrant
     (recursive) condition due to autobegin, affecting among other
     things the recipe documented for SQLite to allow for savepoints and
     serializable isolation support.

     References: #5845(2)

   * `[engine] [bug] [oracle] [postgresql]' ¶. Adjusted the
     “setinputsizes” logic relied upon by the cx_Oracle, asyncpg and
     pg8000 dialects to support a TypeDecorator that
     includes an override the TypeDecorator.get_dbapi_type()
     method.

   * `[engine] [bug]' ¶. Added the “future” keyword to the
     list of words that are known by the engine_from_config()
     function, so that the values “true” and “false” may be
     configured as “boolean” values when using a key such as
     ‘sqlalchemy.future = true’ or ‘sqlalchemy.future = false’.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5911

   (2) http://www.sqlalchemy.org/trac/ticket/5845

8.3.1.33 sql
............

   * `[sql] [feature]' ¶. Implemented support for “table
     valued functions” along with additional syntaxes supported by
     PostgreSQL, one of the most commonly requested features.  Table
     valued functions are SQL functions that return lists of values or
     rows, and are prevalent in PostgreSQL in the area of JSON
     functions, where the “table value” is commonly referred towards as
     the “record” datatype.  Table valued functions are also supported
     by Oracle and SQL Server.

     Features added include:

        * the FunctionElement.table_valued() modifier that
          creates a table-like selectable object from a SQL function

        * A TableValuedAlias construct that renders a SQL
          function as a named table

        * Support for PostgreSQL’s special “derived column” syntax that
          includes column names and sometimes datatypes, such as for the
          ‘json_to_recordset’ function, using the
          TableValuedAlias.render_derived() method.

        * Support for PostgreSQL’s “WITH ORDINALITY” construct using the
          FunctionElement.table_valued.with_ordinality
          parameter

        * Support for selection FROM a SQL function as column-valued
          scalar, a syntax supported by PostgreSQL and Oracle, via the
          FunctionElement.column_valued() method

        * A way to SELECT a single column from a table-valued expression
          without using a FROM clause via the
          FunctionElement.scalar_table_valued() method.

     See also
     ........

     See Table-Valued Functions. - in the SQLAlchemy 1.4 / 2.0 Tutorial.

     References: #3566(1)

   * `[sql] [usecase]' ¶. Multiple calls to “returning”,
     e.g.  see Insert.returning(), may now be chained to add new
     columns to the RETURNING clause.

     References: #5695(2)

   * `[sql] [usecase]' ¶. Added
     Select.outerjoin_from() method to complement
     Select.join_from().

   * `[sql] [usecase]' ¶. Adjusted the “literal_binds”
     feature of ‘Compiler’ to render NULL for a bound parameter that has
     ‘None’ as the value, either explicitly passed or omitted.  The
     previous error message “bind parameter without a renderable value”
     is removed, and a missing or ‘None’ value will now render NULL in
     all cases.  Previously, rendering of NULL was starting to happen
     for DML statements due to internal refactorings, but was not
     explicitly part of test coverage, which it now is.

     While no error is raised, when the context is within that of a
     column comparison, and the operator is not “IS”/”IS NOT”, a warning
     is emitted that this is not generally useful from a SQL
     perspective.

     References: #5888(3)

   * `[sql] [bug]' ¶. Fixed issue in new
     Select.join() method where chaining from the current JOIN
     wasn’t looking at the right state, causing an expression like “FROM
     a JOIN b <onclause>, b JOIN c <onclause>” rather than “FROM a JOIN
     b <onclause> JOIN c <onclause>”.

     References: #5858(4)

   * `[sql] [bug]' ¶. Deprecation warnings are emitted under
     “SQLALCHEMY_WARN_20” mode when passing a plain string to
     Session.execute().

     References: #5754(5)

   * `[sql] [bug] [orm]' ¶. A wide variety of fixes to the
     “lambda SQL” feature introduced at Using Lambdas to add significant speed gains to statement production
     have been
     implemented based on user feedback, with an emphasis on its use
     within the with_loader_criteria() feature where it is
     most prominently used [ticket:5760]:

        * fixed issue where boolean True/False values referred towards
          in the closure variables of the lambda would cause failures
          [ticket:5763]

        * Repaired a non-working detection for Python functions embedded
          in the lambda that produce bound values; this case is likely
          not supportable so raises an informative error, where the
          function should be invoked outside the lambda itself.  New
          documentation has been added to further detail this behavior.
          [ticket:5770]

        * The lambda system by default now rejects the use of non-SQL
          elements within the closure variables of the lambda entirely,
          where the error suggests the two options of either explicitly
          ignoring closure variables that are not SQL parameters, or
          specifying a specific set of values to be considered as part
          of the cache key based on hash value.  This critically
          prevents the lambda system from assuming that arbitrary
          objects within the lambda’s closure are appropriate for
          caching while also refusing to ignore them by default,
          preventing the case where their state might not be constant
          and have an impact on the SQL construct produced.  The error
          message is comprehensive and new documentation has been added
          to further detail this behavior.  [ticket:5765]

        * Fixed support for the edge case where an ‘in_()’ expression
          against a list of SQL elements, such as literal()
          objects, would fail to be accommodated correctly.
          [ticket:5768]

     References: #5760(6), #5763(7), #5765(8), #5768(9), #5770(10)

   * `[sql] [bug] [mysql] [postgresql] [sqlite]' ¶. An
     informative error message is now raised for a selected set of DML
     methods (currently all part of Insert constructs) if
     they are called a second time, which would implicitly cancel out
     the previous setting.  The methods altered include:
     on_conflict_do_update, on_conflict_do_nothing.
     (SQLite), see on_conflict_do_update,
     on_conflict_do_nothing. (PostgreSQL), see
     on_duplicate_key_update. (MySQL)

     References: #5169(11)

   * `[sql] [bug]' ¶. Fixed issue in new Values.
     construct where passing tuples of objects would fall back to
     per-value type detection rather than making use of the
     Column objects passed directly to Values that
     tells SQLAlchemy what the expected type is.  This would lead to
     issues for objects such as enumerations and numpy strings that are
     not actually necessary since the expected type is given.

     References: #5785(12)

   * `[sql] [bug]' ¶. Fixed issue where a
     RemovedIn20Warning would erroneously emit when the ‘.bind’
     attribute were accessed internally on objects, particularly when
     stringifying a SQL construct.

     References: #5717(13)

   * `[sql] [bug]' ¶. Properly render ‘cycle=False’ and
     ‘order=False’ as ‘NO CYCLE’ and ‘NO ORDER’ in ‘Sequence’ and
     ‘Identity’ objects.

     References: #5722(14)

   * `[sql]' ¶. Replace Query.with_labels() and
     GenerativeSelect.apply_labels() with explicit getters
     and setters GenerativeSelect.get_label_style() and
     GenerativeSelect.set_label_style() to accommodate the
     three supported label styles: LABEL_STYLE_DISAMBIGUATE_ONLY,
     see LABEL_STYLE_TABLENAME_PLUS_COL, and
     LABEL_STYLE_NONE.

     In addition, for Core and “future style” ORM queries,
     ‘LABEL_STYLE_DISAMBIGUATE_ONLY’ is now the default label style.
     This style differs from the existing “no labels” style in that
     labeling is applied in the case of column name conflicts; with
     ‘LABEL_STYLE_NONE’, a duplicate column name is not accessible via
     name in any case.

     For cases where labeling is significant, namely that the ‘.c’
     collection of a subquery is able to refer to all columns
     unambiguously, the behavior of ‘LABEL_STYLE_DISAMBIGUATE_ONLY’ is
     now sufficient for all SQLAlchemy features across Core and ORM
     which involve this behavior.  Result set rows since SQLAlchemy 1.0
     are usually aligned with column constructs positionally.

     For legacy ORM queries using Query, the
     table-plus-column names labeling style applied by
     ‘LABEL_STYLE_TABLENAME_PLUS_COL’ continues to be used so that
     existing test suites and logging facilities see no change in
     behavior by default.

     References: #4757(15)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3566

   (2) http://www.sqlalchemy.org/trac/ticket/5695

   (3) http://www.sqlalchemy.org/trac/ticket/5888

   (4) http://www.sqlalchemy.org/trac/ticket/5858

   (5) http://www.sqlalchemy.org/trac/ticket/5754

   (6) http://www.sqlalchemy.org/trac/ticket/5760

   (7) http://www.sqlalchemy.org/trac/ticket/5763

   (8) http://www.sqlalchemy.org/trac/ticket/5765

   (9) http://www.sqlalchemy.org/trac/ticket/5768

   (10) http://www.sqlalchemy.org/trac/ticket/5770

   (11) http://www.sqlalchemy.org/trac/ticket/5169

   (12) http://www.sqlalchemy.org/trac/ticket/5785

   (13) http://www.sqlalchemy.org/trac/ticket/5717

   (14) http://www.sqlalchemy.org/trac/ticket/5722

   (15) http://www.sqlalchemy.org/trac/ticket/4757

8.3.1.34 schema
...............

   * `[schema] [feature]' ¶. Added
     TypeEngine.as_generic() to map dialect-specific types, such
     as sqlalchemy.dialects.mysql.INTEGER, with the “best
     match” generic SQLAlchemy type, in this case Integer.
     Pull request courtesy Andrew Hannigan.

     See also
     ........

     See Reflecting with Database-Agnostic Types. - example
     usage

     References: #5659(1)

   * `[schema] [usecase]' ¶. The
     DDLEvents.column_reflect() event may now be applied to a
     MetaData object where it will take effect for the
     Table objects local to that collection.

     See also
     ........

     See DDLEvents.column_reflect().

     See Automating Column Naming Schemes from Reflected Tables.
     - in the ORM mapping documentation

     See Intercepting Column Definitions. - in the Automap
     documentation

     References: #5712(2)

   * `[schema] [usecase]' ¶. Added parameters
     CreateTable.if_not_exists, CreateIndex.if_not_exists,
     see DropTable.if_exists and
     DropIndex.if_exists to the CreateTable,
     DropTable, CreateIndex and DropIndex
     constructs which result in “IF NOT EXISTS” / “IF EXISTS” DDL
     being added to the CREATE/DROP. These phrases are not accepted by
     all databases and the operation will fail on a database that does
     not support it as there is no similarly compatible fallback within
     the scope of a single DDL statement.  Pull request courtesy Ramon
     Williams.

     References: #2843(3)

   * `[schema] [changed]' ¶. Altered the behavior of the
     Identity construct such that when applied to a
     Column, it will automatically imply that the value of
     ‘Column.nullable’ should default to ‘False’, in a similar manner as
     when the ‘Column.primary_key’ parameter is set to ‘True’.  This
     matches the default behavior of all supporting databases where
     ‘IDENTITY’ implies ‘NOT NULL’.  The PostgreSQL backend is the only
     one that supports adding ‘NULL’ to an ‘IDENTITY’ column, which is
     here supported by passing a ‘True’ value for the ‘Column.nullable’
     parameter at the same time.

     References: #5775(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5659

   (2) http://www.sqlalchemy.org/trac/ticket/5712

   (3) http://www.sqlalchemy.org/trac/ticket/2843

   (4) http://www.sqlalchemy.org/trac/ticket/5775

8.3.1.35 asyncio
................

   * `[asyncio] [usecase]' ¶. The AsyncEngine,
     AsyncConnection and AsyncTransaction
     objects may be compared using Python ‘==’ or ‘!=’, which will
     compare the two given objects based on the “sync” object they are
     proxying towards.  This is useful as there are cases particularly
     for AsyncTransaction where multiple instances of
     AsyncTransaction can be proxying towards the same sync
     Transaction, and are actually equivalent.  The
     AsyncConnection.get_transaction() method will currently
     return a new proxying AsyncTransaction each time as the
     AsyncTransaction is not otherwise statefully associated
     with its originating AsyncConnection.

   * `[asyncio] [bug]' ¶. Adjusted the greenlet integration,
     which provides support for Python asyncio in SQLAlchemy, to
     accommodate for the handling of Python ‘contextvars’ (introduced in
     Python 3.7) for ‘greenlet’ versions greater than 0.4.17.  Greenlet
     version 0.4.17 added automatic handling of contextvars in a
     backwards-incompatible way; we’ve coordinated with the greenlet
     authors to add a preferred API for this in versions subsequent to
     0.4.17 which is now supported by SQLAlchemy’s greenlet integration.
     For greenlet versions prior to 0.4.17 no behavioral change is
     needed, version 0.4.17 itself is blocked from the dependencies.

     References: #5615(1)

   * `[asyncio] [bug]' ¶. Implemented “connection-binding”
     for AsyncSession, the ability to pass an
     AsyncConnection to create an AsyncSession.
     Previously, this use case was not implemented and would use the
     associated engine when the connection were passed.  This fixes the
     issue where the “join a session to an external transaction” use
     case would not work correctly for the AsyncSession.
     Additionally, added methods AsyncConnection.in_transaction(),
     see AsyncConnection.in_nested_transaction(),
     AsyncConnection.get_transaction(),
     AsyncConnection.get_nested_transaction() and
     AsyncConnection.info attribute.

     References: #5811(2)

   * `[asyncio] [bug]' ¶. Fixed bug in asyncio connection
     pool where ‘asyncio.TimeoutError’ would be raised rather than
     TimeoutError.  Also repaired the
     create_engine.pool_timeout parameter set to zero when using
     the async engine, which previously would ignore the timeout and
     block rather than timing out immediately as is the behavior with
     regular QueuePool.

     References: #5827(3)

   * `[asyncio] [bug] [pool]' ¶. When using an asyncio
     engine, the connection pool will now detach and discard a pooled
     connection that is was not explicitly closed/returned to the pool
     when its tracking object is garbage collected, emitting a warning
     that the connection was not properly closed.  As this operation
     occurs during Python gc finalizers, it’s not safe to run any IO
     operations upon the connection including transaction rollback or
     connection close as this will often be outside of the event loop.

     The ‘AsyncAdaptedQueue’ used by default on async dpapis should
     instantiate a queue only when it’s first used to avoid binding it
     to a possibly wrong event loop.

     References: #5823(4)

   * `[asyncio]' ¶. The SQLAlchemy async mode now detects
     and raises an informative error when an non asyncio compatible
     DBAPI is used.  Using a standard ‘DBAPI’ with async SQLAlchemy will
     cause it to block like any sync call, interrupting the executing
     asyncio loop.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5615

   (2) http://www.sqlalchemy.org/trac/ticket/5811

   (3) http://www.sqlalchemy.org/trac/ticket/5827

   (4) http://www.sqlalchemy.org/trac/ticket/5823

8.3.1.36 postgresql
...................

   * `[postgresql] [usecase]' ¶. Added new parameter
     ExcludeConstraint.ops to the ExcludeConstraint
     object, to support operator class specification with this
     constraint.  Pull request courtesy Alon Menczer.

     This change is also `backported' to: 1.3.21

     References: #5604(1)

   * `[postgresql] [usecase]' ¶. Added a read/write
     ‘.autocommit’ attribute to the DBAPI-adaptation layer for the
     asyncpg dialect.  This so that when working with DBAPI-specific
     schemes that need to use “autocommit” directly with the DBAPI
     connection, the same ‘.autocommit’ attribute which works with both
     psycopg2 as well as pg8000 is available.

   * `[postgresql] [changed]' ¶. Fixed issue where the
     psycopg2 dialect would silently pass the ‘use_native_unicode=False’
     flag without actually having any effect under Python 3, as the
     psycopg2 DBAPI uses Unicode unconditionally under Python 3.  This
     usage now raises an ArgumentError when used under
     Python 3.  Added test support for Python 2.

   * `[postgresql] [performance]' ¶. Enhanced the
     performance of the asyncpg dialect by caching the asyncpg
     PreparedStatement objects on a per-connection basis.  For a test
     case that makes use of the same statement on a set of pooled
     connections this appears to grant a 10-20% speed improvement.  The
     cache size is adjustable and may also be disabled.

     See also
     ........

     See Prepared Statement Cache.

   * `[postgresql] [bug] [mysql]' ¶. Fixed regression
     introduced in 1.3.2 for the PostgreSQL dialect, also copied out to
     the MySQL dialect’s feature in 1.3.18, where usage of a non
     Table construct such as text() as the argument to
     Select.with_for_update.of would fail to be accommodated
     correctly within the PostgreSQL or MySQL compilers.

     This change is also `backported' to: 1.3.21

     References: #5729(2)

   * `[postgresql] [bug]' ¶. Fixed a small regression where
     the query for “show standard_conforming_strings” upon
     initialization would be emitted even if the server version info
     were detected as less than version 8.2, previously it would only
     occur for server version 8.2 or greater.  The query fails on Amazon
     Redshift which reports a PG server version older than this value.

     References: #5698(3)

   * `[postgresql] [bug]' ¶. Established support for
     Column objects as well as ORM instrumented attributes as keys
     in the ‘set_’ dictionary passed to the
     Insert.on_conflict_do_update() and
     Insert.on_conflict_do_update() methods, which match to the
     Column objects in the ‘.c’ collection of the target
     Table.  Previously, only string column names were
     expected; a column expression would be assumed to be an
     out-of-table expression that would render fully along with a
     warning.

     References: #5722(4)

   * `[postgresql] [bug] [asyncio]' ¶. Fixed bug in asyncpg
     dialect where a failure during a “commit” or less likely a
     “rollback” should cancel the entire transaction; it’s no longer
     possible to emit rollback.  Previously the connection would
     continue to await a rollback that could not succeed as asyncpg
     would reject it.

     References: #5824(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5604

   (2) http://www.sqlalchemy.org/trac/ticket/5729

   (3) http://www.sqlalchemy.org/trac/ticket/5698

   (4) http://www.sqlalchemy.org/trac/ticket/5722

   (5) http://www.sqlalchemy.org/trac/ticket/5824

8.3.1.37 mysql
..............

   * `[mysql] [feature]' ¶. Added support for the aiomysql
     driver when using the asyncio SQLAlchemy extension.

     See also
     ........

     See aiomysql.

     References: #5747(1)

   * `[mysql] [bug] [reflection]' ¶. Fixed issue where
     reflecting a server default on MariaDB only that contained a
     decimal point in the value would fail to be reflected correctly,
     leading towards a reflected table that lacked any server default.

     This change is also `backported' to: 1.3.21

     References: #5744(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5747

   (2) http://www.sqlalchemy.org/trac/ticket/5744

8.3.1.38 sqlite
...............

   * `[sqlite] [usecase]' ¶. Implemented INSERT… ON CONFLICT
     clause for SQLite.  Pull request courtesy Ramon Williams.

     See also
     ........

     See INSERT…ON CONFLICT (Upsert).

     References: #4010(1)

   * `[sqlite] [bug]' ¶. Use python ‘re.search()’ instead of
     ‘re.match()’ as the operation used by the ‘Column.regexp_match()’
     method when using sqlite.  This matches the behavior of regular
     expressions on other databases as well as that of well-known SQLite
     plugins.

     References: #5699(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4010

   (2) http://www.sqlalchemy.org/trac/ticket/5699

8.3.1.39 mssql
..............

   * `[mssql] [bug] [datatypes] [mysql]' ¶. Decimal accuracy
     and behavior has been improved when extracting floating point
     and/or decimal values from JSON strings using the
     ‘Comparator.as_float()’ method, when the numeric value inside of
     the JSON string has many significant digits; previously, MySQL
     backends would truncate values with many significant digits and SQL
     Server backends would raise an exception due to a DECIMAL cast with
     insufficient significant digits.  Both backends now use a
     FLOAT-compatible approach that does not hardcode significant digits
     for floating point values.  For precision numerics, a new method
     ‘Comparator.as_numeric()’ has been added which accepts arguments
     for precision and scale, and will return values as Python ‘Decimal’
     objects with no floating point conversion assuming the DBAPI
     supports it (all but pysqlite).

     References: #5788(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5788

8.3.1.40 oracle
...............

   * `[oracle] [bug]' ¶. Fixed regression which occured due
     to #5755(1) which implemented isolation level support for Oracle.
     It has been reported that many Oracle accounts don’t actually have
     permission to query the ‘v$transaction’ view so this feature has
     been altered to gracefully fallback when it fails upon database
     connect, where the dialect will assume “READ COMMITTED” is the
     default isolation level as was the case prior to SQLAlchemy 1.3.21.
     However, explicit use of the
     Connection.get_isolation_level() method must now necessarily
     raise an exception, as Oracle databases with this restriction
     explicitly disallow the user from reading the current isolation
     level.

     This change is also `backported' to: 1.3.22

     References: #5784(2)

   * `[oracle] [bug]' ¶. Oracle two-phase transactions at a
     rudimentary level are now no longer deprecated.  After receiving
     support from cx_Oracle devs we can provide for basic xid +
     begin/prepare support with some limitations, which will work more
     fully in an upcoming release of cx_Oracle.  Two phase “recovery” is
     not currently supported.

     References: #5884(3)

   * `[oracle] [bug]' ¶. The Oracle dialect now uses ‘select
     sys_context( 'userenv', 'current_schema' ) from dual’ to get the
     default schema name, rather than ‘SELECT USER FROM DUAL’, to
     accommodate for changes to the session-local schema name under
     Oracle.

     References: #5716(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5755

   (2) http://www.sqlalchemy.org/trac/ticket/5784

   (3) http://www.sqlalchemy.org/trac/ticket/5884

   (4) http://www.sqlalchemy.org/trac/ticket/5716

8.3.1.41 misc
.............

   * `[usecase] [pool] [tests]' ¶. Improve documentation and
     add test for sub-second pool timeouts.  Pull request courtesy
     Jordan Pittier.

     References: #5582(1)

   * `[usecase] [pool]' ¶. The internal mechanics of the
     engine connection routine has been altered such that it’s now
     guaranteed that a user-defined event handler for the
     ‘PoolEvents.connect()’ handler, when established using
     ‘insert=True’, will allow an event handler to run that is
     definitely invoked `before' any dialect-specific initialization
     starts up, most notably when it does things like detect default
     schema name.  Previously, this would occur in most cases but not
     unconditionally.  A new example is added to the schema
     documentation illustrating how to establish the “default schema
     name” within an on-connect event.

     References: #5497(2), #5708(3)

   * `[bug] [reflection]' ¶. Fixed bug where the
     now-deprecated ‘autoload’ parameter was being called internally
     within the reflection routines when a related table were reflected.

     References: #5684(4)

   * `[bug] [pool]' ¶. Fixed regression where a connection
     pool event specified with a keyword, most notably ‘insert=True’,
     would be lost when the event were set up.  This would prevent
     startup events that need to fire before dialect-level events from
     working correctly.

     References: #5708(5)

   * `[bug] [pool] [pypy]' ¶. Fixed issue where connection
     pool would not return connections to the pool or otherwise be
     finalized upon garbage collection under pypy if the checked out
     connection fell out of scope without being closed.  This is a long
     standing issue due to pypy’s difference in GC behavior that does
     not call weakref finalizers if they are relative to another object
     that is also being garbage collected.  A strong reference to the
     related record is now maintained so that the weakref has a
     strong-referenced “base” to trigger off of.

     References: #5842(6)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5582

   (2) http://www.sqlalchemy.org/trac/ticket/5497

   (3) http://www.sqlalchemy.org/trac/ticket/5708

   (4) http://www.sqlalchemy.org/trac/ticket/5684

   (5) http://www.sqlalchemy.org/trac/ticket/5708

   (6) http://www.sqlalchemy.org/trac/ticket/5842

8.3.1.42 1.4.0b1
................

Released: November 2, 2020

8.3.1.43 general
................

   * `[general] [change]' ¶. ”python setup.py test” is no
     longer a test runner, as this is deprecated by Pypa.  Please use
     “tox” with no arguments for a basic test run.

     References: #4789(1)

   * `[general] [bug]' ¶. Refactored the internal
     conventions used to cross-import modules that have mutual
     dependencies between them, such that the inspected arguments of
     functions and methods are no longer modified.  This allows tools
     like pylint, Pycharm, other code linters, as well as hypothetical
     pep-484 implementations added in the future to function correctly
     as they no longer see missing arguments to function calls.  The new
     approach is also simpler and more performant.

     See also
     ........

     See Repaired internal importing conventions such that code linters may work correctly.

     References: #4656(2), #4689(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4789

   (2) http://www.sqlalchemy.org/trac/ticket/4656

   (3) http://www.sqlalchemy.org/trac/ticket/4689

8.3.1.44 platform
.................

   * `[platform] [change]' ¶. The ‘importlib_metadata’
     library is used to scan for setuptools entrypoints rather than
     pkg_resources.  as importlib_metadata is a small library that is
     included as of Python 3.8, the compatibility library is installed
     as a dependency for Python versions older than 3.8.

     References: #5400(1)

   * `[platform] [change]' ¶. Installation has been
     modernized to use setup.cfg for most package metadata.

     References: #5404(2)

   * `[platform] [removed]' ¶. Dropped support for python
     3.4 and 3.5 that has reached EOL. SQLAlchemy 1.4 series requires
     python 2.7 or 3.6+.

     See also
     ........

     See Python 3.6 is the minimum Python 3 version; Python 2.7 still supported.

     References: #5634(3)

   * `[platform] [removed]' ¶. Removed all dialect code
     related to support for Jython and zxJDBC. Jython has not been
     supported by SQLAlchemy for many years and it is not expected that
     the current zxJDBC code is at all functional; for the moment it
     just takes up space and adds confusion by showing up in
     documentation.  At the moment, it appears that Jython has achieved
     Python 2.7 support in its releases but not Python 3.  If Jython
     were to be supported again, the form it should take is against the
     Python 3 version of Jython, and the various zxJDBC stubs for
     various backends should be implemented as a third party dialect.

     References: #5094(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5400

   (2) http://www.sqlalchemy.org/trac/ticket/5404

   (3) http://www.sqlalchemy.org/trac/ticket/5634

   (4) http://www.sqlalchemy.org/trac/ticket/5094

8.3.1.45 orm
............

   * `[orm] [feature]' ¶. The ORM can now generate queries
     previously only available when using Query using the
     select() construct directly.  A new system by which ORM
     “plugins” may establish themselves within a Core Select
     allow the majority of query building logic previously inside of
     Query to now take place within a compilation-level
     extension for Select.  Similar changes have been made for
     the Update and Delete constructs as well.
     The constructs when invoked using Session.execute() now
     do ORM-related work within the method.  For Select, the
     Result object returned now contains ORM-level entities
     and results.

     See also
     ........

     See ORM Query is internally unified with select, update, delete; 2.0 style execution available.

     References: #5159(1)

   * `[orm] [feature]' ¶. Added the ability to add arbitrary
     criteria to the ON clause generated by a relationship attribute in
     a query, which applies to methods such as Query.join()
     as well as loader options like joinedload().
     Additionally, a “global” version of the option allows limiting
     criteria to be applied to particular entities in a query globally.

     See also
     ........

     See Adding Criteria to loader options.

     See Adding global WHERE / ON criteria.

     See with_loader_criteria().

     References: #4472(2)

   * `[orm] [feature]' ¶. The ORM Declarative system is now
     unified into the ORM itself, with new import spaces under
     ‘sqlalchemy.orm’ and new kinds of mappings.  Support for
     decorator-based mappings without using a base class, support for
     classical style-mapper() calls that have access to the declarative
     class registry for relationships, and full integration of
     Declarative with 3rd party class attribute systems like
     ‘dataclasses’ and ‘attrs’ is now supported.

     See also
     ........

     See Declarative is now integrated into the ORM with new features.

     See Python Dataclasses, attrs Supported w/ Declarative, Imperative Mappings.

     References: #5508(3)

   * `[orm] [feature]' ¶. Eager loaders, such as joined
     loading, SELECT IN loading, etc., when configured on a mapper or
     via query options will now be invoked during the refresh on an
     expired object; in the case of selectinload and subqueryload, since
     the additional load is for a single object only, the
     “immediateload” scheme is used in these cases which resembles the
     single-parent query emitted by lazy loading.

     See also
     ........

     See Eager loaders emit during unexpire operations.

     References: #1763(4)

   * `[orm] [feature]' ¶. Added support for direct mapping
     of Python classes that are defined using the Python ‘dataclasses’
     decorator.  Pull request courtesy Václav Klusák.  The new feature
     integrates into new support at the Declarative level for systems
     such as ‘dataclasses’ and ‘attrs’.

     See also
     ........

     See Python Dataclasses, attrs Supported w/ Declarative, Imperative Mappings.

     See Declarative is now integrated into the ORM with new features.

     References: #5027(5)

   * `[orm] [feature]' ¶. Added “raiseload” feature for ORM
     mapped columns via defer.raiseload parameter on
     defer() and deferred().  This provides similar
     behavior for column-expression mapped attributes as the
     raiseload() option does for relationship mapped attributes.
     The change also includes some behavioral changes to deferred
     columns regarding expiration; see the migration notes for details.

     See also
     ........

     See Raiseload for Columns.

     References: #4826(6)

   * `[orm] [usecase]' ¶. The evaluator that takes place
     within the ORM bulk update and delete for
     synchronize_session=”evaluate” now supports the IN and NOT IN
     operators.  Tuple IN is also supported.

     References: #1653(7)

   * `[orm] [usecase]' ¶. Enhanced logic that tracks if
     relationships will be conflicting with each other when they write
     to the same column to include simple cases of two relationships
     that should have a “backref” between them.  This means that if two
     relationships are not viewonly, are not linked with back_populates
     and are not otherwise in an inheriting sibling/overriding
     arrangement, and will populate the same foreign key column, a
     warning is emitted at mapper configuration time warning that a
     conflict may arise.  A new parameter relationship.overlaps
     is added to suit those very rare cases where such an
     overlapping persistence arrangement may be unavoidable.

     References: #5171(8)

   * `[orm] [usecase]' ¶. The ORM bulk update and delete
     operations, historically available via the Query.update()
     and Query.delete() methods as well as via the
     Update and Delete constructs for 2.0 style
     execution, will now automatically accommodate for the additional
     WHERE criteria needed for a single-table inheritance discriminator
     in order to limit the statement to rows referring to the specific
     subtype requested.  The new with_loader_criteria()
     construct is also supported for with bulk update/delete operations.

     References: #3903(9), #5018(10)

   * `[orm] [usecase]' ¶. Update
     relationship.sync_backref flag in a relationship to make it
     implicitly ‘False’ in ‘viewonly=True’ relationships, preventing
     synchronization events.

     See also
     ........

     See Viewonly relationships don’t synchronize backrefs.

     References: #5237(11)

   * `[orm] [change]' ¶. The condition where a pending
     object being flushed with an identity that already exists in the
     identity map has been adjusted to emit a warning, rather than throw
     a FlushError.  The rationale is so that the flush will
     proceed and raise a IntegrityError instead, in the
     same way as if the existing object were not present in the identity
     map already.  This helps with schemes that are using the
     IntegrityError as a means of catching whether or not a row
     already exists in the table.

     See also
     ........

     See The “New instance conflicts with existing identity” error is now a warning.

     References: #4662(12)

   * `[orm] [change] [sql]' ¶. A selection of Core and ORM
     query objects now perform much more of their Python computational
     tasks within the compile step, rather than at construction time.
     This is to support an upcoming caching model that will provide for
     caching of the compiled statement structure based on a cache key
     that is derived from the statement construct, which itself is
     expected to be newly constructed in Python code each time it is
     used.  This means that the internal state of these objects may not
     be the same as it used to be, as well as that some but not all
     error raise scenarios for various kinds of argument validation will
     occur within the compilation / execution phase, rather than at
     statement construction time.  See the migration notes linked below
     for complete details.

     See also
     ........

     See Many Core and ORM statement objects now perform much of their construction and validation in the compile phase.

   * `[orm] [change]' ¶. The automatic uniquing of rows on
     the client side is turned off for the new 2.0 style of ORM
     querying.  This improves both clarity and performance.  However,
     uniquing of rows on the client side is generally necessary when
     using joined eager loading for collections, as there will be
     duplicates of the primary entity for each element in the collection
     because a join was used.  This uniquing must now be manually
     enabled and can be achieved using the new Result.unique()
     modifier.  To avoid silent failure, the ORM explicitly
     requires the method be called when the result of an ORM query in
     2.0 style makes use of joined load collections.  The newer
     selectinload() strategy is likely preferable for eager
     loading of collections in any case.

     See also
     ........

     See ORM Rows not uniquified by default.

     References: #4395(13)

   * `[orm] [change]' ¶. The ORM will now warn when asked to
     coerce a select() construct into a subquery implicitly.
     This occurs within places such as the
     Query.select_entity_from() and Query.select_from()
     methods as well as within the with_polymorphic()
     function.  When a SelectBase. (which is what’s produced
     by select()) or Query object is passed
     directly to these functions and others, the ORM is typically
     coercing them to be a subquery by calling the
     SelectBase.alias() method automatically (which is now
     superseded by the SelectBase.subquery() method).  See
     the migration notes linked below for further details.

     See also
     ........

     See A SELECT statement is no longer implicitly considered to be a FROM clause.

     References: #4617(14)

   * `[orm] [change]' ¶. The “KeyedTuple” class returned by
     Query is now replaced with the Core Row
     class, which behaves in the same way as KeyedTuple.  In SQLAlchemy
     2.0, both Core and ORM will return result rows using the same
     Row object.  In the interim, Core uses a
     backwards-compatibility class LegacyRow that maintains
     the former mapping/tuple hybrid behavior used by “RowProxy”.

     See also
     ........

     See The “KeyedTuple” object returned by Query is replaced by Row.

     References: #4710(15)

   * `[orm] [performance]' ¶. The bulk update and delete
     methods Query.update() and Query.delete(),
     as well as their 2.0-style counterparts, now make use of RETURNING
     when the “fetch” strategy is used in order to fetch the list of
     affected primary key identites, rather than emitting a separate
     SELECT, when the backend in use supports RETURNING. Additionally,
     the “fetch” strategy will in ordinary cases not expire the
     attributes that have been updated, and will instead apply the
     updated values directly in the same way that the “evaluate”
     strategy does, to avoid having to refresh the object.  The
     “evaluate” strategy will also fall back to expiring attributes that
     were updated to a SQL expression that was unevaluable in Python.

     See also
     ........

     See ORM Bulk Update and Delete use RETURNING for “fetch” strategy when available.

   * `[orm] [performance] [postgresql]' ¶. Implemented
     support for the psycopg2 ‘execute_values()’ extension within the
     ORM flush process via the enhancements to Core made in #5401(16),
     so that this extension is used both as a strategy to batch INSERT
     statements together as well as that RETURNING may now be used among
     multiple parameter sets to retrieve primary key values back in
     batch.  This allows nearly all INSERT statements emitted by the ORM
     on behalf of PostgreSQL to be submitted in batch and also via the
     ‘execute_values()’ extension which benches at five times faster
     than plain executemany() for this particular backend.

     See also
     ........

     See ORM Batch inserts with psycopg2 now batch statements with RETURNING in most cases.

     References: #5263(17)

   * `[orm] [bug]' ¶. A query that is against a mapped
     inheritance subclass which also uses
     Query.select_entity_from() or a similar technique in order to
     provide an existing subquery to SELECT from, will now raise an
     error if the given subquery returns entities that do not correspond
     to the given subclass, that is, they are sibling or superclasses in
     the same hierarchy.  Previously, these would be returned without
     error.  Additionally, if the inheritance mapping is a
     single-inheritance mapping, the given subquery must apply the
     appropriate filtering against the polymorphic discriminator column
     in order to avoid this error; previously, the Query
     would add this criteria to the outside query however this
     interferes with some kinds of query that return other kinds of
     entities as well.

     See also
     ........

     See Stricter behavior when querying inheritance mappings using custom queries.

     References: #5122(18)

   * `[orm] [bug]' ¶. The internal attribute symbols
     NO_VALUE and NEVER_SET have been unified, as there was no
     meaningful difference between these two symbols, other than a few
     codepaths where they were differentiated in subtle and undocumented
     ways, these have been fixed.

     References: #4696(19)

   * `[orm] [bug]' ¶. Fixed bug where a versioning column
     specified on a mapper against a select() construct where
     the version_id_col itself were against the underlying table would
     incur additional loads when accessed, even if the value were
     locally persisted by the flush.  The actual fix is a result of the
     changes in #4617(20), by fact that a select() object no
     longer has a ‘.c’ attribute and therefore does not confuse the
     mapper into thinking there’s an unknown column value present.

     References: #4194(21)

   * `[orm] [bug]' ¶. An ‘UnmappedInstanceError’ is now
     raised for InstrumentedAttribute if an instance is an
     unmapped object.  Prior to this an ‘AttributeError’ was raised.
     Pull request courtesy Ramon Williams.

     References: #3858(22)

   * `[orm] [bug]' ¶. The Session object no
     longer initiates a SessionTransaction object
     immediately upon construction or after the previous transaction is
     closed; instead, “autobegin” logic now initiates the new
     SessionTransaction on demand when it is next needed.
     Rationale includes to remove reference cycles from a Session
     that has been closed out, as well as to remove the overhead
     incurred by the creation of SessionTransaction objects
     that are often discarded immediately.  This change affects the
     behavior of the SessionEvents.after_transaction_create()
     hook in that the event will be emitted when the Session
     first requires a SessionTransaction be present,
     rather than whenever the Session were created or the
     previous SessionTransaction were closed.  Interactions
     with the Engine and the database itself remain
     unaffected.

     See also
     ........

     See Session features new “autobegin” behavior.

     References: #5074(23)

   * `[orm] [bug]' ¶. Added new entity-targeting
     capabilities to the ORM query context help with the case where the
     Session is using a bind dictionary against mapped
     classes, rather than a single bind, and the Query is
     against a Core statement that was ultimately generated from a
     method such as Query.subquery().  First implemented
     using a deep search, the current approach leverages the unified
     select() construct to keep track of the first mapper
     that is part of the construct.

     References: #4829(24)

   * `[orm] [bug] [inheritance]' ¶. An ArgumentError
     is now raised if both the ‘selectable’ and ‘flat’ parameters
     are set to True in with_polymorphic().  The selectable
     name is already aliased and applying flat=True overrides the
     selectable name with an anonymous name that would’ve previously
     caused the code to break.  Pull request courtesy Ramon Williams.

     References: #4212(25)

   * `[orm] [bug]' ¶. Fixed issue in polymorphic loading
     internals which would fall back to a more expensive,
     soon-to-be-deprecated form of result column lookup within certain
     unexpiration scenarios in conjunction with the use of
     “with_polymorphic”.

     References: #4718(26)

   * `[orm] [bug]' ¶. An error is raised if any
     persistence-related “cascade” settings are made on a
     relationship() that also sets up viewonly=True.  The “cascade”
     settings now default to non-persistence related settings only when
     viewonly is also set.  This is the continuation from #4993(27)
     where this setting was changed to emit a warning in 1.3.

     See also
     ........

     See Persistence-related cascade operations disallowed with viewonly=True.

     References: #4994(28)

   * `[orm] [bug]' ¶. Improved declarative inheritance
     scanning to not get tripped up when the same base class appears
     multiple times in the base inheritance list.

     References: #4699(29)

   * `[orm] [bug]' ¶. Fixed bug in ORM versioning feature
     where assignment of an explicit version_id for a counter configured
     against a mapped selectable where version_id_col is against the
     underlying table would fail if the previous value were expired;
     this was due to the fact that the mapped attribute would not be
     configured with active_history=True.

     References: #4195(30)

   * `[orm] [bug]' ¶. An exception is now raised if the ORM
     loads a row for a polymorphic instance that has a primary key but
     the discriminator column is NULL, as discriminator columns should
     not be null.

     References: #4836(31)

   * `[orm] [bug]' ¶. Accessing a collection-oriented
     attribute on a newly created object no longer mutates ‘__dict__’,
     but still returns an empty collection as has always been the case.
     This allows collection-oriented attributes to work consistently in
     comparison to scalar attributes which return ‘None’, but also don’t
     mutate ‘__dict__’.  In order to accommodate for the collection
     being mutated, the same empty collection is returned each time once
     initially created, and when it is mutated (e.g.  an item appended,
     added, etc.)  it is then moved into ‘__dict__’.  This removes the
     last of mutating side-effects on read-only attribute access within
     the ORM.

     See also
     ........

     See Accessing an uninitialized collection attribute on a transient object no longer mutates __dict__.

     References: #4519(32)

   * `[orm] [bug]' ¶. The refresh of an expired object will
     now trigger an autoflush if the list of expired attributes include
     one or more attributes that were explicitly expired or refreshed
     using the Session.expire() or Session.refresh()
     methods.  This is an attempt to find a middle ground between
     the normal unexpiry of attributes that can happen in many cases
     where autoflush is not desirable, vs.  the case where attributes
     are being explicitly expired or refreshed and it is possible that
     these attributes depend upon other pending state within the session
     that needs to be flushed.  The two methods now also gain a new flag
     Session.expire.autoflush and
     Session.refresh.autoflush, defaulting to True; when set to
     False, this will disable the autoflush that occurs on unexpire for
     these attributes.

     References: #5226(33)

   * `[orm] [bug]' ¶. The behavior of the
     relationship.cascade_backrefs flag will be reversed in 2.0
     and set to ‘False’ unconditionally, such that backrefs don’t
     cascade save-update operations from a forwards-assignment to a
     backwards assignment.  A 2.0 deprecation warning is emitted when
     the parameter is left at its default of ‘True’ at the point at
     which such a cascade operation actually takes place.  The new
     behavior can be established as always by setting the flag to
     ‘False’ on a specific relationship(), or more generally
     can be set up across the board by setting the the
     Session.future flag to True.

     See also
     ........

     See cascade_backrefs behavior deprecated for removal in 2.0.

     References: #5150(34)

   * `[orm] [deprecated]' ¶. The “slice index” feature used
     by Query as well as by the dynamic relationship loader
     will no longer accept negative indexes in SQLAlchemy 2.0.  These
     operations do not work efficiently and load the entire collection
     in, which is both surprising and undesirable.  These will warn in
     1.4 unless the Session.future flag is set in which case
     they will raise IndexError.

     References: #5606(35)

   * `[orm] [deprecated]' ¶. Calling the
     Query.instances() method without passing a
     QueryContext is deprecated.  The original use case for this
     was that a Query could yield ORM objects when given
     only the entities to be selected as well as a DBAPI cursor object.
     However, for this to work correctly there is essential metadata
     that is passed from a SQLAlchemy ‘ResultProxy’ that is derived from
     the mapped column expressions, which comes originally from the
     QueryContext.  To retrieve ORM results from arbitrary
     SELECT statements, the Query.from_statement() method
     should be used.

     References: #4719(36)

   * `[orm] [deprecated]' ¶. Using strings to represent
     relationship names in ORM operations such as Query.join(),
     as well as strings for all ORM attribute names in loader
     options like selectinload() is deprecated and will be
     removed in SQLAlchemy 2.0.  The class-bound attribute should be
     passed instead.  This provides much better specificity to the given
     method, allows for modifiers such as ‘of_type()’, and reduces
     internal complexity.

     Additionally, the ‘aliased’ and ‘from_joinpoint’ parameters to
     Query.join() are also deprecated.  The aliased()
     construct now provides for a great deal of flexibility and
     capability and should be used directly.

     See also
     ........

     See ORM Query - Joining / loading on relationships uses attributes, not strings.

     See ORM Query - join(…, aliased=True), from_joinpoint removed.

     References: #4705(37), #5202(38)

   * `[orm] [deprecated]' ¶. Deprecated logic in
     Query.distinct() that automatically adds columns in the ORDER
     BY clause to the columns clause; this will be removed in 2.0.

     See also
     ........

     See Using DISTINCT with additional columns, but only select the entity.

     References: #5134(39)

   * `[orm] [deprecated]' ¶. Passing keyword arguments to
     methods such as Session.execute() to be passed into the
     Session.get_bind() method is deprecated; the new
     Session.execute.bind_arguments dictionary should be passed
     instead.

     References: #5573(40)

   * `[orm] [deprecated]' ¶. The eagerload() and
     relation() were old aliases and are now deprecated.
     Use joinedload() and relationship()
     respectively.

     References: #5192(41)

   * `[orm] [removed]' ¶. All long-deprecated “extension”
     classes have been removed, including MapperExtension,
     SessionExtension, PoolListener, ConnectionProxy,
     AttributeExtension.  These classes have been deprecated since
     version 0.7 long superseded by the event listener system.

     References: #4638(42)

   * `[orm] [removed]' ¶. Remove the deprecated loader
     options ‘joinedload_all’, ‘subqueryload_all’, ‘lazyload_all’,
     ‘selectinload_all’.  The normal version with method chaining should
     be used in their place.

     References: #4642(43)

   * `[orm] [removed]' ¶. Remove deprecated function
     ‘comparable_property’.  Please refer to the hybrid
     extension.  This also removes the function ‘comparable_using’ in
     the declarative extension.

     Remove deprecated function ‘compile_mappers’.  Please use
     configure_mappers().

     Remove deprecated method ‘collection.linker’.  Please refer to the
     AttributeEvents.init_collection() and
     AttributeEvents.dispose_collection() event handlers.

     Remove deprecated method ‘Session.prune’ and parameter
     ‘Session.weak_identity_map’.  See the recipe at Session Referencing Behavior
     for an event-based approach to
     maintaining strong identity references.  This change also removes
     the class ‘StrongInstanceDict’.

     Remove deprecated parameter ‘mapper.order_by’.  Use
     Query.order_by() to determine the ordering of a result set.

     Remove deprecated parameter
     ‘Session._enable_transaction_accounting’.

     Remove deprecated parameter ‘Session.is_modified.passive’.

     References: #4643(44)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5159

   (2) http://www.sqlalchemy.org/trac/ticket/4472

   (3) http://www.sqlalchemy.org/trac/ticket/5508

   (4) http://www.sqlalchemy.org/trac/ticket/1763

   (5) http://www.sqlalchemy.org/trac/ticket/5027

   (6) http://www.sqlalchemy.org/trac/ticket/4826

   (7) http://www.sqlalchemy.org/trac/ticket/1653

   (8) http://www.sqlalchemy.org/trac/ticket/5171

   (9) http://www.sqlalchemy.org/trac/ticket/3903

   (10) http://www.sqlalchemy.org/trac/ticket/5018

   (11) http://www.sqlalchemy.org/trac/ticket/5237

   (12) http://www.sqlalchemy.org/trac/ticket/4662

   (13) http://www.sqlalchemy.org/trac/ticket/4395

   (14) http://www.sqlalchemy.org/trac/ticket/4617

   (15) http://www.sqlalchemy.org/trac/ticket/4710

   (16) http://www.sqlalchemy.org/trac/ticket/5401

   (17) http://www.sqlalchemy.org/trac/ticket/5263

   (18) http://www.sqlalchemy.org/trac/ticket/5122

   (19) http://www.sqlalchemy.org/trac/ticket/4696

   (20) http://www.sqlalchemy.org/trac/ticket/4617

   (21) http://www.sqlalchemy.org/trac/ticket/4194

   (22) http://www.sqlalchemy.org/trac/ticket/3858

   (23) http://www.sqlalchemy.org/trac/ticket/5074

   (24) http://www.sqlalchemy.org/trac/ticket/4829

   (25) http://www.sqlalchemy.org/trac/ticket/4212

   (26) http://www.sqlalchemy.org/trac/ticket/4718

   (27) http://www.sqlalchemy.org/trac/ticket/4993

   (28) http://www.sqlalchemy.org/trac/ticket/4994

   (29) http://www.sqlalchemy.org/trac/ticket/4699

   (30) http://www.sqlalchemy.org/trac/ticket/4195

   (31) http://www.sqlalchemy.org/trac/ticket/4836

   (32) http://www.sqlalchemy.org/trac/ticket/4519

   (33) http://www.sqlalchemy.org/trac/ticket/5226

   (34) http://www.sqlalchemy.org/trac/ticket/5150

   (35) http://www.sqlalchemy.org/trac/ticket/5606

   (36) http://www.sqlalchemy.org/trac/ticket/4719

   (37) http://www.sqlalchemy.org/trac/ticket/4705

   (38) http://www.sqlalchemy.org/trac/ticket/5202

   (39) http://www.sqlalchemy.org/trac/ticket/5134

   (40) http://www.sqlalchemy.org/trac/ticket/5573

   (41) http://www.sqlalchemy.org/trac/ticket/5192

   (42) http://www.sqlalchemy.org/trac/ticket/4638

   (43) http://www.sqlalchemy.org/trac/ticket/4642

   (44) http://www.sqlalchemy.org/trac/ticket/4643

8.3.1.46 engine
...............

   * `[engine] [feature]' ¶. Implemented an all-new
     Result object that replaces the previous ‘ResultProxy’ object.
     As implemented in Core, the subclass CursorResult
     features a compatible calling interface with the previous
     ‘ResultProxy’, and additionally adds a great amount of new
     functionality that can be applied to Core result sets as well as
     ORM result sets, which are now integrated into the same model.
     Result includes features such as column selection and
     rearrangement, improved fetchmany patterns, uniquing, as well as a
     variety of implementations that can be used to create database
     results from in-memory structures as well.

     See also
     ........

     See New Result object.

     References: #4395(1), #4959(2), #5087(3)

   * `[engine] [feature] [orm]' ¶. SQLAlchemy now includes
     support for Python asyncio within both Core and ORM, using the
     included asyncio extension.  The extension makes use of
     the greenlet(4) library in order to adapt SQLAlchemy’s
     sync-oriented internals such that an asyncio interface that
     ultimately interacts with an asyncio database adapter is now
     feasible.  The single driver supported at the moment is the
     asyncpg driver for PostgreSQL.

     See also
     ........

     See Asynchronous IO Support for Core and ORM.

     References: #3414(5)

   * `[engine] [feature] [alchemy2]' ¶. Implemented the
     create_engine.future parameter which enables forwards
     compatibility with SQLAlchemy 2.  is used for forwards
     compatibility with SQLAlchemy 2.  This engine features
     always-transactional behavior with autobegin.

     See also
     ........

     See Migrating to SQLAlchemy 2.0.

     References: #4644(6)

   * `[engine] [feature] [pyodbc]' ¶. Reworked the
     “setinputsizes()” set of dialect hooks to be correctly extensible
     for any arbirary DBAPI, by allowing dialects individual hooks that
     may invoke cursor.setinputsizes() in the appropriate style for that
     DBAPI. In particular this is intended to support pyodbc’s style of
     usage which is fundamentally different from that of cx_Oracle.
     Added support for pyodbc.

     References: #5649(7)

   * `[engine] [feature]' ¶. Added new reflection method
     Inspector.get_sequence_names() which returns all the
     sequences defined and Inspector.has_sequence() to
     check if a particular sequence exits.  Support for this method has
     been added to the backend that support Sequence:
     PostgreSQL, Oracle and MariaDB >= 10.3.

     References: #2056(8)

   * `[engine] [feature]' ¶. The Table.autoload_with
     parameter now accepts an Inspector object
     directly, as well as any Engine or Connection
     as was the case before.

     References: #4755(9)

   * `[engine] [change]' ¶. The ‘RowProxy’ class is no
     longer a “proxy” object, and is instead directly populated with the
     post-processed contents of the DBAPI row tuple upon construction.
     Now named Row, the mechanics of how the Python-level
     value processors have been simplified, particularly as it impacts
     the format of the C code, so that a DBAPI row is processed into a
     result tuple up front.  The object returned by the ‘ResultProxy’ is
     now the LegacyRow subclass, which maintains
     mapping/tuple hybrid behavior, however the base Row
     class now behaves more fully like a named tuple.

     See also
     ........

     See RowProxy is no longer a “proxy”; is now called Row and behaves like an enhanced named tuple.

     References: #4710(10)

   * `[engine] [performance]' ¶. The pool “pre-ping” feature
     has been refined to not invoke for a DBAPI connection that was just
     opened in the same checkout operation.  pre ping only applies to a
     DBAPI connection that’s been checked into the pool and is being
     checked out again.

     References: #4524(11)

   * `[engine] [performance] [change] [py3k]' ¶. Disabled
     the “unicode returns” check that runs on dialect startup when
     running under Python 3, which for many years has occurred in order
     to test the current DBAPI’s behavior for whether or not it returns
     Python Unicode or Py2K strings for the VARCHAR and NVARCHAR
     datatypes.  The check still occurs by default under Python 2,
     however the mechanism to test the behavior will be removed in
     SQLAlchemy 2.0 when Python 2 support is also removed.

     This logic was very effective when it was needed, however now that
     Python 3 is standard, all DBAPIs are expected to return Python 3
     strings for character datatypes.  In the unlikely case that a third
     party DBAPI does not support this, the conversion logic within
     String is still available and the third party dialect
     may specify this in its upfront dialect flags by setting the
     dialect level flag ‘returns_unicode_strings’ to one of
     String.RETURNS_CONDITIONAL or String.RETURNS_BYTES,
     both of which will enable Unicode conversion even under
     Python 3.

     References: #5315(12)

   * `[engine] [bug]' ¶. Revised the
     Connection.execution_options.schema_translate_map feature
     such that the processing of the SQL statement to receive a specific
     schema name occurs within the execution phase of the statement,
     rather than at the compile phase.  This is to support the statement
     being efficiently cached.  Previously, the current schema being
     rendered into the statement for a particular run would be
     considered as part of the cache key itself, meaning that for a run
     against hundreds of schemas, there would be hundreds of cache keys,
     rendering the cache much less performant.  The new behavior is that
     the rendering is done in a similar manner as the “post compile”
     rendering added in 1.4 as part of #4645(13), #4808(14).

     References: #5004(15)

   * `[engine] [bug]' ¶. The Connection object
     will now not clear a rolled-back transaction until the outermost
     transaction is explicitly rolled back.  This is essentially the
     same behavior that the ORM Session has had for a long
     time, where an explicit call to ‘.rollback()’ on all enclosing
     transactions is required for the transaction to logically clear,
     even though the DBAPI-level transaction has already been rolled
     back.  The new behavior helps with situations such as the “ORM
     rollback test suite” pattern where the test suite rolls the
     transaction back within the ORM scope, but the test harness which
     seeks to control the scope of the transaction externally does not
     expect a new transaction to start implicitly.

     See also
     ........

     See Connection-level transactions can now be inactive based on subtransaction.

     References: #4712(16)

   * `[engine] [bug]' ¶. Adjusted the dialect initialization
     process such that the Dialect.on_connect() is not
     called a second time on the first connection.  The hook is called
     first, then the Dialect.initialize() is called if that
     connection is the first for that dialect, then no more events are
     called.  This eliminates the two calls to the “on_connect” function
     which can produce very difficult debugging situations.

     References: #5497(17)

   * `[engine] [deprecated]' ¶. The URL object
     is now an immutable named tuple.  To modify a URL object, use the
     URL.set() method to produce a new URL object.

     See also
     ........

     See The URL object is now immutable. - notes on migration

     References: #5526(18)

   * `[engine] [deprecated]' ¶. The MetaData.bind
     argument as well as the overall concept of “bound metadata”
     is deprecated in SQLAlchemy 1.4 and will be removed in SQLAlchemy
     2.0.  The parameter as well as related functions now emit a
     RemovedIn20Warning when SQLAlchemy 2.0 Deprecations Mode
     is in use.

     See also
     ........

     See “Implicit” and “Connectionless” execution, “bound metadata” removed.

     References: #4634(19)

   * `[engine] [deprecated]' ¶. The ‘server_side_cursors’
     engine-wide parameter is deprecated and will be removed in a future
     release.  For unbuffered cursors, the
     Connection.execution_options.stream_results execution option
     should be used on a per-execution basis.

   * `[engine] [deprecated]' ¶. The
     Connection.connect() method is deprecated as is the concept
     of “connection branching”, which copies a Connection
     into a new one that has a no-op “.close()” method.  This pattern is
     oriented around the “connectionless execution” concept which is
     also being removed in 2.0.

     References: #5131(20)

   * `[engine] [deprecated]' ¶. The ‘case_sensitive’ flag on
     create_engine() is deprecated; this flag was part of the
     transition of the result row object to allow case sensitive column
     matching as the default, while providing backwards compatibility
     for the former matching method.  All string access for a row should
     be assumed to be case sensitive just like any other Python mapping.

     References: #4878(21)

   * `[engine] [deprecated]' ¶. ”Implicit autocommit”, which
     is the COMMIT that occurs when a DML or DDL statement is emitted on
     a connection, is deprecated and won’t be part of SQLAlchemy 2.0.  A
     2.0-style warning is emitted when autocommit takes effect, so that
     the calling code may be adjusted to use an explicit transaction.

     As part of this change, DDL methods such as
     MetaData.create_all() when used against an Engine
     will run the operation in a BEGIN block if one is not started
     already.

     See also
     ........

     See SQLAlchemy 2.0 Deprecations Mode.

     References: #4846(22)

   * `[engine] [deprecated]' ¶. Deprecated the behavior by
     which a Column can be used as the key in a result set
     row lookup, when that Column is not part of the SQL
     selectable that is being selected; that is, it is only matched on
     name.  A deprecation warning is now emitted for this case.  Various
     ORM use cases, such as those involving text()
     constructs, have been improved so that this fallback logic is
     avoided in most cases.

     References: #4877(23)

   * `[engine] [deprecated]' ¶. Deprecated remaining
     engine-level introspection and utility methods including
     Engine.run_callable(), Engine.transaction(),
     Engine.table_names(), Engine.has_table().
     The utility methods are superseded by modern context-manager
     patterns, and the table introspection tasks are suited by the
     Inspector object.

     References: #4755(24)

   * `[engine] [removed]' ¶. Remove deprecated method
     ‘get_primary_keys’ in the Dialect and Inspector
     classes.  Please refer to the
     Dialect.get_pk_constraint() and
     ‘Inspector.get_primary_keys()’ methods.

     Remove deprecated event ‘dbapi_error’ and the method
     ‘ConnectionEvents.dbapi_error’.  Please refer to the
     ConnectionEvents.handle_error() event.  This change also
     removes the attributes ‘ExecutionContext.is_disconnect’ and
     ‘ExecutionContext.exception’.

     References: #4643(25)

   * `[engine] [removed]' ¶. The internal dialect method
     ‘Dialect.reflecttable’ has been removed.  A review of third party
     dialects has not found any making use of this method, as it was
     already documented as one that should not be used by external
     dialects.  Additionally, the private ‘Engine._run_visitor’ method
     is also removed.

     References: #4755(26)

   * `[engine] [removed]' ¶. The long-deprecated
     ‘Inspector.get_table_names.order_by’ parameter has been removed.

     References: #4755(27)

   * `[engine] [renamed]' ¶. The
     Inspector.reflecttable() was renamed to
     Inspector.reflect_table().

     References: #5244(28)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4395

   (2) http://www.sqlalchemy.org/trac/ticket/4959

   (3) http://www.sqlalchemy.org/trac/ticket/5087

   (4) https://greenlet.readthedocs.io/en/latest/

   (5) http://www.sqlalchemy.org/trac/ticket/3414

   (6) http://www.sqlalchemy.org/trac/ticket/4644

   (7) http://www.sqlalchemy.org/trac/ticket/5649

   (8) http://www.sqlalchemy.org/trac/ticket/2056

   (9) http://www.sqlalchemy.org/trac/ticket/4755

   (10) http://www.sqlalchemy.org/trac/ticket/4710

   (11) http://www.sqlalchemy.org/trac/ticket/4524

   (12) http://www.sqlalchemy.org/trac/ticket/5315

   (13) http://www.sqlalchemy.org/trac/ticket/4645

   (14) http://www.sqlalchemy.org/trac/ticket/4808

   (15) http://www.sqlalchemy.org/trac/ticket/5004

   (16) http://www.sqlalchemy.org/trac/ticket/4712

   (17) http://www.sqlalchemy.org/trac/ticket/5497

   (18) http://www.sqlalchemy.org/trac/ticket/5526

   (19) http://www.sqlalchemy.org/trac/ticket/4634

   (20) http://www.sqlalchemy.org/trac/ticket/5131

   (21) http://www.sqlalchemy.org/trac/ticket/4878

   (22) http://www.sqlalchemy.org/trac/ticket/4846

   (23) http://www.sqlalchemy.org/trac/ticket/4877

   (24) http://www.sqlalchemy.org/trac/ticket/4755

   (25) http://www.sqlalchemy.org/trac/ticket/4643

   (26) http://www.sqlalchemy.org/trac/ticket/4755

   (27) http://www.sqlalchemy.org/trac/ticket/4755

   (28) http://www.sqlalchemy.org/trac/ticket/5244

8.3.1.47 sql
............

   * `[sql] [feature]' ¶. Added “from linting” as a built-in
     feature to the SQL compiler.  This allows the compiler to maintain
     graph of all the FROM clauses in a particular SELECT statement,
     linked by criteria in either the WHERE or in JOIN clauses that link
     these FROM clauses together.  If any two FROM clauses have no path
     between them, a warning is emitted that the query may be producing
     a cartesian product.  As the Core expression language as well as
     the ORM are built on an “implicit FROMs” model where a particular
     FROM clause is automatically added if any part of the query refers
     to it, it is easy for this to happen inadvertently and it is hoped
     that the new feature helps with this issue.

     See also
     ........

     See Built-in FROM linting will warn for any potential cartesian products in a SELECT statement.

     References: #4737(1)

   * `[sql] [feature] [mssql] [oracle]' ¶. Added new “post
     compile parameters” feature.  This feature allows a
     bindparam() construct to have its value rendered into the SQL
     string before being passed to the DBAPI driver, but after the
     compilation step, using the “literal render” feature of the
     compiler.  The immediate rationale for this feature is to support
     LIMIT/OFFSET schemes that don’t work or perform well as bound
     parameters handled by the database driver, while still allowing for
     SQLAlchemy SQL constructs to be cacheable in their compiled form.
     The immediate targets for the new feature are the “TOP N” clause
     used by SQL Server (and Sybase) which does not support a bound
     parameter, as well as the “ROWNUM” and optional “FIRST_ROWS()”
     schemes used by the Oracle dialect, the former of which has been
     known to perform better without bound parameters and the latter of
     which does not support a bound parameter.  The feature builds upon
     the mechanisms first developed to support “expanding” parameters
     for IN expressions.  As part of this feature, the Oracle
     ‘use_binds_for_limits’ feature is turned on unconditionally and
     this flag is now deprecated.

     See also
     ........

     See New “post compile” bound parameters used for LIMIT/OFFSET in Oracle, SQL Server.

     References: #4808(2)

   * `[sql] [feature]' ¶. Add support for regular expression
     on supported backends.  Two operations have been defined:

        * ColumnOperators.regexp_match() implementing a
          regular expression match like function.

        * ColumnOperators.regexp_replace() implementing a
          regular expression string replace function.

     Supported backends include SQLite, PostgreSQL, MySQL / MariaDB, and
     Oracle.

     See also
     ........

     See Support for SQL Regular Expression operators.

     References: #1390(3)

   * `[sql] [feature]' ¶. The select() construct
     and related constructs now allow for duplication of column labels
     and columns themselves in the columns clause, mirroring exactly how
     column expressions were passed in.  This allows the tuples returned
     by an executed result to match what was SELECTed for in the first
     place, which is how the ORM Query works, so this
     establishes better cross-compatibility between the two constructs.
     Additionally, it allows column-positioning-sensitive structures
     such as UNIONs (i.e.  ‘_selectable.CompoundSelect’) to be more
     intuitively constructed in those cases where a particular column
     might appear in more than one place.  To support this change, the
     ColumnCollection has been revised to support duplicate
     columns as well as to allow integer index access.

     See also
     ........

     See SELECT objects and derived FROM clauses allow for duplicate columns and column labels.

     References: #4753(4)

   * `[sql] [feature]' ¶. Enhanced the disambiguating labels
     feature of the select() construct such that when a
     select statement is used in a subquery, repeated column names from
     different tables are now automatically labeled with a unique label
     name, without the need to use the full “apply_labels()” feature
     that combines tablename plus column name.  The disambiguated labels
     are available as plain string keys in the .c collection of the
     subquery, and most importantly the feature allows an ORM
     aliased() construct against the combination of an entity and
     an arbitrary subquery to work correctly, targeting the correct
     columns despite same-named columns in the source tables, without
     the need for an “apply labels” warning.

     See also
     ........

     See Selecting from the query itself as a subquery, e.g. “from_self()”.
     - Illustrates the new disambiguation feature as
     part of a strategy to migrate away from the
     Query.from_self() method.

     References: #5221(5)

   * `[sql] [feature]' ¶. 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.

     See also
     ........

     See All IN expressions render parameters for each value in the list on the fly (e.g. expanding parameters).

     References: #4645(6)

   * `[sql] [feature]' ¶. Along with the new transparent
     statement caching feature introduced as part of #4369(7), a new
     feature intended to decrease the Python overhead of creating
     statements is added, allowing lambdas to be used when indicating
     arguments being passed to a statement object such as select(),
     Query(), update(), etc., as well as allowing the construction of
     full statements within lambdas in a similar manner as that of the
     “baked query” system.  The rationale of using lambdas is adapted
     from that of the “baked query” approach which uses lambdas to
     encapsulate any amount of Python code into a callable that only
     needs to be called when the statement is first constructed into a
     string.  The new feature however is more sophisticated in that
     Python literal values that would be passed as parameters are
     automatically extracted, so that there is no longer a need to use
     bindparam() objects with such queries.  Use of the feature is
     optional and can be used to as small or as great a degree as is
     desired, while still allowing statements to be fully cacheable.

     See also
     ........

     See Using Lambdas to add significant speed gains to statement production.

     References: #5380(8)

   * `[sql] [usecase]' ¶. The Index.create().
     and Index.drop() methods now have a parameter
     Index.create.checkfirst, in the same way as that of
     Table and Sequence, which when enabled will cause
     the operation to detect if the index exists (or not) before
     performing a create or drop operation.

     References: #527(9)

   * `[sql] [usecase]' ¶. The true() and
     false() operators may now be applied as the “onclause” of a
     join() on a backend that does not support “native
     boolean” expressions, e.g.  Oracle or SQL Server, and the
     expression will render as “1=1” for true and “1=0” false.  This is
     the behavior that was introduced many years ago in #2804(10) for
     and/or expressions.

   * `[sql] [usecase]' ¶. Change the method ‘__str’ of
     ‘ColumnCollection’ to avoid confusing it with a python list of
     string.

     References: #5191(11)

   * `[sql] [usecase]' ¶. Add support to ‘FETCH {FIRST |
     NEXT} [ count ] {ROW | ROWS} {ONLY | WITH TIES}’ in the select for
     the supported backends, currently PostgreSQL, Oracle and MSSQL.

     References: #5576(12)

   * `[sql] [usecase]' ¶. Additional logic has been added
     such that certain SQL expressions which typically wrap a single
     database column will use the name of that column as their
     “anonymous label” name within a SELECT statement, potentially
     making key-based lookups in result tuples more intuitive.  The
     primary example of this is that of a CAST expression, e.g.
     ‘CAST(table.colname AS INTEGER)’, which will export its default
     name as “colname”, rather than the usual “anon_1” label, that is,
     ‘CAST(table.colname AS INTEGER) AS colname’.  If the inner
     expression doesn’t have a name, then the previous “anonymous label”
     logic is used.  When using SELECT statements that make use of
     Select.apply_labels(), such as those emitted by the ORM, the
     labeling logic will produce ‘<tablename>_<inner column name>’ in
     the same was as if the column were named alone.  The logic applies
     right now to the cast() and type_coerce()
     constructs as well as some single-element boolean expressions.

     See also
     ........

     See Improved column labeling for simple column expressions using CAST or similar.

     References: #4449(13)

   * `[sql] [change]' ¶. The “clause coercion” system, which
     is SQLAlchemy Core’s system of receiving arguments and resolving
     them into ClauseElement structures in order to build up
     SQL expression objects, has been rewritten from a series of ad-hoc
     functions to a fully consistent class-based system.  This change is
     internal and should have no impact on end users other than more
     specific error messages when the wrong kind of argument is passed
     to an expression object, however the change is part of a larger set
     of changes involving the role and behavior of select()
     objects.

     References: #4617(14)

   * `[sql] [change]' ¶. Added a core ‘Values’ object that
     enables a VALUES construct to be used in the FROM clause of an SQL
     statement for databases that support it (mainly PostgreSQL and SQL
     Server).

     References: #4868(15)

   * `[sql] [change]' ¶. The select() construct
     is moving towards a new calling form that is ‘select(col1, col2,
     col3, ..)’, with all other keyword arguments removed, as these are
     all suited using generative methods.  The single list of column or
     table arguments passed to ‘select()’ is still accepted, however is
     no longer necessary if expressions are passed in a simple
     positional style.  Other keyword arguments are disallowed when this
     form is used.

     See also
     ........

     See select(), case() now accept positional expressions.

     References: #5284(16)

   * `[sql] [change]' ¶. As part of the SQLAlchemy 2.0
     migration project, a conceptual change has been made to the role of
     the 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
     FromClause.  For end users, the change mostly means that any
     placement of a select() construct in the FROM clause of
     another select() requires first that it be wrapped in a
     subquery first, which historically is through the use of the
     SelectBase.alias() method, and is now also available through
     the use of 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 also
     ........

     See A SELECT statement is no longer implicitly considered to be a FROM clause.

     References: #4617(17)

   * `[sql] [change]' ¶. Added a new Core class
     Subquery, which takes the place of Alias when
     creating named subqueries against a SelectBase object.
     Subquery acts in the same way as Alias and
     is produced from the SelectBase.subquery() method; for
     ease of use and backwards compatibility, the
     SelectBase.alias() method is synonymous with this new method.

     See also
     ........

     See A SELECT statement is no longer implicitly considered to be a FROM clause.

     References: #4617(18)

   * `[sql] [performance]' ¶. An all-encompassing
     reorganization and refactoring of Core and ORM internals now allows
     all Core and ORM statements within the areas of DQL (e.g.  SELECTs)
     and DML (e.g.  INSERT, UPDATE, DELETE) to allow their SQL
     compilation as well as the construction of result-fetching metadata
     to be fully cached in most cases.  This effectively provides a
     transparent and generalized version of what the “Baked Query”
     extension has offered for the ORM in past versions.  The new
     feature can calculate the cache key for any given SQL construction
     based on the string that it would ultimately produce for a given
     dialect, allowing functions that compose the equivalent select(),
     Query(), insert(), update() or delete() object each time to have
     that statement cached after it’s generated the first time.

     The feature is enabled transparently but includes some new
     programming paradigms that may be employed to make the caching even
     more efficient.

     See also
     ........

     See Transparent SQL Compilation Caching added to All DQL, DML Statements in Core, ORM.

     See SQL Compilation Caching.

     References: #4639(19)

   * `[sql] [bug]' ¶. Fixed issue where when constructing
     constraints from ORM-bound columns, primarily ForeignKey
     objects but also UniqueConstraint,
     CheckConstraint and others, the ORM-level
     InstrumentedAttribute is discarded entirely, and all
     ORM-level annotations from the columns are removed; this is so that
     the constraints are still fully pickleable without the ORM-level
     entities being pulled in.  These annotations are not necessary to
     be present at the schema/metadata level.

     References: #5001(20)

   * `[sql] [bug]' ¶. Registered function names based on
     GenericFunction are now retrieved in a case-insensitive
     fashion in all cases, removing the deprecation logic from 1.3 which
     temporarily allowed multiple GenericFunction objects to
     exist with differing cases.  A GenericFunction that
     replaces another on the same name whether or not it’s case
     sensitive emits a warning before replacing the object.

     References: #4569(21), #4649(22)

   * `[sql] [bug]' ¶. Creating an and_() or
     or_() construct with no arguments or empty ‘*args’ will now
     emit a deprecation warning, as the SQL produced is a no-op (i.e.
     it renders as a blank string).  This behavior is considered to be
     non-intuitive, so for empty or possibly empty and_() or
     or_() constructs, an appropriate default boolean should
     be included, such as ‘and_(True, *args)’ or ‘or_(False, *args)’.
     As has been the case for many major versions of SQLAlchemy, these
     particular boolean values will not render if the ‘*args’ portion is
     non-empty.

     References: #5054(23)

   * `[sql] [bug]' ¶. Improved the tuple_().
     construct such that it behaves predictably when used in a
     columns-clause context.  The SQL tuple is not supported as a
     “SELECT” columns clause element on most backends; on those that do
     (PostgreSQL, not surprisingly), the Python DBAPI does not have a
     “nested type” concept so there are still challenges in fetching
     rows for such an object.  Use of tuple_() in a
     select() or Query will now raise a
     CompileError at the point at which the tuple_()
     object is seen as presenting itself for fetching rows (i.e., if the
     tuple is in the columns clause of a subquery, no error is raised).
     For ORM use,the Bundle object is an explicit directive
     that a series of columns should be returned as a sub-tuple per row
     and is suggested by the error message.  Additionally ,the tuple
     will now render with parenthesis in all contexts.  Previously, the
     parenthesization would not render in a columns context leading to
     non-defined behavior.

     References: #5127(24)

   * `[sql] [bug] [postgresql]' ¶. Improved support for
     column names that contain percent signs in the string, including
     repaired issues involving anoymous labels that also embedded a
     column name with a percent sign in it, as well as re-established
     support for bound parameter names with percent signs embedded on
     the psycopg2 dialect, using a late-escaping process similar to that
     used by the cx_Oracle dialect.

     References: #5653(25)

   * `[sql] [bug]' ¶. Custom functions that are created as
     subclasses of FunctionElement will now generate an
     “anonymous label” based on the “name” of the function just like any
     other Function object, e.g.  ‘"SELECT myfunc() AS
     myfunc_1"’.  While SELECT statements no longer require labels in
     order for the result proxy object to function, the ORM still
     targets columns in rows by using objects as mapping keys, which
     works more reliably when the column expressions have distinct
     names.  In any case, the behavior is now made consistent between
     functions generated by ‘func’ and those generated as custom
     FunctionElement objects.

     References: #4887(26)

   * `[sql] [bug]' ¶. Reworked the
     ClauseElement.compare() methods in terms of a new
     visitor-based approach, and additionally added test coverage
     ensuring that all ClauseElement subclasses can be
     accurately compared against each other in terms of structure.
     Structural comparison capability is used to a small degree within
     the ORM currently, however it also may form the basis for new
     caching features.

     References: #4336(27)

   * `[sql] [bug]' ¶. Deprecate usage of ‘DISTINCT ON’ in
     dialect other than PostgreSQL. Deprecate old usage of string
     distinct in MySQL dialect

     References: #4002(28)

   * `[sql] [bug]' ¶. The ORDER BY clause of a
     ‘_selectable.CompoundSelect’, e.g.  UNION, EXCEPT, etc.  will not
     render the table name associated with a given column when applying
     ‘CompoundSelect.order_by()’ in terms of a Table. - bound
     column.  Most databases require that the names in the ORDER BY
     clause be expressed as label names only which are matched to names
     in the first SELECT statement.  The change is related to #4617(29)
     in that a previous workaround was to refer to the ‘.c’ attribute of
     the ‘_selectable.CompoundSelect’ in order to get at a column that
     has no table name.  As the subquery is now named, this change
     allows both the workaround to continue to work, as well as allows
     table-bound columns as well as the
     ‘CompoundSelect.selected_columns’ collections to be usable in the
     ‘CompoundSelect.order_by()’ method.

     References: #4617(30)

   * `[sql] [bug]' ¶. The Join construct no
     longer considers the “onclause” as a source of additional FROM
     objects to be omitted from the FROM list of an enclosing
     Select object as standalone FROM objects.  This applies to an
     ON clause that includes a reference to another FROM object outside
     the JOIN; while this is usually not correct from a SQL perspective,
     it’s also incorrect for it to be omitted, and the behavioral change
     makes the Select. / see Join behave a bit more
     intuitively.

     References: #4621(31)

   * `[sql] [deprecated]' ¶. The Join.alias().
     method is deprecated and will be removed in SQLAlchemy 2.0.  An
     explicit select + subquery, or aliasing of the inner tables, should
     be used instead.

     References: #5010(32)

   * `[sql] [deprecated]' ¶. The Table class now
     raises a deprecation warning when columns with the same name are
     defined.  To replace a column a new parameter
     Table.append_column.replace_existing was added to the
     Table.append_column() method.

     The ColumnCollection.contains_column() will now raises
     an error when called with a string, suggesting the caller to use
     ‘in’ instead.

   * `[sql] [removed]' ¶. The “threadlocal” execution
     strategy, deprecated in 1.3, has been removed for 1.4, as well as
     the concept of “engine strategies” and the
     ‘Engine.contextual_connect’ method.  The “strategy=’mock’” keyword
     argument is still accepted for now with a deprecation warning; use
     create_mock_engine() instead for this use case.

     See also
     ........

     See “threadlocal” engine strategy deprecated. - from the
     1.3 migration notes which discusses the rationale for deprecation.

     References: #4632(33)

   * `[sql] [removed]' ¶. Removed the
     ‘sqlalchemy.sql.visitors.iterate_depthfirst’ and
     ‘sqlalchemy.sql.visitors.traverse_depthfirst’ functions.  These
     functions were unused by any part of SQLAlchemy.  The
     iterate() and traverse() functions are commonly
     used for these functions.  Also removed unused options from the
     remaining functions including “column_collections”,
     “schema_visitor”.

   * `[sql] [removed]' ¶. Removed the concept of a bound
     engine from the ‘Compiler’ object, and removed the ‘.execute()’ and
     ‘.scalar()’ methods from ‘Compiler’.  These were essentially
     forgotten methods from over a decade ago and had no practical use,
     and it’s not appropriate for the ‘Compiler’ object itself to be
     maintaining a reference to an Engine.

   * `[sql] [removed]' ¶. Remove deprecated methods
     ‘Compiled.compile’, ‘ClauseElement.__and__’ and
     ‘ClauseElement.__or__’ and attribute ‘Over.func’.

     Remove deprecated ‘FromClause.count’ method.  Please use the
     count function available from the ‘func’ namespace.

     References: #4643(34)

   * `[sql] [removed]' ¶. Remove deprecated parameters
     ‘text.bindparams’ and ‘text.typemap’.  Please refer to the
     TextClause.bindparams() and TextClause.columns()
     methods.

     Remove deprecated parameter ‘Table.useexisting’.  Please use
     Table.extend_existing.

     References: #4643(35)

   * `[sql] [renamed]' ¶. Table parameter
     ‘mustexist’ has been renamed to Table.must_exist and
     will now warn when used.

   * `[sql] [renamed]' ¶. The SelectBase.as_scalar()
     and Query.as_scalar() methods have been renamed to
     SelectBase.scalar_subquery() and
     Query.scalar_subquery(), respectively.  The old names continue
     to exist within 1.4 series with a deprecation warning.  In
     addition, the implicit coercion of SelectBase,
     Alias, and other SELECT oriented objects into scalar
     subqueries when evaluated in a column context is also deprecated,
     and emits a warning that the SelectBase.scalar_subquery()
     method should be called explicitly.  This warning will in a
     later major release become an error, however the message will
     always be clear when SelectBase.scalar_subquery() needs
     to be invoked.  The latter part of the change is for clarity and to
     reduce the implicit decisionmaking by the query coercion system.
     The Subquery.as_scalar() method, which was previously
     ‘Alias.as_scalar’, is also deprecated; ‘.scalar_subquery()’ should
     be invoked directly from ‘ see select() object or
     Query object.

     This change is part of the larger change to convert select()
     objects to no longer be directly part of the “from clause”
     class hierarchy, which also includes an overhaul of the clause
     coercion system.

     References: #4617(36)

   * `[sql] [renamed]' ¶. Several operators are renamed to
     achieve more consistent naming across SQLAlchemy.

     The operator changes are:

        * ‘isfalse’ is now ‘is_false’

        * ‘isnot_distinct_from’ is now ‘is_not_distinct_from’

        * ‘istrue’ is now ‘is_true’

        * ‘notbetween’ is now ‘not_between’

        * ‘notcontains’ is now ‘not_contains’

        * ‘notendswith’ is now ‘not_endswith’

        * ‘notilike’ is now ‘not_ilike’

        * ‘notlike’ is now ‘not_like’

        * ‘notmatch’ is now ‘not_match’

        * ‘notstartswith’ is now ‘not_startswith’

        * ‘nullsfirst’ is now ‘nulls_first’

        * ‘nullslast’ is now ‘nulls_last’

        * ‘isnot’ is now ‘is_not’

        * ‘not_in_’ is now ‘not_in’

     Because these are core operators, the internal migration strategy
     for this change is to support legacy terms for an extended period
     of time – if not indefinitely – but update all documentation,
     tutorials, and internal usage to the new terms.  The new terms are
     used to define the functions, and the legacy terms have been
     deprecated into aliases of the new terms.

     References: #5429(37), #5435(38)

   * `[sql] [postgresql]' ¶. Allow specifying the data type
     when creating a Sequence in PostgreSQL by using the
     parameter Sequence.data_type.

     References: #5498(39)

   * `[sql] [reflection]' ¶. The “NO ACTION” keyword for
     foreign key “ON UPDATE” is now considered to be the default cascade
     for a foreign key on all supporting backends (SQlite, MySQL,
     PostgreSQL) and when detected is not included in the reflection
     dictionary; this is already the behavior for PostgreSQL and MySQL
     for all previous SQLAlchemy versions in any case.  The “RESTRICT”
     keyword is positively stored when detected; PostgreSQL does report
     on this keyword, and MySQL as of version 8.0 does as well.  On
     earlier MySQL versions, it is not reported by the database.

     References: #4741(40)

   * `[sql] [reflection]' ¶. Added support for reflecting
     “identity” columns, which are now returned as part of the structure
     returned by Inspector.get_columns().  When reflecting
     full Table objects, identity columns will be represented
     using the Identity construct.  Currently the supported
     backends are PostgreSQL >= 10, Oracle >= 12 and MSSQL (with
     different syntax and a subset of functionalities).

     References: #5324(41), #5527(42)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4737

   (2) http://www.sqlalchemy.org/trac/ticket/4808

   (3) http://www.sqlalchemy.org/trac/ticket/1390

   (4) http://www.sqlalchemy.org/trac/ticket/4753

   (5) http://www.sqlalchemy.org/trac/ticket/5221

   (6) http://www.sqlalchemy.org/trac/ticket/4645

   (7) http://www.sqlalchemy.org/trac/ticket/4369

   (8) http://www.sqlalchemy.org/trac/ticket/5380

   (9) http://www.sqlalchemy.org/trac/ticket/527

   (10) http://www.sqlalchemy.org/trac/ticket/2804

   (11) http://www.sqlalchemy.org/trac/ticket/5191

   (12) http://www.sqlalchemy.org/trac/ticket/5576

   (13) http://www.sqlalchemy.org/trac/ticket/4449

   (14) http://www.sqlalchemy.org/trac/ticket/4617

   (15) http://www.sqlalchemy.org/trac/ticket/4868

   (16) http://www.sqlalchemy.org/trac/ticket/5284

   (17) http://www.sqlalchemy.org/trac/ticket/4617

   (18) http://www.sqlalchemy.org/trac/ticket/4617

   (19) http://www.sqlalchemy.org/trac/ticket/4639

   (20) http://www.sqlalchemy.org/trac/ticket/5001

   (21) http://www.sqlalchemy.org/trac/ticket/4569

   (22) http://www.sqlalchemy.org/trac/ticket/4649

   (23) http://www.sqlalchemy.org/trac/ticket/5054

   (24) http://www.sqlalchemy.org/trac/ticket/5127

   (25) http://www.sqlalchemy.org/trac/ticket/5653

   (26) http://www.sqlalchemy.org/trac/ticket/4887

   (27) http://www.sqlalchemy.org/trac/ticket/4336

   (28) http://www.sqlalchemy.org/trac/ticket/4002

   (29) http://www.sqlalchemy.org/trac/ticket/4617

   (30) http://www.sqlalchemy.org/trac/ticket/4617

   (31) http://www.sqlalchemy.org/trac/ticket/4621

   (32) http://www.sqlalchemy.org/trac/ticket/5010

   (33) http://www.sqlalchemy.org/trac/ticket/4632

   (34) http://www.sqlalchemy.org/trac/ticket/4643

   (35) http://www.sqlalchemy.org/trac/ticket/4643

   (36) http://www.sqlalchemy.org/trac/ticket/4617

   (37) http://www.sqlalchemy.org/trac/ticket/5429

   (38) http://www.sqlalchemy.org/trac/ticket/5435

   (39) http://www.sqlalchemy.org/trac/ticket/5498

   (40) http://www.sqlalchemy.org/trac/ticket/4741

   (41) http://www.sqlalchemy.org/trac/ticket/5324

   (42) http://www.sqlalchemy.org/trac/ticket/5527

8.3.1.48 schema
...............

   * `[schema] [change]' ¶. The
     Enum.create_constraint and Boolean.create_constraint
     parameters now default to False, indicating when a so-called
     “non-native” version of these two datatypes is created, a CHECK
     constraint will not be generated by default.  These CHECK
     constraints present schema-management maintenance complexities that
     should be opted in to, rather than being turned on by default.

     See also
     ........

     See Enum and Boolean datatypes no longer default to “create constraint”.

     References: #5367(1)

   * `[schema] [bug]' ¶. Cleaned up the internal ‘str()’ for
     datatypes so that all types produce a string representation without
     any dialect present, including that it works for third-party
     dialect types without that dialect being present.  The string
     representation defaults to being the UPPERCASE name of that type
     with nothing else.

     References: #4262(2)

   * `[schema] [removed]' ¶. Remove deprecated class
     ‘Binary’.  Please use LargeBinary.

     References: #4643(3)

   * `[schema] [renamed]' ¶. Renamed the
     Table.tometadata() method to Table.to_metadata().
     The previous name remains with a deprecation warning.

     References: #5413(4)

   * `[schema] [sql]' ¶. Added the Identity.
     construct that can be used to configure identity columns rendered
     with GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY. Currently the
     supported backends are PostgreSQL >= 10, Oracle >= 12 and MSSQL
     (with different syntax and a subset of functionalities).

     References: #5324(5), #5360(6), #5362(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5367

   (2) http://www.sqlalchemy.org/trac/ticket/4262

   (3) http://www.sqlalchemy.org/trac/ticket/4643

   (4) http://www.sqlalchemy.org/trac/ticket/5413

   (5) http://www.sqlalchemy.org/trac/ticket/5324

   (6) http://www.sqlalchemy.org/trac/ticket/5360

   (7) http://www.sqlalchemy.org/trac/ticket/5362

8.3.1.49 extensions
...................

   * `[extensions] [usecase]' ¶. Custom compiler constructs
     created using the ‘sqlalchemy.ext.compiled’ extension will
     automatically add contextual information to the compiler when a
     custom construct is interpreted as an element in the columns clause
     of a SELECT statement, such that the custom element will be
     targetable as a key in result row mappings, which is the kind of
     targeting that the ORM uses in order to match column elements into
     result tuples.

     References: #4887(1)

   * `[extensions] [change]' ¶. Added new parameter
     AutomapBase.prepare.autoload_with which supersedes
     AutomapBase.prepare.reflect and
     AutomapBase.prepare.engine.

     References: #5142(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4887

   (2) http://www.sqlalchemy.org/trac/ticket/5142

8.3.1.50 postgresql
...................

   * `[postgresql] [usecase]' ¶. Added support for
     PostgreSQL “readonly” and “deferrable” flags for all of psycopg2,
     asyncpg and pg8000 dialects.  This takes advantage of a newly
     generalized version of the “isolation level” API to support other
     kinds of session attributes set via execution options that are
     reliably reset when connections are returned to the connection
     pool.

     See also
     ........

     See Setting READ ONLY / DEFERRABLE.

     References: #5549(1)

   * `[postgresql] [usecase]' ¶. The maximum buffer size for
     the ‘BufferedRowResultProxy’, which is used by dialects such as
     PostgreSQL when ‘stream_results=True’, can now be set to a number
     greater than 1000 and the buffer will grow to that size.
     Previously, the buffer would not go beyond 1000 even if the value
     were set larger.  The growth of the buffer is also now based on a
     simple multiplying factor currently set to 5.  Pull request
     courtesy Soumaya Mauthoor.

     References: #4914(2)

   * `[postgresql] [change]' ¶. When using the psycopg2
     dialect for PostgreSQL, psycopg2 minimum version is set at 2.7.
     The psycopg2 dialect relies upon many features of psycopg2 released
     in the past few years, so to simplify the dialect, version 2.7,
     released in March, 2017 is now the minimum version required.

   * `[postgresql] [performance]' ¶. The psycopg2 dialect
     now defaults to using the very performant ‘execute_values()’
     psycopg2 extension for compiled INSERT statements, and also
     implements RETURNING support when this extension is used.  This
     allows INSERT statements that even include an autoincremented
     SERIAL or IDENTITY value to run very fast while still being able to
     return the newly generated primary key values.  The ORM will then
     integrate this new feature in a separate change.

     See also
     ........

     See psycopg2 dialect features “execute_values” with RETURNING for INSERT statements by default.
     - full list of changes
     regarding the ‘executemany_mode’ parameter.

     References: #5401(3)

   * `[postgresql] [bug]' ¶. The pg8000 dialect has been
     revised and modernized for the most recent version of the pg8000
     driver for PostgreSQL. Changes to the dialect include:

        * All data types are now sent as text rather than binary.

        * Using adapters, custom types can be plugged in to pg8000.

        * Previously, named prepared statements were used for all
          statements.  Now unnamed prepared statements are used by
          default, and named prepared statements can be used explicitly
          by calling the Connection.prepare() method, which returns a
          PreparedStatement object.

     Pull request courtesy Tony Locke.

   * `[postgresql] [deprecated]' ¶. The pygresql and
     py-postgresql dialects are deprecated.

     References: #5189(4)

   * `[postgresql] [removed]' ¶. Remove support for
     deprecated engine URLs of the form ‘postgres://’; this has emitted
     a warning for many years and projects should be using
     ‘postgresql://’.

     References: #4643(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5549

   (2) http://www.sqlalchemy.org/trac/ticket/4914

   (3) http://www.sqlalchemy.org/trac/ticket/5401

   (4) http://www.sqlalchemy.org/trac/ticket/5189

   (5) http://www.sqlalchemy.org/trac/ticket/4643

8.3.1.51 mysql
..............

   * `[mysql] [feature]' ¶. Added support for MariaDB
     Connector/Python to the mysql dialect.  Original pull request
     courtesy Georg Richter.

     References: #5459(1)

   * `[mysql] [usecase]' ¶. Added a new dialect token
     “mariadb” that may be used in place of “mysql” in the
     create_engine(). URL. This will deliver a MariaDB dialect
     subclass of the MySQLDialect in use that forces the “is_mariadb”
     flag to True.  The dialect will raise an error if a server version
     string that does not indicate MariaDB in use is received.  This is
     useful for MariaDB-specific testing scenarios as well as to support
     applications that are hardcoding to MariaDB-only concepts.  As
     MariaDB and MySQL featuresets and usage patterns continue to
     diverge, this pattern may become more prominent.

     References: #5496(2)

   * `[mysql] [usecase]' ¶. Added support for use of the
     Sequence construct with MariaDB 10.3 and greater, as
     this is now supported by this database.  The construct integrates
     with the Table object in the same way that it does for
     other databases like PostgreSQL and Oracle; if is present on the
     integer primary key “autoincrement” column, it is used to generate
     defaults.  For backwards compatibility, to support a Table
     that has a Sequence on it to support sequence only
     databases like Oracle, while still not having the sequence fire off
     for MariaDB, the optional=True flag should be set, which indicates
     the sequence should only be used to generate the primary key if the
     target database offers no other option.

     See also
     ........

     See Added Sequence support for MariaDB 10.3.

     References: #4976(3)

   * `[mysql] [bug]' ¶. The MySQL and MariaDB dialects now
     query from the information_schema.tables system view in order to
     determine if a particular table exists or not.  Previously, the
     “DESCRIBE” command was used with an exception catch to detect
     non-existent, which would have the undesirable effect of emitting a
     ROLLBACK on the connection.  There appeared to be legacy encoding
     issues which prevented the use of “SHOW TABLES”, for this, but as
     MySQL support is now at 5.0.2 or above due to #4189(4), the
     information_schema tables are now available in all cases.

   * `[mysql] [bug]' ¶. The “skip_locked” keyword used with
     ‘with_for_update()’ will render “SKIP LOCKED” on all MySQL
     backends, meaning it will fail for MySQL less than version 8 and on
     current MariaDB backends.  This is because those backends do not
     support “SKIP LOCKED” or any equivalent, so this error should not
     be silently ignored.  This is upgraded from a warning in the 1.3
     series.

     References: #5568(5)

   * `[mysql] [bug]' ¶. MySQL dialect’s server_version_info
     tuple is now all numeric.  String tokens like “MariaDB” are no
     longer present so that numeric comparison works in all cases.  The
     .is_mariadb flag on the dialect should be consulted for whether or
     not mariadb was detected.  Additionally removed structures meant to
     support extremely old MySQL versions 3.x and 4.x; the minimum MySQL
     version supported is now version 5.0.2.

     References: #4189(6)

   * `[mysql] [deprecated]' ¶. The OurSQL dialect is
     deprecated.

     References: #5189(7)

   * `[mysql] [removed]' ¶. Remove deprecated dialect
     ‘mysql+gaerdbms’ that has been deprecated since version 1.0.  Use
     the MySQLdb dialect directly.

     Remove deprecated parameter ‘quoting’ from ENUM and
     SET in the ‘mysql’ dialect.  The values passed to the
     enum or the set are quoted by SQLAlchemy when needed automatically.

     References: #4643(8)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5459

   (2) http://www.sqlalchemy.org/trac/ticket/5496

   (3) http://www.sqlalchemy.org/trac/ticket/4976

   (4) http://www.sqlalchemy.org/trac/ticket/4189

   (5) http://www.sqlalchemy.org/trac/ticket/5568

   (6) http://www.sqlalchemy.org/trac/ticket/4189

   (7) http://www.sqlalchemy.org/trac/ticket/5189

   (8) http://www.sqlalchemy.org/trac/ticket/4643

8.3.1.52 sqlite
...............

   * `[sqlite] [change]' ¶. Dropped support for right-nested
     join rewriting to support old SQLite versions prior to 3.7.16,
     released in 2013.  It is expected that all modern Python versions
     among those now supported should all include much newer versions of
     SQLite.

     See also
     ........

     See Removed “join rewriting” logic from SQLite dialect; updated imports.

     References: #4895(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4895

8.3.1.53 mssql
..............

   * `[mssql] [feature] [sql]' ¶. Added support for the
     JSON datatype on the SQL Server dialect using the
     JSON implementation, which implements SQL Server’s JSON
     functionality against the ‘NVARCHAR(max)’ datatype as per SQL
     Server documentation.  Implementation courtesy Gord Thompson.

     References: #4384(1)

   * `[mssql] [feature]' ¶. Added support for “CREATE
     SEQUENCE” and full Sequence support for Microsoft SQL
     Server.  This removes the deprecated feature of using
     Sequence objects to manipulate IDENTITY characteristics which
     should now be performed using ‘mssql_identity_start’ and
     ‘mssql_identity_increment’ as documented at Auto Increment Behavior / IDENTITY Columns.
     The change includes a new
     parameter Sequence.data_type to accommodate SQL
     Server’s choice of datatype, which for that backend includes
     INTEGER, BIGINT, and DECIMAL(n, 0).  The default starting value for
     SQL Server’s version of Sequence has been set at 1;
     this default is now emitted within the CREATE SEQUENCE DDL for all
     backends.

     See also
     ........

     See Added Sequence support distinct from IDENTITY to SQL Server.

     References: #4235(2), #4633(3)

   * `[mssql] [usecase] [postgresql] [reflection] [schema]' ¶.
     Improved support for covering indexes (with INCLUDE columns).
     Added the ability for postgresql to render CREATE INDEX statements
     with an INCLUDE clause from Core.  Index reflection also report
     INCLUDE columns separately for both mssql and postgresql (11+).

     References: #4458(4)

   * `[mssql] [usecase] [postgresql]' ¶. Added support for
     inspection / reflection of partial indexes / filtered indexes, i.e.
     those which use the ‘mssql_where’ or ‘postgresql_where’ parameters,
     with Index.  The entry is both part of the dictionary
     returned by Inspector.get_indexes() as well as part of
     a reflected Index construct that was reflected.  Pull
     request courtesy Ramon Williams.

     References: #4966(5)

   * `[mssql] [usecase] [reflection]' ¶. Added support for
     reflection of temporary tables with the SQL Server dialect.  Table
     names that are prefixed by a pound sign “#” are now introspected
     from the MSSQL “tempdb” system catalog.

     References: #5506(6)

   * `[mssql] [change]' ¶. SQL Server OFFSET and FETCH
     keywords are now used for limit/offset, rather than using a window
     function, for SQL Server versions 11 and higher.  TOP is still used
     for a query that features only LIMIT. Pull request courtesy Elkin.

     References: #5084(7)

   * `[mssql] [bug] [schema]' ¶. Fixed an issue where
     ‘sqlalchemy.engine.reflection.has_table()’ always returned ‘False’
     for temporary tables.

     References: #5597(8)

   * `[mssql] [bug]' ¶. Fixed the base class of the
     DATETIMEOFFSET datatype to be based on the DateTime
     class hierarchy, as this is a datetime-holding datatype.

     References: #4980(9)

   * `[mssql] [deprecated]' ¶. The adodbapi and mxODBC
     dialects are deprecated.

     References: #5189(10)

   * `[mssql]' ¶. The mssql dialect will assume that at
     least MSSQL 2005 is used.  There is no hard exception raised if a
     previous version is detected, but operations may fail for older
     versions.

   * `[mssql] [reflection]' ¶. As part of the support for
     reflecting Identity objects, the method
     Inspector.get_columns() no longer returns
     ‘mssql_identity_start’ and ‘mssql_identity_increment’ as part of
     the ‘dialect_options’.  Use the information in the ‘identity’ key
     instead.

     References: #5527(11)

   * `[mssql] [engine]' ¶. Deprecated the
     ‘legacy_schema_aliasing’ parameter to
     sqlalchemy.create_engine().  This is a long-outdated parameter
     that has defaulted to False since version 1.1.

     References: #4809(12)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4384

   (2) http://www.sqlalchemy.org/trac/ticket/4235

   (3) http://www.sqlalchemy.org/trac/ticket/4633

   (4) http://www.sqlalchemy.org/trac/ticket/4458

   (5) http://www.sqlalchemy.org/trac/ticket/4966

   (6) http://www.sqlalchemy.org/trac/ticket/5506

   (7) http://www.sqlalchemy.org/trac/ticket/5084

   (8) http://www.sqlalchemy.org/trac/ticket/5597

   (9) http://www.sqlalchemy.org/trac/ticket/4980

   (10) http://www.sqlalchemy.org/trac/ticket/5189

   (11) http://www.sqlalchemy.org/trac/ticket/5527

   (12) http://www.sqlalchemy.org/trac/ticket/4809

8.3.1.54 oracle
...............

   * `[oracle] [usecase]' ¶. The max_identifier_length for
     the Oracle dialect is now 128 characters by default, unless
     compatibility version less than 12.2 upon first connect, in which
     case the legacy length of 30 characters is used.  This is a
     continuation of the issue as committed to the 1.3 series which adds
     max identifier length detection upon first connect as well as warns
     for the change in Oracle server.

     See also
     ........

     See Max Identifier Lengths. - in the Oracle dialect
     documentation

     References: #4857(1)

   * `[oracle] [change]' ¶. The LIMIT / OFFSET scheme used
     in Oracle now makes use of named subqueries rather than unnamed
     subqueries when it transparently rewrites a SELECT statement to one
     that uses a subquery that includes ROWNUM. The change is part of a
     larger change where unnamed subqueries are no longer directly
     supported by Core, as well as to modernize the internal use of the
     select() construct within the Oracle dialect.

   * `[oracle] [bug]' ¶. Correctly render Sequence
     and Identity column options ‘nominvalue’ and
     ‘nomaxvalue’ as ‘NOMAXVALUE` and ``NOMINVALUE’ on oracle database.

   * `[oracle] [bug]' ¶. The INTERVAL class of
     the Oracle dialect is now correctly a subclass of the abstract
     version of Interval as well as the correct “emulated”
     base class, which allows for correct behavior under both native and
     non-native modes; previously it was only based on TypeEngine.

     References: #4971(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4857

   (2) http://www.sqlalchemy.org/trac/ticket/4971

8.3.1.55 firebird
.................

   * `[firebird] [deprecated]' ¶. The Firebird dialect is
     deprecated, as there is now a 3rd party dialect that supports this
     database.

     References: #5189(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5189

8.3.1.56 misc
.............

   * `[misc] [deprecated]' ¶. The Sybase dialect is
     deprecated.

     References: #5189(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5189

8.3.2.1 1.3.24
..............

no release date

8.3.2.2 orm
...........

   * `[orm] [bug]' ¶. Fixed issue where the process of
     joining two tables could fail if one of the tables had an
     unrelated, unresolvable foreign key constraint which would raise
     NoReferenceError within the join process, which
     nonetheless could be bypassed to allow the join to complete.  The
     logic which tested the exception for significance within the
     process would make assumptions about the construct which would
     fail.

     References: #5952(1)

   * `[orm] [bug]' ¶. Removed very old warning that states
     that passive_deletes is not intended for many-to-one relationships.
     While it is likely that in many cases placing this parameter on a
     many-to-one relationship is not what was intended, there are use
     cases where delete cascade may want to be disallowed following from
     such a relationship.

     References: #5983(2)

   * `[orm] [bug]' ¶. Fixed issue where the
     MutableComposite construct could be placed into an invalid
     state when the parent object was already loaded, and then covered
     by a subsequent query, due to the composite properties’ refresh
     handler replacing the object with a new one not handled by the
     mutable extension.

     References: #6001(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5952

   (2) http://www.sqlalchemy.org/trac/ticket/5983

   (3) http://www.sqlalchemy.org/trac/ticket/6001

8.3.2.3 engine
..............

   * `[engine] [bug]' ¶. Fixed bug where the
     “schema_translate_map” feature failed to be taken into account for
     the use case of direct execution of DefaultGenerator
     objects such as sequences, which included the case where they were
     “pre-executed” in order to generate primary key values when
     implicit_returning was disabled.

     References: #5929(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5929

8.3.2.4 sql
...........

   * `[sql] [bug] [sqlite]' ¶. Fixed issue where the CHECK
     constraint generated by Boolean or Enum
     would fail to render the naming convention correctly after the
     first compilation, due to an unintended change of state within the
     name given to the constraint.  This issue was first introduced in
     0.9 in the fix for issue #3067, and the fix revises the approach
     taken at that time which appears to have been more involved than
     what was needed.

     References: #6007(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/6007

8.3.2.5 schema
..............

   * `[schema] [bug]' ¶. Repaired / implemented support for
     primary key constraint naming conventions that use column
     names/keys/etc as part of the convention.  In particular, this
     includes that the PrimaryKeyConstraint object that’s
     automatically associated with a Table will update its
     name as new primary key Column objects are added to the
     table and then to the constraint.  Internal failure modes related
     to this constraint construction process including no columns
     present, no name present or blank name present are now
     accommodated.

     References: #5919(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5919

8.3.2.6 postgresql
..................

   * `[postgresql] [bug]' ¶. Fixed issue where using
     aggregate_order_by would return ARRAY(NullType) under
     certain conditions, interfering with the ability of the result
     object to return data correctly.

     References: #5989(1)

   * `[postgresql] [bug] [types]' ¶. Adjusted the psycopg2
     dialect to emit an explicit PostgreSQL-style cast for bound
     parameters that contain ARRAY elements.  This allows the full range
     of datatypes to function correctly within arrays.  The asyncpg
     dialect already generated these internal casts in the final
     statement.  This also includes support for array slice updates as
     well as the PostgreSQL-specific ‘ARRAY.contains()’ method.

     References: #6023(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5989

   (2) http://www.sqlalchemy.org/trac/ticket/6023

8.3.2.7 1.3.23
..............

Released: February 1, 2021

8.3.2.8 sql
...........

   * `[sql] [bug]' ¶. Fixed bug where making use of the
     TypeEngine.with_variant() method on a
     TypeDecorator type would fail to take into account the
     dialect-specific mappings in use, due to a rule in
     TypeDecorator that was instead attempting to check for
     chains of TypeDecorator instances.

     References: #5816(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5816

8.3.2.9 postgresql
..................

   * `[postgresql] [bug]' ¶. For SQLAlchemy 1.3 only,
     setup.py pins pg8000 to a version lower than 1.16.6.  Version
     1.16.6 and above is supported by SQLAlchemy 1.4.  Pull request
     courtesy Giuseppe Lumia.

     References: #5645(1)

   * `[postgresql] [bug]' ¶. Fixed issue where using
     Table.to_metadata(). (called Table.tometadata()
     in 1.3) in conjunction with a PostgreSQL ExcludeConstraint
     that made use of ad-hoc column expressions would fail to copy
     correctly.

     References: #5850(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5645

   (2) http://www.sqlalchemy.org/trac/ticket/5850

8.3.2.10 mysql
..............

   * `[mysql] [usecase]' ¶. Casting to ‘FLOAT’ is now
     supported in MySQL >= (8, 0, 17) and MariaDb >= (10, 4, 5).

     References: #5808(1)

   * `[mysql] [bug] [reflection]' ¶. Fixed bug where MySQL
     server default reflection would fail for numeric values with a
     negation symbol present.

     References: #5860(2)

   * `[mysql] [bug]' ¶. Fixed long-lived bug in MySQL
     dialect where the maximum identifier length of 255 was too long for
     names of all types of constraints, not just indexes, all of which
     have a size limit of 64.  As metadata naming conventions can create
     too-long names in this area, apply the limit to the identifier
     generator within the DDL compiler.

     References: #5898(3)

   * `[mysql] [bug]' ¶. Fixed deprecation warnings that
     arose as a result of the release of PyMySQL 1.0, including
     deprecation warnings for the “db” and “passwd” parameters now
     replaced with “database” and “password”.

     References: #5821(4)

   * `[mysql] [bug]' ¶. Fixed regression from SQLAlchemy
     1.3.20 caused by the fix for #5462(5) which adds double-parenthesis
     for MySQL functional expressions in indexes, as is required by the
     backend, this inadvertently extended to include arbitrary
     text() expressions as well as Alembic’s internal textual
     component, which are required by Alembic for arbitrary index
     expressions which don’t imply double parenthesis.  The check has
     been narrowed to include only binary/ unary/functional expressions
     directly.

     References: #5800(6)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5808

   (2) http://www.sqlalchemy.org/trac/ticket/5860

   (3) http://www.sqlalchemy.org/trac/ticket/5898

   (4) http://www.sqlalchemy.org/trac/ticket/5821

   (5) http://www.sqlalchemy.org/trac/ticket/5462

   (6) http://www.sqlalchemy.org/trac/ticket/5800

8.3.2.11 oracle
...............

   * `[oracle] [bug]' ¶. Fixed regression in Oracle dialect
     introduced by #4894(1) in SQLAlchemy 1.3.11 where use of a SQL
     expression in RETURNING for an UPDATE would fail to compile, due to
     a check for “server_default” when an arbitrary SQL expression is
     not a column.

     References: #5813(2)

   * `[oracle] [bug]' ¶. Fixed bug in Oracle dialect where
     retriving a CLOB/BLOB column via Insert.returning()
     would fail as the LOB value would need to be read when returned;
     additionally, repaired support for retrieval of Unicode values via
     RETURNING under Python 2.

     References: #5812(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4894

   (2) http://www.sqlalchemy.org/trac/ticket/5813

   (3) http://www.sqlalchemy.org/trac/ticket/5812

8.3.2.12 misc
.............

   * `[bug] [ext]' ¶. Fixed issue where the stringification
     that is sometimes called when attempting to generate the “key” for
     the ‘.c’ collection on a selectable would fail if the column were
     an unlabeled custom SQL construct using the
     ‘sqlalchemy.ext.compiler’ extension, and did not provide a default
     compilation form; while this seems like an unusual case, it can get
     invoked for some ORM scenarios such as when the expression is used
     in an “order by” in combination with joined eager loading.  The
     issue is that the lack of a default compiler function was raising
     CompileError and not UnsupportedCompilationError.

     References: #5836(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5836

8.3.2.13 1.3.22
...............

Released: December 18, 2020

8.3.2.14 oracle
...............

   * `[oracle] [bug]' ¶. Fixed regression which occured due
     to #5755(1) which implemented isolation level support for Oracle.
     It has been reported that many Oracle accounts don’t actually have
     permission to query the ‘v$transaction’ view so this feature has
     been altered to gracefully fallback when it fails upon database
     connect, where the dialect will assume “READ COMMITTED” is the
     default isolation level as was the case prior to SQLAlchemy 1.3.21.
     However, explicit use of the
     Connection.get_isolation_level() method must now necessarily
     raise an exception, as Oracle databases with this restriction
     explicitly disallow the user from reading the current isolation
     level.

     References: #5784(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5755

   (2) http://www.sqlalchemy.org/trac/ticket/5784

8.3.2.15 1.3.21
...............

Released: December 17, 2020

8.3.2.16 orm
............

   * `[orm] [bug]' ¶. Added a comprehensive check and an
     informative error message for the case where a mapped class, or a
     string mapped class name, is passed to
     relationship.secondary.  This is an extremely common error
     which warrants a clear message.

     Additionally, added a new rule to the class registry resolution
     such that with regards to the relationship.secondary
     parameter, if a mapped class and its table are of the identical
     string name, the Table will be favored when resolving
     this parameter.  In all other cases, the class continues to be
     favored if a class and table share the identical name.

     References: #5774(1)

   * `[orm] [bug]' ¶. Fixed bug in Query.update()
     where objects in the ‘_ormsession.Session’ that were already
     expired would be unnecessarily SELECTed individually when they were
     refreshed by the “evaluate”synchronize strategy.

     References: #5664(2)

   * `[orm] [bug]' ¶. Fixed bug involving the
     ‘restore_load_context’ option of ORM events such as
     ‘InstanceEvents.load()’ such that the flag would not be carried
     along to subclasses which were mapped after the event handler were
     first established.

     References: #5737(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5774

   (2) http://www.sqlalchemy.org/trac/ticket/5664

   (3) http://www.sqlalchemy.org/trac/ticket/5737

8.3.2.17 sql
............

   * `[sql] [bug]' ¶. A warning is emmitted if a returning()
     method such as Insert.returning() is called multiple
     times, as this does not yet support additive operation.  Version
     1.4 will support additive operation for this.  Additionally, any
     combination of the Insert.returning() and
     ValuesBase.return_defaults() methods now raises an error as
     these methods are mutually exclusive; previously the operation
     would fail silently.

     References: #5691(1)

   * `[sql] [bug]' ¶. Fixed structural compiler issue where
     some constructs such as MySQL / PostgreSQL “on conflict / on
     duplicate key” would rely upon the state of the ‘Compiler’ object
     being fixed against their statement as the top level statement,
     which would fail in cases where those statements are branched from
     a different context, such as a DDL construct linked to a SQL
     statement.

     References: #5656(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5691

   (2) http://www.sqlalchemy.org/trac/ticket/5656

8.3.2.18 postgresql
...................

   * `[postgresql] [usecase]' ¶. Added new parameter
     ExcludeConstraint.ops to the ExcludeConstraint
     object, to support operator class specification with this
     constraint.  Pull request courtesy Alon Menczer.

     References: #5604(1)

   * `[postgresql] [bug] [mysql]' ¶. Fixed regression
     introduced in 1.3.2 for the PostgreSQL dialect, also copied out to
     the MySQL dialect’s feature in 1.3.18, where usage of a non
     Table construct such as text() as the argument to
     Select.with_for_update.of would fail to be accommodated
     correctly within the PostgreSQL or MySQL compilers.

     References: #5729(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5604

   (2) http://www.sqlalchemy.org/trac/ticket/5729

8.3.2.19 mysql
..............

   * `[mysql] [bug] [reflection]' ¶. Fixed issue where
     reflecting a server default on MariaDB only that contained a
     decimal point in the value would fail to be reflected correctly,
     leading towards a reflected table that lacked any server default.

     References: #5744(1)

   * `[mysql] [sql]' ¶. Added missing keywords to the
     ‘RESERVED_WORDS’ list for the MySQL dialect: ‘action’, ‘level’,
     ‘mode’, ‘status’, ‘text’, ‘time’.  Pull request courtesy Oscar
     Batori.

     References: #5696(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5744

   (2) http://www.sqlalchemy.org/trac/ticket/5696

8.3.2.20 sqlite
...............

   * `[sqlite] [usecase]' ¶. Added ‘sqlite_with_rowid=False’
     dialect keyword to enable creating tables as ‘CREATE TABLE …
     WITHOUT ROWID’.  Patch courtesy Sean Anderson.

     References: #5685(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5685

8.3.2.21 mssql
..............

   * `[mssql] [bug]' ¶. Fixed bug where a CREATE INDEX
     statement was rendered incorrectly when both ‘mssql-include’ and
     ‘mssql_where’ were specified.  Pull request courtesy @Adiorz.

     References: #5751(1)

   * `[mssql] [bug]' ¶. Added SQL Server code “01000” to the
     list of disconnect codes.

     References: #5646(2)

   * `[mssql] [reflection] [sqlite]' ¶. Fixed issue with
     composite primary key columns not being reported in the correct
     order.  Patch courtesy @fulpm.

     References: #5661(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5751

   (2) http://www.sqlalchemy.org/trac/ticket/5646

   (3) http://www.sqlalchemy.org/trac/ticket/5661

8.3.2.22 oracle
...............

   * `[oracle] [usecase]' ¶. Implemented support for the
     SERIALIZABLE isolation level for Oracle databases, as well as a
     real implementation for Connection.get_isolation_level().

     See also
     ........

     See Transaction Isolation Level / Autocommit.

     References: #5755(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5755

8.3.2.23 1.3.20
...............

Released: October 12, 2020

8.3.2.24 orm
............

   * `[orm] [bug]' ¶. An ArgumentError with more
     detail is now raised if the target parameter for
     Query.join() is set to an unmapped object.  Prior to this
     change a less detailed ‘AttributeError’ was raised.  Pull request
     courtesy Ramon Williams.

     References: #4428(1)

   * `[orm] [bug]' ¶. Fixed issue where using a loader
     option against a string attribute name that is not actually a
     mapped attribute, such as a plain Python descriptor, would raise an
     uninformative AttributeError; a descriptive error is now raised.

     References: #4589(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4428

   (2) http://www.sqlalchemy.org/trac/ticket/4589

8.3.2.25 engine
...............

   * `[engine] [bug]' ¶. Fixed issue where a non-string
     object sent to SQLAlchemyError or a subclass, as
     occurs with some third party dialects, would fail to stringify
     correctly.  Pull request courtesy Andrzej Bartosiński.

     References: #5599(1)

   * `[engine] [bug]' ¶. Repaired a function-level import
     that was not using SQLAlchemy’s standard late-import system within
     the sqlalchemy.exc module.

     References: #5632(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5599

   (2) http://www.sqlalchemy.org/trac/ticket/5632

8.3.2.26 sql
............

   * `[sql] [bug]' ¶. Fixed issue where the ‘pickle.dumps()’
     operation against Over construct would produce a
     recursion overflow.

     References: #5644(1)

   * `[sql] [bug]' ¶. Fixed bug where an error was not
     raised in the case where a column() were added to more
     than one table() at a time.  This raised correctly for
     the Column and Table objects.  An
     ArgumentError is now raised when this occurs.

     References: #5618(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5644

   (2) http://www.sqlalchemy.org/trac/ticket/5618

8.3.2.27 postgresql
...................

   * `[postgresql] [usecase]' ¶. The psycopg2 dialect now
     support PostgreSQL multiple host connections, by passing host/port
     combinations to the query string.  Pull request courtesy Ramon
     Williams.

     See also
     ........

     See Specifiying multiple fallback hosts.

     References: #4392(1)

   * `[postgresql] [bug]' ¶. Adjusted the
     Comparator.any() and Comparator.all() methods to
     implement a straight “NOT” operation for negation, rather than
     negating the comparison operator.

     References: #5518(2)

   * `[postgresql] [bug]' ¶. Fixed issue where the
     ENUM type would not consult the schema translate map when
     emitting a CREATE TYPE or DROP TYPE during the test to see if the
     type exists or not.  Additionally, repaired an issue where if the
     same enum were encountered multiple times in a single DDL sequence,
     the “check” query would run repeatedly rather than relying upon a
     cached value.

     References: #5520(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4392

   (2) http://www.sqlalchemy.org/trac/ticket/5518

   (3) http://www.sqlalchemy.org/trac/ticket/5520

8.3.2.28 mysql
..............

   * `[mysql] [usecase]' ¶. Adjusted the MySQL dialect to
     correctly parenthesize functional index expressions as accepted by
     MySQL 8.  Pull request courtesy Ramon Williams.

     References: #5462(1)

   * `[mysql] [change]' ¶. Add new MySQL reserved words:
     ‘cube’, ‘lateral’ added in MySQL 8.0.1 and 8.0.14, respectively;
     this indicates that these terms will be quoted if used as table or
     column identifier names.

     References: #5539(2)

   * `[mysql] [bug]' ¶. The “skip_locked” keyword used with
     ‘with_for_update()’ will emit a warning when used on MariaDB
     backends, and will then be ignored.  This is a deprecated behavior
     that will raise in SQLAlchemy 1.4, as an application that requests
     “skip locked” is looking for a non-blocking operation which is not
     available on those backends.

     References: #5568(3)

   * `[mysql] [bug]' ¶. Fixed bug where an UPDATE statement
     against a JOIN using MySQL multi-table format would fail to include
     the table prefix for the target table if the statement had no WHERE
     clause, as only the WHERE clause were scanned to detect a “multi
     table update” at that particular point.  The target is now also
     scanned if it’s a JOIN to get the leftmost table as the primary
     table and the additional entries as additional FROM entries.

     References: #5617(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5462

   (2) http://www.sqlalchemy.org/trac/ticket/5539

   (3) http://www.sqlalchemy.org/trac/ticket/5568

   (4) http://www.sqlalchemy.org/trac/ticket/5617

8.3.2.29 mssql
..............

   * `[mssql] [bug]' ¶. Fixed issue where a SQLAlchemy
     connection URI for Azure DW with
     ‘authentication=ActiveDirectoryIntegrated’ (and no
     username+password) was not constructing the ODBC connection string
     in a way that was acceptable to the Azure DW instance.

     References: #5592(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5592

8.3.2.30 misc
.............

   * `[bug] [pool]' ¶. Fixed issue where the following pool
     parameters were not being propagated to the new pool created when
     Engine.dispose() were called: ‘pre_ping’, ‘use_lifo’.
     Additionally the ‘recycle’ and ‘reset_on_return’ parameter is now
     propagated for the ‘AssertionPool’ class.

     References: #5582(1)

   * `[bug] [associationproxy] [ext]' ¶. An informative
     error is now raised when attempting to use an association proxy
     element as a plain column expression to be SELECTed from or used in
     a SQL function; this use case is not currently supported.

     References: #5541(2), #5542(3)

   * `[bug] [tests]' ¶. Fixed incompatibilities in the test
     suite when running against Pytest 6.x.

     References: #5635(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5582

   (2) http://www.sqlalchemy.org/trac/ticket/5541

   (3) http://www.sqlalchemy.org/trac/ticket/5542

   (4) http://www.sqlalchemy.org/trac/ticket/5635

8.3.2.31 1.3.19
...............

Released: August 17, 2020

8.3.2.32 orm
............

   * `[orm] [usecase]' ¶. Adjusted the workings of the
     Mapper.all_orm_descriptors() accessor to represent the
     attributes in the order that they are located in a deterministic
     way, assuming the use of Python 3.6 or higher which maintains the
     sorting order of class attributes based on how they were declared.
     This sorting is not guaranteed to match the declared order of
     attributes in all cases however; see the method documentation for
     the exact scheme.

     References: #5494(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5494

8.3.2.33 orm declarative
........................

   * `[orm] [declarative] [usecase]' ¶. The name of the
     virtual column used when using the AbstractConcreteBase
     and ConcreteBase classes can now be customized, to
     allow for models that have a column that is actually named ‘type’.
     Pull request courtesy Jesse-Bakker.

     References: #5513(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5513

8.3.2.34 sql
............

   * `[sql] [bug]' ¶. Repaired an issue where the “ORDER BY”
     clause rendering a label name rather than a complete expression,
     which is particularly important for SQL Server, would fail to occur
     if the expression were enclosed in a parenthesized grouping in some
     cases.  This case has been added to test support.  The change
     additionally adjusts the “automatically add ORDER BY columns when
     DISTINCT is present” behavior of ORM query, deprecated in 1.4, to
     more accurately detect column expressions that are already present.

     References: #5470(1)

   * `[sql] [bug] [datatypes]' ¶. The ‘LookupError’ message
     will now provide the user with up to four possible values that a
     column is constrained to via the Enum.  Values longer
     than 11 characters will be truncated and replaced with ellipses.
     Pull request courtesy Ramon Williams.

     References: #4733(2)

   * `[sql] [bug]' ¶. Fixed issue where the
     Connection.execution_options.schema_translate_map feature
     would not take effect when the Sequence.next_value()
     function function for a Sequence were used in the
     Column.server_default parameter and the create table DDL were
     emitted.

     References: #5500(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5470

   (2) http://www.sqlalchemy.org/trac/ticket/4733

   (3) http://www.sqlalchemy.org/trac/ticket/5500

8.3.2.35 postgresql
...................

   * `[postgresql] [bug]' ¶. Fixed issue where the return
     type for the various RANGE comparison operators would itself be the
     same RANGE type rather than BOOLEAN, which would cause an
     undesirable result in the case that a TypeDecorator
     that defined result-processing behavior were in use.  Pull request
     courtesy Jim Bosch.

     References: #5476(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5476

8.3.2.36 mysql
..............

   * `[mysql] [usecase]' ¶. The MySQL dialect will render
     FROM DUAL for a SELECT statement that has no FROM clause but has a
     WHERE clause.  This allows things like “SELECT 1 WHERE EXISTS
     (subquery)” kinds of queries to be used as well as other use cases.

     References: #5481(1)

   * `[mysql] [bug]' ¶. Fixed an issue where CREATE TABLE
     statements were not specifying the COLLATE keyword correctly.

     References: #5411(2)

   * `[mysql] [bug]' ¶. Added MariaDB code 1927 to the list
     of “disconnect” codes, as recent MariaDB versions apparently use
     this code when the database server was stopped.

     References: #5493(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5481

   (2) http://www.sqlalchemy.org/trac/ticket/5411

   (3) http://www.sqlalchemy.org/trac/ticket/5493

8.3.2.37 sqlite
...............

   * `[sqlite] [bug] [mssql] [reflection]' ¶. Applied a
     sweep through all included dialects to ensure names that contain
     single or double quotes are properly escaped when querying system
     tables, for all Inspector methods that accept object
     names as an argument (e.g.  table names, view names, etc).  SQLite
     and MSSQL contained two quoting issues that were repaired.

     References: #5456(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5456

8.3.2.38 mssql
..............

   * `[mssql] [bug] [sql]' ¶. Fixed bug where the mssql
     dialect incorrectly escaped object names that contained ‘]’
     character(s).

     References: #5467(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5467

8.3.2.39 misc
.............

   * `[usecase] [py3k]' ¶. Added a ‘**kw’ argument to the
     ‘DeclarativeMeta.__init__()’ method.  This allows a class to
     support the PEP 487(1) metaclass hook ‘__init_subclass__’.  Pull
     request courtesy Ewen Gillies.

     References: ##5357(2)

   ---------- Footnotes ----------

   (1) https://www.python.org/dev/peps/pep-0487

   (2) http://www.sqlalchemy.org/trac/ticket/#5357

8.3.2.40 1.3.18
...............

Released: June 25, 2020

8.3.2.41 orm
............

   * `[orm] [usecase]' ¶. Improve error message when using
     Query.filter_by() in a query where the first entity is
     not a mapped class.

     References: #5326(1)

   * `[orm] [usecase]' ¶. Added a new parameter
     query_expression.default_expr to the
     query_expression() construct, which will be appled to queries
     automatically if the with_expression() option is not
     used.  Pull request courtesy Haoyu Sun.

     References: #5198(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5326

   (2) http://www.sqlalchemy.org/trac/ticket/5198

8.3.2.42 engine
...............

   * `[engine] [bug]' ¶. Further refinements to the fixes to
     the “reset” agent fixed in #5326(1), which now emits a warning when
     it is not being correctly invoked and corrects for the behavior.
     Additional scenarios have been identified and fixed where this
     warning was being emitted.

     References: #5326(2)

   * `[engine] [bug]' ¶. Fixed issue in URL.
     object where stringifying the object would not URL encode special
     characters, preventing the URL from being re-consumable as a real
     URL. Pull request courtesy Miguel Grinberg.

     References: #5341(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5326

   (2) http://www.sqlalchemy.org/trac/ticket/5326

   (3) http://www.sqlalchemy.org/trac/ticket/5341

8.3.2.43 sql
............

   * `[sql] [usecase]' ¶. Added a “.schema” parameter to the
     table() construct, allowing ad-hoc table expressions to
     also include a schema name.  Pull request courtesy Dylan Modesitt.

     References: #5309(1)

   * `[sql] [change] [sybase]' ¶. Added ‘.offset’ support to
     sybase dialect.  Pull request courtesy Alan D. Snow.

     References: #5294(2)

   * `[sql] [bug]' ¶. Correctly apply self_group in
     type_coerce element.

     The type coerce element did not correctly apply grouping rules when
     using in an expression

     References: #5344(3)

   * `[sql] [bug]' ¶. Added Select.with_hint().
     output to the generic SQL string that is produced when calling
     ‘str()’ on a statement.  Previously, this clause would be omitted
     under the assumption that it was dialect specific.  The hint text
     is presented within brackets to indicate the rendering of such
     hints varies among backends.

     References: #5353(4)

   * `[sql] [schema]' ¶. Introduce ‘IdentityOptions’ to
     store common parameters for sequences and identity columns.

     References: #5324(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5309

   (2) http://www.sqlalchemy.org/trac/ticket/5294

   (3) http://www.sqlalchemy.org/trac/ticket/5344

   (4) http://www.sqlalchemy.org/trac/ticket/5353

   (5) http://www.sqlalchemy.org/trac/ticket/5324

8.3.2.44 schema
...............

   * `[schema] [bug]' ¶. Fixed issue where ‘dialect_options’
     were omitted when a database object (e.g., see Table) was
     copied using ‘tometadata()’.

     References: #5276(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5276

8.3.2.45 mysql
..............

   * `[mysql] [usecase]' ¶. Implemented row-level locking
     support for mysql.  Pull request courtesy Quentin Somerville.

     References: #4860(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4860

8.3.2.46 sqlite
...............

   * `[sqlite] [usecase]' ¶. SQLite 3.31 added support for
     computed column.  This change enables their support in SQLAlchemy
     when targeting SQLite.

     References: #5297(1)

   * `[sqlite] [bug]' ¶. Added “exists” to the list of
     reserved words for SQLite so that this word will be quoted when
     used as a label or column name.  Pull request courtesy Thodoris
     Sotiropoulos.

     References: #5395(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5297

   (2) http://www.sqlalchemy.org/trac/ticket/5395

8.3.2.47 mssql
..............

   * `[mssql] [change]' ¶. Moved the
     ‘supports_sane_rowcount_returning = False’ requirement from the
     ‘PyODBCConnector’ level to the ‘MSDialect_pyodbc’ since pyodbc does
     work properly in some circumstances.

     References: #5321(1)

   * `[mssql] [bug]' ¶. Refined the logic used by the SQL
     Server dialect to interpret multi-part schema names that contain
     many dots, to not actually lose any dots if the name does not have
     bracking or quoting used, and additionally to support a “dbname”
     token that has many parts including that it may have multiple,
     independently-bracketed sections.

     References: #5364(2), #5366(3)

   * `[mssql] [bug] [pyodbc]' ¶. Fixed an issue in the
     pyodbc connector such that a warning about pyodbc “drivername”
     would be emitted when using a totally empty URL. Empty URLs are
     normal when producing a non-connected dialect object or when using
     the “creator” argument to create_engine().  The warning now only
     emits if the driver name is missing but other parameters are still
     present.

     References: #5346(4)

   * `[mssql] [bug]' ¶. Fixed issue with assembling the ODBC
     connection string for the pyodbc DBAPI. Tokens containing
     semicolons and/or braces “{}” were not being correctly escaped,
     causing the ODBC driver to misinterpret the connection string
     attributes.

     References: #5373(5)

   * `[mssql] [bug]' ¶. Fixed issue where ‘datetime.time’
     parameters were being converted to ‘datetime.datetime’, making them
     incompatible with comparisons like ‘>=’ against an actual
     TIME column.

     References: #5339(6)

   * `[mssql] [bug]' ¶. Fixed an issue where the
     ‘is_disconnect’ function in the SQL Server pyodbc dialect was
     incorrectly reporting the disconnect state when the exception
     messsage had a substring that matched a SQL Server ODBC error code.

     References: #5359(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5321

   (2) http://www.sqlalchemy.org/trac/ticket/5364

   (3) http://www.sqlalchemy.org/trac/ticket/5366

   (4) http://www.sqlalchemy.org/trac/ticket/5346

   (5) http://www.sqlalchemy.org/trac/ticket/5373

   (6) http://www.sqlalchemy.org/trac/ticket/5339

   (7) http://www.sqlalchemy.org/trac/ticket/5359

8.3.2.48 oracle
...............

   * `[oracle] [bug] [reflection]' ¶. Fixed bug in Oracle
     dialect where indexes that contain the full set of primary key
     columns would be mistaken as the primary key index itself, which is
     omitted, even if there were multiples.  The check has been refined
     to compare the name of the primary key constraint against the index
     name itself, rather than trying to guess based on the columns
     present in the index.

     References: #5421(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5421

8.3.2.49 misc
.............

   * `[change] [examples]' ¶. Added new option ‘--raw’ to
     the examples.performance suite which will dump the raw profile test
     for consumption by any number of profiling visualizer tools.
     Removed the “runsnake” option as runsnake is very hard to build at
     this point;

8.3.2.50 1.3.17
...............

Released: May 13, 2020

8.3.2.51 orm
............

   * `[orm] [usecase]' ¶. Added an accessor
     Comparator.expressions which provides access to the group of
     columns mapped under a multi-column ColumnProperty
     attribute.

     References: #5262(1)

   * `[orm] [usecase]' ¶. Introduce
     relationship.sync_backref flag in a relationship to control
     if the synchronization events that mutate the in-Python attributes
     are added.  This supersedes the previous change #5149(2), which
     warned that ‘viewonly=True’ relationship target of a back_populates
     or backref configuration would be disallowed.

     References: #5237(3)

   * `[orm] [bug]' ¶. Fixed bug where using
     with_polymorphic() as the target of a join via
     ‘RelationshipComparator.of_type()’ on a mapper that already has a
     subquery-based with_polymorphic setting that’s equivalent to the
     one requested would not correctly alias the ON clause in the join.

     References: #5288(4)

   * `[orm] [bug]' ¶. Fixed issue in the area of where
     loader options such as selectinload() interact with the baked query
     system, such that the caching of a query is not supposed to occur
     if the loader options themselves have elements such as
     with_polymorphic() objects in them that currently are not
     cache-compatible.  The baked loader could sometimes not fully
     invalidate itself in these some of these scenarios leading to
     missed eager loads.

     References: #5303(5)

   * `[orm] [bug]' ¶. Modified the internal “identity set”
     implementation, which is a set that hashes objects on their id()
     rather than their hash values, to not actually call the
     ‘__hash__()’ method of the objects, which are typically user-mapped
     objects.  Some methods were calling this method as a side effect of
     the implementation.

     References: #5304(6)

   * `[orm] [bug]' ¶. An informative error message is raised
     when an ORM many-to-one comparison is attempted against an object
     that is not an actual mapped instance.  Comparisons such as those
     to scalar subqueries aren’t supported; generalized comparison with
     subqueries is better achieved using Comparator.has().

     References: #5269(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5262

   (2) http://www.sqlalchemy.org/trac/ticket/5149

   (3) http://www.sqlalchemy.org/trac/ticket/5237

   (4) http://www.sqlalchemy.org/trac/ticket/5288

   (5) http://www.sqlalchemy.org/trac/ticket/5303

   (6) http://www.sqlalchemy.org/trac/ticket/5304

   (7) http://www.sqlalchemy.org/trac/ticket/5269

8.3.2.52 engine
...............

   * `[engine] [bug]' ¶. Fixed fairly critical issue where
     the DBAPI connection could be returned to the connection pool while
     still in an un-rolled-back state.  The reset agent responsible for
     rolling back the connection could be corrupted in the case that the
     transaction was “closed” without being rolled back or committed,
     which can occur in some scenarios when using ORM sessions and
     emitting .close() in a certain pattern involving savepoints.  The
     fix ensures that the reset agent is always active.

     References: #5326(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5326

8.3.2.53 schema
...............

   * `[schema] [bug]' ¶. Fixed issue where an Index
     that is deferred in being associated with a table, such as as
     when it contains a Column that is not associated with
     any Table yet, would fail to attach correctly if it also
     contained a non table-oriented expression.

     References: #5298(1)

   * `[schema] [bug]' ¶. A warning is emitted when making
     use of the MetaData.sorted_tables attribute as well as
     the sort_tables() function, and the given tables
     cannot be correctly sorted due to a cyclic dependency between
     foreign key constraints.  In this case, the functions will no
     longer sort the involved tables by foreign key, and a warning will
     be emitted.  Other tables that are not part of the cycle will still
     be returned in dependency order.  Previously, the sorted_table
     routines would return a collection that would unconditionally omit
     all foreign keys when a cycle was detected, and no warning was
     emitted.

     References: #5316(2)

   * `[schema]' ¶. Add ‘comment’ attribute to Column.
     ‘__repr__’ method.

     References: #4138(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5298

   (2) http://www.sqlalchemy.org/trac/ticket/5316

   (3) http://www.sqlalchemy.org/trac/ticket/4138

8.3.2.54 postgresql
...................

   * `[postgresql] [usecase]' ¶. Added support for columns
     or type ARRAY of Enum, JSON or
     JSONB in PostgreSQL. Previously a workaround was
     required in these use cases.

     References: #5265(1)

   * `[postgresql] [usecase]' ¶. Raise an explicit
     CompileError when adding a table with a column of type
     ARRAY of Enum configured with
     Enum.native_enum set to ‘False’ when
     Enum.create_constraint is not set to ‘False’

     References: #5266(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5265

   (2) http://www.sqlalchemy.org/trac/ticket/5266

8.3.2.55 mssql
..............

   * `[mssql] [bug] [reflection]' ¶. Fix a regression
     introduced by the reflection of computed column in MSSQL when using
     the legacy TDS version 4.2.  The dialect will try to detect the
     protocol version of first connect and run in compatibility mode if
     it cannot detect it.

     References: #5255(1)

   * `[mssql] [bug] [reflection]' ¶. Fix a regression
     introduced by the reflection of computed column in MSSQL when using
     SQL server versions before 2012, which does not support the
     ‘concat’ function.

     References: #5271(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5255

   (2) http://www.sqlalchemy.org/trac/ticket/5271

8.3.2.56 oracle
...............

   * `[oracle] [performance] [bug]' ¶. Changed the
     implementation of fetching CLOB and BLOB objects to use cx_Oracle’s
     native implementation which fetches CLOB/BLOB objects inline with
     other result columns, rather than performing a separate fetch.  As
     always, this can be disabled by setting auto_convert_lobs to False.

     As part of this change, the behavior of a CLOB that was given a
     blank string on INSERT now returns None on SELECT, which is now
     consistent with that of VARCHAR on Oracle.

     References: #5314(1)

   * `[oracle] [bug]' ¶. Some modifications to how the
     cx_oracle dialect sets up per-column outputtype handlers for LOB
     and numeric datatypes to adjust for potential changes coming in
     cx_Oracle 8.

     References: #5246(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5314

   (2) http://www.sqlalchemy.org/trac/ticket/5246

8.3.2.57 firebird
.................

   * `[firebird] [change]' ¶. Adjusted dialect loading for
     ‘firebird://’ URIs so the external sqlalchemy-firebird dialect will
     be used if it has been installed, otherwise fall back to the (now
     deprecated) internal Firebird dialect.

     References: #5278(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5278

8.3.2.58 1.3.16
...............

Released: April 7, 2020

8.3.2.59 orm
............

   * `[orm] [performance]' ¶. Modified the queries used by
     subqueryload and selectinload to no longer ORDER BY the primary key
     of the parent entity; this ordering was there to allow the rows as
     they come in to be copied into lists directly with a minimal level
     of Python-side collation.  However, these ORDER BY clauses can
     negatively impact the performance of the query as in many scenarios
     these columns are derived from a subquery or are otherwise not
     actual primary key columns such that SQL planners cannot make use
     of indexes.  The Python-side collation uses the native
     itertools.group_by() to collate the incoming rows, and has been
     modified to allow multiple row-groups-per-parent to be assembled
     together using list.extend(), which should still allow for
     relatively fast Python-side performance.  There will still be an
     ORDER BY present for a relationship that includes an explicit
     order_by parameter, however this is the only ORDER BY that will be
     added to the query for both kinds of loading.

     References: #5162(1)

   * `[orm] [bug]' ¶. Fixed bug in selectinload()
     loading option where two or more loaders that represent
     different relationships with the same string key name as referenced
     from a single with_polymorphic() construct with
     multiple subclass mappers would fail to invoke each subqueryload
     separately, instead making use of a single string-based slot that
     would prevent the other loaders from being invoked.

     References: #5228(2)

   * `[orm] [bug]' ¶. Fixed issue where a lazyload that uses
     session-local “get” against a target many-to-one relationship where
     an object with the correct primary key is present, however it’s an
     instance of a sibling class, does not correctly return None as is
     the case when the lazy loader actually emits a load for that row.

     References: #5210(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5162

   (2) http://www.sqlalchemy.org/trac/ticket/5228

   (3) http://www.sqlalchemy.org/trac/ticket/5210

8.3.2.60 orm declarative
........................

   * `[orm] [declarative] [bug]' ¶. The string argument
     accepted as the first positional argument by the
     relationship() function when using the Declarative API is no
     longer interpreted using the Python ‘eval()’ function; instead, the
     name is dot separated and the names are looked up directly in the
     name resolution dictionary without treating the value as a Python
     expression.  However, passing a string argument to the other
     relationship() parameters that necessarily must accept Python
     expressions will still use ‘eval()’; the documentation has been
     clarified to ensure that there is no ambiguity that this is in use.

     See also
     ........

     See Evaluation of relationship arguments. - details on
     string evaluation

     References: #5238(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5238

8.3.2.61 sql
............

   * `[sql] [types]' ¶. Add ability to literal compile a
     ‘DateTime’, ‘Date’ or ‘Time’ when using the string dialect for
     debugging purposes.  This change does not impact real dialect
     implementation that retain their current behavior.

     References: #5052(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5052

8.3.2.62 schema
...............

   * `[schema] [reflection]' ¶. Added support for reflection
     of “computed” columns, which are now returned as part of the
     structure returned by Inspector.get_columns().  When
     reflecting full Table objects, computed columns will be
     represented using the Computed construct.

     References: #5063(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5063

8.3.2.63 postgresql
...................

   * `[postgresql] [bug]' ¶. Fixed issue where a “covering”
     index, e.g.  those which have an INCLUDE clause, would be reflected
     including all the columns in INCLUDE clause as regular columns.  A
     warning is now emitted if these additional columns are detected
     indicating that they are currently ignored.  Note that full support
     for “covering” indexes is part of #4458(1).  Pull request courtesy
     Marat Sharafutdinov.

     References: #5205(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4458

   (2) http://www.sqlalchemy.org/trac/ticket/5205

8.3.2.64 mysql
..............

   * `[mysql] [bug]' ¶. Fixed issue in MySQL dialect when
     connecting to a pseudo-MySQL database such as that provided by
     ProxySQL, the up front check for isolation level when it returns no
     row will not prevent the dialect from continuing to connect.  A
     warning is emitted that the isolation level could not be detected.

     References: #5239(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5239

8.3.2.65 sqlite
...............

   * `[sqlite] [usecase]' ¶. Implemented AUTOCOMMIT
     isolation level for SQLite when using pysqlite.

     References: #5164(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5164

8.3.2.66 mssql
..............

   * `[mssql] [usecase] [mysql] [oracle]' ¶. Added support
     for ColumnOperators.is_distinct_from() and
     ColumnOperators.isnot_distinct_from() to SQL Server, MySQL,
     and Oracle.

     References: #5137(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5137

8.3.2.67 oracle
...............

   * `[oracle] [usecase]' ¶. Implemented AUTOCOMMIT
     isolation level for Oracle when using cx_Oracle.  Also added a
     fixed default isolation level of READ COMMITTED for Oracle.

     References: #5200(1)

   * `[oracle] [bug] [reflection]' ¶. Fixed regression /
     incorrect fix caused by fix for #5146(2) where the Oracle dialect
     reads from the “all_tab_comments” view to get table comments but
     fails to accommodate for the current owner of the table being
     requested, causing it to read the wrong comment if multiple tables
     of the same name exist in multiple schemas.

     References: #5146(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5200

   (2) http://www.sqlalchemy.org/trac/ticket/5146

   (3) http://www.sqlalchemy.org/trac/ticket/5146

8.3.2.68 misc
.............

   * `[bug] [tests]' ¶. Fixed an issue that prevented the
     test suite from running with the recently released py.test 5.4.0.

     References: #5201(1)

   * `[enum] [types]' ¶. The Enum type now
     supports the parameter Enum.length to specify the
     length of the VARCHAR column to create when using non native enums
     by setting Enum.native_enum to ‘False’

     References: #5183(2)

   * `[installer]' ¶. Ensured that the “pyproject.toml” file
     is not included in builds, as the presence of this file indicates
     to pip that a pep-517 installation process should be used.  As this
     mode of operation appears to be not well supported by current tools
     / distros, these problems are avoided within the scope of
     SQLAlchemy installation by omitting the file.

     References: #5207(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5201

   (2) http://www.sqlalchemy.org/trac/ticket/5183

   (3) http://www.sqlalchemy.org/trac/ticket/5207

8.3.2.69 1.3.15
...............

Released: March 11, 2020

8.3.2.70 orm
............

   * `[orm] [bug]' ¶. Adjusted the error message emitted by
     Query.join() when a left hand side can’t be located
     that the Query.select_from() method is the best way to
     resolve the issue.  Also, within the 1.3 series, used a
     deterministic ordering when determining the FROM clause from a
     given column entity passed to Query so that the same
     expression is determined each time.

     References: #5194(1)

   * `[orm] [bug]' ¶. Fixed regression in 1.3.14 due to
     #4849(2) where a sys.exc_info() call failed to be invoked correctly
     when a flush error would occur.  Test coverage has been added for
     this exception case.

     References: #5196(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5194

   (2) http://www.sqlalchemy.org/trac/ticket/4849

   (3) http://www.sqlalchemy.org/trac/ticket/5196

8.3.2.71 1.3.14
...............

Released: March 10, 2020

8.3.2.72 general
................

   * `[general] [bug] [py3k]' ¶. Applied an explicit “cause”
     to most if not all internally raised exceptions that are raised
     from within an internal exception catch, to avoid misleading
     stacktraces that suggest an error within the handling of an
     exception.  While it would be preferable to suppress the internally
     caught exception in the way that the ‘__suppress_context__’
     attribute would, there does not as yet seem to be a way to do this
     without suppressing an enclosing user constructed context, so for
     now it exposes the internally caught exception as the cause so that
     full information about the context of the error is maintained.

     References: #4849(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4849

8.3.2.73 orm
............

   * `[orm] [usecase]' ¶. Added a new flag
     InstanceEvents.restore_load_context and
     SessionEvents.restore_load_context which apply to the
     InstanceEvents.load(), InstanceEvents.refresh(),
     and SessionEvents.loaded_as_persistent() events, which
     when set will restore the “load context” of the object after the
     event hook has been called.  This ensures that the object remains
     within the “loader context” of the load operation that is already
     ongoing, rather than the object being transferred to a new load
     context due to refresh operations which may have occurred in the
     event.  A warning is now emitted when this condition occurs, which
     recommends use of the flag to resolve this case.  The flag is
     “opt-in” so that there is no risk introduced to existing
     applications.

     The change additionally adds support for the ‘raw=True’ flag to
     session lifecycle events.

     References: #5129(1)

   * `[orm] [bug]' ¶. Fixed regression caused in 1.3.13 by
     #5056(2) where a refactor of the ORM path registry system made it
     such that a path could no longer be compared to an empty tuple,
     which can occur in a particular kind of joined eager loading path.
     The “empty tuple” use case has been resolved so that the path
     registry is compared to a path registry in all cases; the
     ‘PathRegistry’ object itself now implements ‘__eq__()’ and
     ‘__ne__()’ methods which will take place for all equality
     comparisons and continue to succeed in the not anticipated case
     that a non- ‘PathRegistry’ object is compared, while emitting a
     warning that this object should not be the subject of the
     comparison.

     References: #5110(3)

   * `[orm] [bug]' ¶. Setting a relationship to
     viewonly=True which is also the target of a back_populates or
     backref configuration will now emit a warning and eventually be
     disallowed.  back_populates refers specifically to mutation of an
     attribute or collection, which is disallowed when the attribute is
     subject to viewonly=True.  The viewonly attribute is not subject to
     persistence behaviors which means it will not reflect correct
     results when it is locally mutated.

     References: #5149(4)

   * `[orm] [bug]' ¶. Fixed an additional regression in the
     same area as that of #5080(5) introduced in 1.3.0b3 via #4468(6)
     where the ability to create a joined option across a
     with_polymorphic() into a relationship against the base class
     of that with_polymorphic, and then further into regular mapped
     relationships would fail as the base class component would not add
     itself to the load path in a way that could be located by the
     loader strategy.  The changes applied in #5080(7) have been further
     refined to also accommodate this scenario.

     References: #5121(8)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5129

   (2) http://www.sqlalchemy.org/trac/ticket/5056

   (3) http://www.sqlalchemy.org/trac/ticket/5110

   (4) http://www.sqlalchemy.org/trac/ticket/5149

   (5) http://www.sqlalchemy.org/trac/ticket/5080

   (6) http://www.sqlalchemy.org/trac/ticket/4468

   (7) http://www.sqlalchemy.org/trac/ticket/5080

   (8) http://www.sqlalchemy.org/trac/ticket/5121

8.3.2.74 engine
...............

   * `[engine] [bug]' ¶. Expanded the scope of
     cursor/connection cleanup when a statement is executed to include
     when the result object fails to be constructed, or an
     after_cursor_execute() event raises an error, or autocommit /
     autoclose fails.  This allows the DBAPI cursor to be cleaned up on
     failure and for connectionless execution allows the connection to
     be closed out and returned to the connection pool, where previously
     it waiting until garbage collection would trigger a pool return.

     References: #5182(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5182

8.3.2.75 sql
............

   * `[sql] [bug] [postgresql]' ¶. Fixed bug where a CTE of
     an INSERT/UPDATE/DELETE that also uses RETURNING could then not be
     SELECTed from directly, as the internal state of the compiler would
     try to treat the outer SELECT as a DELETE statement itself and
     access nonexistent state.

     References: #5181(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5181

8.3.2.76 postgresql
...................

   * `[postgresql] [bug]' ¶. Fixed issue where the
     “schema_translate_map” feature would not work with a PostgreSQL
     native enumeration type (i.e.  see Enum, ENUM)
     in that while the “CREATE TYPE” statement would be emitted with the
     correct schema, the schema would not be rendered in the CREATE
     TABLE statement at the point at which the enumeration was
     referenced.

     References: #5158(1)

   * `[postgresql] [bug] [reflection]' ¶. Fixed bug where
     PostgreSQL reflection of CHECK constraints would fail to parse the
     constraint if the SQL text contained newline characters.  The
     regular expression has been adjusted to accommodate for this case.
     Pull request courtesy Eric Borczuk.

     References: #5170(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5158

   (2) http://www.sqlalchemy.org/trac/ticket/5170

8.3.2.77 mysql
..............

   * `[mysql] [bug]' ¶. Fixed issue in MySQL
     Insert.on_duplicate_key_update() construct where using a SQL
     function or other composed expression for a column argument would
     not properly render the ‘VALUES’ keyword surrounding the column
     itself.

     References: #5173(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5173

8.3.2.78 mssql
..............

   * `[mssql] [bug]' ¶. Fixed issue where the
     DATETIMEOFFSET type would not accommodate for the ‘None’
     value, introduced as part of the series of fixes for this type
     first introduced in #4983(1), #5045(2).  Additionally, added
     support for passing a backend-specific date formatted string
     through this type, as is typically allowed for date/time types on
     most other DBAPIs.

     References: #5132(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4983

   (2) http://www.sqlalchemy.org/trac/ticket/5045

   (3) http://www.sqlalchemy.org/trac/ticket/5132

8.3.2.79 oracle
...............

   * `[oracle] [bug]' ¶. Fixed a reflection bug where table
     comments could only be retrieved for tables actually owned by the
     user but not for tables visible to the user but owned by someone
     else.  Pull request courtesy Dave Hirschfeld.

     References: #5146(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5146

8.3.2.80 misc
.............

   * `[usecase] [ext]' ¶. Added keyword arguments to the
     MutableList.sort() function so that a key function as
     well as the “reverse” keyword argument can be provided.

     References: #5114(1)

   * `[performance] [bug]' ¶. Revised an internal change to
     the test system added as a result of #5085(2) where a
     testing-related module per dialect would be loaded unconditionally
     upon making use of that dialect, pulling in SQLAlchemy’s testing
     framework as well as the ORM into the module import space.  This
     would only impact initial startup time and memory to a modest
     extent, however it’s best that these additional modules aren’t
     reverse-dependent on straight Core usage.

     References: #5180(3)

   * `[bug] [installation]' ¶. Vendored the
     ‘inspect.formatannotation’ function inside of
     ‘sqlalchemy.util.compat’, which is needed for the vendored version
     of ‘inspect.formatargspec’.  The function is not documented in
     cPython and is not guaranteed to be available in future Python
     versions.

     References: #5138(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5114

   (2) http://www.sqlalchemy.org/trac/ticket/5085

   (3) http://www.sqlalchemy.org/trac/ticket/5180

   (4) http://www.sqlalchemy.org/trac/ticket/5138

8.3.2.81 1.3.13
...............

Released: January 22, 2020

8.3.2.82 orm
............

   * `[orm] [performance]' ¶. Identified a performance issue
     in the system by which a join is constructed based on a mapped
     relationship.  The clause adaption system would be used for the
     majority of join expressions including in the common case where no
     adaptation is needed.  The conditions under which this adaptation
     occur have been refined so that average non-aliased joins along a
     simple relationship without a “secondary” table use about 70% less
     function calls.

   * `[orm] [bug] [engine]' ¶. Added test support and
     repaired a wide variety of unnecessary reference cycles created for
     short-lived objects, mostly in the area of ORM queries.  Thanks
     much to Carson Ip for the help on this.

     References: #5050(1), #5056(2), #5071(3)

   * `[orm] [bug]' ¶. Fixed regression in loader options
     introduced in 1.3.0b3 via #4468(4) where the ability to create a
     loader option using PropComparator.of_type() targeting
     an aliased entity that is an inheriting subclass of the entity
     which the preceding relationship refers to would fail to produce a
     matching path.  See also #5082(5) fixed in this same release which
     involves a similar kind of issue.

     References: #5107(6)

   * `[orm] [bug]' ¶. Fixed regression in joined eager
     loading introduced in 1.3.0b3 via #4468(7) where the ability to
     create a joined option across a with_polymorphic() into
     a polymorphic subclass using ‘RelationshipProperty.of_type()’ and
     then further along regular mapped relationships would fail as the
     polymorphic subclass would not add itself to the load path in a way
     that could be located by the loader strategy.  A tweak has been
     made to resolve this scenario.

     References: #5082(8)

   * `[orm] [bug]' ¶. Repaired a warning in the ORM flush
     process that was not covered by test coverage when deleting objects
     that use the “version_id” feature.  This warning is generally
     unreachable unless using a dialect that sets the
     “supports_sane_rowcount” flag to False, which is not typically the
     case however is possible for some MySQL configurations as well as
     older Firebird drivers, and likely some third party dialects.

     References: #5068(9)

   * `[orm] [bug]' ¶. Fixed bug where usage of joined eager
     loading would not properly wrap the query inside of a subquery when
     Query.group_by() were used against the query.  When any
     kind of result-limiting approach is used, such as DISTINCT, LIMIT,
     OFFSET, joined eager loading embeds the row-limited query inside of
     a subquery so that the collection results are not impacted.  For
     some reason, the presence of GROUP BY was never included in this
     criterion, even though it has a similar effect as using DISTINCT.
     Additionally, the bug would prevent using GROUP BY at all for a
     joined eager load query for most database platforms which forbid
     non-aggregated, non-grouped columns from being in the query, as the
     additional columns for the joined eager load would not be accepted
     by the database.

     References: #5065(10)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5050

   (2) http://www.sqlalchemy.org/trac/ticket/5056

   (3) http://www.sqlalchemy.org/trac/ticket/5071

   (4) http://www.sqlalchemy.org/trac/ticket/4468

   (5) http://www.sqlalchemy.org/trac/ticket/5082

   (6) http://www.sqlalchemy.org/trac/ticket/5107

   (7) http://www.sqlalchemy.org/trac/ticket/4468

   (8) http://www.sqlalchemy.org/trac/ticket/5082

   (9) http://www.sqlalchemy.org/trac/ticket/5068

   (10) http://www.sqlalchemy.org/trac/ticket/5065

8.3.2.83 engine
...............

   * `[engine] [bug]' ¶. Fixed issue where the collection of
     value processors on a 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 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.

     References: #5048(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5048

8.3.2.84 sql
............

   * `[sql] [usecase]' ¶. A function created using
     GenericFunction can now specify that the name of the function
     should be rendered with or without quotes by assigning the
     quoted_name construct to the .name element of the object.
     Prior to 1.3.4, quoting was never applied to function names, and
     some quoting was introduced in #4467(1) but no means to force
     quoting for a mixed case name was available.  Additionally, the
     quoted_name construct when used as the name will
     properly register its lowercase name in the function registry so
     that the name continues to be available via the ‘func.’ registry.

     See also
     ........

     See GenericFunction.

     References: #5079(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4467

   (2) http://www.sqlalchemy.org/trac/ticket/5079

8.3.2.85 postgresql
...................

   * `[postgresql] [usecase]' ¶. Added support for prefixes
     to the CTE construct, to allow support for Postgresql
     12 “MATERIALIZED” and “NOT MATERIALIZED” phrases.  Pull request
     courtesy Marat Sharafutdinov.

     See also
     ........

     See HasCTE.cte().

     References: #5040(1)

   * `[postgresql] [bug]' ¶. Fixed issue where the
     PostgreSQL dialect would fail to parse a reflected CHECK constraint
     that was a boolean-valued function (as opposed to a boolean-valued
     expression).

     References: #5039(2)

   * `[postgresql] [tests]' ¶. Improved detection of two
     phase transactions requirement for the PostgreSQL database by
     testing that max_prepared_transactions is set to a value greater
     than 0.  Pull request courtesy Federico Caselli.

     References: #5057(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5040

   (2) http://www.sqlalchemy.org/trac/ticket/5039

   (3) http://www.sqlalchemy.org/trac/ticket/5057

8.3.2.86 mssql
..............

   * `[mssql] [bug]' ¶. Fixed issue where a timezone-aware
     ‘datetime’ value being converted to string for use as a parameter
     value of a DATETIMEOFFSET column was omitting the
     fractional seconds.

     References: #5045(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5045

8.3.2.87 misc
.............

   * `[bug] [ext]' ¶. Fixed bug in sqlalchemy.ext.serializer
     where a unique BindParameter object could conflict with
     itself if it were present in the mapping itself, as well as the
     filter condition of the query, as one side would be used against
     the non-deserialized version and the other side would use the
     deserialized version.  Logic is added to BindParameter
     similar to its “clone” method which will uniquify the parameter
     name upon deserialize so that it doesn’t conflict with its
     original.

     References: #5086(1)

   * `[bug] [tests]' ¶. Fixed a few test failures which
     would occur on Windows due to SQLite file locking issues, as well
     as some timing issues in connection pool related tests; pull
     request courtesy Federico Caselli.

     References: #4946(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5086

   (2) http://www.sqlalchemy.org/trac/ticket/4946

8.3.2.88 1.3.12
...............

Released: December 16, 2019

8.3.2.89 orm
............

   * `[orm] [bug]' ¶. Fixed issue involving ‘lazy="raise"’
     strategy where an ORM delete of an object would raise for a simple
     “use-get” style many-to-one relationship that had lazy=”raise”
     configured.  This is inconsistent vs.  the change introduced in 1.3
     as part of #4353(1), where it was established that a history
     operation that does not expect emit SQL should bypass the
     ‘lazy="raise"’ check, and instead effectively treat it as
     ‘lazy="raise_on_sql"’ for this case.  The fix adjusts the lazy
     loader strategy to not raise for the case where the lazy load was
     instructed that it should not emit SQL if the object were not
     present.

     References: #4997(2)

   * `[orm] [bug]' ¶. Fixed regression introduced in 1.3.0
     related to the association proxy refactor in #4351(3) that
     prevented composite() attributes from working in terms
     of an association proxy that references them.

     References: #5000(4)

   * `[orm] [bug]' ¶. Setting persistence-related flags on
     relationship() while also setting viewonly=True will now
     emit a regular warning, as these flags do not make sense for a
     viewonly=True relationship.  In particular, the “cascade” settings
     have their own warning that is generated based on the individual
     values, such as “delete, delete-orphan”, that should not apply to a
     viewonly relationship.  Note however that in the case of “cascade”,
     these settings are still erroneously taking effect even though the
     relationship is set up as “viewonly”.  In 1.4, all
     persistence-related cascade settings will be disallowed on a
     viewonly=True relationship in order to resolve this issue.

     References: #4993(5)

   * `[orm] [bug] [py3k]' ¶. Fixed issue where when
     assigning a collection to itself as a slice, the mutation operation
     would fail as it would first erase the assigned collection
     inadvertently.  As an assignment that does not change the contents
     should not generate events, the operation is now a no-op.  Note
     that the fix only applies to Python 3; in Python 2, the
     ‘__setitem__’ hook isn’t called in this case; ‘__setslice__’ is
     used instead which recreates the list item-by-item in all cases.

     References: #4990(6)

   * `[orm] [bug]' ¶. Fixed issue where by if the “begin” of
     a transaction failed at the Core engine/connection level, such as
     due to network error or database is locked for some transactional
     recipes, within the context of the Session procuring
     that connection from the connection pool and then immediately
     returning it, the ORM Session would not close the
     connection despite this connection not being stored within the
     state of that Session.  This would lead to the connection
     being cleaned out by the connection pool weakref handler within
     garbage collection which is an unpreferred codepath that in some
     special configurations can emit errors in standard error.

     References: #5034(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4353

   (2) http://www.sqlalchemy.org/trac/ticket/4997

   (3) http://www.sqlalchemy.org/trac/ticket/4351

   (4) http://www.sqlalchemy.org/trac/ticket/5000

   (5) http://www.sqlalchemy.org/trac/ticket/4993

   (6) http://www.sqlalchemy.org/trac/ticket/4990

   (7) http://www.sqlalchemy.org/trac/ticket/5034

8.3.2.90 sql
............

   * `[sql] [bug]' ¶. Fixed bug where “distinct” keyword
     passed to select() would not treat a string value as a
     “label reference” in the same way that the ‘select.distinct()’
     does; it would instead raise unconditionally.  This keyword
     argument and the others passed to select() will
     ultimately be deprecated for SQLAlchemy 2.0.

     References: #5028(1)

   * `[sql] [bug]' ¶. Changed the text of the exception for
     “Can’t resolve label reference” to include other kinds of label
     coercions, namely that “DISTINCT” is also in this category under
     the PostgreSQL dialect.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5028

8.3.2.91 sqlite
...............

   * `[sqlite] [bug]' ¶. Fixed issue to workaround SQLite’s
     behavior of assigning “numeric” affinity to JSON datatypes, first
     described at Support for SQLite JSON Added, which
     returns scalar numeric JSON values as a number and not as a string
     that can be JSON deserialized.  The SQLite-specific JSON
     deserializer now gracefully degrades for this case as an exception
     and bypasses deserialization for single numeric values, as from a
     JSON perspective they are already deserialized.

     References: #5014(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/5014

8.3.2.92 mssql
..............

   * `[mssql] [bug]' ¶. Repaired support for the
     DATETIMEOFFSET datatype on PyODBC, by adding PyODBC-level
     result handlers as it does not include native support for this
     datatype.  This includes usage of the Python 3 “timezone” tzinfo
     subclass in order to set up a timezone, which on Python 2 makes use
     of a minimal backport of “timezone” in sqlalchemy.util.

     References: #4983(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4983

8.3.2.93 1.3.11
...............

Released: November 11, 2019

8.3.2.94 orm
............

   * `[orm] [usecase]' ¶. Added accessor
     Query.is_single_entity() to Query, which will
     indicate if the results returned by this Query will be
     a list of ORM entities, or a tuple of entities or column
     expressions.  SQLAlchemy hopes to improve upon the behavior of
     single entity / tuples in future releases such that the behavior
     would be explicit up front, however this attribute should be
     helpful with the current behavior.  Pull request courtesy Patrick
     Hayes.

     References: #4934(1)

   * `[orm] [bug]' ¶. The relationship.omit_join.
     flag was not intended to be manually set to True, and will now emit
     a warning when this occurs.  The omit_join optimization is detected
     automatically, and the ‘omit_join’ flag was only intended to
     disable the optimization in the hypothetical case that the
     optimization may have interfered with correct results, which has
     not been observed with the modern version of this feature.  Setting
     the flag to True when it is not automatically detected may cause
     the selectin load feature to not work correctly when a non-default
     primary join condition is in use.

     References: #4954(2)

   * `[orm] [bug]' ¶. A warning is emitted if a primary key
     value is passed to Query.get() that consists of None
     for all primary key column positions.  Previously, passing a single
     None outside of a tuple would raise a ‘TypeError’ and passing a
     composite None (tuple of None values) would silently pass through.
     The fix now coerces the single None into a tuple where it is
     handled consistently with the other None conditions.  Thanks to Lev
     Izraelit for the help with this.

     References: #4915(3)

   * `[orm] [bug]' ¶. The BakedQuery will not
     cache a query that was modified by a
     QueryEvents.before_compile() event, so that compilation hooks
     that may be applying ad-hoc modifications to queries will take
     effect on each run.  In particular this is helpful for events that
     modify queries used in lazy loading as well as eager loading such
     as “select in” loading.  In order to re-enable caching for a query
     modified by this event, a new flag ‘bake_ok’ is added; see
     Using the before_compile event for details.

     A longer term plan to provide a new form of SQL caching should
     solve this kind of issue more comprehensively.

     References: #4947(4)

   * `[orm] [bug]' ¶. Fixed ORM bug where a “secondary”
     table that referred to a selectable which in some way would refer
     to the local primary table would apply aliasing to both sides of
     the join condition when a relationship-related join, either via
     Query.join() or by joinedload(), were
     generated.  The “local” side is now excluded.

     References: #4974(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4934

   (2) http://www.sqlalchemy.org/trac/ticket/4954

   (3) http://www.sqlalchemy.org/trac/ticket/4915

   (4) http://www.sqlalchemy.org/trac/ticket/4947

   (5) http://www.sqlalchemy.org/trac/ticket/4974

8.3.2.95 engine
...............

   * `[engine] [bug]' ¶. Fixed bug where parameter repr as
     used in logging and error reporting needs additional context in
     order to distinguish between a list of parameters for a single
     statement and a list of parameter lists, as the “list of lists”
     structure could also indicate a single parameter list where the
     first parameter itself is a list, such as for an array parameter.
     The engine/connection now passes in an additional boolean
     indicating how the parameters should be considered.  The only
     SQLAlchemy backend that expects arrays as parameters is that of
     psycopg2 which uses pyformat parameters, so this issue has not been
     too apparent, however as other drivers that use positional gain
     more features it is important that this be supported.  It also
     eliminates the need for the parameter repr function to guess based
     on the parameter structure passed.

     References: #4902(1)

   * `[engine] [bug] [postgresql]' ¶. Fixed bug in
     Inspector where the cache key generation did not take into
     account arguments passed in the form of tuples, such as the tuple
     of view name styles to return for the PostgreSQL dialect.  This
     would lead the inspector to cache too generally for a more specific
     set of criteria.  The logic has been adjusted to include every
     keyword element in the cache, as every argument is expected to be
     appropriate for a cache else the caching decorator should be
     bypassed by the dialect.

     References: #4955(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4902

   (2) http://www.sqlalchemy.org/trac/ticket/4955

8.3.2.96 sql
............

   * `[sql] [usecase]' ¶. Added new accessors to expressions
     of type JSON to allow for specific datatype access and
     comparison, covering strings, integers, numeric, boolean elements.
     This revises the documented approach of CASTing to string when
     comparing values, instead adding specific functionality into the
     PostgreSQL, SQlite, MySQL dialects to reliably deliver these basic
     types in all cases.

     See also
     ........

     See JSON.

     See Comparator.as_string().

     See Comparator.as_boolean().

     See Comparator.as_float().

     See Comparator.as_integer().

     References: #4276(1)

   * `[sql] [usecase]' ¶. The text() construct
     now supports “unique” bound parameters, which will dynamically
     uniquify themselves on compilation thus allowing multiple
     text() constructs with the same bound parameter names to be
     combined together.

     References: #4933(2)

   * `[sql] [bug] [py3k]' ¶. Changed the ‘repr()’ of the
     quoted_name construct to use regular string repr()
     under Python 3, rather than running it through “backslashreplace”
     escaping, which can be misleading.

     References: #4931(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4276

   (2) http://www.sqlalchemy.org/trac/ticket/4933

   (3) http://www.sqlalchemy.org/trac/ticket/4931

8.3.2.97 schema
...............

   * `[schema] [usecase]' ¶. Added DDL support for “computed
     columns”; these are DDL column specifications for columns that have
     a server-computed value, either upon SELECT (known as “virtual”) or
     at the point of which they are INSERTed or UPDATEd (known as
     “stored”).  Support is established for Postgresql, MySQL, Oracle
     SQL Server and Firebird.  Thanks to Federico Caselli for lots of
     work on this one.

     See also
     ........

     See Computed Columns (GENERATED ALWAYS AS).

     References: #4894(1)

   * `[schema] [bug]' ¶. Fixed bug where a table that would
     have a column label overlap with a plain column name, such as
     “foo.id AS foo_id” vs.  “foo.foo_id”, would prematurely generate
     the ‘._label’ attribute for a column before this overlap could be
     detected due to the use of the ‘index=True’ or ‘unique=True’ flag
     on the column in conjunction with the default naming convention of
     ‘"column_0_label"’.  This would then lead to failures when
     ‘._label’ were used later to generate a bound parameter name, in
     particular those used by the ORM when generating the WHERE clause
     for an UPDATE statement.  The issue has been fixed by using an
     alternate ‘._label’ accessor for DDL generation that does not
     affect the state of the Column.  The accessor also
     bypasses the key-deduplication step as it is not necessary for DDL,
     the naming is now consistently ‘"<tablename>_<columnname>"’ without
     any subsequent numeric symbols when used in DDL.

     References: #4911(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4894

   (2) http://www.sqlalchemy.org/trac/ticket/4911

8.3.2.98 mysql
..............

   * `[mysql] [bug]' ¶. Added “Connection was killed”
     message interpreted from the base pymysql.Error class in order to
     detect closed connection, based on reports that this message is
     arriving via a pymysql.InternalError() object which indicates
     pymysql is not handling it correctly.

     References: #4945(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4945

8.3.2.99 mssql
..............

   * `[mssql] [bug]' ¶. Fixed issue in MSSQL dialect where
     an expression-based OFFSET value in a SELECT would be rejected,
     even though the dialect can render this expression inside of a ROW
     NUMBER-oriented LIMIT/OFFSET construct.

     References: #4973(1)

   * `[mssql] [bug]' ¶. Fixed an issue in the
     Engine.table_names() method where it would feed the
     dialect’s default schema name back into the dialect level table
     function, which in the case of SQL Server would interpret it as a
     dot-tokenized schema name as viewed by the mssql dialect, which
     would cause the method to fail in the case where the database
     username actually had a dot inside of it.  In 1.3, this method is
     still used by the MetaData.reflect() function so is a
     prominent codepath.  In 1.4, which is the current master
     development branch, this issue doesn’t exist, both because
     MetaData.reflect() isn’t using this method nor does the
     method pass the default schema name explicitly.  The fix
     nonetheless guards against the default server name value returned
     by the dialect from being interpreted as dot-tokenized name under
     any circumstances by wrapping it in quoted_name().

     References: #4923(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4973

   (2) http://www.sqlalchemy.org/trac/ticket/4923

8.3.2.100 oracle
................

   * `[oracle] [usecase]' ¶. Added dialect-level flag
     ‘encoding_errors’ to the cx_Oracle dialect, which can be specified
     as part of create_engine().  This is passed to
     SQLAlchemy’s unicode decoding converter under Python 2, and to
     cx_Oracle’s ‘cursor.var()’ object as the ‘encodingErrors’ parameter
     under Python 3, for the very unusual case that broken encodings are
     present in the target database which cannot be fetched unless error
     handling is relaxed.  The value is ultimately one of the Python
     “encoding errors” parameters passed to ‘decode()’.

     References: #4799(1)

   * `[oracle] [bug] [firebird]' ¶. Modified the approach of
     “name normalization” for the Oracle and Firebird dialects, which
     converts from the UPPERCASE-as-case-insensitive convention of these
     dialects into lowercase-as-case-insensitive for SQLAlchemy, to not
     automatically apply the quoted_name construct to a name
     that matches itself under upper or lower case conversion, as is the
     case for many non-european characters.  All names used within
     metadata structures are converted to quoted_name
     objects in any case; the change here would only affect the output
     of some inspection functions.

     References: #4931(2)

   * `[oracle] [bug]' ¶. The NCHAR datatype
     will now bind to the ‘cx_Oracle.FIXED_NCHAR’ DBAPI data bindings
     when used in a bound parameter, which supplies proper comparison
     behavior against a variable-length string.  Previously, the
     NCHAR datatype would bind to ‘cx_oracle.NCHAR’ which is not
     fixed length; the CHAR datatype already binds to
     ‘cx_Oracle.FIXED_CHAR’ so it is now consistent that NCHAR
     binds to ‘cx_Oracle.FIXED_NCHAR’.

     References: #4913(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4799

   (2) http://www.sqlalchemy.org/trac/ticket/4931

   (3) http://www.sqlalchemy.org/trac/ticket/4913

8.3.2.101 firebird
..................

   * `[firebird] [bug]' ¶. Added additional “disconnect”
     message “Error writing data to the connection” to Firebird
     disconnection detection.  Pull request courtesy lukens.

     References: #4903(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4903

8.3.2.102 misc
..............

   * `[bug] [tests]' ¶. Fixed test failures which would
     occur with newer SQLite as of version 3.30 or greater, due to their
     addition of nulls ordering syntax as well as new restrictions on
     aggregate functions.  Pull request courtesy Nils Philippsen.

     References: #4920(1)

   * `[bug] [installation] [windows]' ¶. Added a workaround
     for a setuptools-related failure that has been observed as
     occurring on Windows installations, where setuptools is not
     correctly reporting a build error when the MSVC build dependencies
     are not installed and therefore not allowing graceful degradation
     into non C extensions builds.

     References: #4967(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4920

   (2) http://www.sqlalchemy.org/trac/ticket/4967

8.3.2.103 1.3.10
................

Released: October 9, 2019

8.3.2.104 mssql
...............

   * `[mssql] [bug]' ¶. Fixed bug in SQL Server dialect with
     new “max_identifier_length” feature where the mssql dialect already
     featured this flag, and the implementation did not accommodate for
     the new initialization hook correctly.

     References: #4857(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4857

8.3.2.105 oracle
................

   * `[oracle] [bug]' ¶. Fixed regression in Oracle dialect
     that was inadvertently using max identifier length of 128
     characters on Oracle server 12.2 and greater even though the stated
     contract for the remainder of the 1.3 series is that this value
     stays at 30 until version SQLAlchemy 1.4.  Also repaired issues
     with the retrieval of the “compatibility” version, and removed the
     warning emitted when the “v$parameter” view was not accessible as
     this was causing user confusion.

     References: #4857(1), #4898(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4857

   (2) http://www.sqlalchemy.org/trac/ticket/4898

8.3.2.106 1.3.9
...............

Released: October 4, 2019

8.3.2.107 orm
.............

   * `[orm] [bug]' ¶. Fixed regression in selectinload
     loader strategy caused by #4775(1) (released in version 1.3.6)
     where a many-to-one attribute of None would no longer be populated
     by the loader.  While this was usually not noticeable due to the
     lazyloader populating None upon get, it would lead to a detached
     instance error if the object were detached.

     References: #4872(2)

   * `[orm] [bug]' ¶. Passing a plain string expression to
     Session.query() is deprecated, as all string coercions
     were removed in #4481(3) and this one should have been included.
     The literal_column() function may be used to produce a
     textual column expression.

     References: #4873(4)

   * `[orm] [bug]' ¶. A warning is emitted for a condition
     in which the Session may implicitly swap an object out
     of the identity map for another one with the same primary key,
     detaching the old one, which can be an observed result of load
     operations which occur within the
     SessionEvents.after_flush() hook.  The warning is intended to
     notify the user that some special condition has caused this to
     happen and that the previous object may not be in the expected
     state.

     References: #4890(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4775

   (2) http://www.sqlalchemy.org/trac/ticket/4872

   (3) http://www.sqlalchemy.org/trac/ticket/4481

   (4) http://www.sqlalchemy.org/trac/ticket/4873

   (5) http://www.sqlalchemy.org/trac/ticket/4890

8.3.2.108 engine
................

   * `[engine] [usecase]' ¶. Added new
     create_engine() parameter
     create_engine.max_identifier_length.  This overrides the
     dialect-coded “max identifier length” in order to accommodate for
     databases that have recently changed this length and the SQLAlchemy
     dialect has not yet been adjusted to detect for that version.  This
     parameter interacts with the existing
     create_engine.label_length parameter in that it establishes
     the maximum (and default) value for anonymously generated labels.
     Additionally, post-connection detection of max identifier lengths
     has been added to the dialect system.  This feature is first being
     used by the Oracle dialect.

     See also
     ........

     See Max Identifier Lengths. - in the Oracle dialect
     documentation

     References: #4857(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4857

8.3.2.109 sql
.............

   * `[sql] [usecase]' ¶. Added an explicit error message
     for the case when objects passed to Table are not
     SchemaItem objects, rather than resolving to an attribute
     error.

     References: #4847(1)

   * `[sql] [bug]' ¶. Characters that interfere with
     “pyformat” or “named” formats in bound parameters, namely ‘%, (, )’
     and the space character, as well as a few other typically
     undesirable characters, are stripped early for a bindparam()
     that is using an anonymized name, which is typically generated
     automatically from a named column which itself includes these
     characters in its name and does not use a ‘.key’, so that they do
     not interfere either with the SQLAlchemy compiler’s use of string
     formatting or with the driver-level parsing of the parameter, both
     of which could be demonstrated before the fix.  The change only
     applies to anonymized parameter names that are generated and
     consumed internally, not end-user defined names, so the change
     should have no impact on any existing code.  Applies in particular
     to the psycopg2 driver which does not otherwise quote special
     parameter names, but also strips leading underscores to suit Oracle
     (but not yet leading numbers, as some anon parameters are currently
     entirely numeric/underscore based); Oracle in any case continues to
     quote parameter names that include special characters.

     References: #4837(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4847

   (2) http://www.sqlalchemy.org/trac/ticket/4837

8.3.2.110 sqlite
................

   * `[sqlite] [usecase]' ¶. Added support for sqlite “URI”
     connections, which allow for sqlite-specific flags to be passed in
     the query string such as “read only” for Python sqlite3 drivers
     that support this.

     See also
     ........

     See URI Connections.

     References: #4863(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4863

8.3.2.111 mssql
...............

   * `[mssql] [bug]' ¶. Added identifier quoting to the
     schema name applied to the “use” statement which is invoked when a
     SQL Server multipart schema name is used within a Table
     that is being reflected, as well as for Inspector
     methods such as Inspector.get_table_names(); this
     accommodates for special characters or spaces in the database name.
     Additionally, the “use” statement is not emitted if the current
     database matches the target owner database name being passed.

     References: #4883(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4883

8.3.2.112 oracle
................

   * `[oracle] [usecase]' ¶. The Oracle dialect now emits a
     warning if Oracle version 12.2 or greater is used, and the
     create_engine.max_identifier_length parameter is not set.
     The version in this specific case defaults to that of the
     “compatibility” version set in the Oracle server configuration, not
     the actual server version.  In version 1.4, the default
     max_identifier_length for 12.2 or greater will move to 128
     characters.  In order to maintain forwards compatibility,
     applications should set create_engine.max_identifier_length
     to 30 in order to maintain the same length behavior, or to
     128 in order to test the upcoming behavior.  This length determines
     among other things how generated constraint names are truncated for
     statements like ‘CREATE CONSTRAINT’ and ‘DROP CONSTRAINT’, which
     means a the new length may produce a name-mismatch against a name
     that was generated with the old length, impacting database
     migrations.

     See also
     ........

     See Max Identifier Lengths. - in the Oracle dialect
     documentation

     References: #4857(1)

   * `[oracle] [bug]' ¶. Restored adding cx_Oracle.DATETIME
     to the setinputsizes() call when a SQLAlchemy Date,
     DateTime or Time datatype is used, as some
     complex queries require this to be present.  This was removed in
     the 1.2 series for arbitrary reasons.

     References: #4886(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4857

   (2) http://www.sqlalchemy.org/trac/ticket/4886

8.3.2.113 misc
..............

   * `[bug] [tests]' ¶. Fixed unit test regression released
     in 1.3.8 that would cause failure for Oracle, SQL Server and other
     non-native ENUM platforms due to new enumeration tests added as
     part of #4285(1) enum sortability in the unit of work; the
     enumerations created constraints that were duplicated on name.

     References: #4285(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4285

   (2) http://www.sqlalchemy.org/trac/ticket/4285

8.3.2.114 1.3.8
...............

Released: August 27, 2019

8.3.2.115 orm
.............

   * `[orm] [usecase]' ¶. Added support for the use of an
     Enum datatype using Python pep-435 enumeration objects
     as values for use as a primary key column mapped by the ORM. As
     these values are not inherently sortable, as required by the ORM
     for primary keys, a new TypeEngine.sort_key_function
     attribute is added to the typing system which allows any SQL type
     to implement a sorting for Python objects of its type which is
     consulted by the unit of work.  The Enum type then
     defines this using the database value of a given enumeration.  The
     sorting scheme can be also be redefined by passing a callable to
     the Enum.sort_key_function parameter.  Pull request
     courtesy Nicolas Caniart.

     References: #4285(1)

   * `[orm] [bug]' ¶. Fixed bug where Load.
     objects were not pickleable due to mapper/relationship state in the
     internal context dictionary.  These objects are now converted to
     picklable using similar techniques as that of other elements within
     the loader option system that have long been serializable.

     References: #4823(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4285

   (2) http://www.sqlalchemy.org/trac/ticket/4823

8.3.2.116 engine
................

   * `[engine] [feature]' ¶. Added new parameter
     create_engine.hide_parameters which when set to True will
     cause SQL parameters to no longer be logged, nor rendered in the
     string representation of a StatementError object.

     References: #4815(1)

   * `[engine] [bug]' ¶. Fixed an issue whereby if the
     dialect “initialize” process which occurs on first connect would
     encounter an unexpected exception, the initialize process would
     fail to complete and then no longer attempt on subsequent
     connection attempts, leaving the dialect in an un-initialized, or
     partially initialized state, within the scope of parameters that
     need to be established based on inspection of a live connection.
     The “invoke once” logic in the event system has been reworked to
     accommodate for this occurrence using new, private API features
     that establish an “exec once” hook that will continue to allow the
     initializer to fire off on subsequent connections, until it
     completes without raising an exception.  This does not impact the
     behavior of the existing ‘once=True’ flag within the event system.

     References: #4807(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4815

   (2) http://www.sqlalchemy.org/trac/ticket/4807

8.3.2.117 postgresql
....................

   * `[postgresql] [usecase]' ¶. Added support for
     reflection of CHECK constraints that include the special PostgreSQL
     qualifier “NOT VALID”, which can be present for CHECK constraints
     that were added to an existing table with the directive that they
     not be applied to existing data in the table.  The PostgreSQL
     dictionary for CHECK constraints as returned by
     Inspector.get_check_constraints() may include an additional
     entry ‘dialect_options’ which within will contain an entry
     ‘"not_valid": True’ if this symbol is detected.  Pull request
     courtesy Bill Finn.

     References: #4824(1)

   * `[postgresql] [bug]' ¶. Revised the approach for the
     just added support for the psycopg2 “execute_values()” feature
     added in 1.3.7 for #4623(2).  The approach relied upon a regular
     expression that would fail to match for a more complex INSERT
     statement such as one which had subqueries involved.  The new
     approach matches exactly the string that was rendered as the VALUES
     clause.

     References: #4623(3)

   * `[postgresql] [bug]' ¶. Fixed bug where Postgresql
     operators such as Comparator.contains() and
     Comparator.contained_by() would fail to function correctly
     for non-integer values when used against a array
     object, due to an erroneous assert statement.

     References: #4822(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4824

   (2) http://www.sqlalchemy.org/trac/ticket/4623

   (3) http://www.sqlalchemy.org/trac/ticket/4623

   (4) http://www.sqlalchemy.org/trac/ticket/4822

8.3.2.118 sqlite
................

   * `[sqlite] [bug] [reflection]' ¶. Fixed bug where a
     FOREIGN KEY that was set up to refer to the parent table by table
     name only without the column names would not correctly be reflected
     as far as setting up the “referred columns”, since SQLite’s PRAGMA
     does not report on these columns if they weren’t given explicitly.
     For some reason this was hardcoded to assume the name of the local
     column, which might work for some cases but is not correct.  The
     new approach reflects the primary key of the referred table and
     uses the constraint columns list as the referred columns list, if
     the remote column(s) aren’t present in the reflected pragma
     directly.

     References: #4810(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4810

8.3.2.119 1.3.7
...............

Released: August 14, 2019

8.3.2.120 orm
.............

   * `[orm] [bug]' ¶. Fixed regression caused by new
     selectinload for many-to-one logic where a primaryjoin condition
     not based on real foreign keys would cause KeyError if a related
     object did not exist for a given key value on the parent object.

     References: #4777(1)

   * `[orm] [bug]' ¶. Fixed bug where using
     Query.first() or a slice expression in conjunction with a
     query that has an expression based “offset” applied would raise
     TypeError, due to an “or” conditional against “offset” that did not
     expect it to be a SQL expression as opposed to an integer or None.

     References: #4803(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4777

   (2) http://www.sqlalchemy.org/trac/ticket/4803

8.3.2.121 sql
.............

   * `[sql] [bug]' ¶. Fixed issue where Index.
     object which contained a mixture of functional expressions which
     were not resolvable to a particular column, in combination with
     string-based column names, would fail to initialize its internal
     state correctly leading to failures during DDL compilation.

     References: #4778(1)

   * `[sql] [bug]' ¶. Fixed bug where
     TypeEngine.column_expression() method would not be applied
     to subsequent SELECT statements inside of a UNION or other
     ‘_selectable.CompoundSelect’, even though the SELECT statements are
     rendered at the topmost level of the statement.  New logic now
     differentiates between rendering the column expression, which is
     needed for all SELECTs in the list, vs.  gathering the returned
     data type for the result row, which is needed only for the first
     SELECT.

     References: #4787(2)

   * `[sql] [bug]' ¶. Fixed issue where internal cloning of
     SELECT constructs could lead to a key error if the copy of the
     SELECT changed its state such that its list of columns changed.
     This was observed to be occurring in some ORM scenarios which may
     be unique to 1.3 and above, so is partially a regression fix.

     References: #4780(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4778

   (2) http://www.sqlalchemy.org/trac/ticket/4787

   (3) http://www.sqlalchemy.org/trac/ticket/4780

8.3.2.122 postgresql
....................

   * `[postgresql] [usecase]' ¶. Added new dialect flag for
     the psycopg2 dialect, ‘executemany_mode’ which supersedes the
     previous experimental ‘use_batch_mode’ flag.  ‘executemany_mode’
     supports both the “execute batch” and “execute values” functions
     provided by psycopg2, the latter which is used for compiled
     insert() constructs.  Pull request courtesy Yuval Dinari.

     See also
     ........

     See Psycopg2 Fast Execution Helpers.

     References: #4623(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4623

8.3.2.123 mysql
...............

   * `[mysql] [usecase]' ¶. Added reserved words ARRAY and
     MEMBER to the MySQL reserved words list, as MySQL 8.0 has now made
     these reserved.

     References: #4783(1)

   * `[mysql] [bug]' ¶. The MySQL dialects will emit “SET
     NAMES” at the start of a connection when charset is given to the
     MySQL driver, to appease an apparent behavior observed in MySQL 8.0
     that raises a collation error when a UNION includes string columns
     unioned against columns of the form CAST(NULL AS CHAR(..)), which
     is what SQLAlchemy’s polymorphic_union function does.  The issue
     seems to have affected PyMySQL for at least a year, however has
     recently appeared as of mysqlclient 1.4.4 based on changes in how
     this DBAPI creates a connection.  As the presence of this directive
     impacts three separate MySQL charset settings which each have
     intricate effects based on their presense, SQLAlchemy will now emit
     the directive on new connections to ensure correct behavior.

     References: #4804(2)

   * `[mysql] [bug]' ¶. Added another fix for an upstream
     MySQL 8 issue where a case sensitive table name is reported
     incorrectly in foreign key constraint reflection, this is an
     extension of the fix first added for #4344(3) which affects a case
     sensitive column name.  The new issue occurs through MySQL 8.0.17,
     so the general logic of the 88718 fix remains in place.

     See also
     ........

     ‘https://bugs.mysql.com/bug.php?id=96365’ - upstream bug

     References: #4751(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4783

   (2) http://www.sqlalchemy.org/trac/ticket/4804

   (3) http://www.sqlalchemy.org/trac/ticket/4344

   (4) http://www.sqlalchemy.org/trac/ticket/4751

8.3.2.124 sqlite
................

   * `[sqlite] [bug]' ¶. The dialects that support json are
     supposed to take arguments ‘json_serializer’ and
     ‘json_deserializer’ at the create_engine() level, however the
     SQLite dialect calls them ‘_json_serializer’ and
     ‘_json_deserilalizer’.  The names have been corrected, the old
     names are accepted with a change warning, and these parameters are
     now documented as create_engine.json_serializer and
     create_engine.json_deserializer.

     References: #4798(1)

   * `[sqlite] [bug]' ¶. Fixed bug where usage of “PRAGMA
     table_info” in SQLite dialect meant that reflection features to
     detect for table existence, list of table columns, and list of
     foreign keys, would default to any table in any attached database,
     when no schema name was given and the table did not exist in the
     base schema.  The fix explicitly runs PRAGMA for the ‘main’ schema
     and then the ‘temp’ schema if the ‘main’ returned no rows, to
     maintain the behavior of tables + temp tables in the “no schema”
     namespace, attached tables only in the “schema” namespace.

     References: #4793(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4798

   (2) http://www.sqlalchemy.org/trac/ticket/4793

8.3.2.125 mssql
...............

   * `[mssql] [usecase]' ¶. Added new try_cast()
     construct for SQL Server which emits “TRY_CAST” syntax.  Pull
     request courtesy Leonel Atencio.

     References: #4782(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4782

8.3.2.126 misc
..............

   * `[bug] [events]' ¶. Fixed issue in event system where
     using the ‘once=True’ flag with dynamically generated listener
     functions would cause event registration of future events to fail
     if those listener functions were garbage collected after they were
     used, due to an assumption that a listened function is strongly
     referenced.  The “once” wrapped is now modified to strongly
     reference the inner function persistently, and documentation is
     updated that using “once” does not imply automatic de-registration
     of listener functions.

     References: #4794(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4794

8.3.2.127 1.3.6
...............

Released: July 21, 2019

8.3.2.128 orm
.............

   * `[orm] [feature]' ¶. Added new loader option method
     Load.options() which allows loader options to be
     constructed hierarchically, so that many sub-options can be applied
     to a particular path without needing to call defaultload()
     many times.  Thanks to Alessio Bogon for the idea.

     References: #4736(1)

   * `[orm] [performance]' ¶. The optimization applied to
     selectin loading in #4340(2) where a JOIN is not needed to eagerly
     load related items is now applied to many-to-one relationships as
     well, so that only the related table is queried for a simple join
     condition.  In this case, the related items are queried based on
     the value of a foreign key column on the parent; if these columns
     are deferred or otherwise not loaded on any of the parent objects
     in the collection, the loader falls back to the JOIN method.

     References: #4775(3)

   * `[orm] [bug]' ¶. Fixed regression caused by #4365(4)
     where a join from an entity to itself without using aliases no
     longer raises an informative error message, instead failing on an
     assertion.  The informative error condition has been restored.

     References: #4773(5)

   * `[orm] [bug]' ¶. Fixed an issue where the
     ‘_ORMJoin.join()’ method, which is a not-internally-used ORM-level
     method that exposes what is normally an internal process of
     Query.join(), did not propagate the ‘full’ and ‘outerjoin’
     keyword arguments correctly.  Pull request courtesy Denis Kataev.

     References: #4713(6)

   * `[orm] [bug]' ¶. Fixed bug where a many-to-one
     relationship that specified ‘uselist=True’ would fail to update
     correctly during a primary key change where a related column needs
     to change.

     References: #4772(7)

   * `[orm] [bug]' ¶. Fixed bug where the detection for
     many-to-one or one-to-one use with a “dynamic” relationship, which
     is an invalid configuration, would fail to raise if the
     relationship were configured with ‘uselist=True’.  The current fix
     is that it warns, instead of raises, as this would otherwise be
     backwards incompatible, however in a future release it will be a
     raise.

     References: #4772(8)

   * `[orm] [bug]' ¶. Fixed bug where a synonym created
     against a mapped attribute that does not exist yet, as is the case
     when it refers to backref before mappers are configured, would
     raise recursion errors when trying to test for attributes on it
     which ultimately don’t exist (as occurs when the classes are run
     through Sphinx autodoc), as the unconfigured state of the synonym
     would put it into an attribute not found loop.

     References: #4767(9)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4736

   (2) http://www.sqlalchemy.org/trac/ticket/4340

   (3) http://www.sqlalchemy.org/trac/ticket/4775

   (4) http://www.sqlalchemy.org/trac/ticket/4365

   (5) http://www.sqlalchemy.org/trac/ticket/4773

   (6) http://www.sqlalchemy.org/trac/ticket/4713

   (7) http://www.sqlalchemy.org/trac/ticket/4772

   (8) http://www.sqlalchemy.org/trac/ticket/4772

   (9) http://www.sqlalchemy.org/trac/ticket/4767

8.3.2.129 engine
................

   * `[engine] [bug]' ¶. Fixed bug where using reflection
     function such as MetaData.reflect() with an
     Engine object that had execution options applied to it would
     fail, as the resulting ‘OptionEngine’ proxy object failed to
     include a ‘.engine’ attribute used within the reflection routines.

     References: #4754(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4754

8.3.2.130 sql
.............

   * `[sql] [bug]' ¶. Adjusted the initialization for
     Enum to minimize how often it invokes the ‘.__members__’
     attribute of a given PEP-435 enumeration object, to suit the case
     where this attribute is expensive to invoke, as is the case for
     some popular third party enumeration libraries.

     References: #4758(1)

   * `[sql] [bug] [postgresql]' ¶. Fixed issue where the
     array_agg construct in combination with
     FunctionElement.filter() would not produce the correct
     operator precedence in combination with the array index operator.

     References: #4760(2)

   * `[sql] [bug]' ¶. Fixed an unlikely issue where the
     “corresponding column” routine for unions and other
     ‘_selectable.CompoundSelect’ objects could return the wrong column
     in some overlapping column situations, thus potentially impacting
     some ORM operations when set operations are in use, if the
     underlying select() constructs were used previously in
     other similar kinds of routines, due to a cached value not being
     cleared.

     References: #4747(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4758

   (2) http://www.sqlalchemy.org/trac/ticket/4760

   (3) http://www.sqlalchemy.org/trac/ticket/4747

8.3.2.131 postgresql
....................

   * `[postgresql] [usecase]' ¶. Added support for
     reflection of indexes on PostgreSQL partitioned tables, which was
     added to PostgreSQL as of version 11.

     References: #4771(1)

   * `[postgresql] [usecase]' ¶. Added support for
     multidimensional Postgresql array literals via nesting the
     array object within another one.  The multidimensional array
     type is detected automatically.

     See also
     ........

     See array.

     References: #4756(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4771

   (2) http://www.sqlalchemy.org/trac/ticket/4756

8.3.2.132 mysql
...............

   * `[mysql] [bug]' ¶. Fixed bug where the special logic to
     render “NULL” for the TIMESTAMP datatype when
     ‘nullable=True’ would not work if the column’s datatype were a
     TypeDecorator or a Variant.  The logic now
     ensures that it unwraps down to the original TIMESTAMP
     so that this special case NULL keyword is correctly rendered when
     requested.

     References: #4743(1)

   * `[mysql] [bug]' ¶. Enhanced MySQL/MariaDB version
     string parsing to accommodate for exotic MariaDB version strings
     where the “MariaDB” word is embedded among other alphanumeric
     characters such as “MariaDBV1”.  This detection is critical in
     order to correctly accommodate for API features that have split
     between MySQL and MariaDB such as the “transaction_isolation”
     system variable.

     References: #4624(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4743

   (2) http://www.sqlalchemy.org/trac/ticket/4624

8.3.2.133 sqlite
................

   * `[sqlite] [usecase]' ¶. Added support for composite
     (tuple) IN operators with SQLite, by rendering the VALUES keyword
     for this backend.  As other backends such as DB2 are known to use
     the same syntax, the syntax is enabled in the base compiler using a
     dialect-level flag ‘tuple_in_values’.  The change also includes
     support for “empty IN tuple” expressions for SQLite when using
     “in_()” between a tuple value and an empty set.

     References: #4766(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4766

8.3.2.134 mssql
...............

   * `[mssql] [bug]' ¶. Ensured that the queries used to
     reflect indexes and view definitions will explicitly CAST string
     parameters into NVARCHAR, as many SQL Server drivers frequently
     treat string values, particularly those with non-ascii characters
     or larger string values, as TEXT which often don’t compare
     correctly against VARCHAR characters in SQL Server’s information
     schema tables for some reason.  These CAST operations already take
     place for reflection queries against SQL Server
     ‘information_schema.’ tables but were missing from three additional
     queries that are against ‘sys.’ tables.

     References: #4745(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4745

8.3.2.135 1.3.5
...............

Released: June 17, 2019

8.3.2.136 orm
.............

   * `[orm] [bug]' ¶. Fixed a series of related bugs
     regarding joined table inheritance more than two levels deep, in
     conjunction with modification to primary key values, where those
     primary key columns are also linked together in a foreign key
     relationship as is typical for joined table inheritance.  The
     intermediary table in a three-level inheritance hierarchy will now
     get its UPDATE if only the primary key value has changed and
     passive_updates=False (e.g.  foreign key constraints not being
     enforced), whereas before it would be skipped; similarly, with
     passive_updates=True (e.g.  ON UPDATE CASCADE in effect), the
     third-level table will not receive an UPDATE statement as was the
     case earlier which would fail since CASCADE already modified it.
     In a related issue, a relationship linked to a three-level
     inheritance hierarchy on the primary key of an intermediary table
     of a joined-inheritance hierarchy will also correctly have its
     foreign key column updated when the parent object’s primary key is
     modified, even if that parent object is a subclass of the linked
     parent class, whereas before these classes would not be counted.

     References: #4723(1)

   * `[orm] [bug]' ¶. Fixed bug where the
     Mapper.all_orm_descriptors accessor would return an entry for
     the Mapper itself under the declarative ‘__mapper___’
     key, when this is not a descriptor.  The ‘.is_attribute’ flag
     that’s present on all InspectionAttr objects is now
     consulted, which has also been modified to be ‘True’ for an
     association proxy, as it was erroneously set to False for this
     object.

     References: #4729(2)

   * `[orm] [bug]' ¶. Fixed regression in
     Query.join() where the ‘aliased=True’ flag would not properly
     apply clause adaptation to filter criteria, if a previous join were
     made to the same entity.  This is because the adapters were placed
     in the wrong order.  The order has been reversed so that the
     adapter for the most recent ‘aliased=True’ call takes precedence as
     was the case in 1.2 and earlier.  This broke the “elementtree”
     examples among other things.

     References: #4704(3)

   * `[orm] [bug] [py3k]' ¶. Replaced the Python
     compatibility routines for ‘getfullargspec()’ with a fully vendored
     version from Python 3.3.  Originally, Python was emitting
     deprecation warnings for this function in Python 3.8 alphas.  While
     this change was reverted, it was observed that Python 3
     implementations for ‘getfullargspec()’ are an order of magnitude
     slower as of the 3.4 series where it was rewritten against
     ‘Signature’.  While Python plans to improve upon this situation,
     SQLAlchemy projects for now are using a simple replacement to avoid
     any future issues.

     References: #4674(4)

   * `[orm] [bug]' ¶. Reworked the attribute mechanics used
     by AliasedClass to no longer rely upon calling
     ‘__getattribute__’ on the MRO of the wrapped class, and to instead
     resolve the attribute normally on the wrapped class using
     getattr(), and then unwrap/adapt that.  This allows a greater range
     of attribute styles on the mapped class including special
     ‘__getattr__()’ schemes; but it also makes the code simpler and
     more resilient in general.

     References: #4694(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4723

   (2) http://www.sqlalchemy.org/trac/ticket/4729

   (3) http://www.sqlalchemy.org/trac/ticket/4704

   (4) http://www.sqlalchemy.org/trac/ticket/4674

   (5) http://www.sqlalchemy.org/trac/ticket/4694

8.3.2.137 sql
.............

   * `[sql] [bug]' ¶. Fixed a series of quoting issues which
     all stemmed from the concept of the literal_column()
     construct, which when being “proxied” through a subquery to be
     referred towards by a label that matches its text, the label would
     not have quoting rules applied to it, even if the string in the
     Label were set up as a quoted_name
     construct.  Not applying quoting to the text of the Label
     is a bug because this text is strictly a SQL identifier name
     and not a SQL expression, and the string should not have quotes
     embedded into it already unlike the literal_column()
     which it may be applied towards.  The existing behavior of a
     non-labeled literal_column() being propagated as is on
     the outside of a subquery is maintained in order to help with
     manual quoting schemes, although it’s not clear if valid SQL can be
     generated for such a construct in any case.

     References: #4730(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4730

8.3.2.138 postgresql
....................

   * `[postgresql] [usecase]' ¶. Added support for column
     sorting flags when reflecting indexes for PostgreSQL, including
     ASC, DESC, NULLSFIRST, NULLSLAST. Also adds this facility to the
     reflection system in general which can be applied to other dialects
     in future releases.  Pull request courtesy Eli Collins.

     References: #4717(1)

   * `[postgresql] [bug]' ¶. Fixed bug where PostgreSQL
     dialect could not correctly reflect an ENUM datatype that has no
     members, returning a list with ‘None’ for the ‘get_enums()’ call
     and raising a TypeError when reflecting a column which has such a
     datatype.  The inspection now returns an empty list.

     References: #4701(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4717

   (2) http://www.sqlalchemy.org/trac/ticket/4701

8.3.2.139 mysql
...............

   * `[mysql] [bug]' ¶. Fixed bug where MySQL ON DUPLICATE
     KEY UPDATE would not accommodate setting a column to the value
     NULL. Pull request courtesy Lukáš Banič.

     References: #4715(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4715

8.3.2.140 1.3.4
...............

Released: May 27, 2019

8.3.2.141 orm
.............

   * `[orm] [bug]' ¶. Fixed issue where the
     AttributeEvents.active_history flag would not be set for an
     event listener that propagated to a subclass via the
     AttributeEvents.propagate flag.  This bug has been present
     for the full span of the AttributeEvents system.

     References: #4695(1)

   * `[orm] [bug]' ¶. Fixed regression where new association
     proxy system was still not proxying hybrid attributes when they
     made use of the ‘@hybrid_property.expression’ decorator to return
     an alternate SQL expression, or when the hybrid returned an
     arbitrary PropComparator, at the expression level.  This
     involved further generalization of the heuristics used to detect
     the type of object being proxied at the level of
     QueryableAttribute, to better detect if the descriptor
     ultimately serves mapped classes or column expressions.

     References: #4690(2)

   * `[orm] [bug]' ¶. Applied the mapper “configure mutex”
     against the declarative class mapping process, to guard against the
     race which can occur if mappers are used while dynamic module
     import schemes are still in the process of configuring mappers for
     related classes.  This does not guard against all possible race
     conditions, such as if the concurrent import has not yet
     encountered the dependent classes as of yet, however it guards
     against as much as possible within the SQLAlchemy declarative
     process.

     References: #4686(3)

   * `[orm] [bug]' ¶. A warning is now emitted for the case
     where a transient object is being merged into the session with
     Session.merge() when that object is already transient
     in the Session.  This warns for the case where the object
     would normally be double-inserted.

     References: #4647(4)

   * `[orm] [bug]' ¶. Fixed regression in new relationship
     m2o comparison logic first introduced at Improvement to the behavior of many-to-one query expressions
     when comparing to
     an attribute that is persisted as NULL and is in an un-fetched
     state in the mapped instance.  Since the attribute has no explicit
     default, it needs to default to NULL when accessed in a persistent
     setting.

     References: #4676(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4695

   (2) http://www.sqlalchemy.org/trac/ticket/4690

   (3) http://www.sqlalchemy.org/trac/ticket/4686

   (4) http://www.sqlalchemy.org/trac/ticket/4647

   (5) http://www.sqlalchemy.org/trac/ticket/4676

8.3.2.142 engine
................

   * `[engine] [bug] [postgresql]' ¶. Moved the “rollback”
     which occurs during dialect initialization so that it occurs after
     additional dialect-specific initialize steps, in particular those
     of the psycopg2 dialect which would inadvertently leave
     transactional state on the first new connection, which could
     interfere with some psycopg2-specific APIs which require that no
     transaction is started.  Pull request courtesy Matthew Wilkes.

     References: #4663(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4663

8.3.2.143 sql
.............

   * `[sql] [bug]' ¶. Fixed that the GenericFunction
     class was inadvertently registering itself as one of the named
     functions.  Pull request courtesy Adrien Berchet.

     References: #4653(1)

   * `[sql] [bug]' ¶. Fixed issue where double negation of a
     boolean column wouldn’t reset the “NOT” operator.

     References: #4618(2)

   * `[sql] [bug]' ¶. The GenericFunction.
     namespace is being migrated so that function names are looked up in
     a case-insensitive manner, as SQL functions do not collide on case
     sensitive differences nor is this something which would occur with
     user-defined functions or stored procedures.  Lookups for functions
     declared with GenericFunction now use a case
     insensitive scheme, however a deprecation case is supported which
     allows two or more GenericFunction objects with the
     same name of different cases to exist, which will cause case
     sensitive lookups to occur for that particular name, while emitting
     a warning at function registration time.  Thanks to Adrien Berchet
     for a lot of work on this complicated feature.

     References: #4569(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4653

   (2) http://www.sqlalchemy.org/trac/ticket/4618

   (3) http://www.sqlalchemy.org/trac/ticket/4569

8.3.2.144 postgresql
....................

   * `[postgresql] [bug] [orm]' ¶. Fixed an issue where the
     “number of rows matched” warning would emit even if the dialect
     reported “supports_sane_multi_rowcount=False”, as is the case for
     psycogp2 with ‘use_batch_mode=True’ and others.

     References: #4661(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4661

8.3.2.145 mysql
...............

   * `[mysql] [bug]' ¶. Added support for DROP CHECK
     constraint which is required by MySQL 8.0.16 to drop a CHECK
     constraint; MariaDB supports plain DROP CONSTRAINT. The logic
     distinguishes between the two syntaxes by checking the server
     version string for MariaDB presence.  Alembic migrations has
     already worked around this issue by implementing its own DROP for
     MySQL / MariaDB CHECK constraints, however this change implements
     it straight in Core so that its available for general use.  Pull
     request courtesy Hannes Hansen.

     References: #4650(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4650

8.3.2.146 mssql
...............

   * `[mssql] [feature]' ¶. Added support for SQL Server
     filtered indexes, via the ‘mssql_where’ parameter which works
     similarly to that of the ‘postgresql_where’ index function in the
     PostgreSQL dialect.

     See also
     ........

     See Filtered Indexes.

     References: #4657(1)

   * `[mssql] [bug]' ¶. Added error code 20047 to
     “is_disconnect” for pymssql.  Pull request courtesy Jon Schuff.

     References: #4680(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4657

   (2) http://www.sqlalchemy.org/trac/ticket/4680

8.3.2.147 misc
..............

   * `[misc] [bug]' ¶. Removed errant “sqla_nose.py” symbol
     from MANIFEST.in which created an undesirable warning message.

     References: #4625(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4625

8.3.2.148 1.3.3
...............

Released: April 15, 2019

8.3.2.149 orm
.............

   * `[orm] [bug]' ¶. Fixed 1.3 regression in new “ambiguous
     FROMs” query logic introduced in Query.join() handles ambiguity in deciding the “left” side more explicitly
     where
     a Query that explicitly places an entity in the FROM
     clause with Query.select_from() and also joins to it
     using Query.join() would later cause an “ambiguous
     FROM” error if that entity were used in additional joins, as the
     entity appears twice in the “from” list of the Query.
     The fix resolves this ambiguity by folding the standalone entity
     into the join that it’s already a part of in the same way that
     ultimately happens when the SELECT statement is rendered.

     References: #4584(1)

   * `[orm] [bug]' ¶. Adjusted the Query.filter_by()
     method to not call ‘and()’ internally against multiple
     criteria, instead passing it off to Query.filter() as a
     series of criteria, instead of a single criteria.  This allows
     Query.filter_by() to defer to Query.filter().
     ’s treatment of variable numbers of clauses, including the case
     where the list is empty.  In this case, the Query
     object will not have a ‘.whereclause’, which allows subsequent “no
     whereclause” methods like Query.select_from() to behave
     consistently.

     References: #4606(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4584

   (2) http://www.sqlalchemy.org/trac/ticket/4606

8.3.2.150 postgresql
....................

   * `[postgresql] [bug]' ¶. Fixed regression from release
     1.3.2 caused by #4562(1) where a URL that contained only a query
     string and no hostname, such as for the purposes of specifying a
     service file with connection information, would no longer be
     propagated to psycopg2 properly.  The change in #4562(2) has been
     adjusted to further suit psycopg2’s exact requirements, which is
     that if there are any connection parameters whatsoever, the “dsn”
     parameter is no longer required, so in this case the query string
     parameters are passed alone.

     References: #4601(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4562

   (2) http://www.sqlalchemy.org/trac/ticket/4562

   (3) http://www.sqlalchemy.org/trac/ticket/4601

8.3.2.151 mssql
...............

   * `[mssql] [bug]' ¶. Fixed issue in SQL Server dialect
     where if a bound parameter were present in an ORDER BY expression
     that would ultimately not be rendered in the SQL Server version of
     the statement, the parameters would still be part of the execution
     parameters, leading to DBAPI-level errors.  Pull request courtesy
     Matt Lewellyn.

     References: #4587(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4587

8.3.2.152 misc
..............

   * `[bug] [pool]' ¶. Fixed behavioral regression as a
     result of deprecating the “use_threadlocal” flag for Pool,
     where the SingletonThreadPool no longer makes
     use of this option which causes the “rollback on return” logic to
     take place when the same Engine is used multiple times
     in the context of a transaction to connect or implicitly execute,
     thereby cancelling the transaction.  While this is not the
     recommended way to work with engines and connections, it is
     nonetheless a confusing behavioral change as when using
     SingletonThreadPool, the transaction should stay open
     regardless of what else is done with the same engine in the same
     thread.  The ‘use_threadlocal’ flag remains deprecated however the
     SingletonThreadPool now implements its own version of
     the same logic.

     References: #4585(1)

   * `[bug] [ext]' ¶. Fixed bug where using ‘copy.copy()’ or
     ‘copy.deepcopy()’ on MutableList would cause the items
     within the list to be duplicated, due to an inconsistency in how
     Python pickle and copy both make use of ‘__getstate__()’ and
     ‘__setstate__()’ regarding lists.  In order to resolve, a
     ‘__reduce_ex__’ method had to be added to MutableList.
     In order to maintain backwards compatibility with existing pickles
     based on ‘__getstate__()’, the ‘__setstate__()’ method remains as
     well; the test suite asserts that pickles made against the old
     version of the class can still be deserialized by the pickle
     module.

     References: #4603(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4585

   (2) http://www.sqlalchemy.org/trac/ticket/4603

8.3.2.153 1.3.2
...............

Released: April 2, 2019

8.3.2.154 orm
.............

   * `[orm] [bug] [ext]' ¶. Restored instance-level support
     for plain Python descriptors, e.g.  ‘@property’ objects, in
     conjunction with association proxies, in that if the proxied object
     is not within ORM scope at all, it gets classified as “ambiguous”
     but is proxed directly.  For class level access, a basic class
     level‘‘__get__()‘‘ now returns the
     ‘AmbiguousAssociationProxyInstance’ directly, rather than raising
     its exception, which is the closest approximation to the previous
     behavior that returned the AssociationProxy itself
     that’s possible.  Also improved the stringification of these
     objects to be more descriptive of current state.

     References: #4573(1), #4574(2)

   * `[orm] [bug]' ¶. Fixed bug where use of
     with_polymorphic() or other aliased construct would not
     properly adapt when the aliased target were used as the
     Select.correlate_except() target of a subquery used inside of
     a column_property().  This required a fix to the clause
     adaption mechanics to properly handle a selectable that shows up in
     the “correlate except” list, in a similar manner as which occurs
     for selectables that show up in the “correlate” list.  This is
     ultimately a fairly fundamental bug that has lasted for a long time
     but it is hard to come across it.

     References: #4537(3)

   * `[orm] [bug]' ¶. Fixed regression where a new error
     message that was supposed to raise when attempting to link a
     relationship option to an AliasedClass without using
     PropComparator.of_type() would instead raise an
     ‘AttributeError’.  Note that in 1.3, it is no longer valid to
     create an option path from a plain mapper relationship to an
     AliasedClass without using PropComparator.of_type().

     References: #4566(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4573

   (2) http://www.sqlalchemy.org/trac/ticket/4574

   (3) http://www.sqlalchemy.org/trac/ticket/4537

   (4) http://www.sqlalchemy.org/trac/ticket/4566

8.3.2.155 sql
.............

   * `[sql] [bug] [documentation]' ¶. Thanks to
     TypeEngine methods bind_expression, column_expression work with Variant, type-specific types,
     we no longer need to rely on
     recipes that subclass dialect-specific types directly, see
     TypeDecorator can now handle all cases.  Additionally, the
     above change made it slightly less likely that a direct subclass of
     a base SQLAlchemy type would work as expected, which could be
     misleading.  Documentation has been updated to use
     TypeDecorator for these examples including the PostgreSQL
     “ArrayOfEnum” example datatype and direct support for the “subclass
     a type directly” has been removed.

     References: #4580(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4580

8.3.2.156 postgresql
....................

   * `[postgresql] [feature]' ¶. Added support for
     parameter-less connection URLs for the psycopg2 dialect, meaning,
     the URL can be passed to create_engine() as
     ‘"postgresql+psycopg2://"’ with no additional arguments to indicate
     an empty DSN passed to libpq, which indicates to connect to
     “localhost” with no username, password, or database given.  Pull
     request courtesy Julian Mehnle.

     References: #4562(1)

   * `[postgresql] [bug]' ¶. Modified the
     Select.with_for_update.of parameter so that if a join or
     other composed selectable is passed, the individual Table
     objects will be filtered from it, allowing one to pass a join()
     object to the parameter, as occurs normally when using joined table
     inheritance with the ORM. Pull request courtesy Raymond Lu.

     References: #4550(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4562

   (2) http://www.sqlalchemy.org/trac/ticket/4550

8.3.2.157 1.3.1
...............

Released: March 9, 2019

8.3.2.158 orm
.............

   * `[orm] [bug] [ext]' ¶. Fixed regression where an
     association proxy linked to a synonym would no longer work, both at
     instance level and at class level.

     References: #4522(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4522

8.3.2.159 mssql
...............

   * `[mssql] [bug]' ¶. A commit() is emitted after an
     isolation level change to SNAPSHOT, as both pyodbc and pymssql open
     an implicit transaction which blocks subsequent SQL from being
     emitted in the current transaction.

     This change is also `backported' to: 1.2.19

     References: #4536(1)

   * `[mssql] [bug]' ¶. Fixed regression in SQL Server
     reflection due to #4393(2) where the removal of open-ended ‘**kw’
     from the Float datatype caused reflection of this type
     to fail due to a “scale” argument being passed.

     References: #4525(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4536

   (2) http://www.sqlalchemy.org/trac/ticket/4393

   (3) http://www.sqlalchemy.org/trac/ticket/4525

8.3.2.160 1.3.0
...............

Released: March 4, 2019

8.3.2.161 orm
.............

   * `[orm] [feature]' ¶. The Query.get() method
     can now accept a dictionary of attribute keys and values as a means
     of indicating the primary key value to load; is particularly useful
     for composite primary keys.  Pull request courtesy Sanjana S.

     References: #4316(1)

   * `[orm] [feature]' ¶. A SQL expression can now be
     assigned to a primary key attribute for an ORM flush in the same
     manner as ordinary attributes as described in Embedding SQL Insert/Update Expressions into a Flush
     where the expression
     will be evaulated and then returned to the ORM using RETURNING, or
     in the case of pysqlite, works using the cursor.lastrowid
     attribute.Requires either a database that supports RETURNING (e.g.
     Postgresql, Oracle, SQL Server) or pysqlite.

     References: #3133(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4316

   (2) http://www.sqlalchemy.org/trac/ticket/3133

8.3.2.162 engine
................

   * `[engine] [feature]' ¶. Revised the formatting for
     StatementError when stringified.  Each error detail is
     broken up over multiple newlines instead of spaced out on a single
     line.  Additionally, the SQL representation now stringifies the SQL
     statement rather than using ‘repr()’, so that newlines are rendered
     as is.  Pull request courtesy Nate Clark.

     See also
     ........

     See Changed StatementError formatting (newlines and %s).

     References: #4500(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4500

8.3.2.163 sql
.............

   * `[sql] [bug]' ¶. The Alias class and
     related subclasses CTE, Lateral and
     TableSample have been reworked so that it is not possible for
     a user to construct the objects directly.  These constructs require
     that the standalone construction function or selectable-bound
     method be used to instantiate new objects.

     References: #4509(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4509

8.3.2.164 schema
................

   * `[schema] [feature]' ¶. Added new parameters
     Table.resolve_fks and MetaData.reflect.resolve_fks
     which when set to False will disable the automatic reflection
     of related tables encountered in ForeignKey objects,
     which can both reduce SQL overhead for omitted tables as well as
     avoid tables that can’t be reflected for database-specific reasons.
     Two Table objects present in the same MetaData
     collection can still refer to each other even if the reflection
     of the two tables occurred separately.

     References: #4517(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4517

8.3.2.165 1.3.0b3
.................

Released: February 8, 2019

8.3.2.166 orm
.............

   * `[orm] [bug]' ¶. Improved the behavior of
     with_polymorphic() in conjunction with loader options, in
     particular wildcard operations as well as load_only().
     The polymorphic object will be more accurately targeted so that
     column-level options on the entity will correctly take effect.The
     issue is a continuation of the same kinds of things fixed in
     #4468(1).

     References: #4469(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4468

   (2) http://www.sqlalchemy.org/trac/ticket/4469

8.3.2.167 orm declarative
.........................

   * `[orm] [declarative] [bug]' ¶. Added some helper
     exceptions that invoke when a mapping based on
     AbstractConcreteBase, DeferredReflection, or
     ‘AutoMap’ is used before the mapping is ready to be used, which
     contain descriptive information on the class, rather than falling
     through into other failure modes that are less informative.

     References: #4470(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4470

8.3.2.168 sql
.............

   * `[sql] [bug]' ¶. Fully removed the behavior of strings
     passed directly as components of a select() or
     Query object being coerced to text() constructs
     automatically; the warning that has been emitted is now an
     ArgumentError or in the case of order_by() / group_by() a
     CompileError.  This has emitted a warning since version 1.0 however
     its presence continues to create concerns for the potential of
     mis-use of this behavior.

     Note that public CVEs have been posted for order_by() / group_by()
     which are resolved by this commit: CVE-2019-7164 CVE-2019-7548

     See also
     ........

     See Coercion of string SQL fragments to text() fully removed.

     References: #4481(1)

   * `[sql] [bug]' ¶. Quoting is applied to Function
     names, those which are usually but not necessarily generated
     from the sqlalchemy.sql.expression.func construct, at
     compile time if they contain illegal characters, such as spaces or
     punctuation.  The names are as before treated as case insensitive
     however, meaning if the names contain uppercase or mixed case
     characters, that alone does not trigger quoting.  The case
     insensitivity is currently maintained for backwards compatibility.

     References: #4467(2)

   * `[sql] [bug]' ¶. Added “SQL phrase validation” to key
     DDL phrases that are accepted as plain strings, including
     ForeignKeyConstraint.on_delete,
     ForeignKeyConstraint.on_update,
     ExcludeConstraint.using,
     ForeignKeyConstraint.initially, for areas where a series of
     SQL keywords only are expected.Any non-space characters that
     suggest the phrase would need to be quoted will raise a
     CompileError.  This change is related to the series of changes
     committed as part of #4481(3).

     References: #4481(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4481

   (2) http://www.sqlalchemy.org/trac/ticket/4467

   (3) http://www.sqlalchemy.org/trac/ticket/4481

   (4) http://www.sqlalchemy.org/trac/ticket/4481

8.3.2.169 postgresql
....................

   * `[postgresql] [bug]' ¶. Fixed issue where using an
     uppercase name for an index type (e.g.  GIST, BTREE, etc.  ) or an
     EXCLUDE constraint would treat it as an identifier to be quoted,
     rather than rendering it as is.  The new behavior converts these
     types to lowercase and ensures they contain only valid SQL
     characters.

     References: #4473(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4473

8.3.2.170 misc
..............

   * `[change] [tests]' ¶. The test system has removed
     support for Nose, which is unmaintained for several years and is
     producing warnings under Python 3.  The test suite is currently
     standardized on Pytest.  Pull request courtesy Parth Shandilya.

     References: #4460(1)

   * `[bug] [ext]' ¶. Implemented a more comprehensive
     assignment operation (e.g.  “bulk replace”) when using association
     proxy with sets or dictionaries.  Fixes the problem of redundant
     proxy objects being created to replace the old ones, which leads to
     excessive events and SQL and in the case of unique constraints will
     cause the flush to fail.

     See also
     ........

     See Implemented bulk replace for sets, dicts with AssociationProxy.

     References: #2642(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4460

   (2) http://www.sqlalchemy.org/trac/ticket/2642

8.3.2.171 1.3.0b2
.................

Released: January 25, 2019

8.3.2.172 general
.................

   * `[general] [change]' ¶. A large change throughout the
     library has ensured that all objects, parameters, and behaviors
     which have been noted as deprecated or legacy now emit
     ‘DeprecationWarning’ warnings when invoked.As the Python 3
     interpreter now defaults to displaying deprecation warnings, as
     well as that modern test suites based on tools like tox and pytest
     tend to display deprecation warnings, this change should make it
     easier to note what API features are obsolete.  A major rationale
     for this change is so that long- deprecated features that
     nonetheless still see continue to see real world use can finally be
     removed in the near future; the biggest example of this are the
     ‘SessionExtension’ and ‘MapperExtension’ classes as well as a
     handful of other pre-event extension hooks, which have been
     deprecated since version 0.7 but still remain in the library.
     Another is that several major longstanding behaviors are to be
     deprecated as well, including the threadlocal engine strategy, the
     convert_unicode flag, and non primary mappers.

     See also
     ........

     See Deprecation warnings are emitted for all deprecated elements; new deprecations added.

     References: #4393(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4393

8.3.2.173 orm
.............

   * `[orm] [feature]' ¶. Implemented a new feature whereby
     the AliasedClass construct can now be used as the
     target of a relationship().  This allows the concept of
     “non primary mappers” to no longer be necessary, as the
     AliasedClass is much easier to configure and automatically
     inherits all the relationships of the mapped class, as well as
     preserves the ability for loader options to work normally.

     See also
     ........

     See Relationship to AliasedClass replaces the need for non primary mappers.

     References: #4423(1)

   * `[orm] [feature]' ¶. Added new
     MapperEvents.before_mapper_configured() event.  This event
     complements the other “configure” stage mapper events with a per
     mapper event that receives each Mapper right before its
     configure step, and additionally may be used to prevent or delay
     the configuration of specific Mapper objects using a
     new return value ‘interfaces.EXT_SKIP’.  See the documentation link
     for an example.

     See also
     ........

     See MapperEvents.before_mapper_configured().

     References: #4397(2)

   * `[orm] [change]' ¶. Added a new function
     close_all_sessions() which takes over the task of the
     Session.close_all() method, which is now deprecated as this
     is confusing as a classmethod.  Pull request courtesy Augustin
     Trancart.

     References: #4412(3)

   * `[orm] [bug]' ¶. Fixed long-standing issue where
     duplicate collection members would cause a backref to delete the
     association between the member and its parent object when one of
     the duplicates were removed, as occurs as a side effect of swapping
     two objects in one statement.

     See also
     ........

     See Many-to-one backref checks for collection duplicates during remove operation.

     References: #1103(4)

   * `[orm] [bug]' ¶. Extended the fix first made as part of
     #3287(5), where a loader option made against a subclass using a
     wildcard would extend itself to include application of the wildcard
     to attributes on the super classes as well, to a “bound” loader
     option as well, e.g.  in an expression like
     ‘Load(SomeSubClass).load_only('foo')’.  Columns that are part of
     the parent class of ‘SomeSubClass’ will also be excluded in the
     same way as if the unbound option ‘load_only('foo')’ were used.

     References: #4373(6)

   * `[orm] [bug]' ¶. Improved error messages emitted by the
     ORM in the area of loader option traversal.  This includes early
     detection of mis-matched loader strategies along with a clearer
     explanation why these strategies don’t match.

     References: #4433(7)

   * `[orm] [bug]' ¶. The “remove” event for collections is
     now called before the item is removed in the case of the
     ‘collection.remove()’ method, as is consistent with the behavior
     for most other forms of collection item removal (such as
     ‘__delitem__’, replacement under ‘__setitem__’).  For ‘pop()’
     methods, the remove event still fires after the operation.

   * `[orm] [bug] [engine]' ¶. Added accessors for execution
     options to Core and ORM, via Query.get_execution_options(),
     see Connection.get_execution_options(),
     Engine.get_execution_options(), and
     Executable.get_execution_options().  PR courtesy Daniel
     Lister.

     References: #4464(8)

   * `[orm] [bug]' ¶. Fixed issue in association proxy due
     to #3423(9) which caused the use of custom PropComparator
     objects with hybrid attributes, such as the one demonstrated
     in the ‘dictlike-polymorphic’ example to not function within an
     association proxy.  The strictness that was added in #3423(10) has
     been relaxed, and additional logic to accommodate for an
     association proxy that links to a custom hybrid have been added.

     References: #4446(11)

   * `[orm] [bug]' ¶. Implemented the ‘.get_history()’
     method, which also implies availability of
     AttributeState.history, for synonym() attributes.
     Previously, trying to access attribute history via a synonym would
     raise an ‘AttributeError’.

     References: #3777(12)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4423

   (2) http://www.sqlalchemy.org/trac/ticket/4397

   (3) http://www.sqlalchemy.org/trac/ticket/4412

   (4) http://www.sqlalchemy.org/trac/ticket/1103

   (5) http://www.sqlalchemy.org/trac/ticket/3287

   (6) http://www.sqlalchemy.org/trac/ticket/4373

   (7) http://www.sqlalchemy.org/trac/ticket/4433

   (8) http://www.sqlalchemy.org/trac/ticket/4464

   (9) http://www.sqlalchemy.org/trac/ticket/3423

   (10) http://www.sqlalchemy.org/trac/ticket/3423

   (11) http://www.sqlalchemy.org/trac/ticket/4446

   (12) http://www.sqlalchemy.org/trac/ticket/3777

8.3.2.174 orm declarative
.........................

   * `[bug] [orm declarative]' ¶. Added a
     ‘__clause_element__()’ method to ColumnProperty which
     can allow the usage of a not-fully-declared column or deferred
     attribute in a declarative mapped class slightly more friendly when
     it’s used in a constraint or other column-oriented scenario within
     the class declaration, though this still can’t work in open-ended
     expressions; prefer to call the ColumnProperty.expression
     attribute if receiving ‘TypeError’.

     References: #4372(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4372

8.3.2.175 engine
................

   * `[engine] [feature]' ¶. Added public accessor
     ‘QueuePool.timeout()’ that returns the configured timeout for a
     QueuePool object.  Pull request courtesy Irina
     Delamare.

     References: #3689(1)

   * `[engine] [change]' ¶. The “threadlocal” engine
     strategy which has been a legacy feature of SQLAlchemy since around
     version 0.2 is now deprecated, along with the
     Pool.threadlocal parameter of Pool which has no
     effect in most modern use cases.

     See also
     ........

     See “threadlocal” engine strategy deprecated.

     References: #4393(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3689

   (2) http://www.sqlalchemy.org/trac/ticket/4393

8.3.2.176 sql
.............

   * `[sql] [feature]' ¶. Amended the AnsiFunction
     class, the base of common SQL functions like
     ‘CURRENT_TIMESTAMP’, to accept positional arguments like a regular
     ad-hoc function.  This to suit the case that many of these
     functions on specific backends accept arguments such as “fractional
     seconds” precision and such.  If the function is created with
     arguments, it renders the parenthesis and the arguments.  If no
     arguments are present, the compiler generates the non-parenthesized
     form.

     References: #4386(1)

   * `[sql] [change]' ¶. The
     create_engine.convert_unicode and
     String.convert_unicode parameters have been deprecated.
     These parameters were built back when most Python DBAPIs had little
     to no support for Python Unicode objects, and SQLAlchemy needed to
     take on the very complex task of marshalling data and SQL strings
     between Unicode and bytestrings throughout the system in a
     performant way.  Thanks to Python 3, DBAPIs were compelled to adapt
     to Unicode-aware APIs and today all DBAPIs supported by SQLAlchemy
     support Unicode natively, including on Python 2, allowing this
     long-lived and very complicated feature to finally be (mostly)
     removed.  There are still of course a few Python 2 edge cases where
     SQLAlchemy has to deal with Unicode however these are handled
     automatically; in modern use, there should be no need for end-user
     interaction with these flags.

     See also
     ........

     See convert_unicode parameters deprecated.

     References: #4393(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4386

   (2) http://www.sqlalchemy.org/trac/ticket/4393

8.3.2.177 mssql
...............

   * `[mssql] [bug]' ¶. The ‘literal_processor’ for the
     Unicode and UnicodeText datatypes now
     render an ‘N’ character in front of the literal string expression
     as required by SQL Server for Unicode string values rendered in SQL
     expressions.

     References: #4442(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4442

8.3.2.178 misc
..............

   * `[bug] [ext]' ¶. Fixed a regression in 1.3.0b1 caused
     by #3423(1) where association proxy objects that access an
     attribute that’s only present on a polymorphic subclass would raise
     an ‘AttributeError’ even though the actual instance being accessed
     was an instance of that subclass.

     References: #4401(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3423

   (2) http://www.sqlalchemy.org/trac/ticket/4401

8.3.2.179 1.3.0b1
.................

Released: November 16, 2018

8.3.2.180 orm
.............

   * `[orm] [feature]' ¶. Added new feature
     Query.only_return_tuples().  Causes the Query
     object to return keyed tuple objects unconditionally even if the
     query is against a single entity.  Pull request courtesy Eric
     Atkin.

     This change is also `backported' to: 1.2.5

   * `[orm] [feature]' ¶. Added new flag
     Session.bulk_save_objects.preserve_order to the
     Session.bulk_save_objects() method, which defaults to True.
     When set to False, the given mappings will be grouped into inserts
     and updates per each object type, to allow for greater
     opportunities to batch common operations together.  Pull request
     courtesy Alessandro Cucci.

   * `[orm] [feature]' ¶. The “selectin” loader strategy now
     omits the JOIN in the case of a simple one-to-many load, where it
     instead relies loads only from the related table, relying upon the
     foreign key columns of the related table in order to match up to
     primary keys in the parent table.  This optimization can be
     disabled by setting the relationship.omit_join flag to
     False.  Many thanks to Jayson Reis for the efforts on this.

     See also
     ........

     See selectin loading no longer uses JOIN for simple one-to-many.

     References: #4340(1)

   * `[orm] [feature]' ¶. Added ‘.info’ dictionary to the
     InstanceState class, the object that comes from calling
     inspect() on a mapped object.

     See also
     ........

     See info dictionary added to InstanceState.

     References: #4257(2)

   * `[orm] [bug]' ¶. Fixed bug where use of Lateral
     construct in conjunction with Query.join() as well
     as Query.select_entity_from() would not apply clause
     adaption to the right side of the join.  “lateral” introduces the
     use case of the right side of a join being correlatable.
     Previously, adaptation of this clause wasn’t considered.  Note that
     in 1.2 only, a selectable introduced by Query.subquery()
     is still not adapted due to #4304(3); the selectable needs to
     be produced by the select() function to be the right
     side of the “lateral” join.

     This change is also `backported' to: 1.2.12

     References: #4334(4)

   * `[orm] [bug]' ¶. Fixed issue regarding
     passive_deletes=”all”, where the foreign key attribute of an object
     is maintained with its value even after the object is removed from
     its parent collection.  Previously, the unit of work would set this
     to NULL even though passive_deletes indicated it should not be
     modified.

     See also
     ........

     See passive_deletes=’all’ will leave FK unchanged for object removed from collection.

     References: #3844(5)

   * `[orm] [bug]' ¶. Improved the behavior of a
     relationship-bound many-to-one object expression such that the
     retrieval of column values on the related object are now resilient
     against the object being detached from its parent Session,
     even if the attribute has been expired.  New features within
     the InstanceState are used to memoize the last known
     value of a particular column attribute before its expired, so that
     the expression can still evaluate when the object is detached and
     expired at the same time.  Error conditions are also improved using
     modern attribute state features to produce more specific messages
     as needed.

     See also
     ........

     See Improvement to the behavior of many-to-one query expressions.

     References: #4359(6)

   * `[orm] [bug] [mysql] [postgresql]' ¶. The ORM now
     doubles the “FOR UPDATE” clause within the subquery that renders in
     conjunction with joined eager loading in some cases, as it has been
     observed that MySQL does not lock the rows from a subquery.  This
     means the query renders with two FOR UPDATE clauses; note that on
     some backends such as Oracle, FOR UPDATE clauses on subqueries are
     silently ignored since they are unnecessary.  Additionally, in the
     case of the “OF” clause used primarily with PostgreSQL, the FOR
     UPDATE is rendered only on the inner subquery when this is used so
     that the selectable can be targeted to the table within the SELECT
     statement.

     See also
     ........

     See FOR UPDATE clause is rendered within the joined eager load subquery as well as outside.

     References: #4246(7)

   * `[orm] [bug]' ¶. Refactored Query.join() to
     further clarify the individual components of structuring the join.
     This refactor adds the ability for Query.join() to
     determine the most appropriate “left” side of the join when there
     is more than one element in the FROM list or the query is against
     multiple entities.  If more than one FROM/entity matches, an error
     is raised that asks for an ON clause to be specified to resolve the
     ambiguity.  In particular this targets the regression we saw in
     #4363(8) but is also of general use.  The codepaths within
     Query.join() are now easier to follow and the error cases are
     decided more specifically at an earlier point in the operation.

     See also
     ........

     See Query.join() handles ambiguity in deciding the “left” side more explicitly.

     References: #4365(9)

   * `[orm] [bug]' ¶. Fixed long-standing issue in
     Query where a scalar subquery such as produced by
     Query.exists(), Query.as_scalar() and other
     derivations from Query.statement would not correctly be
     adapted when used in a new Query that required entity
     adaptation, such as when the query were turned into a union, or a
     from_self(), etc.  The change removes the “no adaptation”
     annotation from the select() object produced by the
     Query.statement accessor.

     References: #4304(10)

   * `[orm] [bug]' ¶. An informative exception is re-raised
     when a primary key value is not sortable in Python during an ORM
     flush under Python 3, such as an ‘Enum’ that has no ‘__lt__()’
     method; normally Python 3 raises a ‘TypeError’ in this case.  The
     flush process sorts persistent objects by primary key in Python so
     the values must be sortable.

     References: #4232(11)

   * `[orm] [bug]' ¶. Removed the collection converter used
     by the MappedCollection class.  This converter was used
     only to assert that the incoming dictionary keys matched that of
     their corresponding objects, and only during a bulk set operation.
     The converter can interfere with a custom validator or
     AttributeEvents.bulk_replace() listener that wants to convert
     incoming values further.  The ‘TypeError’ which would be raised by
     this converter when an incoming key didn’t match the value is
     removed; incoming values during a bulk assignment will be keyed to
     their value-generated key, and not the key that’s explicitly
     present in the dictionary.

     Overall, @converter is superseded by the
     AttributeEvents.bulk_replace() event handler added as part of
     #3896(12).

     References: #3604(13)

   * `[orm] [bug]' ¶. Added new behavior to the lazy load
     that takes place when the “old” value of a many-to-one is
     retrieved, such that exceptions which would be raised due to either
     ‘lazy="raise"’ or a detached session error are skipped.

     See also
     ........

     See Many-to-one replacement won’t raise for “raiseload” or detached for “old” object.

     References: #4353(14)

   * `[orm] [bug]' ¶. A long-standing oversight in the ORM,
     the ‘__delete__’ method for a many- to-one relationship was
     non-functional, e.g.  for an operation such as ‘del a.b’.  This is
     now implemented and is equivalent to setting the attribute to
     ‘None’.

     See also
     ........

     See “del” implemented for ORM attributes.

     References: #4354(15)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4340

   (2) http://www.sqlalchemy.org/trac/ticket/4257

   (3) http://www.sqlalchemy.org/trac/ticket/4304

   (4) http://www.sqlalchemy.org/trac/ticket/4334

   (5) http://www.sqlalchemy.org/trac/ticket/3844

   (6) http://www.sqlalchemy.org/trac/ticket/4359

   (7) http://www.sqlalchemy.org/trac/ticket/4246

   (8) http://www.sqlalchemy.org/trac/ticket/4363

   (9) http://www.sqlalchemy.org/trac/ticket/4365

   (10) http://www.sqlalchemy.org/trac/ticket/4304

   (11) http://www.sqlalchemy.org/trac/ticket/4232

   (12) http://www.sqlalchemy.org/trac/ticket/3896

   (13) http://www.sqlalchemy.org/trac/ticket/3604

   (14) http://www.sqlalchemy.org/trac/ticket/4353

   (15) http://www.sqlalchemy.org/trac/ticket/4354

8.3.2.181 orm declarative
.........................

   * `[orm] [declarative] [bug]' ¶. Fixed bug where
     declarative would not update the state of the Mapper as
     far as what attributes were present, when additional attributes
     were added or removed after the mapper attribute collections had
     already been called and memoized.  Additionally, a
     ‘NotImplementedError’ is now raised if a fully mapped attribute
     (e.g.  column, relationship, etc.)  is deleted from a class that is
     currently mapped, since the mapper will not function correctly if
     the attribute has been removed.

     References: #4133(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4133

8.3.2.182 engine
................

   * `[engine] [feature]' ¶. Added new “lifo” mode to
     QueuePool, typically enabled by setting the flag
     create_engine.pool_use_lifo to True.  “lifo” mode means the
     same connection just checked in will be the first to be checked out
     again, allowing excess connections to be cleaned up from the server
     side during periods of the pool being only partially utilized.
     Pull request courtesy Taem Park.

     See also
     ........

     See New last-in-first-out strategy for QueuePool.

8.3.2.183 sql
.............

   * `[sql] [feature]' ¶. Refactored SQLCompiler
     to expose a SQLCompiler.group_by_clause() method
     similar to the SQLCompiler.order_by_clause() and
     ‘SQLCompiler.limit_clause()’ methods, which can be overridden by
     dialects to customize how GROUP BY renders.  Pull request courtesy
     Samuel Chou.

     This change is also `backported' to: 1.2.13

   * `[sql] [feature]' ¶. Added Sequence to the
     “string SQL” system that will render a meaningful string expression
     (‘"<next sequence value: my_sequence>"’) when stringifying without
     a dialect a statement that includes a “sequence nextvalue”
     expression, rather than raising a compilation error.

     References: #4144(1)

   * `[sql] [feature]' ¶. Added new naming convention tokens
     ‘column_0N_name’, ‘column_0_N_name’, etc., which will render the
     names / keys / labels for all columns referenced by a particular
     constraint in a sequence.  In order to accommodate for the length
     of such a naming convention, the SQL compiler’s auto-truncation
     feature now applies itself to constraint names as well, which
     creates a shortened, deterministically generated name for the
     constraint that will apply to a target backend without going over
     the character limit of that backend.

     The change also repairs two other issues.  One is that the
     ‘column_0_key’ token wasn’t available even though this token was
     documented, the other was that the ‘referred_column_0_name’ token
     would inadvertently render the ‘.key’ and not the ‘.name’ of the
     column if these two values were different.

     See also
     ........

     See New multi-column naming convention tokens, long name truncation.

     References: #3989(2)

   * `[sql] [feature]' ¶. 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.

     See also
     ........

     See Expanding IN feature now supports empty lists.

     References: #4271(3)

   * `[sql] [feature]' ¶. The Python builtin ‘dir()’ is now
     supported for a SQLAlchemy “properties” object, such as that of a
     Core columns collection (e.g.  ‘.c’), ‘mapper.attrs’, etc.  Allows
     iPython autocompletion to work as well.  Pull request courtesy Uwe
     Korn.

   * `[sql] [feature]' ¶. Added new feature
     FunctionElement.as_comparison() which allows a SQL function
     to act as a binary comparison operation that can work within the
     ORM.

     See also
     ........

     See Binary comparison interpretation for SQL functions.

     References: #3831(4)

   * `[sql] [bug]' ¶. Added “like” based operators as
     “comparison” operators, including
     ColumnOperators.startswith(). See
     ColumnOperators.endswith(). See ColumnOperators.ilike().
     ColumnOperators.notilike() among many others, so
     that all of these operators can be the basis for an ORM
     “primaryjoin” condition.

     References: #4302(5)

   * `[sql] [bug]' ¶. Fixed issue with
     TypeEngine.bind_expression() and
     TypeEngine.column_expression() methods where these methods
     would not work if the target type were part of a Variant,
     or other target type of a TypeDecorator.
     Additionally, the SQL compiler now calls upon the dialect-level
     implementation when it renders these methods so that dialects can
     now provide for SQL-level processing for built-in types.

     See also
     ........

     See TypeEngine methods bind_expression, column_expression work with Variant, type-specific types.

     References: #3981(6)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4144

   (2) http://www.sqlalchemy.org/trac/ticket/3989

   (3) http://www.sqlalchemy.org/trac/ticket/4271

   (4) http://www.sqlalchemy.org/trac/ticket/3831

   (5) http://www.sqlalchemy.org/trac/ticket/4302

   (6) http://www.sqlalchemy.org/trac/ticket/3981

8.3.2.184 postgresql
....................

   * `[postgresql] [feature]' ¶. Added new PG type
     REGCLASS which assists in casting table names to OID values.
     Pull request courtesy Sebastian Bank.

     This change is also `backported' to: 1.2.7

     References: #4160(1)

   * `[postgresql] [feature]' ¶. Added rudimental support
     for reflection of PostgreSQL partitioned tables, e.g.  that
     relkind=’p’ is added to reflection queries that return table
     information.

     See also
     ........

     See Added basic reflection support for PostgreSQL partitioned tables.

     References: #4237(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4160

   (2) http://www.sqlalchemy.org/trac/ticket/4237

8.3.2.185 mysql
...............

   * `[mysql] [feature]' ¶. Support added for the “WITH
     PARSER” syntax of CREATE FULLTEXT INDEX in MySQL, using the
     ‘mysql_with_parser’ keyword argument.  Reflection is also
     supported, which accommodates MySQL’s special comment format for
     reporting on this option as well.  Additionally, the “FULLTEXT” and
     “SPATIAL” index prefixes are now reflected back into the
     ‘mysql_prefix’ index option.

     References: #4219(1)

   * `[mysql] [feature]' ¶. Added support for the parameters
     in an ON DUPLICATE KEY UPDATE statement on MySQL to be ordered,
     since parameter order in a MySQL UPDATE clause is significant, in a
     similar manner as that described at Parameter-Ordered Updates.
     Pull request courtesy Maxim Bublis.

     See also
     ........

     See Control of parameter ordering within ON DUPLICATE KEY UPDATE.

   * `[mysql] [feature]' ¶. The “pre-ping” feature of the
     connection pool now uses the ‘ping()’ method of the DBAPI
     connection in the case of mysqlclient, PyMySQL and
     mysql-connector-python.  Pull request courtesy Maxim Bublis.

     See also
     ........

     See Protocol-level ping now used for pre-ping.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4219

8.3.2.186 sqlite
................

   * `[sqlite] [feature]' ¶. Added support for SQLite’s json
     functionality via the new SQLite implementation for JSON,
     see JSON.  The name used for the type is ‘JSON’,
     following an example found at SQLite’s own documentation.  Pull
     request courtesy Ilja Everilä.

     See also
     ........

     See Support for SQLite JSON Added.

     References: #3850(1)

   * `[sqlite] [feature]' ¶. Implemented the SQLite ‘ON
     CONFLICT’ clause as understood at the DDL level, e.g.  for primary
     key, unique, and CHECK constraints as well as specified on a
     Column to satisfy inline primary key and NOT NULL. Pull
     request courtesy Denis Kataev.

     See also
     ........

     See Support for SQLite ON CONFLICT in constraints added.

     References: #4360(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3850

   (2) http://www.sqlalchemy.org/trac/ticket/4360

8.3.2.187 mssql
...............

   * `[mssql] [feature]' ¶. Added ‘fast_executemany=True’
     parameter to the SQL Server pyodbc dialect, which enables use of
     pyodbc’s new performance feature of the same name when using
     Microsoft ODBC drivers.

     See also
     ........

     See Support for pyodbc fast_executemany.

     References: #4158(1)

   * `[mssql] [bug]' ¶. Deprecated the use of
     Sequence with SQL Server in order to affect the “start” and
     “increment” of the IDENTITY value, in favor of new parameters
     ‘mssql_identity_start’ and ‘mssql_identity_increment’ which set
     these parameters directly.  Sequence will be used to
     generate real ‘CREATE SEQUENCE’ DDL with SQL Server in a future
     release.

     See also
     ........

     See New parameters to affect IDENTITY start and increment, use of Sequence deprecated.

     References: #4362(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4158

   (2) http://www.sqlalchemy.org/trac/ticket/4362

8.3.2.188 oracle
................

   * `[oracle] [feature]' ¶. Added a new event currently
     used only by the cx_Oracle dialect, ‘DialectEvents.setiputsizes()’.
     The event passes a dictionary of BindParameter objects
     to DBAPI-specific type objects that will be passed, after
     conversion to parameter names, to the cx_Oracle
     ‘cursor.setinputsizes()’ method.  This allows both visibility into
     the setinputsizes process as well as the ability to alter the
     behavior of what datatypes are passed to this method.

     See also
     ........

     See Fine grained control over cx_Oracle data binding performance with setinputsizes.

     This change is also `backported' to: 1.2.9

     References: #4290(1)

   * `[oracle] [bug]' ¶. Updated the parameters that can be
     sent to the cx_Oracle DBAPI to both allow for all current
     parameters as well as for future parameters not added yet.  In
     addition, removed unused parameters that were deprecated in version
     1.2, and additionally we are now defaulting “threaded” to False.

     See also
     ........

     See cx_Oracle connect arguments modernized, deprecated parameters removed.

     References: #4369(2)

   * `[oracle] [bug]' ¶. The Oracle dialect will no longer
     use the NCHAR/NCLOB datatypes represent generic unicode strings or
     clob fields in conjunction with Unicode and
     UnicodeText unless the flag ‘use_nchar_for_unicode=True’ is
     passed to create_engine(). - this includes CREATE TABLE
     behavior as well as ‘setinputsizes()’ for bound parameters.  On the
     read side, automatic Unicode conversion under Python 2 has been
     added to CHAR/VARCHAR/CLOB result rows, to match the behavior of
     cx_Oracle under Python 3.  In order to mitigate the performance hit
     under Python 2, SQLAlchemy’s very performant (when C extensions are
     built) native Unicode handlers are used under Python 2.

     See also
     ........

     See National char datatypes de-emphasized for generic unicode, re-enabled with option.

     References: #4242(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4290

   (2) http://www.sqlalchemy.org/trac/ticket/4369

   (3) http://www.sqlalchemy.org/trac/ticket/4242

8.3.2.189 misc
..............

   * `[feature] [ext]' ¶. Added new attribute
     Query.lazy_loaded_from which is populated with an
     InstanceState that is using this Query in order
     to lazy load a relationship.  The rationale for this is that it
     serves as a hint for the horizontal sharding feature to use, such
     that the identity token of the state can be used as the default
     identity token to use for the query within id_chooser().

     This change is also `backported' to: 1.2.9

     References: #4243(1)

   * `[feature] [ext]' ¶. Added new feature
     BakedQuery.to_query(), which allows for a clean way of using
     one BakedQuery as a subquery inside of another
     BakedQuery without needing to refer explicitly to a
     Session.

     References: #4318(2)

   * `[feature] [ext]' ¶. The AssociationProxy.
     now has standard column comparison operations such as
     ColumnOperators.like() and
     ColumnOperators.startswith() available when the target
     attribute is a plain column - the EXISTS expression that joins to
     the target table is rendered as usual, but the column expression is
     then use within the WHERE criteria of the EXISTS. Note that this
     alters the behavior of the ‘.contains()’ method on the association
     proxy to make use of ColumnOperators.contains() when
     used on a column-based attribute.

     See also
     ........

     See AssociationProxy now provides standard column operators for a column-oriented target.

     References: #4351(3)

   * `[feature] [ext]' ¶. Added support for bulk
     Query.update() and Query.delete() to the
     ShardedQuery class within the horizontal sharding extension.
     This also adds an additional expansion hook to the bulk
     update/delete methods ‘Query._execute_crud()’.

     See also
     ........

     See Horizontal Sharding extension supports bulk update and delete methods.

     References: #4196(4)

   * `[bug] [ext]' ¶. Reworked AssociationProxy.
     to store state that’s specific to a parent class in a separate
     object, so that a single AssociationProxy can serve for
     multiple parent classes, as is intrinsic to inheritance, without
     any ambiguity in the state returned by it.  A new method
     AssociationProxy.for_class() is added to allow inspection of
     class-specific state.

     See also
     ........

     See AssociationProxy stores class-specific state on a per-class basis.

     References: #3423(5)

   * `[bug] [ext]' ¶. The long-standing behavior of the
     association proxy collection maintaining only a weak reference to
     the parent object is reverted; the proxy will now maintain a strong
     reference to the parent for as long as the proxy collection itself
     is also in memory, eliminating the “stale association proxy” error.
     This change is being made on an experimental basis to see if any
     use cases arise where it causes side effects.

     See also
     ........

     See New Features and Improvements - Core.

     References: #4268(6)

   * `[bug] [ext]' ¶. Fixed multiple issues regarding
     de-association of scalar objects with the association proxy.  ‘del’
     now works, and additionally a new flag
     AssociationProxy.cascade_scalar_deletes is added, which when
     set to True indicates that setting a scalar attribute to ‘None’ or
     deleting via ‘del’ will also set the source association to ‘None’.

     See also
     ........

     See Association proxy has new cascade_scalar_deletes flag.

     References: #4308(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4243

   (2) http://www.sqlalchemy.org/trac/ticket/4318

   (3) http://www.sqlalchemy.org/trac/ticket/4351

   (4) http://www.sqlalchemy.org/trac/ticket/4196

   (5) http://www.sqlalchemy.org/trac/ticket/3423

   (6) http://www.sqlalchemy.org/trac/ticket/4268

   (7) http://www.sqlalchemy.org/trac/ticket/4308

8.3.3.1 1.2.19
..............

Released: April 15, 2019

8.3.3.2 orm
...........

   * `[orm] [bug]' ¶. Fixed a regression in 1.2 due to the
     introduction of baked queries for relationship lazy loaders, where
     a race condition is created during the generation of the “lazy
     clause” which occurs within a memoized attribute.  If two threads
     initialize the memoized attribute concurrently, the baked query
     could be generated with bind parameter keys that are then replaced
     with new keys by the next run, leading to a lazy load query that
     specifies the related criteria as ‘None’.  The fix establishes that
     the parameter names are fixed before the new clause and parameter
     objects are generated, so that the names are the same every time.

     References: #4507(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4507

8.3.3.3 engine
..............

   * `[engine] [bug]' ¶. Comparing two objects of URL
     using ‘__eq__()’ did not take port number into consideration,
     two objects differing only by port number were considered equal.
     Port comparison is now added in ‘__eq__()’ method of URL,
     objects differing by port number are now not equal.
     Additionally, ‘__ne__()’ was not implemented for URL
     which caused unexpected result when ‘!=’ was used in Python2, since
     there are no implied relationships among the comparison operators
     in Python2.

     References: #4406(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4406

8.3.3.4 mssql
.............

   * `[mssql] [bug]' ¶. A commit() is emitted after an
     isolation level change to SNAPSHOT, as both pyodbc and pymssql open
     an implicit transaction which blocks subsequent SQL from being
     emitted in the current transaction.

     References: #4536(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4536

8.3.3.5 oracle
..............

   * `[oracle] [bug]' ¶. Added support for reflection of the
     NCHAR datatype to the Oracle dialect, and added
     NCHAR to the list of types exported by the Oracle dialect.

     References: #4506(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4506

8.3.3.6 misc
............

   * `[bug] [examples]' ¶. Fixed bug in large_resultsets
     example case where a re-named “id” variable due to code
     reformatting caused the test to fail.  Pull request courtesy Matt
     Schuchhardt.

     References: #4528(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4528

8.3.3.7 1.2.18
..............

Released: February 15, 2019

8.3.3.8 orm
...........

   * `[orm] [bug]' ¶. Fixed a regression in 1.2 where a
     wildcard/load_only loader option would not work correctly against a
     loader path where of_type() were used to limit to a particular
     subclass.  The fix only works for of_type() of a simple subclass so
     far, not a with_polymorphic entity which will be addressed in a
     separate issue; it is unlikely this latter case was working
     previously.

     References: #4468(1)

   * `[orm] [bug]' ¶. Fixed fairly simple but critical issue
     where the SessionEvents.pending_to_persistent() event
     would be invoked for objects not just when they move from pending
     to persistent, but when they were also already persistent and just
     being updated, thus causing the event to be invoked for all objects
     on every update.

     References: #4489(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4468

   (2) http://www.sqlalchemy.org/trac/ticket/4489

8.3.3.9 sql
...........

   * `[sql] [bug]' ¶. Fixed issue where the JSON.
     type had a read-only JSON.should_evaluate_none
     attribute, which would cause failures when making use of the
     TypeEngine.evaluates_none() method in conjunction with this
     type.  Pull request courtesy Sanjana S.

     References: #4485(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4485

8.3.3.10 mysql
..............

   * `[mysql] [bug]' ¶. Fixed a second regression caused by
     #4344(1) (the first was #4361(2)), which works around MySQL issue
     88718, where the lower casing function used was not correct for
     Python 2 with OSX/Windows casing conventions, which would then
     raise ‘TypeError’.  Full coverage has been added to this logic so
     that every codepath is exercised in a mock style for all three
     casing conventions on all versions of Python.  MySQL 8.0 has
     meanwhile fixed issue 88718 so the workaround is only applies to a
     particular span of MySQL 8.0 versions.

     References: #4492(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4344

   (2) http://www.sqlalchemy.org/trac/ticket/4361

   (3) http://www.sqlalchemy.org/trac/ticket/4492

8.3.3.11 sqlite
...............

   * `[sqlite] [bug]' ¶. Fixed bug in SQLite DDL where using
     an expression as a server side default required that it be
     contained within parenthesis to be accepted by the sqlite parser.
     Pull request courtesy Bartlomiej Biernacki.

     References: #4474(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4474

8.3.3.12 mssql
..............

   * `[mssql] [bug]' ¶. Fixed bug where the SQL Server
     “IDENTITY_INSERT” logic that allows an INSERT to proceed with an
     explicit value on an IDENTITY column was not detecting the case
     where Insert.values() were used with a dictionary that
     contained a Column as key and a SQL expression as a
     value.

     References: #4499(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4499

8.3.3.13 1.2.17
...............

Released: January 25, 2019

8.3.3.14 orm
............

   * `[orm] [feature]' ¶. Added new event hooks
     QueryEvents.before_compile_update() and
     QueryEvents.before_compile_delete() which complement
     QueryEvents.before_compile() in the case of the
     Query.update() and Query.delete() methods.

     References: #4461(1)

   * `[orm] [bug]' ¶. Fixed issue where when using
     single-table inheritance in conjunction with a joined inheritance
     hierarchy that uses “with polymorphic” loading, the “single table
     criteria” for that single-table entity could get confused for that
     of other entities from the same hierarchy used in the same
     query.The adaption of the “single table criteria” is made more
     specific to the target entity to avoid it accidentally getting
     adapted to other tables in the query.

     References: #4454(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4461

   (2) http://www.sqlalchemy.org/trac/ticket/4454

8.3.3.15 postgresql
...................

   * `[postgresql] [bug]' ¶. Revised the query used when
     reflecting CHECK constraints to make use of the
     ‘pg_get_constraintdef’ function, as the ‘consrc’ column is being
     deprecated in PG 12.  Thanks to John A Stevenson for the tip.

     References: #4463(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4463

8.3.3.16 oracle
...............

   * `[oracle] [bug]' ¶. Fixed regression in integer
     precision logic due to the refactor of the cx_Oracle dialect in
     1.2.  We now no longer apply the cx_Oracle.NATIVE_INT type to
     result columns sending integer values (detected as positive
     precision with scale ==0) which encounters integer overflow issues
     with values that go beyond the 32 bit boundary.  Instead, the
     output variable is left untyped so that cx_Oracle can choose the
     best option.

     References: #4457(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4457

8.3.3.17 1.2.16
...............

Released: January 11, 2019

8.3.3.18 engine
...............

   * `[engine] [bug]' ¶. Fixed a regression introduced in
     version 1.2 where a refactor of the SQLAlchemyError
     base exception class introduced an inappropriate coercion of a
     plain string message into Unicode under python 2k, which is not
     handled by the Python interpreter for characters outside of the
     platform’s encoding (typically ascii).  The SQLAlchemyError
     class now passes a bytestring through under Py2K for
     ‘__str__()’ as is the behavior of exception objects in general
     under Py2K, does a safe coercion to unicode utf-8 with backslash
     fallback for ‘__unicode__()’.  For Py3K the message is typically
     unicode already, but if not is again safe-coerced with utf-8 with
     backslash fallback for the ‘__str__()’ method.

     References: #4429(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4429

8.3.3.19 sql
............

   * `[sql] [bug] [mysql] [oracle]' ¶. Fixed issue where the
     DDL emitted for ‘DropTableComment’, which will be used by an
     upcoming version of Alembic, was incorrect for the MySQL and Oracle
     databases.

     References: #4436(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4436

8.3.3.20 postgresql
...................

   * `[postgresql] [bug]' ¶. Fixed issue where a ENUM
     or a custom domain present in a remote schema would not be
     recognized within column reflection if the name of the enum/domain
     or the name of the schema required quoting.  A new parsing scheme
     now fully parses out quoted or non-quoted tokens including support
     for SQL-escaped quotes.

     References: #4416(1)

   * `[postgresql] [bug]' ¶. Fixed issue where multiple
     ENUM objects referred to by the same MetaData
     object would fail to be created if multiple objects had the
     same name under different schema names.  The internal memoization
     the PostgreSQL dialect uses to track if it has created a particular
     ENUM in the database during a DDL creation sequence
     now takes schema name into account.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4416

8.3.3.21 sqlite
...............

   * `[sqlite] [bug]' ¶. Reflection of an index based on SQL
     expressions are now skipped with a warning, in the same way as that
     of the Postgresql dialect, where we currently do not support
     reflecting indexes that have SQL expressions within them.
     Previously, an index with columns of None were produced which would
     break tools like Alembic.

     References: #4431(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4431

8.3.3.22 misc
.............

   * `[no_tags]' ¶. 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.

     References: #4394(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4394

8.3.3.23 1.2.15
...............

Released: December 11, 2018

8.3.3.24 orm
............

   * `[orm] [bug]' ¶. Fixed bug where the ORM annotations
     could be incorrect for the primaryjoin/secondaryjoin a relationship
     if one used the pattern ‘ForeignKey(SomeClass.id)’ in the
     declarative mappings.  This pattern would leak undesired
     annotations into the join conditions which can break aliasing
     operations done within Query that are not supposed to
     impact elements in that join condition.  These annotations are now
     removed up front if present.

     References: #4367(1)

   * `[orm] [bug]' ¶. In continuing with a similar theme as
     that of very recent #4349(2), repaired issue with
     Comparator.any() and Comparator.has() where the
     “secondary” selectable needs to be explicitly part of the FROM
     clause in the EXISTS subquery to suit the case where this
     “secondary” is a Join object.

     References: #4366(3)

   * `[orm] [bug]' ¶. Fixed regression caused by #4349(4)
     where adding the “secondary” table to the FROM clause for a dynamic
     loader would affect the ability of the Query to make a
     subsequent join to another entity.  The fix adds the primary entity
     as the first element of the FROM list since Query.join()
     wants to jump from that.  Version 1.3 will have a more
     comprehensive solution to this problem as well (#4365(5)).

     References: #4363(6)

   * `[orm] [bug]' ¶. Fixed bug where chaining of mapper
     options using ‘RelationshipProperty.of_type()’ in conjunction with
     a chained option that refers to an attribute name by string only
     would fail to locate the attribute.

     References: #4400(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4367

   (2) http://www.sqlalchemy.org/trac/ticket/4349

   (3) http://www.sqlalchemy.org/trac/ticket/4366

   (4) http://www.sqlalchemy.org/trac/ticket/4349

   (5) http://www.sqlalchemy.org/trac/ticket/4365

   (6) http://www.sqlalchemy.org/trac/ticket/4363

   (7) http://www.sqlalchemy.org/trac/ticket/4400

8.3.3.25 orm declarative
........................

   * `[orm] [declarative] [bug]' ¶. A warning is emitted in
     the case that a column() object is applied to a
     declarative class, as it seems likely this intended to be a
     Column object.

     References: #4374(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4374

8.3.3.26 misc
.............

   * `[no_tags]' ¶. Added support for the ‘write_timeout’
     flag accepted by mysqlclient and pymysql to be passed in the URL
     string.

     References: #4381(1)

   * `[no_tags]' ¶. Fixed issue where reflection of a
     PostgreSQL domain that is expressed as an array would fail to be
     recognized.  Pull request courtesy Jakub Synowiec.

     References: #4377(2), #4380(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4381

   (2) http://www.sqlalchemy.org/trac/ticket/4377

   (3) http://www.sqlalchemy.org/trac/ticket/4380

8.3.3.27 1.2.14
...............

Released: November 10, 2018

8.3.3.28 orm
............

   * `[orm] [bug]' ¶. Fixed bug in
     Session.bulk_update_mappings() where alternate mapped
     attribute names would result in the primary key column of the
     UPDATE statement being included in the SET clause, as well as the
     WHERE clause; while usually harmless, for SQL Server this can raise
     an error due to the IDENTITY column.  This is a continuation of the
     same bug that was fixed in #3849(1), where testing was insufficient
     to catch this additional flaw.

     References: #4357(2)

   * `[orm] [bug]' ¶. Fixed a minor performance issue which
     could in some cases add unnecessary overhead to result fetching,
     involving the use of ORM columns and entities that include those
     same columns at the same time within a query.  The issue has to do
     with hash / eq overhead when referring to the column in different
     ways.

     References: #4347(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3849

   (2) http://www.sqlalchemy.org/trac/ticket/4357

   (3) http://www.sqlalchemy.org/trac/ticket/4347

8.3.3.29 mysql
..............

   * `[mysql] [bug]' ¶. Fixed regression caused by #4344(1)
     released in 1.2.13, where the fix for MySQL 8.0’s case sensitivity
     problem with referenced column names when reflecting foreign key
     referents is worked around using the ‘information_schema.columns’
     view.  The workaround was failing on OSX /
     ‘lower_case_table_names=2’ which produces non-matching casing for
     the ‘information_schema.columns’ vs.  that of ‘SHOW CREATE TABLE’,
     so in case-insensitive SQL modes case-insensitive matching is now
     used.

     References: #4361(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4344

   (2) http://www.sqlalchemy.org/trac/ticket/4361

8.3.3.30 1.2.13
...............

Released: October 31, 2018

8.3.3.31 orm
............

   * `[orm] [bug]' ¶. Fixed bug where “dynamic” loader needs
     to explicitly set the “secondary” table in the FROM clause of the
     query, to suit the case where the secondary is a join object that
     is otherwise not pulled into the query from its columns alone.

     References: #4349(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4349

8.3.3.32 orm declarative
........................

   * `[orm] [declarative] [bug]' ¶. Fixed regression caused
     by #4326(1) in version 1.2.12 where using declared_attr
     with a mixin in conjunction with synonym() would fail
     to map the synonym properly to an inherited subclass.

     References: #4350(2)

   * `[orm] [declarative] [bug]' ¶. The column conflict
     resolution technique discussed at declarative_column_conflicts is
     now functional for a Column that is also a primary key
     column.  Previously, a check for primary key columns declared on a
     single-inheritance subclass would occur before the column copy were
     allowed to pass.

     References: #4352(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4326

   (2) http://www.sqlalchemy.org/trac/ticket/4350

   (3) http://www.sqlalchemy.org/trac/ticket/4352

8.3.3.33 sql
............

   * `[sql] [feature]' ¶. Refactored SQLCompiler
     to expose a SQLCompiler.group_by_clause() method
     similar to the SQLCompiler.order_by_clause() and
     ‘SQLCompiler.limit_clause()’ methods, which can be overridden by
     dialects to customize how GROUP BY renders.  Pull request courtesy
     Samuel Chou.

   * `[sql] [bug]' ¶. Fixed bug where the
     Enum.create_constraint flag on the Enum datatype
     would not be propagated to copies of the type, which affects use
     cases such as declarative mixins and abstract bases.

     References: #4341(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4341

8.3.3.34 postgresql
...................

   * `[postgresql] [bug]' ¶. Added support for the
     aggregate_order_by function to receive multiple ORDER BY
     elements, previously only a single element was accepted.

     References: #4337(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4337

8.3.3.35 mysql
..............

   * `[mysql] [bug]' ¶. Added word ‘function’ to the list of
     reserved words for MySQL, which is now a keyword in MySQL 8.0

     References: #4348(1)

   * `[mysql] [bug]' ¶. Added a workaround for a MySQL bug
     #88718 introduced in the 8.0 series, where the reflection of a
     foreign key constraint is not reporting the correct case
     sensitivity for the referred column, leading to errors during use
     of the reflected constraint such as when using the automap
     extension.  The workaround emits an additional query to the
     information_schema tables in order to retrieve the correct case
     sensitive name.

     References: #4344(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4348

   (2) http://www.sqlalchemy.org/trac/ticket/4344

8.3.3.36 misc
.............

   * `[misc] [bug]' ¶. Fixed issue where part of the utility
     language helper internals was passing the wrong kind of argument to
     the Python ‘__import__’ builtin as the list of modules to be
     imported.  The issue produced no symptoms within the core library
     but could cause issues with external applications that redefine the
     ‘__import__’ builtin or otherwise instrument it.  Pull request
     courtesy Joe Urciuoli.

   * `[misc] [bug] [py3k]' ¶. Fixed additional warnings
     generated by Python 3.7 due to changes in the organization of the
     Python ‘collections’ and ‘collections.abc’ packages.  Previous
     ‘collections’ warnings were fixed in version 1.2.11.  Pull request
     courtesy xtreak.

     References: #4339(1)

   * `[bug] [ext]' ¶. Added missing ‘.index()’ method to
     list-based association collections in the association proxy
     extension.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4339

8.3.3.37 1.2.12
...............

Released: September 19, 2018

8.3.3.38 orm
............

   * `[orm] [bug]' ¶. Added a check within the weakref
     cleanup for the InstanceState object to check for the
     presence of the ‘dict’ builtin, in an effort to reduce error
     messages generated when these cleanups occur during interpreter
     shutdown.  Pull request courtesy Romuald Brunet.

   * `[orm] [bug]' ¶. Fixed bug where use of Lateral
     construct in conjunction with Query.join() as well
     as Query.select_entity_from() would not apply clause
     adaption to the right side of the join.  “lateral” introduces the
     use case of the right side of a join being correlatable.
     Previously, adaptation of this clause wasn’t considered.  Note that
     in 1.2 only, a selectable introduced by Query.subquery()
     is still not adapted due to #4304(1); the selectable needs to
     be produced by the select() function to be the right
     side of the “lateral” join.

     References: #4334(2)

   * `[orm] [bug]' ¶. Fixed 1.2 regression caused by
     #3472(3) where the handling of an “updated_at” style column within
     the context of a post-update operation would also occur for a row
     that is to be deleted following the update, meaning both that a
     column with a Python-side value generator would show the
     now-deleted value that was emitted for the UPDATE before the DELETE
     (which was not the previous behavior), as well as that a SQL-
     emitted value generator would have the attribute expired, meaning
     the previous value would be unreachable due to the row having been
     deleted and the object detached from the session.The “postfetch”
     logic that was added as part of #3472(4) is now skipped entirely
     for an object that ultimately is to be deleted.

     References: #4327(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4304

   (2) http://www.sqlalchemy.org/trac/ticket/4334

   (3) http://www.sqlalchemy.org/trac/ticket/3472

   (4) http://www.sqlalchemy.org/trac/ticket/3472

   (5) http://www.sqlalchemy.org/trac/ticket/4327

8.3.3.39 orm declarative
........................

   * `[orm] [declarative] [bug]' ¶. Fixed bug where the
     declarative scan for attributes would receive the expression proxy
     delivered by a hybrid attribute at the class level, and not the
     hybrid attribute itself, when receiving the descriptor via the
     ‘@declared_attr’ callable on a subclass of an already-mapped class.
     This would lead to an attribute that did not report itself as a
     hybrid when viewed within Mapper.all_orm_descriptors.

     References: #4326(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4326

8.3.3.40 postgresql
...................

   * `[postgresql] [bug]' ¶. Fixed bug in PostgreSQL dialect
     where compiler keyword arguments such as ‘literal_binds=True’ were
     not being propagated to a DISTINCT ON expression.

     References: #4325(1)

   * `[postgresql] [bug]' ¶. Fixed the array_agg()
     function, which is a slightly altered version of the usual
     array_agg() function, to also accept an incoming “type”
     argument without forcing an ARRAY around it, essentially the same
     thing that was fixed for the generic function in 1.1 in #4107(2).

     References: #4324(3)

   * `[postgresql] [bug]' ¶. Fixed bug in PostgreSQL ENUM
     reflection where a case-sensitive, quoted name would be reported by
     the query including quotes, which would not match a target column
     during table reflection as the quotes needed to be stripped off.

     References: #4323(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4325

   (2) http://www.sqlalchemy.org/trac/ticket/4107

   (3) http://www.sqlalchemy.org/trac/ticket/4324

   (4) http://www.sqlalchemy.org/trac/ticket/4323

8.3.3.41 oracle
...............

   * `[oracle] [bug]' ¶. Fixed issue for cx_Oracle 7.0 where
     the behavior of Oracle param.getvalue() now returns a list, rather
     than a single scalar value, breaking autoincrement logic throughout
     the Core and ORM. The dml_ret_array_val compatibility flag is used
     for cx_Oracle 6.3 and 6.4 to establish compatible behavior with 7.0
     and forward, for cx_Oracle 6.2.1 and prior a version number check
     falls back to the old logic.

     References: #4335(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4335

8.3.3.42 misc
.............

   * `[bug] [ext]' ¶. Fixed issue where BakedQuery
     did not include the specific query class used by the
     Session as part of the cache key, leading to incompatibilities
     when using custom query classes, in particular the
     ShardedQuery which has some different argument signatures.

     References: #4328(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4328

8.3.3.43 1.2.11
...............

Released: August 20, 2018

8.3.3.44 orm declarative
........................

   * `[orm] [declarative] [bug]' ¶. Fixed issue in
     previously untested use case, allowing a declarative mapped class
     to inherit from a classically-mapped class outside of the
     declarative base, including that it accommodates for unmapped
     intermediate classes.  An unmapped intermediate class may specify
     ‘__abstract__’, which is now interpreted correctly, or the
     intermediate class can remain unmarked, and the classically mapped
     base class will be detected within the hierarchy regardless.  In
     order to anticipate existing scenarios which may be mixing in
     classical mappings into existing declarative hierarchies, an error
     is now raised if multiple mapped bases are detected for a given
     class.

     References: #4321(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4321

8.3.3.45 sql
............

   * `[sql] [bug]' ¶. Fixed issue that is closely related to
     #3639(1) where an expression rendered in a boolean context on a
     non-native boolean backend would be compared to 1/0 even though it
     is already an implicitly boolean expression, when
     ColumnElement.self_group() were used.  While this does not
     affect the user-friendly backends (MySQL, SQLite) it was not
     handled by Oracle (and possibly SQL Server).  Whether or not the
     expression is implicitly boolean on any database is now determined
     up front as an additional check to not generate the integer
     comparison within the compilation of the statement.

     References: #4320(2)

   * `[sql] [bug]' ¶. Added missing window function
     parameters WithinGroup.over.range_ and
     WithinGroup.over.rows parameters to the
     WithinGroup.over() and FunctionFilter.over()
     methods, to correspond to the range/rows feature added to the
     “over” method of SQL functions as part of #3049(3) in version 1.1.

     References: #4322(4)

   * `[sql] [bug]' ¶. Fixed bug where the multi-table
     support for UPDATE and DELETE statements did not consider the
     additional FROM elements as targets for correlation, when a
     correlated SELECT were also combined with the statement.  This
     change now includes that a SELECT statement in the WHERE clause for
     such a statement will try to auto-correlate back to these
     additional tables in the parent UPDATE/DELETE or unconditionally
     correlate if Select.correlate() is used.  Note that
     auto-correlation raises an error if the SELECT statement would have
     no FROM clauses as a result, which can now occur if the parent
     UPDATE/DELETE specifies the same tables in its additional set of
     tables; specify Select.correlate() explicitly to
     resolve.

     References: #4313(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3639

   (2) http://www.sqlalchemy.org/trac/ticket/4320

   (3) http://www.sqlalchemy.org/trac/ticket/3049

   (4) http://www.sqlalchemy.org/trac/ticket/4322

   (5) http://www.sqlalchemy.org/trac/ticket/4313

8.3.3.46 oracle
...............

   * `[oracle] [bug]' ¶. For cx_Oracle, Integer datatypes
     will now be bound to “int”, per advice from the cx_Oracle
     developers.  Previously, using cx_Oracle.NUMBER caused a loss in
     precision within the cx_Oracle 6.x series.

     References: #4309(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4309

8.3.3.47 misc
.............

   * `[bug] [py3k]' ¶. Started importing “collections” from
     “collections.abc” under Python 3.3 and greater for Python 3.8
     compatibility.  Pull request courtesy Nathaniel Knight.

   * `[no_tags]' ¶. Fixed issue where the “schema” name used
     for a SQLite database within table reflection would not quote the
     schema name correctly.  Pull request courtesy Phillip Cloud.

8.3.3.48 1.2.10
...............

Released: July 13, 2018

8.3.3.49 orm
............

   * `[orm] [bug]' ¶. Fixed bug in Bundle.
     construct where placing two columns of the same name would be
     de-duplicated, when the Bundle were used as part of the
     rendered SQL, such as in the ORDER BY or GROUP BY of the statement.

     References: #4295(1)

   * `[orm] [bug]' ¶. Fixed regression in 1.2.9 due to
     #4287(2) where using a Load option in conjunction with
     a string wildcard would result in a TypeError.

     References: #4298(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4295

   (2) http://www.sqlalchemy.org/trac/ticket/4287

   (3) http://www.sqlalchemy.org/trac/ticket/4298

8.3.3.50 sql
............

   * `[sql] [bug]' ¶. Fixed bug where a Sequence.
     would be dropped explicitly before any Table that refers
     to it, which breaks in the case when the sequence is also involved
     in a server-side default for that table, when using
     MetaData.drop_all().  The step which processes sequences to be
     dropped via non server-side column default functions is now invoked
     after the table itself is dropped.

     References: #4300(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4300

8.3.3.51 1.2.9
..............

Released: June 29, 2018

8.3.3.52 orm
............

   * `[orm] [bug]' ¶. Fixed issue where chaining multiple
     join elements inside of Query.join() might not
     correctly adapt to the previous left-hand side, when chaining
     joined inheritance classes that share the same base class.

     References: #3505(1)

   * `[orm] [bug]' ¶. Fixed bug in cache key generation for
     baked queries which could cause a too-short cache key to be
     generated for the case of eager loads across subclasses.  This
     could in turn cause the eagerload query to be cached in place of a
     non-eagerload query, or vice versa, for a polymorphic “selectin”
     load, or possibly for lazy loads or selectin loads as well.

     References: #4287(2)

   * `[orm] [bug]' ¶. Fixed bug in new polymorphic selectin
     loading where the BakedQuery used internally would be mutated by
     the given loader options, which would both inappropriately mutate
     the subclass query as well as carry over the effect to subsequent
     queries.

     References: #4286(3)

   * `[orm] [bug]' ¶. Fixed regression caused by #4256(4)
     (itself a regression fix for #4228(5)) which breaks an undocumented
     behavior which converted for a non-sequence of entities passed
     directly to the Query constructor into a single-element
     sequence.  While this behavior was never supported or documented,
     it’s already in use so has been added as a behavioral contract to
     Query.

     References: #4269(6)

   * `[orm] [bug]' ¶. Fixed an issue that was both a
     performance regression in 1.2 as well as an incorrect result
     regarding the “baked” lazy loader, involving the generation of
     cache keys from the original Query object’s loader
     options.  If the loader options were built up in a “branched” style
     using common base elements for multiple options, the same options
     would be rendered into the cache key repeatedly, causing both a
     performance issue as well as generating the wrong cache key.  This
     is fixed, along with a performance improvement when such “branched”
     options are applied via Query.options() to prevent the
     same option objects from being applied repeatedly.

     References: #4270(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3505

   (2) http://www.sqlalchemy.org/trac/ticket/4287

   (3) http://www.sqlalchemy.org/trac/ticket/4286

   (4) http://www.sqlalchemy.org/trac/ticket/4256

   (5) http://www.sqlalchemy.org/trac/ticket/4228

   (6) http://www.sqlalchemy.org/trac/ticket/4269

   (7) http://www.sqlalchemy.org/trac/ticket/4270

8.3.3.53 sql
............

   * `[sql] [bug]' ¶. Fixed regression in 1.2 due to
     #4147(1) where a Table that has had some of its indexed
     columns redefined with new ones, as would occur when overriding
     columns during reflection or when using
     Table.extend_existing, such that the
     Table.tometadata() method would fail when attempting to copy
     those indexes as they still referred to the replaced column.  The
     copy logic now accommodates for this condition.

     References: #4279(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4147

   (2) http://www.sqlalchemy.org/trac/ticket/4279

8.3.3.54 mysql
..............

   * `[mysql] [bug]' ¶. Fixed percent-sign doubling in
     mysql-connector-python dialect, which does not require de-doubling
     of percent signs.  Additionally, the mysql- connector-python driver
     is inconsistent in how it passes the column names in
     cursor.description, so a workaround decoder has been added to
     conditionally decode these randomly-sometimes-bytes values to
     unicode only if needed.  Also improved test support for
     mysql-connector-python, however it should be noted that this driver
     still has issues with unicode that continue to be unresolved as of
     yet.

   * `[mysql] [bug]' ¶. Fixed bug in index reflection where
     on MySQL 8.0 an index that includes ASC or DESC in an indexed
     column specification would not be correctly reflected, as MySQL 8.0
     introduces support for returning this information in a table
     definition string.

     References: #4293(1)

   * `[mysql] [bug]' ¶. Fixed bug in MySQLdb dialect and
     variants such as PyMySQL where an additional “unicode returns”
     check upon connection makes explicit use of the “utf8” character
     set, which in MySQL 8.0 emits a warning that utf8mb4 should be
     used.  This is now replaced with a utf8mb4 equivalent.
     Documentation is also updated for the MySQL dialect to specify
     utf8mb4 in all examples.  Additional changes have been made to the
     test suite to use utf8mb3 charsets and databases (there seem to be
     collation issues in some edge cases with utf8mb4), and to support
     configuration default changes made in MySQL 8.0 such as
     explicit_defaults_for_timestamp as well as new errors raised for
     invalid MyISAM indexes.

     References: #4283(2)

   * `[mysql] [bug]' ¶. The Update construct now
     accommodates a Join object as supported by MySQL for
     UPDATE..FROM. As the construct already accepted an alias object for
     a similar purpose, the feature of UPDATE against a non-table was
     already implied so this has been added.

     References: #3645(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4293

   (2) http://www.sqlalchemy.org/trac/ticket/4283

   (3) http://www.sqlalchemy.org/trac/ticket/3645

8.3.3.55 sqlite
...............

   * `[sqlite] [bug]' ¶. Fixed issue in test suite where
     SQLite 3.24 added a new reserved word that conflicted with a usage
     in TypeReflectionTest.  Pull request courtesy Nils Philippsen.

8.3.3.56 mssql
..............

   * `[mssql] [bug]' ¶. Fixed bug in MSSQL reflection where
     when two same-named tables in different schemas had same-named
     primary key constraints, foreign key constraints referring to one
     of the tables would have their columns doubled, causing errors.
     Pull request courtesy Sean Dunn.

     References: #4288(1)

   * `[mssql] [bug] [py3k]' ¶. Fixed issue within the SQL
     Server dialect under Python 3 where when running against a
     non-standard SQL server database that does not contain either the
     “sys.dm_exec_sessions” or “sys.dm_pdw_nodes_exec_sessions” views,
     leading to a failure to fetch the isolation level, the error raise
     would fail due to an UnboundLocalError.

     References: #4273(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4288

   (2) http://www.sqlalchemy.org/trac/ticket/4273

8.3.3.57 oracle
...............

   * `[oracle] [feature]' ¶. Added a new event currently
     used only by the cx_Oracle dialect, ‘DialectEvents.setiputsizes()’.
     The event passes a dictionary of BindParameter objects
     to DBAPI-specific type objects that will be passed, after
     conversion to parameter names, to the cx_Oracle
     ‘cursor.setinputsizes()’ method.  This allows both visibility into
     the setinputsizes process as well as the ability to alter the
     behavior of what datatypes are passed to this method.

     See also
     ........

     See Fine grained control over cx_Oracle data binding performance with setinputsizes.

     References: #4290(1)

   * `[oracle] [bug] [mysql]' ¶. Fixed INSERT FROM SELECT
     with CTEs for the Oracle and MySQL dialects, where the CTE was
     being placed above the entire statement as is typical with other
     databases, however Oracle and MariaDB 10.2 wants the CTE underneath
     the “INSERT” segment.  Note that the Oracle and MySQL dialects
     don’t yet work when a CTE is applied to a subquery inside of an
     UPDATE or DELETE statement, as the CTE is still applied to the top
     rather than inside the subquery.

     References: #4275(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4290

   (2) http://www.sqlalchemy.org/trac/ticket/4275

8.3.3.58 misc
.............

   * `[feature] [ext]' ¶. Added new attribute
     Query.lazy_loaded_from which is populated with an
     InstanceState that is using this Query in order
     to lazy load a relationship.  The rationale for this is that it
     serves as a hint for the horizontal sharding feature to use, such
     that the identity token of the state can be used as the default
     identity token to use for the query within id_chooser().

     References: #4243(1)

   * `[bug] [py3k]' ¶. Replaced the usage of
     inspect.formatargspec() with a vendored version copied from the
     Python standard library, as inspect.formatargspec() is deprecated
     and as of Python 3.7.0 is emitting a warning.

     References: #4291(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4243

   (2) http://www.sqlalchemy.org/trac/ticket/4291

8.3.3.59 1.2.8
..............

Released: May 28, 2018

8.3.3.60 orm
............

   * `[orm] [bug]' ¶. Fixed regression in 1.2.7 caused by
     #4228(1), which itself was fixing a 1.2-level regression, where the
     ‘query_cls’ callable passed to a Session was assumed to
     be a subclass of Query with class method availability,
     as opposed to an arbitrary callable.  In particular, the dogpile
     caching example illustrates ‘query_cls’ as a function and not a
     Query subclass.

     References: #4256(2)

   * `[orm] [bug]' ¶. Fixed a long-standing regression that
     occurred in version 1.0, which prevented the use of a custom
     ‘MapperOption’ that alters the _params of a Query
     object for a lazy load, since the lazy loader itself would
     overwrite those parameters.  This applies to the “temporal range”
     example on the wiki.  Note however that the
     Query.populate_existing() method is now required in order to
     rewrite the mapper options associated with an object already loaded
     in the identity map.

     As part of this change, a custom defined ‘MapperOption’ will now
     cause lazy loaders related to the target object to use a non-baked
     query by default unless the ‘MapperOption._generate_cache_key()’
     method is implemented.  In particular, this repairs one regression
     which occurred when using the dogpile.cache “advanced” example,
     which was not returning cached results and instead emitting SQL due
     to an incompatibility with the baked query loader; with the change,
     the ‘RelationshipCache’ option included for many releases in the
     dogpile example will disable the “baked” query altogether.  Note
     that the dogpile example is also modernized to avoid both of these
     issues as part of issue #4258(3).

     References: #4128(4)

   * `[orm] [bug]' ¶. Fixed bug where the new
     Result.with_post_criteria() method would not interact with a
     subquery-eager loader correctly, in that the “post criteria” would
     not be applied to embedded subquery eager loaders.  This is related
     to #4128(5) in that the post criteria feature is now used by the
     lazy loader.

   * `[orm] [bug]' ¶. Updated the dogpile.caching example to
     include new structures that accommodate for the “baked” query
     system, which is used by default within lazy loaders and some eager
     relationship loaders.  The dogpile.caching “relationship_caching”
     and “advanced” examples were also broken due to #4256(6).  The
     issue here is also worked-around by the fix in #4128(7).

     References: #4258(8)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4228

   (2) http://www.sqlalchemy.org/trac/ticket/4256

   (3) http://www.sqlalchemy.org/trac/ticket/4258

   (4) http://www.sqlalchemy.org/trac/ticket/4128

   (5) http://www.sqlalchemy.org/trac/ticket/4128

   (6) http://www.sqlalchemy.org/trac/ticket/4256

   (7) http://www.sqlalchemy.org/trac/ticket/4128

   (8) http://www.sqlalchemy.org/trac/ticket/4258

8.3.3.61 engine
...............

   * `[engine] [bug]' ¶. Fixed connection pool issue whereby
     if a disconnection error were raised during the connection pool’s
     “reset on return” sequence in conjunction with an explicit
     transaction opened against the enclosing Connection
     object (such as from calling Session.close() without a
     rollback or commit, or calling Connection.close()
     without first closing a transaction declared with
     Connection.begin()), a double-checkin would result, which
     could then lead towards concurrent checkouts of the same
     connection.  The double-checkin condition is now prevented overall
     by an assertion, as well as the specific double-checkin scenario
     has been fixed.

     References: #4252(1)

   * `[engine] [bug]' ¶. Fixed a reference leak issue where
     the values of the parameter dictionary used in a statement
     execution would remain referenced by the “compiled cache”, as a
     result of storing the key view used by Python 3 dictionary keys().
     Pull request courtesy Olivier Grisel.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4252

8.3.3.62 sql
............

   * `[sql] [bug]' ¶. Fixed issue where the “ambiguous
     literal” error message used when interpreting literal values as SQL
     expression values would encounter a tuple value, and fail to format
     the message properly.  Pull request courtesy Miguel Ventura.

8.3.3.63 mssql
..............

   * `[mssql] [bug]' ¶. Fixed a 1.2 regression caused by
     #4061(1) where the SQL Server “BIT” type would be considered to be
     “native boolean”.  The goal here was to avoid creating a CHECK
     constraint on the column, however the bigger issue is that the BIT
     value does not behave like a true/false constant and cannot be
     interpreted as a standalone expression, e.g.  “WHERE <column>”.
     The SQL Server dialect now goes back to being non-native boolean,
     but with an extra flag that still avoids creating the CHECK
     constraint.

     References: #4250(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4061

   (2) http://www.sqlalchemy.org/trac/ticket/4250

8.3.3.64 oracle
...............

   * `[oracle] [bug]' ¶. The Oracle BINARY_FLOAT and
     BINARY_DOUBLE datatypes now participate within
     cx_Oracle.setinputsizes(), passing along NATIVE_FLOAT, so as to
     support the NaN value.  Additionally, ‘BINARY_FLOAT’,
     ‘BINARY_DOUBLE’ and DOUBLE_PRECISION now subclass
     Float, since these are floating point datatypes, not
     decimal.  These datatypes were already defaulting the
     Float.asdecimal flag to False in line with what Float
     already does.

     References: #4264(1)

   * `[oracle] [bug]' ¶. Added reflection capabilities for
     the ‘BINARY_FLOAT’, ‘BINARY_DOUBLE’ datatypes.

   * `[oracle] [bug]' ¶. Altered the Oracle dialect such
     that when an Integer type is in use, the
     cx_Oracle.NUMERIC type is set up for setinputsizes().  In
     SQLAlchemy 1.1 and earlier, cx_Oracle.NUMERIC was passed for all
     numeric types unconditionally, and in 1.2 this was removed to allow
     for better numeric precision.  However, for integers, some
     database/client setups will fail to coerce boolean values
     True/False into integers which introduces regressive behavior when
     using SQLAlchemy 1.2.  Overall, the setinputsizes logic seems like
     it will need a lot more flexibility going forward so this is a
     start for that.

     References: #4259(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4264

   (2) http://www.sqlalchemy.org/trac/ticket/4259

8.3.3.65 misc
.............

   * `[bug] [ext]' ¶. The horizontal sharding extension now
     makes use of the identity token added to ORM identity keys as part
     of #4137(1), when an object refresh or column-based deferred load
     or unexpiration operation occurs.  Since we know the “shard” that
     the object originated from, we make use of this value when
     refreshing, thereby avoiding queries against other shards that
     don’t match this object’s identity in any case.

     References: #4247(2)

   * `[bug] [ext]' ¶. Fixed a race condition which could
     occur if automap AutomapBase.prepare() were used within
     a multi-threaded context against other threads which may call
     configure_mappers() as a result of use of other mappers.  The
     unfinished mapping work of automap is particularly sensitive to
     being pulled in by a configure_mappers() step leading
     to errors.

     References: #4266(3)

   * `[bug] [tests]' ¶. Fixed a bug in the test suite where
     if an external dialect returned ‘None’ for ‘server_version_info’,
     the exclusion logic would raise an ‘AttributeError’.

     References: #4249(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4137

   (2) http://www.sqlalchemy.org/trac/ticket/4247

   (3) http://www.sqlalchemy.org/trac/ticket/4266

   (4) http://www.sqlalchemy.org/trac/ticket/4249

8.3.3.66 1.2.7
..............

Released: April 20, 2018

8.3.3.67 orm
............

   * `[orm] [bug]' ¶. Fixed regression in 1.2 within sharded
     query feature where the new “identity_token” element was not being
     correctly considered within the scope of a lazy load operation,
     when searching the identity map for a related many-to-one element.
     The new behavior will allow for making use of the “id_chooser” in
     order to determine the best identity key to retrieve from the
     identity map.  In order to achieve this, some refactoring of 1.2’s
     “identity_token” approach has made some slight changes to the
     implementation of ‘ShardedQuery’ which should be noted for other
     derivations of this class.

     References: #4228(1)

   * `[orm] [bug]' ¶. Fixed issue in single-inheritance
     loading where the use of an aliased entity against a
     single-inheritance subclass in conjunction with the
     Query.select_from() method would cause the SQL to be rendered
     with the unaliased table mixed in to the query, causing a cartesian
     product.  In particular this was affecting the new “selectin”
     loader when used against a single-inheritance subclass.

     References: #4241(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4228

   (2) http://www.sqlalchemy.org/trac/ticket/4241

8.3.3.68 sql
............

   * `[sql] [bug]' ¶. Fixed issue where the compilation of
     an INSERT statement with the “literal_binds” option that also uses
     an explicit sequence and “inline” generation, as on PostgreSQL and
     Oracle, would fail to accommodate the extra keyword argument within
     the sequence processing routine.

     References: #4231(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4231

8.3.3.69 postgresql
...................

   * `[postgresql] [feature]' ¶. Added new PG type
     REGCLASS which assists in casting table names to OID values.
     Pull request courtesy Sebastian Bank.

     References: #4160(1)

   * `[postgresql] [bug]' ¶. Fixed bug where the special
     “not equals” operator for the PostgreSQL “range” datatypes such as
     DATERANGE would fail to render “IS NOT NULL” when compared to the
     Python ‘None’ value.

     References: #4229(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4160

   (2) http://www.sqlalchemy.org/trac/ticket/4229

8.3.3.70 mssql
..............

   * `[mssql] [bug]' ¶. Fixed 1.2 regression caused by
     #4060(1) where the query used to reflect SQL Server cross-schema
     foreign keys was limiting the criteria incorrectly.

     References: #4234(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4060

   (2) http://www.sqlalchemy.org/trac/ticket/4234

8.3.3.71 oracle
...............

   * `[oracle] [bug]' ¶. The Oracle NUMBER datatype is
     reflected as INTEGER if the precision is NULL and the scale is
     zero, as this is how INTEGER values come back when reflected from
     Oracle’s tables.  Pull request courtesy Kent Bower.

8.3.3.72 1.2.6
..............

Released: March 30, 2018

8.3.3.73 orm
............

   * `[orm] [bug]' ¶. Fixed bug where using
     Mutable.associate_with() or Mutable.as_mutable()
     in conjunction with a class that has non- primary mappers set up
     with alternatively-named attributes would produce an attribute
     error.  Since non-primary mappers are not used for persistence, the
     mutable extension now excludes non-primary mappers from its
     instrumentation steps.

     References: #4215(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4215

8.3.3.74 engine
...............

   * `[engine] [bug]' ¶. Fixed bug in connection pool where
     a connection could be present in the pool without all of its
     “connect” event handlers called, if a previous “connect” handler
     threw an exception; note that the dialects themselves have connect
     handlers that emit SQL, such as those which set transaction
     isolation, which can fail if the database is in a non-available
     state, but still allows a connection.  The connection is now
     invalidated first if any of the connect handlers fail.

     References: #4225(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4225

8.3.3.75 sql
............

   * `[sql] [bug]' ¶. Fixed a regression that occurred from
     the previous fix to #4204(1) in version 1.2.5, where a CTE that
     refers to itself after the CTE.alias() method has been
     called would not refer to itself correctly.

     References: #4204(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4204

   (2) http://www.sqlalchemy.org/trac/ticket/4204

8.3.3.76 postgresql
...................

   * `[postgresql] [feature]' ¶. Added support for
     “PARTITION BY” in PostgreSQL table definitions, using
     “postgresql_partition_by”.  Pull request courtesy Vsevolod
     Solovyov.

8.3.3.77 mssql
..............

   * `[mssql] [bug]' ¶. Adjusted the SQL Server version
     detection for pyodbc to only allow for numeric tokens, filtering
     out non-integers, since the dialect does tuple- numeric comparisons
     with this value.  This is normally true for all known SQL Server /
     pyodbc drivers in any case.

     References: #4227(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4227

8.3.3.78 oracle
...............

   * `[oracle] [bug]' ¶. The minimum cx_Oracle version
     supported is 5.2 (June 2015).  Previously, the dialect asserted
     against version 5.0 but as of 1.2.2 we are using some symbols that
     did not appear until 5.2.

     References: #4211(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4211

8.3.3.79 misc
.............

   * `[bug] [declarative]' ¶. Removed a warning that would
     be emitted when calling upon ‘__table_args__’, ‘__mapper_args__’ as
     named with a ‘@declared_attr’ method, when called from a non-mapped
     declarative mixin.  Calling these directly is documented as the
     approach to use when one is overriding one of these methods on a
     mapped class.  The warning still emits for regular attribute names.

     References: #4221(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4221

8.3.3.80 1.2.5
..............

Released: March 6, 2018

8.3.3.81 orm
............

   * `[orm] [feature]' ¶. Added new feature
     Query.only_return_tuples().  Causes the Query
     object to return keyed tuple objects unconditionally even if the
     query is against a single entity.  Pull request courtesy Eric
     Atkin.

   * `[orm] [bug]' ¶. Fixed bug in new “polymorphic
     selectin” loading when a selection of polymorphic objects were to
     be partially loaded from a relationship lazy loader, leading to an
     “empty IN” condition within the load that raises an error for the
     “inline” form of “IN”.

     References: #4199(1)

   * `[orm] [bug]' ¶. Fixed 1.2 regression where a mapper
     option that contains an AliasedClass object, as is
     typical when using the QueryableAttribute.of_type()
     method, could not be pickled.  1.1’s behavior was to omit the
     aliased class objects from the path, so this behavior is restored.

     References: #4209(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4199

   (2) http://www.sqlalchemy.org/trac/ticket/4209

8.3.3.82 sql
............

   * `[sql] [bug]' ¶. Fixed bug in :class:.‘CTE‘ construct
     along the same lines as that of #4204(1) where a CTE
     that was aliased would not copy itself correctly during a “clone”
     operation as is frequent within the ORM as well as when using the
     ClauseElement.params() method.

     References: #4210(2)

   * `[sql] [bug]' ¶. Fixed bug in CTE rendering where a
     CTE that was also turned into an Alias
     would not render its “ctename AS aliasname” clause appropriately if
     there were more than one reference to the CTE in a FROM clause.

     References: #4204(3)

   * `[sql] [bug]' ¶. Fixed bug in new “expanding IN
     parameter” feature where the bind parameter processors for values
     wasn’t working at all, tests failed to cover this pretty basic case
     which includes that ENUM values weren’t working.

     References: #4198(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4204

   (2) http://www.sqlalchemy.org/trac/ticket/4210

   (3) http://www.sqlalchemy.org/trac/ticket/4204

   (4) http://www.sqlalchemy.org/trac/ticket/4198

8.3.3.83 postgresql
...................

   * `[postgresql] [bug] [py3k]' ¶. Fixed bug in PostgreSQL
     COLLATE / ARRAY adjustment first introduced in #4006(1) where new
     behaviors in Python 3.7 regular expressions caused the fix to fail.

     This change is also `backported' to: 1.1.18

     References: #4208(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4006

   (2) http://www.sqlalchemy.org/trac/ticket/4208

8.3.3.84 mysql
..............

   * `[mysql] [bug]' ¶. MySQL dialects now query the server
     version using ‘SELECT @@version’ explicitly to the server to ensure
     we are getting the correct version information back.  Proxy servers
     like MaxScale interfere with the value that is passed to the
     DBAPI’s connection.server_version value so this is no longer
     reliable.

     This change is also `backported' to: 1.1.18

     References: #4205(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4205

8.3.3.85 1.2.4
..............

Released: February 22, 2018

8.3.3.86 orm
............

   * `[orm] [bug]' ¶. Fixed 1.2 regression in ORM versioning
     feature where a mapping against a select() or
     alias() that also used a versioning column against the
     underlying table would fail due to the check added as part of
     #3673(1).

     References: #4193(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3673

   (2) http://www.sqlalchemy.org/trac/ticket/4193

8.3.3.87 engine
...............

   * `[engine] [bug]' ¶. Fixed regression caused in 1.2.3
     due to fix from #4181(1) where the changes to the event system
     involving Engine and ‘OptionEngine’ did not accommodate
     for event removals, which would raise an ‘AttributeError’ when
     invoked at the class level.

     References: #4190(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4181

   (2) http://www.sqlalchemy.org/trac/ticket/4190

8.3.3.88 sql
............

   * `[sql] [bug]' ¶. Fixed bug where CTE expressions would
     not have their name or alias name quoted when the given name is
     case sensitive or otherwise requires quoting.  Pull request
     courtesy Eric Atkin.

     References: #4197(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4197

8.3.3.89 1.2.3
..............

Released: February 16, 2018

8.3.3.90 orm
............

   * `[orm] [feature]' ¶. Added new argument
     set_attribute.inititator to the set_attribute()
     function, allowing an event token received from a listener function
     to be propagated to subsequent set events.

   * `[orm] [bug]' ¶. Fixed issue in post_update feature
     where an UPDATE is emitted when the parent object has been deleted
     but the dependent object is not.  This issue has existed for a long
     time however since 1.2 now asserts rows matched for post_update,
     this was raising an error.

     This change is also `backported' to: 1.1.16

     References: #4187(1)

   * `[orm] [bug]' ¶. Fixed regression caused by fix for
     issue #4116(2) affecting versions 1.2.2 as well as 1.1.15, which
     had the effect of mis-calculation of the “owning class” of an
     AssociationProxy as the ‘NoneType’ class in some declarative
     mixin/inheritance situations as well as if the association proxy
     were accessed off of an un-mapped class.  The “figure out the
     owner” logic has been replaced by an in-depth routine that searches
     through the complete mapper hierarchy assigned to the class or
     subclass to determine the correct (we hope) match; will not assign
     the owner if no match is found.  An exception is now raised if the
     proxy is used against an un-mapped instance.

     This change is also `backported' to: 1.1.16

     References: #4185(3)

   * `[orm] [bug]' ¶. Fixed bug where the Bundle.
     object did not correctly report upon the primary Mapper
     object represented by the bundle, if any.  An immediate side effect
     of this issue was that the new selectinload loader strategy
     wouldn’t work with the horizontal sharding extension.

     References: #4175(4)

   * `[orm] [bug]' ¶. Fixed bug in concrete inheritance
     mapping where user-defined attributes such as hybrid properties
     that mirror the names of mapped attributes from sibling classes
     would be overwritten by the mapper as non-accessible at the
     instance level.  Additionally ensured that user-bound descriptors
     are not implicitly invoked at the class level during the mapper
     configuration stage.

     References: #4188(5)

   * `[orm] [bug]' ¶. Fixed bug where the
     reconstructor() event helper would not be recognized if it
     were applied to the ‘__init__()’ method of the mapped class.

     References: #4178(6)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4187

   (2) http://www.sqlalchemy.org/trac/ticket/4116

   (3) http://www.sqlalchemy.org/trac/ticket/4185

   (4) http://www.sqlalchemy.org/trac/ticket/4175

   (5) http://www.sqlalchemy.org/trac/ticket/4188

   (6) http://www.sqlalchemy.org/trac/ticket/4178

8.3.3.91 engine
...............

   * `[engine] [bug]' ¶. Fixed bug where events associated
     with an ‘Engine’ at the class level would be doubled when the
     Engine.execution_options() method were used.  To achieve
     this, the semi-private class ‘OptionEngine’ no longer accepts
     events directly at the class level and will raise an error; the
     class only propagates class-level events from its parent
     Engine.  Instance-level events continue to work as before.

     References: #4181(1)

   * `[engine] [bug]' ¶. The URL object now
     allows query keys to be specified multiple times where their values
     will be joined into a list.  This is to support the plugins feature
     documented at CreateEnginePlugin which documents that
     “plugin” can be passed multiple times.  Additionally, the plugin
     names can be passed to create_engine() outside of the
     URL using the new create_engine.plugins parameter.

     References: #4170(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4181

   (2) http://www.sqlalchemy.org/trac/ticket/4170

8.3.3.92 sql
............

   * `[sql] [feature]' ¶. Added support for Enum.
     to persist the values of the enumeration, rather than the keys,
     when using a Python pep-435 style enumerated object.  The user
     supplies a callable function that will return the string values to
     be persisted.  This allows enumerations against non-string values
     to be value-persistable as well.  Pull request courtesy Jon Snyder.

     References: #3906(1)

   * `[sql] [bug]' ¶. Fixed bug where the Enum.
     type wouldn’t handle enum “aliases” correctly, when more than one
     key refers to the same value.  Pull request courtesy Daniel Knell.

     References: #4180(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3906

   (2) http://www.sqlalchemy.org/trac/ticket/4180

8.3.3.93 postgresql
...................

   * `[postgresql] [bug]' ¶. Added “SSL SYSCALL error:
     Operation timed out” to the list of messages that trigger a
     “disconnect” scenario for the psycopg2 driver.  Pull request
     courtesy André Cruz.

     This change is also `backported' to: 1.1.16

   * `[postgresql] [bug]' ¶. Added “TRUNCATE” to the list of
     keywords accepted by the PostgreSQL dialect as an
     “autocommit”-triggering keyword.  Pull request courtesy Jacob
     Hayes.

     This change is also `backported' to: 1.1.16

8.3.3.94 sqlite
...............

   * `[sqlite] [bug]' ¶. Fixed the import error raised when
     a platform has neither pysqlite2 nor sqlite3 installed, such that
     the sqlite3-related import error is raised, not the pysqlite2 one
     which is not the actual failure mode.  Pull request courtesy Robin.

8.3.3.95 oracle
...............

   * `[oracle] [feature]' ¶. The ON DELETE options for
     foreign keys are now part of Oracle reflection.  Oracle does not
     support ON UPDATE cascades.  Pull request courtesy Miroslav
     Shubernetskiy.

   * `[oracle] [bug]' ¶. Fixed bug in cx_Oracle disconnect
     detection, used by pre_ping and other features, where an error
     could be raised as DatabaseError which includes a numeric error
     code; previously we weren’t checking in this case for a disconnect
     code.

     References: #4182(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4182

8.3.3.96 misc
.............

   * `[bug] [pool]' ¶. Fixed a fairly serious connection
     pool bug where a connection that is acquired after being refreshed
     as a result of a user-defined DisconnectionError or
     due to the 1.2-released “pre_ping” feature would not be correctly
     reset if the connection were returned to the pool by weakref
     cleanup (e.g.  the front-facing object is garbage collected); the
     weakref would still refer to the previously invalidated DBAPI
     connection which would have the reset operation erroneously called
     upon it instead.  This would lead to stack traces in the logs and a
     connection being checked into the pool without being reset, which
     can cause locking issues.

     This change is also `backported' to: 1.1.16

     References: #4184(1)

   * `[bug] [tests]' ¶. A test added in 1.2 thought to
     confirm a Python 2.7 behavior turns out to be confirming the
     behavior only as of Python 2.7.8.  Python bug #8743 still impacts
     set comparison in Python 2.7.7 and earlier, so the test in question
     involving AssociationSet no longer runs for these older Python 2.7
     versions.

     References: #3265(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4184

   (2) http://www.sqlalchemy.org/trac/ticket/3265

8.3.3.97 1.2.2
..............

Released: January 24, 2018

8.3.3.98 orm
............

   * `[orm] [bug]' ¶. Fixed 1.2 regression regarding new
     bulk_replace event where a backref would fail to remove an object
     from the previous owner when a bulk-assignment assigned the object
     to a new owner.

     References: #4171(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4171

8.3.3.99 mysql
..............

   * `[mysql] [bug]' ¶. Added more MySQL 8.0 reserved words
     to the MySQL dialect for quoting purposes.  Pull request courtesy
     Riccardo Magliocchetti.

8.3.3.100 mssql
...............

   * `[mssql] [bug]' ¶. Added ODBC error code 10054 to the
     list of error codes that count as a disconnect for ODBC / MSSQL
     server.

     References: #4164(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4164

8.3.3.101 oracle
................

   * `[oracle] [bug]' ¶. The cx_Oracle dialect now calls
     setinputsizes() with cx_Oracle.NCHAR unconditionally when the
     NVARCHAR2 datatype, in SQLAlchemy corresponding to
     sqltypes.Unicode(), is in use.  Per cx_Oracle’s author this allows
     the correct conversions to occur within the Oracle client
     regardless of the setting for NLS_NCHAR_CHARACTERSET.

     References: #4163(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4163

8.3.3.102 1.2.1
...............

Released: January 15, 2018

8.3.3.103 orm
.............

   * `[orm] [bug]' ¶. Fixed bug where an object that is
     expunged during a rollback of a nested or subtransaction which also
     had its primary key mutated would not be correctly removed from the
     session, causing subsequent issues in using the session.

     This change is also `backported' to: 1.1.16

     References: #4151(1)

   * `[orm] [bug]' ¶. Fixed regression where pickle format
     of a Load / _UnboundLoad object (e.g.  loader options) changed and
     ‘__setstate__()’ was raising an UnboundLocalError for an object
     received from the legacy format, even though an attempt was made to
     do so.  tests are now added to ensure this works.

     References: #4159(2)

   * `[orm] [bug]' ¶. Fixed regression caused by new
     lazyload caching scheme in #3954(3) where a query that makes use of
     loader options with of_type would cause lazy loads of unrelated
     paths to fail with a TypeError.

     References: #4153(4)

   * `[orm] [bug]' ¶. Fixed bug in new “selectin”
     relationship loader where the loader could try to load a
     non-existent relationship when loading a collection of polymorphic
     objects, where only some of the mappers include that relationship,
     typically when PropComparator.of_type() is being used.

     References: #4156(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4151

   (2) http://www.sqlalchemy.org/trac/ticket/4159

   (3) http://www.sqlalchemy.org/trac/ticket/3954

   (4) http://www.sqlalchemy.org/trac/ticket/4153

   (5) http://www.sqlalchemy.org/trac/ticket/4156

8.3.3.104 sql
.............

   * `[sql] [bug]' ¶. Fixed bug in Insert.values()
     where using the “multi-values” format in combination with
     Column objects as keys rather than strings would fail.  Pull
     request courtesy Aubrey Stark-Toller.

     This change is also `backported' to: 1.1.16

     References: #4162(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4162

8.3.3.105 mssql
...............

   * `[mssql] [bug]' ¶. Fixed regression in 1.2 where newly
     repaired quoting of collation names in #3785(1) breaks SQL Server,
     which explicitly does not understand a quoted collation name.
     Whether or not mixed-case collation names are quoted or not is now
     deferred down to a dialect-level decision so that each dialect can
     prepare these identifiers directly.

     References: #4154(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3785

   (2) http://www.sqlalchemy.org/trac/ticket/4154

8.3.3.106 oracle
................

   * `[oracle] [bug]' ¶. Fixed regression where the removal
     of most setinputsizes rules from cx_Oracle dialect impacted the
     TIMESTAMP datatype’s ability to retrieve fractional seconds.

     References: #4157(1)

   * `[oracle] [bug]' ¶. Fixed regression in Oracle imports
     where a missing comma caused an undefined symbol to be present.
     Pull request courtesy Miroslav Shubernetskiy.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4157

8.3.3.107 misc
..............

   * `[bug] [ext]' ¶. Fixed regression in association proxy
     due to #3769(1) (allow for chained any() / has()) where contains()
     against an association proxy chained in the form (o2m relationship,
     associationproxy(m2o relationship, m2o relationship)) would raise
     an error regarding the re-application of contains() on the final
     link of the chain.

     References: #4150(2)

   * `[bug] [tests]' ¶. Removed an oracle-specific
     requirements rule from the public test suite that was interfering
     with third party dialect suites.

   * `[bug] [tests]' ¶. Added a new exclusion rule
     group_by_complex_expression which disables tests that use “GROUP BY
     <expr>”, which seems to be not viable for at least two third party
     dialects.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3769

   (2) http://www.sqlalchemy.org/trac/ticket/4150

8.3.3.108 1.2.0
...............

Released: December 27, 2017

8.3.3.109 orm
.............

   * `[orm] [feature]' ¶. Added a new data member to the
     identity key tuple used by the ORM’s identity map, known as the
     “identity_token”.  This token defaults to None but may be used by
     database sharding schemes to differentiate objects in memory with
     the same primary key that come from different databases.  The
     horizontal sharding extension integrates this token applying the
     shard identifier to it, thus allowing primary keys to be duplicated
     across horizontally sharded backends.

     See also
     ........

     See Identity key enhancements to support sharding.

     References: #4137(1)

   * `[orm] [bug] [ext]' ¶. Fixed bug where the association
     proxy would inadvertently link itself to an AliasedClass
     object if it were called first with the AliasedClass
     as a parent, causing errors upon subsequent usage.

     This change is also `backported' to: 1.1.15

     References: #4116(2)

   * `[orm] [bug]' ¶. Fixed bug in contains_eager()
     query option where making use of a path that used
     PropComparator.of_type() to refer to a subclass across more
     than one level of joins would also require that the “alias”
     argument were provided with the same subtype in order to avoid
     adding unwanted FROM clauses to the query; additionally, using
     contains_eager() across subclasses that use
     aliased() objects of subclasses as the
     PropComparator.of_type() argument will also render correctly.

     References: #4130(3)

   * `[orm] [bug]' ¶. The Query.exists() method
     will now disable eager loaders for when the query is rendered.
     Previously, joined-eager load joins would be rendered unnecessarily
     as well as subquery eager load queries would be needlessly
     generated.  The new behavior matches that of the
     Query.subquery() method.

     References: #4032(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4137

   (2) http://www.sqlalchemy.org/trac/ticket/4116

   (3) http://www.sqlalchemy.org/trac/ticket/4130

   (4) http://www.sqlalchemy.org/trac/ticket/4032

8.3.3.110 orm declarative
.........................

   * `[orm] [declarative] [bug]' ¶. Fixed bug where a
     descriptor that is elsewhere a mapped column or relationship within
     a hierarchy based on AbstractConcreteBase would be
     referred towards during a refresh operation, causing an error as
     the attribute is not mapped as a mapper property.  A similar issue
     can arise for other attributes like the “type” column added by
     AbstractConcreteBase if the class fails to include
     “concrete=True” in its mapper, however the check here should also
     prevent that scenario from causing a problem.

     This change is also `backported' to: 1.1.15

     References: #4124(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4124

8.3.3.111 engine
................

   * `[engine] [feature]' ¶. The “password” attribute of the
     ‘URL’ object can now be any user-defined or user-subclassed string
     object that responds to the Python ‘str()’ builtin.  The object
     passed will be maintained as the datamember ‘URL.password_original’
     and will be consulted when the ‘URL.password’ attribute is read to
     produce the string value.

     References: #4089(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4089

8.3.3.112 sql
.............

   * `[sql] [bug]' ¶. Fixed bug where ‘__repr__’ of
     ColumnDefault would fail if the argument were a tuple.  Pull
     request courtesy Nicolas Caniart.

     This change is also `backported' to: 1.1.15

     References: #4126(1)

   * `[sql] [bug]' ¶. Reworked the new “autoescape” feature
     introduced in New “autoescape” option for startswith(), endswith()
     in 1.2.0b2 to be fully automatic; the escape
     character now defaults to a forwards slash ‘"/"’ and is applied to
     percent, underscore, as well as the escape character itself, for
     fully automatic escaping.  The character can also be changed using
     the “escape” parameter.

     See also
     ........

     See New “autoescape” option for startswith(), endswith().

     References: #2694(2)

   * `[sql] [bug]' ¶. Fixed bug where the
     Table.tometadata() method would not properly accommodate
     Index objects that didn’t consist of simple column
     expressions, such as indexes against a text() construct,
     indexes that used SQL expressions or ‘func’, etc.  The routine now
     copies expressions fully to a new Index object while
     substituting all table-bound Column objects for those of
     the target table.

     References: #4147(3)

   * `[sql] [bug]' ¶. Changed the “visit name” of
     ColumnElement from “column” to “column_element”, so that when
     this element is used as the basis for a user-defined SQL element,
     it is not assumed to behave like a table-bound ColumnClause
     when processed by various SQL traversal utilities, as are
     commonly used by the ORM.

     References: #4142(4)

   * `[sql] [bug] [ext]' ¶. Fixed issue in ARRAY.
     datatype which is essentially the same issue as that of #3832(5),
     except not a regression, where column attachment events on top of
     ARRAY would not fire correctly, thus interfering with
     systems which rely upon this.  A key use case that was broken by
     this is the use of mixins to declare columns that make use of
     ‘MutableList.as_mutable()’.

     References: #4141(6)

   * `[sql] [bug]' ¶. 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.

     References: #4140(7)

   * `[sql] [enhancement]' ¶. Implemented “DELETE..FROM”
     syntax for PostgreSQL, MySQL, MS SQL Server (as well as within the
     unsupported Sybase dialect) in a manner similar to how
     “UPDATE..FROM” works.  A DELETE statement that refers to more than
     one table will switch into “multi-table” mode and render the
     appropriate “USING” or multi-table “FROM” clause as understood by
     the database.  Pull request courtesy Pieter Mulder.

     See also
     ........

     See Multiple-table criteria support for DELETE.

     References: #959(8)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4126

   (2) http://www.sqlalchemy.org/trac/ticket/2694

   (3) http://www.sqlalchemy.org/trac/ticket/4147

   (4) http://www.sqlalchemy.org/trac/ticket/4142

   (5) http://www.sqlalchemy.org/trac/ticket/3832

   (6) http://www.sqlalchemy.org/trac/ticket/4141

   (7) http://www.sqlalchemy.org/trac/ticket/4140

   (8) http://www.sqlalchemy.org/trac/ticket/959

8.3.3.113 postgresql
....................

   * `[postgresql] [feature]' ¶. Added new MONEY
     datatype.  Pull request courtesy Cleber J Santos.

8.3.3.114 mysql
...............

   * `[mysql] [bug]' ¶. MySQL 5.7.20 now warns for use of
     the @tx_isolation variable; a version check is now performed and
     uses @transaction_isolation instead to prevent this warning.

     This change is also `backported' to: 1.1.15

     References: #4120(1)

   * `[mysql] [bug]' ¶. Fixed regression from issue 1.2.0b3
     where “MariaDB” version comparison can fail for some particular
     MariaDB version strings under Python 3.

     References: #4115(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4120

   (2) http://www.sqlalchemy.org/trac/ticket/4115

8.3.3.115 mssql
...............

   * `[mssql] [bug]' ¶. Fixed bug where sqltypes.BINARY and
     sqltypes.VARBINARY datatypes would not include correct bound-value
     handlers for pyodbc, which allows the pyodbc.NullParam value to be
     passed that helps with FreeTDS.

     References: #4121(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4121

8.3.3.116 oracle
................

   * `[oracle] [bug]' ¶. Added some additional rules to
     fully handle ‘Decimal('Infinity')’, ‘Decimal('-Infinity')’ values
     with cx_Oracle numerics when using ‘asdecimal=True’.

     References: #4064(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4064

8.3.3.117 misc
..............

   * `[misc] [feature]' ¶. Added a new errors section to the
     documentation with background about common error messages.
     Selected exceptions within SQLAlchemy will include a link in their
     string output to the relevant section within this page.

   * `[enhancement] [ext]' ¶. Added new method
     Result.with_post_criteria() to baked query system, allowing
     non-SQL-modifying transformations to take place after the query has
     been pulled from the cache.  Among other things, this method can be
     used with ShardedQuery to set the shard identifier.
     ShardedQuery has also been modified such that its
     ‘ShardedQuery.get()’ method interacts correctly with that of
     Result.

     References: #4135(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4135

8.3.3.118 1.2.0b3
.................

Released: October 13, 2017

8.3.3.119 orm
.............

   * `[orm] [bug]' ¶. Fixed bug where ORM relationship would
     warn against conflicting sync targets (e.g.  two relationships
     would both write to the same column) for sibling classes in an
     inheritance hierarchy, where the two relationships would never
     actually conflict during writes.

     This change is also `backported' to: 1.1.15

     References: #4078(1)

   * `[orm] [bug]' ¶. Fixed bug where correlated select used
     against single-table inheritance entity would fail to render
     correctly in the outer query, due to adjustment for single
     inheritance discriminator criteria inappropriately re-applying the
     criteria to the outer query.

     This change is also `backported' to: 1.1.15

     References: #4103(2)

   * `[orm] [bug]' ¶. Fixed bug in Session.merge()
     following along similar lines as that of #4030(3), where an
     internal check for a target object in the identity map could lead
     to an error if it were to be garbage collected immediately before
     the merge routine actually retrieves the object.

     This change is also `backported' to: 1.1.14

     References: #4069(4)

   * `[orm] [bug]' ¶. Fixed bug where an
     undefer_group() option would not be recognized if it extended
     from a relationship that was loading using joined eager loading.
     Additionally, as the bug led to excess work being performed, Python
     function call counts are also improved by 20% within the initial
     calculation of result set columns, complementing the joined eager
     load improvements of #3915(5).

     This change is also `backported' to: 1.1.14

     References: #4048(6)

   * `[orm] [bug]' ¶. Fixed bug in Session.merge()
     where objects in a collection that had the primary key
     attribute set to ‘None’ for a key that is typically
     autoincrementing would be considered to be a database-persisted key
     for part of the internal deduplication process, causing only one
     object to actually be inserted in the database.

     This change is also `backported' to: 1.1.14

     References: #4056(7)

   * `[orm] [bug]' ¶. An InvalidRequestError is
     raised when a synonym() is used against an attribute
     that is not against a MapperProperty, such as an
     association proxy.  Previously, a recursion overflow would occur
     trying to locate non-existent attributes.

     This change is also `backported' to: 1.1.14

     References: #4067(8)

   * `[orm] [bug]' ¶. Fixed regression introduced in 1.2.0b1
     due to #3934(9) where the Session would fail to
     “deactivate” the transaction, if a rollback failed (the target
     issue is when MySQL loses track of a SAVEPOINT). This would cause a
     subsequent call to Session.rollback() to raise an error
     a second time, rather than completing and bringing the
     Session back to ACTIVE.

     References: #4050(10)

   * `[orm] [bug]' ¶. Fixed issue where the
     make_transient_to_detached() function would expire all
     attributes on the target object, including “deferred” attributes,
     which has the effect of the attribute being undeferred for the next
     refresh, causing an unexpected load of the attribute.

     References: #4084(11)

   * `[orm] [bug]' ¶. Fixed bug involving delete-orphan
     cascade where a related item that becomes an orphan before the
     parent object is part of a session is still tracked as moving into
     orphan status, which results in it being expunged from the session
     rather than being flushed.

          Note: This fix was inadvertently merged during the 1.2.0b3
          release and was `not added to the changelog' at that time.
          This changelog note was added to the release retroactively as
          of version 1.2.13.

     References: #4040(12)

   * `[orm] [bug]' ¶. Fixed bug in “selectin” polymorphic loading, loads subclasses using separate IN queries
     which prevented “selectin” and “inline” settings in a
     multi-level class hierarchy from interacting together as expected.
     A new example is added to the documentation.

     See also
     ........

     See Combining selectin and with_polymorphic.

     References: #4026(13)

   * `[orm] [bug]' ¶. Removed the warnings that are emitted
     when the LRU caches employed by the mapper as well as loader
     strategies reach their threshold; the purpose of this warning was
     at first a guard against excess cache keys being generated but
     became basically a check on the “creating many engines”
     antipattern.  While this is still an antipattern, the presence of
     test suites which both create an engine per test as well as raise
     on all warnings will be an inconvenience; it should not be critical
     that such test suites change their architecture just for this
     warning (though engine-per-test suite is always better).

     References: #4071(14)

   * `[orm] [bug]' ¶. Fixed regression where the use of a
     undefer_group() option in conjunction with a lazy
     loaded relationship option would cause an attribute error, due to a
     bug in the SQL cache key generation added in 1.2 as part of
     #3954(15).

     References: #4049(16)

   * `[orm] [bug]' ¶. Modified the change made to the ORM
     update/delete evaluator in #3366(17) such that if an unmapped
     column expression is present in the update or delete, if the
     evaluator can match its name to the mapped columns of the target
     class, a warning is emitted, rather than raising
     UnevaluatableError.  This is essentially the pre-1.2 behavior, and
     is to allow migration for applications that are currently relying
     upon this pattern.  However, if the given attribute name cannot be
     matched to the columns of the mapper, the UnevaluatableError is
     still raised, which is what was fixed in #3366(18).

     References: #4073(19)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4078

   (2) http://www.sqlalchemy.org/trac/ticket/4103

   (3) http://www.sqlalchemy.org/trac/ticket/4030

   (4) http://www.sqlalchemy.org/trac/ticket/4069

   (5) http://www.sqlalchemy.org/trac/ticket/3915

   (6) http://www.sqlalchemy.org/trac/ticket/4048

   (7) http://www.sqlalchemy.org/trac/ticket/4056

   (8) http://www.sqlalchemy.org/trac/ticket/4067

   (9) http://www.sqlalchemy.org/trac/ticket/3934

   (10) http://www.sqlalchemy.org/trac/ticket/4050

   (11) http://www.sqlalchemy.org/trac/ticket/4084

   (12) http://www.sqlalchemy.org/trac/ticket/4040

   (13) http://www.sqlalchemy.org/trac/ticket/4026

   (14) http://www.sqlalchemy.org/trac/ticket/4071

   (15) http://www.sqlalchemy.org/trac/ticket/3954

   (16) http://www.sqlalchemy.org/trac/ticket/4049

   (17) http://www.sqlalchemy.org/trac/ticket/3366

   (18) http://www.sqlalchemy.org/trac/ticket/3366

   (19) http://www.sqlalchemy.org/trac/ticket/4073

8.3.3.120 orm declarative
.........................

   * `[orm] [declarative] [bug]' ¶. A warning is emitted if
     a subclass attempts to override an attribute that was declared on a
     superclass using ‘@declared_attr.cascading’ that the overridden
     attribute will be ignored.  This use case cannot be fully supported
     down to further subclasses without more complex development
     efforts, so for consistency the “cascading” is honored all the way
     down regardless of overriding attributes.

     References: #4091(1)

   * `[orm] [declarative] [bug]' ¶. A warning is emitted if
     the ‘@declared_attr.cascading’ attribute is used with a special
     declarative name such as ‘__tablename__’, as this has no effect.

     References: #4092(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4091

   (2) http://www.sqlalchemy.org/trac/ticket/4092

8.3.3.121 engine
................

   * `[engine] [feature]' ¶. Added ‘__next__()’ and ‘next()’
     methods to ‘ResultProxy’, so that the ‘next()’ builtin function
     works on the object directly.  ‘ResultProxy’ has long had an
     ‘__iter__()’ method which already allows it to respond to the
     ‘iter()’ builtin.  The implementation for ‘__iter__()’ is
     unchanged, as performance testing has indicated that iteration
     using a ‘__next__()’ method with ‘StopIteration’ is about 20%
     slower in both Python 2.7 and 3.6.

     References: #4077(1)

   * `[engine] [bug]' ¶. Made some adjustments to
     Pool and Connection such that recovery logic is
     not run underneath exception catches for ‘pool.Empty’,
     ‘AttributeError’, since when the recovery operation itself fails,
     Python 3 creates a misleading stack trace referring to the ‘Empty’
     / ‘AttributeError’ as the cause, when in fact these exception
     catches are part of control flow.

     References: #4028(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4077

   (2) http://www.sqlalchemy.org/trac/ticket/4028

8.3.3.122 sql
.............

   * `[sql] [bug]' ¶. Fixed bug where the recently added
     ColumnOperators.any_() and
     ColumnOperators.all_() methods didn’t work when called as
     methods, as opposed to using the standalone functions any_()
     and all_().  Also added documentation examples for
     these relatively unintuitive SQL operators.

     This change is also `backported' to: 1.1.15

     References: #4093(1)

   * `[sql] [bug]' ¶. Added a new method
     DefaultExecutionContext.get_current_parameters() which is
     used within a function-based default value generator in order to
     retrieve the current parameters being passed to the statement.  The
     new function differs from the
     DefaultExecutionContext.current_parameters attribute in that
     it also provides for optional grouping of parameters that
     correspond to a multi-valued “insert” construct.  Previously it was
     not possible to identify the subset of parameters that were
     relevant to the function call.

     See also
     ........

     See Parameter helper for multi-valued INSERT with contextual default generator.

     See Context-Sensitive Default Functions.

     References: #4075(2)

   * `[sql] [bug]' ¶. Fixed bug in new SQL comments feature
     where table and column comment would not be copied when using
     Table.tometadata().

     References: #4087(3)

   * `[sql] [bug]' ¶. In release 1.1, the Boolean
     type was broken in that boolean coercion via ‘bool()’ would
     occur for backends that did not feature “native boolean”, but would
     not occur for native boolean backends, meaning the string ‘"0"’ now
     behaved inconsistently.  After a poll, a consensus was reached that
     non-boolean values should be raising an error, especially in the
     ambiguous case of string ‘"0"’; so the Boolean datatype
     will now raise ‘ValueError’ if an incoming value is not within the
     range ‘None, True, False, 1, 0’.

     See also
     ........

     See Boolean datatype now enforces strict True/False/None values.

     References: #4102(4)

   * `[sql] [bug]' ¶. Refined the behavior of
     Operators.op() such that in all cases, if the
     Operators.op.is_comparison flag is set to True, the return
     type of the resulting expression will be Boolean, and if
     the flag is False, the return type of the resulting expression will
     be the same type as that of the left-hand expression, which is the
     typical default behavior of other operators.  Also added a new
     parameter Operators.op.return_type as well as a helper
     method Operators.bool_op().

     See also
     ........

     See The typing behavior of custom operators has been made consistent.

     References: #4063(5)

   * `[sql] [bug]' ¶. Internal refinements to the
     Enum, Interval, and Boolean types,
     which now extend a common mixin ‘Emulated’ that indicates a type
     that provides Python-side emulation of a DB native type, switching
     out to the DB native type when a supporting backend is in use.  The
     PostgreSQL INTERVAL type when used directly will now
     include the correct type coercion rules for SQL expressions that
     also take effect for Interval. (such as adding a date
     to an interval yields a datetime).

     References: #4088(6)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4093

   (2) http://www.sqlalchemy.org/trac/ticket/4075

   (3) http://www.sqlalchemy.org/trac/ticket/4087

   (4) http://www.sqlalchemy.org/trac/ticket/4102

   (5) http://www.sqlalchemy.org/trac/ticket/4063

   (6) http://www.sqlalchemy.org/trac/ticket/4088

8.3.3.123 postgresql
....................

   * `[postgresql] [feature]' ¶. Added a new flag
     ‘use_batch_mode’ to the psycopg2 dialect.  This flag enables the
     use of psycopg2’s ‘psycopg2.extras.execute_batch’ extension when
     the Engine calls upon ‘cursor.executemany()’.  This
     extension provides a critical performance increase by over an order
     of magnitude when running INSERT statements in batch.  The flag is
     False by default as it is considered to be experimental for now.

     See also
     ........

     See Support for Batch Mode / Fast Execution Helpers.

     References: #4109(1)

   * `[postgresql] [bug]' ¶. Made further fixes to the
     ARRAY class in conjunction with COLLATE, as the fix made in
     #4006(2) failed to accommodate for a multidimensional array.

     This change is also `backported' to: 1.1.15

     References: #4006(3)

   * `[postgresql] [bug]' ¶. Fixed bug in array_agg
     function where passing an argument that is already of type
     ARRAY, such as a PostgreSQL array
     construct, would produce a ‘ValueError’, due to the function
     attempting to nest the arrays.

     This change is also `backported' to: 1.1.15

     References: #4107(4)

   * `[postgresql] [bug]' ¶. Fixed bug in PostgreSQL
     ‘Insert.on_conflict_do_update()’ which would prevent the insert
     statement from being used as a CTE, e.g.  via ‘Insert.cte()’,
     within another statement.

     This change is also `backported' to: 1.1.15

     References: #4074(5)

   * `[postgresql] [bug]' ¶. Fixed bug where the pg8000
     driver would fail if using MetaData.reflect() with a
     schema name, since the schema name would be sent as a “quoted_name”
     object that’s a string subclass, which pg8000 doesn’t recognize.
     The quoted_name type is added to pg8000’s py_types collection on
     connect.

     References: #4041(6)

   * `[postgresql] [bug]' ¶. Enabled UUID support for the
     pg8000 driver, which supports native Python uuid round trips for
     this datatype.  Arrays of UUID are still not supported, however.

     References: #4016(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4109

   (2) http://www.sqlalchemy.org/trac/ticket/4006

   (3) http://www.sqlalchemy.org/trac/ticket/4006

   (4) http://www.sqlalchemy.org/trac/ticket/4107

   (5) http://www.sqlalchemy.org/trac/ticket/4074

   (6) http://www.sqlalchemy.org/trac/ticket/4041

   (7) http://www.sqlalchemy.org/trac/ticket/4016

8.3.3.124 mysql
...............

   * `[mysql] [bug]' ¶. Warning emitted when MariaDB 10.2.8
     or earlier in the 10.2 series is detected as there are major issues
     with CHECK constraints within these versions that were resolved as
     of 10.2.9.

     Note that this changelog message was NOT released with SQLAlchemy
     1.2.0b3 and was added retroactively.

     This change is also `backported' to: 1.1.15

     References: #4097(1)

   * `[mysql] [bug]' ¶. Fixed issue where CURRENT_TIMESTAMP
     would not reflect correctly in the MariaDB 10.2 series due to a
     syntax change, where the function is now represented as
     ‘current_timestamp()’.

     This change is also `backported' to: 1.1.15

     References: #4096(2)

   * `[mysql] [bug]' ¶. MariaDB 10.2 now supports CHECK
     constraints (warning: use version 10.2.9 or greater due to upstream
     issues noted in #4097(3)).  Reflection now takes these CHECK
     constraints into account when they are present in the ‘SHOW CREATE
     TABLE’ output.

     This change is also `backported' to: 1.1.15

     References: #4098(4)

   * `[mysql] [bug]' ¶. Changed the name of the ‘.values’
     attribute of the new MySQL INSERT..ON DUPLICATE KEY UPDATE
     construct to ‘.inserted’, as Insert already has a method
     called Insert.values().  The ‘.inserted’ attribute
     ultimately renders the MySQL ‘VALUES()’ function.

     References: #4072(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4097

   (2) http://www.sqlalchemy.org/trac/ticket/4096

   (3) http://www.sqlalchemy.org/trac/ticket/4097

   (4) http://www.sqlalchemy.org/trac/ticket/4098

   (5) http://www.sqlalchemy.org/trac/ticket/4072

8.3.3.125 sqlite
................

   * `[sqlite] [bug]' ¶. Fixed bug where SQLite CHECK
     constraint reflection would fail if the referenced table were in a
     remote schema, e.g.  on SQLite a remote database referred to by
     ATTACH.

     This change is also `backported' to: 1.1.15

     References: #4099(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4099

8.3.3.126 mssql
...............

   * `[mssql] [feature]' ¶. Added a new TIMESTAMP
     datatype, that correctly acts like a binary datatype for SQL
     Server rather than a datetime type, as SQL Server breaks the SQL
     standard here.  Also added ROWVERSION, as the
     “TIMESTAMP” type in SQL Server is deprecated in favor of
     ROWVERSION.

     References: #4086(1)

   * `[mssql] [feature]' ¶. Added support for “AUTOCOMMIT”
     isolation level, as established via
     Connection.execution_options(), to the PyODBC and pymssql
     dialects.  This isolation level sets the appropriate DBAPI-specific
     flags on the underlying connection object.

     References: #4058(2)

   * `[mssql] [bug]' ¶. Added a full range of “connection
     closed” exception codes to the PyODBC dialect for SQL Server,
     including ‘08S01’, ‘01002’, ‘08003’, ‘08007’, ‘08S02’, ‘08001’,
     ‘HYT00’, ‘HY010’.  Previously, only ‘08S01’ was covered.

     This change is also `backported' to: 1.1.15

     References: #4095(3)

   * `[mssql] [bug]' ¶. SQL Server supports what SQLAlchemy
     calls “native boolean” with its BIT type, as this type only accepts
     0 or 1 and the DBAPIs return its value as True/False.  So the SQL
     Server dialects now enable “native boolean” support, in that a
     CHECK constraint is not generated for a Boolean
     datatype.  The only difference vs.  other native boolean is that
     there are no “true” / “false” constants so “1” and “0” are still
     rendered here.

     References: #4061(4)

   * `[mssql] [bug]' ¶. Fixed the pymssql dialect so that
     percent signs in SQL text, such as used in modulus expressions or
     literal textual values, are `not' doubled up, as seems to be what
     pymssql expects.  This is despite the fact that the pymssql DBAPI
     uses the “pyformat” parameter style which itself considers the
     percent sign to be significant.

     References: #4057(5)

   * `[mssql] [bug]' ¶. Fixed bug where the SQL Server
     dialect could pull columns from multiple schemas when reflecting a
     self-referential foreign key constraint, if multiple schemas
     contained a constraint of the same name against a table of the same
     name.

     References: #4060(6)

   * `[mssql] [bug] [orm]' ¶. Added a new class of “rowcount
     support” for dialects that is specific to when “RETURNING”, which
     on SQL Server looks like “OUTPUT inserted”, is in use, as the
     PyODBC backend isn’t able to give us rowcount on an UPDATE or
     DELETE statement when OUTPUT is in effect.  This primarily affects
     the ORM when a flush is updating a row that contains
     server-calculated values, raising an error if the backend does not
     return the expected row count.  PyODBC now states that it supports
     rowcount except if OUTPUT.inserted is present, which is taken into
     account by the ORM during a flush as to whether it will look for a
     rowcount.

     References: #4062(7)

   * `[mssql] [bug] [orm]' ¶. Enabled the “sane_rowcount”
     flag for the pymssql dialect, indicating that the DBAPI now reports
     the correct number of rows affected from an UPDATE or DELETE
     statement.  This impacts mostly the ORM versioning feature in that
     it now can verify the number of rows affected on a target version.

   * `[mssql] [bug]' ¶. Added a rule to SQL Server index
     reflection to ignore the so-called “heap” index that is implicitly
     present on a table that does not specify a clustered index.

     References: #4059(8)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4086

   (2) http://www.sqlalchemy.org/trac/ticket/4058

   (3) http://www.sqlalchemy.org/trac/ticket/4095

   (4) http://www.sqlalchemy.org/trac/ticket/4061

   (5) http://www.sqlalchemy.org/trac/ticket/4057

   (6) http://www.sqlalchemy.org/trac/ticket/4060

   (7) http://www.sqlalchemy.org/trac/ticket/4062

   (8) http://www.sqlalchemy.org/trac/ticket/4059

8.3.3.127 oracle
................

   * `[oracle] [performance] [bug] [py2k]' ¶. Fixed
     performance regression caused by the fix for #3937(1) where
     cx_Oracle as of version 5.3 dropped the ‘.UNICODE’ symbol from its
     namespace, which was interpreted as cx_Oracle’s “WITH_UNICODE” mode
     being turned on unconditionally, which invokes functions on the
     SQLAlchemy side which convert all strings to unicode
     unconditionally and causing a performance impact.  In fact, per
     cx_Oracle’s author the “WITH_UNICODE” mode has been removed
     entirely as of 5.1, so the expensive unicode conversion functions
     are no longer necessary and are disabled if cx_Oracle 5.1 or
     greater is detected under Python 2.  The warning against
     “WITH_UNICODE” mode that was removed under #3937(2) is also
     restored.

     This change is also `backported' to: 1.1.13, 1.0.19

     References: #4035(3)

   * `[oracle] [bug]' ¶. Partial support for persisting and
     retrieving the Oracle value “infinity” is implemented with
     cx_Oracle, using Python float values only, e.g.  ‘float("inf")’.
     Decimal support is not yet fulfilled by the cx_Oracle DBAPI driver.

     References: #4064(4)

   * `[oracle] [bug]' ¶. The cx_Oracle dialect has been
     reworked and modernized to take advantage of new patterns that
     weren’t present in the old 4.x series of cx_Oracle.  This includes
     that the minimum cx_Oracle version is the 5.x series and that
     cx_Oracle 6.x is now fully tested.  The most significant change
     involves type conversions, primarily regarding the numeric /
     floating point and LOB datatypes, making more effective use of
     cx_Oracle type handling hooks to simplify how bind parameter and
     result data is processed.

     See also
     ........

     See Major Refactor to cx_Oracle Dialect, Typing System.

   * `[oracle] [bug]' ¶ two phase support for cx_Oracle has
     been completely removed for all versions of cx_Oracle, whereas in
     1.2.0b1 this change only took effect for the 6.x series of
     cx_Oracle.  This feature never worked correctly in any version of
     cx_Oracle and in cx_Oracle 6.x, the API which SQLAlchemy relied
     upon was removed.

     See also
     ........

     See Major Refactor to cx_Oracle Dialect, Typing System.

     References: #3997(5)

   * `[oracle] [bug]' ¶. The column keys present in a result
     set when using Insert.returning() with the cx_Oracle
     backend now use the correct column / label names like that of all
     other dialects.  Previously, these came out as ‘ret_nnn’.

     See also
     ........

     See Major Refactor to cx_Oracle Dialect, Typing System.

   * `[oracle] [bug]' ¶. Several parameters to the cx_Oracle
     dialect are now deprecated and will have no effect:
     ‘auto_setinputsizes’, ‘exclude_setinputsizes’, ‘allow_twophase’.

     See also
     ........

     See Major Refactor to cx_Oracle Dialect, Typing System.

   * `[oracle] [bug]' ¶. Fixed bug where an index reflected
     under Oracle with an expression like “column DESC” would not be
     returned, if the table also had no primary key, as a result of
     logic that attempts to filter out the index implicitly added by
     Oracle onto the primary key columns.

     References: #4042(6)

   * `[oracle] [bug]' ¶. Fixed more regressions caused by
     cx_Oracle 6.0; at the moment, the only behavioral change for users
     is disconnect detection now detects for cx_Oracle.DatabaseError in
     addition to cx_Oracle.InterfaceError, as this behavior seems to
     have changed.  Other issues regarding numeric precision and
     uncloseable connections are pending with the upstream cx_Oracle
     issue tracker.

     References: #4045(7)

   * `[oracle] [bug]' ¶. Fixed bug where Oracle 8 “non ansi”
     join mode would not add the ‘(+)’ operator to expressions that used
     an operator other than the ‘=’ operator.  The ‘(+)’ needs to be on
     all columns that are part of the right-hand side.

     References: #4076(8)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3937

   (2) http://www.sqlalchemy.org/trac/ticket/3937

   (3) http://www.sqlalchemy.org/trac/ticket/4035

   (4) http://www.sqlalchemy.org/trac/ticket/4064

   (5) http://www.sqlalchemy.org/trac/ticket/3997

   (6) http://www.sqlalchemy.org/trac/ticket/4042

   (7) http://www.sqlalchemy.org/trac/ticket/4045

   (8) http://www.sqlalchemy.org/trac/ticket/4076

8.3.3.128 1.2.0b2
.................

Released: July 24, 2017

8.3.3.129 orm
.............

   * `[orm] [bug]' ¶. Fixed regression from 1.1.11 where
     adding additional non-entity columns to a query that includes an
     entity with subqueryload relationships would fail, due to an
     inspection added in 1.1.11 as a result of #4011(1).

     This change is also `backported' to: 1.1.12

     References: #4033(2)

   * `[orm] [bug]' ¶. Fixed bug involving JSON NULL
     evaluation logic added in 1.1 as part of #3514(3) where the logic
     would not accommodate ORM mapped attributes named differently from
     the Column that was mapped.

     This change is also `backported' to: 1.1.12

     References: #4031(4)

   * `[orm] [bug]' ¶. Added ‘KeyError’ checks to all methods
     within ‘WeakInstanceDict’ where a check for ‘key in dict’ is
     followed by indexed access to that key, to guard against a race
     against garbage collection that under load can remove the key from
     the dict after the code assumes its present, leading to very
     infrequent ‘KeyError’ raises.

     This change is also `backported' to: 1.1.12

     References: #4030(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4011

   (2) http://www.sqlalchemy.org/trac/ticket/4033

   (3) http://www.sqlalchemy.org/trac/ticket/3514

   (4) http://www.sqlalchemy.org/trac/ticket/4031

   (5) http://www.sqlalchemy.org/trac/ticket/4030

8.3.3.130 misc
..............

   * `[bug] [py3k] [tests]' ¶. Fixed issue in testing
     fixtures which was incompatible with a change made as of Python
     3.6.2 involving context managers.

     This change is also `backported' to: 1.1.12, 1.0.18

     References: #4034(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4034

8.3.3.131 1.2.0b1
.................

Released: July 10, 2017

8.3.3.132 orm
.............

   * `[orm] [feature]' ¶. An aliased() construct
     can now be passed to the Query.select_entity_from()
     method.  Entities will be pulled from the selectable represented by
     the aliased() construct.  This allows special options
     for aliased() such as aliased.adapt_on_names
     to be used in conjunction with
     Query.select_entity_from().

     This change is also `backported' to: 1.1.7

     References: #3933(1)

   * `[orm] [feature]' ¶. Added ‘.autocommit’ attribute to
     scoped_session, proxying the ‘.autocommit’ attribute of
     the underling Session currently assigned to the thread.
     Pull request courtesy Ben Fagin.

   * `[orm] [feature]' ¶. Added a new feature
     with_expression() that allows an ad-hoc SQL expression to be
     added to a specific entity in a query at result time.  This is an
     alternative to the SQL expression being delivered as a separate
     element in the result tuple.

     See also
     ........

     See ORM attributes that can receive ad-hoc SQL expressions.

     References: #3058(2)

   * `[orm] [feature]' ¶. Added a new style of mapper-level
     inheritance loading “polymorphic selectin”.  This style of loading
     emits queries for each subclass in an inheritance hierarchy
     subsequent to the load of the base object type, using IN to specify
     the desired primary key values.

     See also
     ........

     See “selectin” polymorphic loading, loads subclasses using separate IN queries.

     References: #3948(3)

   * `[orm] [feature]' ¶. Added a new kind of eager loading
     called “selectin” loading.  This style of loading is very similar
     to “subquery” eager loading, except that it uses an IN expression
     given a list of primary key values from the loaded parent objects,
     rather than re-stating the original query.  This produces a more
     efficient query that is “baked” (e.g.  the SQL string is cached)
     and also works in the context of Query.yield_per().

     See also
     ........

     See New “selectin” eager loading, loads all collections at once using IN.

     References: #3944(4)

   * `[orm] [feature]' ¶. The ‘lazy="select"’ loader
     strategy now makes used of the BakedQuery query caching
     system in all cases.  This removes most overhead of generating a
     Query object and running it into a select()
     and then string SQL statement from the process of lazy-loading
     related collections and objects.  The “baked” lazy loader has also
     been improved such that it can now cache in most cases where query
     load options are used.

     See also
     ........

     See “Baked” loading now the default for lazy loads.

     References: #3954(5)

   * `[orm] [feature] [ext]' ¶. The Query.update()
     method can now accommodate both hybrid attributes as well as
     composite attributes as a source of the key to be placed in the SET
     clause.  For hybrids, an additional decorator
     hybrid_property.update_expression() is supplied for which the
     user supplies a tuple-returning function.

     See also
     ........

     See Support for bulk updates of hybrids, composites.

     References: #3229(6)

   * `[orm] [feature]' ¶. Added new attribute event
     AttributeEvents.bulk_replace().  This event is triggered when
     a collection is assigned to a relationship, before the incoming
     collection is compared with the existing one.  This early event
     allows for conversion of incoming non-ORM objects as well.  The
     event is integrated with the ‘@validates’ decorator.

     See also
     ........

     See New bulk_replace event.

     References: #3896(7)

   * `[orm] [feature]' ¶. Added new event handler
     AttributeEvents.modified() which is triggered when the
     func:‘.attributes.flag_modified’ function is invoked, which is
     common when using the sqlalchemy.ext.mutable extension
     module.

     See also
     ........

     See New “modified” event handler for sqlalchemy.ext.mutable.

     References: #3303(8)

   * `[orm] [bug]' ¶. Fixed issue with subquery eagerloading
     which continues on from the series of issues fixed in #2699(9),
     #3106(10), #3893(11) involving that the “subquery” contains the
     correct FROM clause when beginning from a joined inheritance
     subclass and then subquery eager loading onto a relationship from
     the base class, while the query also includes criteria against the
     subclass.  The fix in the previous tickets did not accommodate for
     additional subqueryload operations loading more deeply from the
     first level, so the fix has been further generalized.

     This change is also `backported' to: 1.1.11

     References: #4011(12)

   * `[orm] [bug]' ¶. Fixed bug where a cascade such as
     “delete-orphan” (but others as well) would fail to locate an object
     linked to a relationship that itself is local to a subclass in an
     inheritance relationship, thus causing the operation to not take
     place.

     This change is also `backported' to: 1.1.10

     References: #3986(13)

   * `[orm] [bug]' ¶. Fixed a race condition which could
     occur under threaded environments as a result of the caching added
     via #3915(14).  An internal collection of ‘Column’ objects could be
     regenerated on an alias object inappropriately, confusing a joined
     eager loader when it attempts to render SQL and collect results and
     resulting in an attribute error.  The collection is now generated
     up front before the alias object is cached and shared among
     threads.

     This change is also `backported' to: 1.1.7

     References: #3947(15)

   * `[orm] [bug]' ¶. An UPDATE emitted as a result of the
     relationship.post_update feature will now integrate
     with the versioning feature to both bump the version id of the row
     as well as assert that the existing version number was matched.

     See also
     ........

     See post_update integrates with ORM versioning.

     References: #3496(16)

   * `[orm] [bug]' ¶. Repaired several use cases involving
     the relationship.post_update feature when used in
     conjunction with a column that has an “onupdate” value.  When the
     UPDATE emits, the corresponding object attribute is now expired or
     refreshed so that the newly generated “onupdate” value can populate
     on the object; previously the stale value would remain.
     Additionally, if the target attribute is set in Python for the
     INSERT of the object, the value is now re-sent during the UPDATE so
     that the “onupdate” does not overwrite it (note this works just as
     well for server-generated onupdates).  Finally, the
     ‘SessionEvents.refresh_flush()’ event is now emitted for these
     attributes when refreshed within the flush.

     See also
     ........

     See Refinements to post_update in conjunction with onupdate.

     References: #3471(17), #3472(18)

   * `[orm] [bug]' ¶. Fixed bug where programmatic
     version_id counter in conjunction with joined table inheritance
     would fail if the version_id counter were not actually incremented
     and no other values on the base table were modified, as the UPDATE
     would have an empty SET clause.  Since programmatic version_id
     where version counter is not incremented is a documented use case,
     this specific condition is now detected and the UPDATE now sets the
     version_id value to itself, so that concurrency checks still take
     place.

     References: #3996(19)

   * `[orm] [bug]' ¶. The versioning feature does not
     support NULL for the version counter.  An exception is now raised
     if the version id is programmatic and was set to NULL for an
     UPDATE. Pull request courtesy Diana Clarke.

     References: #3673(20)

   * `[orm] [bug]' ¶. Removed a very old keyword argument
     from scoped_session called ‘scope’.  This keyword was
     never documented and was an early attempt at allowing for variable
     scopes.

     See also
     ........

     See “scope” keyword removed from scoped_session.

     References: #3796(21)

   * `[orm] [bug]' ¶. Fixed bug where combining a
     “with_polymorphic” load in conjunction with subclass-linked
     relationships that specify joinedload with innerjoin=True, would
     fail to demote those “innerjoins” to “outerjoins” to suit the other
     polymorphic classes that don’t support that relationship.  This
     applies to both a single and a joined inheritance polymorphic load.

     References: #3988(22)

   * `[orm] [bug]' ¶. Added new argument ‘with_for_update’
     to the Session.refresh() method.  When the
     ‘Query.with_lockmode()’ method were deprecated in favor of
     Query.with_for_update(), the Session.refresh()
     method was never updated to reflect the new option.

     See also
     ........

     See Added “for update” arguments to Session.refresh.

     References: #3991(23)

   * `[orm] [bug]' ¶. Fixed bug where a
     column_property() that is also marked as “deferred” would be
     marked as “expired” during a flush, causing it to be loaded along
     with the unexpiry of regular attributes even though this attribute
     was never accessed.

     References: #3984(24)

   * `[orm] [bug]' ¶. Fixed bug in subquery eager loading
     where the “join_depth” parameter for self-referential relationships
     would not be correctly honored, loading all available levels deep
     rather than correctly counting the specified number of levels for
     eager loading.

     References: #3967(25)

   * `[orm] [bug]' ¶. Added warnings to the LRU “compiled
     cache” used by the Mapper. (and ultimately will be for
     other ORM-based LRU caches) such that when the cache starts hitting
     its size limits, the application will emit a warning that this is a
     performance-degrading situation that may require attention.  The
     LRU caches can reach their size limits primarily if an application
     is making use of an unbounded number of Engine objects,
     which is an antipattern.  Otherwise, this may suggest an issue that
     should be brought to the SQLAlchemy developer’s attention.

   * `[orm] [bug]' ¶. Fixed bug to improve upon the
     specificity of loader options that take effect subsequent to the
     lazy load of a related entity, so that the loader options will
     match to an aliased or non-aliased entity more specifically if
     those options include entity information.

     References: #3963(26)

   * `[orm] [bug]' ¶. The flag_modified().
     function now raises InvalidRequestError if the named
     attribute key is not present within the object, as this is assumed
     to be present in the flush process.  To mark an object “dirty” for
     a flush without referring to any specific attribute, the
     flag_dirty() function may be used.

     See also
     ........

     See Use flag_dirty() to mark an object as “dirty” without any attribute changing.

     References: #3753(27)

   * `[orm] [bug]' ¶. The “evaluate” strategy used by
     Query.update() and Query.delete() can now
     accommodate a simple object comparison from a many-to-one
     relationship to an instance, when the attribute names of the
     primary key / foreign key columns don’t match the actual names of
     the columns.  Previously this would do a simple name-based match
     and fail with an AttributeError.

     References: #3366(28)

   * `[orm] [bug]' ¶. The ‘@validates’ decorator now allows
     the decorated method to receive objects from a “bulk collection
     set” operation that have not yet been compared to the existing
     collection.  This allows incoming values to be converted to
     compatible ORM objects as is already allowed from an “append”
     event.  Note that this means that the ‘@validates’ method is called
     for `all' values during a collection assignment, rather than just
     the ones that are new.

     See also
     ........

     See A @validates method receives all values on bulk-collection set before comparison.

     References: #3896(29)

   * `[orm] [bug]' ¶. Fixed bug in single-table inheritance
     where the select_from() argument would not be taken into account
     when limiting rows to a subclass.  Previously, only expressions in
     the columns requested would be taken into account.

     See also
     ........

     See Fixed issue involving single-table inheritance with select_from().

     References: #3891(30)

   * `[orm] [bug]' ¶. When assigning a collection to an
     attribute mapped by a relationship, the previous collection is no
     longer mutated.  Previously, the old collection would be emptied
     out in conjunction with the “item remove” events that fire off; the
     events now fire off without affecting the old collection.

     See also
     ........

     See Previous collection is no longer mutated upon replacement.

     References: #3913(31)

   * `[orm] [bug]' ¶. The state of the Session is
     now present when the SessionEvents.after_rollback()
     event is emitted, that is, the attribute state of objects prior to
     their being expired.  This is now consistent with the behavior of
     the SessionEvents.after_commit() event which also emits
     before the attribute state of objects is expired.

     See also
     ........

     See The after_rollback() Session event now emits before the expiration of objects.

     References: #3934(32)

   * `[orm] [bug]' ¶. Fixed bug where
     Query.with_parent() would not work if the Query
     were against an aliased() construct rather than a
     regular mapped class.  Also adds a new parameter
     ‘with_parent.from_entity’ to the standalone ‘with_parent()’
     function as well as Query.with_parent().

     References: #3607(33)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3933

   (2) http://www.sqlalchemy.org/trac/ticket/3058

   (3) http://www.sqlalchemy.org/trac/ticket/3948

   (4) http://www.sqlalchemy.org/trac/ticket/3944

   (5) http://www.sqlalchemy.org/trac/ticket/3954

   (6) http://www.sqlalchemy.org/trac/ticket/3229

   (7) http://www.sqlalchemy.org/trac/ticket/3896

   (8) http://www.sqlalchemy.org/trac/ticket/3303

   (9) http://www.sqlalchemy.org/trac/ticket/2699

   (10) http://www.sqlalchemy.org/trac/ticket/3106

   (11) http://www.sqlalchemy.org/trac/ticket/3893

   (12) http://www.sqlalchemy.org/trac/ticket/4011

   (13) http://www.sqlalchemy.org/trac/ticket/3986

   (14) http://www.sqlalchemy.org/trac/ticket/3915

   (15) http://www.sqlalchemy.org/trac/ticket/3947

   (16) http://www.sqlalchemy.org/trac/ticket/3496

   (17) http://www.sqlalchemy.org/trac/ticket/3471

   (18) http://www.sqlalchemy.org/trac/ticket/3472

   (19) http://www.sqlalchemy.org/trac/ticket/3996

   (20) http://www.sqlalchemy.org/trac/ticket/3673

   (21) http://www.sqlalchemy.org/trac/ticket/3796

   (22) http://www.sqlalchemy.org/trac/ticket/3988

   (23) http://www.sqlalchemy.org/trac/ticket/3991

   (24) http://www.sqlalchemy.org/trac/ticket/3984

   (25) http://www.sqlalchemy.org/trac/ticket/3967

   (26) http://www.sqlalchemy.org/trac/ticket/3963

   (27) http://www.sqlalchemy.org/trac/ticket/3753

   (28) http://www.sqlalchemy.org/trac/ticket/3366

   (29) http://www.sqlalchemy.org/trac/ticket/3896

   (30) http://www.sqlalchemy.org/trac/ticket/3891

   (31) http://www.sqlalchemy.org/trac/ticket/3913

   (32) http://www.sqlalchemy.org/trac/ticket/3934

   (33) http://www.sqlalchemy.org/trac/ticket/3607

8.3.3.133 orm declarative
.........................

   * `[orm] [declarative] [bug]' ¶. Fixed bug where using
     declared_attr on an AbstractConcreteBase
     where a particular return value were some non-mapped symbol,
     including ‘None’, would cause the attribute to hard-evaluate just
     once and store the value to the object dictionary, not allowing it
     to invoke for subclasses.  This behavior is normal when
     declared_attr is on a mapped class, and does not occur on a
     mixin or abstract class.  Since AbstractConcreteBase is
     both “abstract” and actually “mapped”, a special exception case is
     made here so that the “abstract” behavior takes precedence for
     declared_attr.

     References: #3848(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3848

8.3.3.134 engine
................

   * `[engine] [feature]' ¶. Added native “pessimistic
     disconnection” handling to the Pool object.  The new
     parameter Pool.pre_ping, available from the engine as
     create_engine.pool_pre_ping, applies an efficient form
     of the “pre-ping” recipe featured in the pooling documentation,
     which upon each connection check out, emits a simple statement,
     typically “SELECT 1”, to test the connection for liveness.  If the
     existing connection is no longer able to respond to commands, the
     connection is transparently recycled, and all other connections
     made prior to the current timestamp are invalidated.

     See also
     ........

     See Disconnect Handling - Pessimistic.

     See Pessimistic disconnection detection added to the connection pool.

     References: #3919(1)

   * `[engine] [bug]' ¶. Added an exception handler that
     will warn for the “cause” exception on Py2K when the “autorollback”
     feature of Connection itself raises an exception.  In
     Py3K, the two exceptions are naturally reported by the interpreter
     as one occurring during the handling of the other.  This is
     continuing with the series of changes for rollback failure handling
     that were last visited as part of #2696(2) in 1.0.12.

     This change is also `backported' to: 1.1.7

     References: #3946(3)

   * `[engine] [bug]' ¶. Fixed bug where in the unusual case
     of passing a Compiled object directly to
     Connection.execute(), the dialect with which the
     Compiled object were generated was not consulted for the
     paramstyle of the string statement, instead assuming it would match
     the dialect-level paramstyle, causing mismatches to occur.

     References: #3938(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3919

   (2) http://www.sqlalchemy.org/trac/ticket/2696

   (3) http://www.sqlalchemy.org/trac/ticket/3946

   (4) http://www.sqlalchemy.org/trac/ticket/3938

8.3.3.135 sql
.............

   * `[sql] [feature]' ¶. Added a new kind of
     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.

     See also
     ........

     See Late-expanded IN parameter sets allow IN expressions with cached statements.

     References: #3953(1)

   * `[sql] [feature] [mysql] [oracle] [postgresql]' ¶.
     Added support for SQL comments on Table and
     Column objects, via the new Table.comment and
     Column.comment arguments.  The comments are included
     as part of DDL on table creation, either inline or via an
     appropriate ALTER statement, and are also reflected back within
     table reflection, as well as via the Inspector.
     Supported backends currently include MySQL, PostgreSQL, and Oracle.
     Many thanks to Frazer McLean for a large amount of effort on this.

     See also
     ........

     See Support for SQL Comments on Table, Column, includes DDL, reflection.

     References: #1546(2)

   * `[sql] [feature]' ¶. The longstanding behavior of the
     ColumnOperators.in_() and
     ColumnOperators.notin_() operators emitting a warning when
     the right-hand condition is an empty sequence has been revised; a
     simple “static” expression of “1 != 1” or “1 = 1” is now rendered
     by default, rather than pulling in the original left-hand
     expression.  This causes the result for a NULL column comparison
     against an empty set to change from NULL to true/false.  The
     behavior is configurable, and the old behavior can be enabled using
     the create_engine.empty_in_strategy parameter to
     create_engine().

     See also
     ........

     See The IN / NOT IN operator’s empty collection behavior is now configurable; default expression simplified.

     References: #3907(3)

   * `[sql] [feature]' ¶. Added a new option ‘autoescape’ to
     the “startswith” and “endswith” classes of comparators; this
     supplies an escape character also applies it to all occurrences of
     the wildcard characters “%” and “_” automatically.  Pull request
     courtesy Diana Clarke.

          Note: This feature has been changed as of 1.2.0 from its
          initial implementation in 1.2.0b2 such that autoescape is now
          passed as a boolean value, rather than a specific character to
          use as the escape character.

     See also
     ........

     See New “autoescape” option for startswith(), endswith().

     References: #2694(4)

   * `[sql] [bug]' ¶. Fixed AttributeError which would occur
     in WithinGroup construct during an iteration of the
     structure.

     This change is also `backported' to: 1.1.11

     References: #4012(5)

   * `[sql] [bug]' ¶. Fixed regression released in 1.1.5 due
     to #3859(6) where adjustments to the “right-hand-side” evaluation
     of an expression based on Variant to honor the
     underlying type’s “right-hand-side” rules caused the Variant
     type to be inappropriately lost, in those cases when we `do'
     want the left-hand side type to be transferred directly to the
     right hand side so that bind-level rules can be applied to the
     expression’s argument.

     This change is also `backported' to: 1.1.9

     References: #3952(7)

   * `[sql] [bug] [postgresql]' ¶. Changed the mechanics of
     ‘ResultProxy’ to unconditionally delay the “autoclose” step until
     the Connection is done with the object; in the case
     where PostgreSQL ON CONFLICT with RETURNING returns no rows,
     autoclose was occurring in this previously non-existent use case,
     causing the usual autocommit behavior that occurs unconditionally
     upon INSERT/UPDATE/DELETE to fail.

     This change is also `backported' to: 1.1.9

     References: #3955(8)

   * `[sql] [bug]' ¶. The rules for type coercion between
     Numeric, Integer, and date-related types now
     include additional logic that will attempt to preserve the settings
     of the incoming type on the “resolved” type.  Currently the target
     for this is the ‘asdecimal’ flag, so that a math operation between
     Numeric or Float and Integer
     will preserve the “asdecimal” flag as well as if the type should be
     the Float subclass.

     See also
     ........

     See Stronger typing added to “float” datatypes.

     References: #4018(9)

   * `[sql] [bug] [mysql]' ¶. The result processor for the
     Float type now unconditionally runs values through the
     ‘float()’ processor if the dialect specifies that it also supports
     “native decimal” mode.  While most backends will deliver Python
     ‘float’ objects for a floating point datatype, the MySQL backends
     in some cases lack the typing information in order to provide this
     and return ‘Decimal’ unless the float conversion is done.

     See also
     ........

     See Stronger typing added to “float” datatypes.

     References: #4020(10)

   * `[sql] [bug]' ¶. Added some extra strictness to the
     handling of Python “float” values passed to SQL statements.  A
     “float” value will be associated with the Float
     datatype and not the Decimal-coercing Numeric datatype
     as was the case before, eliminating a confusing warning emitted on
     SQLite as well as unnecessary coercion to Decimal.

     See also
     ........

     See Stronger typing added to “float” datatypes.

     References: #4017(11)

   * `[sql] [bug]' ¶. The operator precedence for all
     comparison operators such as LIKE, IS, IN, MATCH, equals, greater
     than, less than, etc.  has all been merged into one level, so that
     expressions which make use of these against each other will produce
     parentheses between them.  This suits the stated operator
     precedence of databases like Oracle, MySQL and others which place
     all of these operators as equal precedence, as well as PostgreSQL
     as of 9.5 which has also flattened its operator precedence.

     See also
     ........

     See Flattened operator precedence for comparison operators.

     References: #3999(12)

   * `[sql] [bug]' ¶. Repaired issue where the type of an
     expression that used ColumnOperators.is_() or similar
     would not be a “boolean” type, instead the type would be
     “nulltype”, as well as when using custom comparison operators
     against an untyped expression.  This typing can impact how the
     expression behaves in larger contexts as well as in
     result-row-handling.

     References: #3873(13)

   * `[sql] [bug]' ¶. Fixed the negation of a Label
     construct so that the inner element is negated correctly, when
     the not_() modifier is applied to the labeled
     expression.

     References: #3969(14)

   * `[sql] [bug]' ¶. The system by which percent signs in
     SQL statements are “doubled” for escaping purposes has been
     refined.  The “doubling” of percent signs mostly associated with
     the literal_column construct as well as operators like
     ColumnOperators.contains() now occurs based on the
     stated paramstyle of the DBAPI in use; for percent-sensitive
     paramstyles as are common with the PostgreSQL and MySQL drivers the
     doubling will occur, for others like that of SQLite it will not.
     This allows more database-agnostic use of the literal_column
     construct to be possible.

     See also
     ........

     See Percent signs in literal_column() now conditionally escaped.

     References: #3740(15)

   * `[sql] [bug]' ¶. Fixed bug where a column-level
     CheckConstraint would fail to compile the SQL expression
     using the underlying dialect compiler as well as apply proper flags
     to generate literal values as inline, in the case that the sqltext
     is a Core expression and not just a plain string.  This was
     long-ago fixed for table-level check constraints in 0.9 as part of
     #2742(16), which more commonly feature Core SQL expressions as
     opposed to plain string expressions.

     References: #3957(17)

   * `[sql] [bug]' ¶. Fixed bug where a SQL-oriented
     Python-side column default could fail to be executed properly upon
     INSERT in the “pre-execute” codepath, if the SQL itself were an
     untyped expression, such as plain text.  The “pre- execute”
     codepath is fairly uncommon however can apply to non-integer
     primary key columns with SQL defaults when RETURNING is not used.

     References: #3923(18)

   * `[sql] [bug]' ¶. The expression used for COLLATE as
     rendered by the column-level collate() and
     ColumnOperators.collate() is now quoted as an identifier when
     the name is case sensitive, e.g.  has uppercase characters.  Note
     that this does not impact type-level collation, which is already
     quoted.

     See also
     ........

     See The column-level COLLATE keyword now quotes the collation name.

     References: #3785(19)

   * `[sql] [bug]' ¶. Fixed bug where the use of an
     Alias object in a column context would raise an argument
     error when it tried to group itself into a parenthesized
     expression.  Using Alias in this way is not yet a fully
     supported API, however it applies to some end-user recipes and may
     have a more prominent role in support of some future PostgreSQL
     features.

     References: #3939(20)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3953

   (2) http://www.sqlalchemy.org/trac/ticket/1546

   (3) http://www.sqlalchemy.org/trac/ticket/3907

   (4) http://www.sqlalchemy.org/trac/ticket/2694

   (5) http://www.sqlalchemy.org/trac/ticket/4012

   (6) http://www.sqlalchemy.org/trac/ticket/3859

   (7) http://www.sqlalchemy.org/trac/ticket/3952

   (8) http://www.sqlalchemy.org/trac/ticket/3955

   (9) http://www.sqlalchemy.org/trac/ticket/4018

   (10) http://www.sqlalchemy.org/trac/ticket/4020

   (11) http://www.sqlalchemy.org/trac/ticket/4017

   (12) http://www.sqlalchemy.org/trac/ticket/3999

   (13) http://www.sqlalchemy.org/trac/ticket/3873

   (14) http://www.sqlalchemy.org/trac/ticket/3969

   (15) http://www.sqlalchemy.org/trac/ticket/3740

   (16) http://www.sqlalchemy.org/trac/ticket/2742

   (17) http://www.sqlalchemy.org/trac/ticket/3957

   (18) http://www.sqlalchemy.org/trac/ticket/3923

   (19) http://www.sqlalchemy.org/trac/ticket/3785

   (20) http://www.sqlalchemy.org/trac/ticket/3939

8.3.3.136 schema
................

   * `[schema] [bug]' ¶. An ArgumentError is now
     raised if a ForeignKeyConstraint object is created with
     a mismatched number of “local” and “remote” columns, which
     otherwise causes the internal state of the constraint to be
     incorrect.  Note that this also impacts the condition where a
     dialect’s reflection process produces a mismatched set of columns
     for a foreign key constraint.

     This change is also `backported' to: 1.1.10

     References: #3949(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3949

8.3.3.137 postgresql
....................

   * `[postgresql] [bug]' ¶. Continuing with the fix that
     correctly handles PostgreSQL version string “10devel” released in
     1.1.8, an additional regexp bump to handle version strings of the
     form “10beta1”.  While PostgreSQL now offers better ways to get
     this information, we are sticking w/ the regexp at least through
     1.1.x for the least amount of risk to compatibility w/ older or
     alternate PostgreSQL databases.

     This change is also `backported' to: 1.1.11

     References: #4005(1)

   * `[postgresql] [bug]' ¶. Fixed bug where using
     ARRAY with a string type that features a collation would fail
     to produce the correct syntax within CREATE TABLE.

     This change is also `backported' to: 1.1.11

     References: #4006(2)

   * `[postgresql] [bug]' ¶. Added “autocommit” support for
     GRANT, REVOKE keywords.  Pull request courtesy Jacob Hayes.

     This change is also `backported' to: 1.1.10

   * `[postgresql] [bug]' ¶. Added support for parsing the
     PostgreSQL version string for a development version like
     “PostgreSQL 10devel”.  Pull request courtesy Sean McCully.

     This change is also `backported' to: 1.1.8

   * `[postgresql] [bug]' ¶. Fixed bug where the base
     ARRAY datatype would not invoke the bind/result processors of
     ARRAY.

     References: #3964(3)

   * `[postgresql] [bug]' ¶. Added support for all possible
     “fields” identifiers when reflecting the PostgreSQL ‘INTERVAL’
     datatype, e.g.  “YEAR”, “MONTH”, “DAY TO MINUTE”, etc..  In
     addition, the INTERVAL datatype itself now includes a
     new parameter INTERVAL.fields where these qualifiers
     can be specified; the qualifier is also reflected back into the
     resulting datatype upon reflection / inspection.

     See also
     ........

     See Support for fields specification in INTERVAL, including full reflection.

     References: #3959(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4005

   (2) http://www.sqlalchemy.org/trac/ticket/4006

   (3) http://www.sqlalchemy.org/trac/ticket/3964

   (4) http://www.sqlalchemy.org/trac/ticket/3959

8.3.3.138 mysql
...............

   * `[mysql] [feature]' ¶. Added support for MySQL’s ON
     DUPLICATE KEY UPDATE MySQL-specific ‘Insert’ object.  Pull request
     courtesy Michael Doronin.

     See also
     ........

     See Support for INSERT..ON DUPLICATE KEY UPDATE.

     References: #4009(1)

   * `[mysql] [bug]' ¶. MySQL 5.7 has introduced permission
     limiting for the “SHOW VARIABLES” command; the MySQL dialect will
     now handle when SHOW returns no row, in particular for the initial
     fetch of SQL_MODE, and will emit a warning that user permissions
     should be modified to allow the row to be present.

     This change is also `backported' to: 1.1.11

     References: #4007(2)

   * `[mysql] [bug]' ¶. Removed an ancient and unnecessary
     intercept of the UTC_TIMESTAMP MySQL function, which was getting in
     the way of using it with a parameter.

     This change is also `backported' to: 1.1.10

     References: #3966(3)

   * `[mysql] [bug]' ¶. Fixed bug in MySQL dialect regarding
     rendering of table options in conjunction with PARTITION options
     when rendering CREATE TABLE. The PARTITION related options need to
     follow the table options, whereas previously this ordering was not
     enforced.

     This change is also `backported' to: 1.1.10

     References: #3961(4)

   * `[mysql] [bug]' ¶. Added support for views that are
     unreflectable due to stale table definitions, when calling
     MetaData.reflect(); a warning is emitted for the table that
     cannot respond to ‘DESCRIBE’, but the operation succeeds.

     References: #3871(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4009

   (2) http://www.sqlalchemy.org/trac/ticket/4007

   (3) http://www.sqlalchemy.org/trac/ticket/3966

   (4) http://www.sqlalchemy.org/trac/ticket/3961

   (5) http://www.sqlalchemy.org/trac/ticket/3871

8.3.3.139 mssql
...............

   * `[mssql] [bug]' ¶. Fixed bug where SQL Server
     transaction isolation must be fetched from a different view when
     using Azure data warehouse, the query is now attempted against both
     views and then a NotImplemented is raised unconditionally if
     failure continues to provide the best resiliency against future
     arbitrary API changes in new SQL Server versions.

     This change is also `backported' to: 1.1.11

     References: #3994(1)

   * `[mssql] [bug]' ¶. Added a placeholder type XML
     to the SQL Server dialect, so that a reflected table which
     includes this type can be re-rendered as a CREATE TABLE. The type
     has no special round-trip behavior nor does it currently support
     additional qualifying arguments.

     This change is also `backported' to: 1.1.11

     References: #3973(2)

   * `[mssql] [bug]' ¶. The SQL Server dialect now allows
     for a database and/or owner name with a dot inside of it, using
     brackets explicitly in the string around the owner and optionally
     the database name as well.  In addition, sending the
     quoted_name construct for the schema name will not split on
     the dot and will deliver the full string as the “owner”.
     quoted_name is also now available from the ‘sqlalchemy.sql’
     import space.

     See also
     ........

     See SQL Server schema names with embedded dots supported.

     References: #2626(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3994

   (2) http://www.sqlalchemy.org/trac/ticket/3973

   (3) http://www.sqlalchemy.org/trac/ticket/2626

8.3.3.140 oracle
................

   * `[oracle] [feature] [postgresql]' ¶. Added new keywords
     Sequence.cache and Sequence.order to
     Sequence, to allow rendering of the CACHE parameter
     understood by Oracle and PostgreSQL, and the ORDER parameter
     understood by Oracle.  Pull request courtesy David Moore.

     This change is also `backported' to: 1.1.12

   * `[oracle] [feature]' ¶. The Oracle dialect now inspects
     unique and check constraints when using
     Inspector.get_unique_constraints(),
     Inspector.get_check_constraints().  As Oracle does not have
     unique constraints that are separate from a unique Index,
     a Table that’s reflected will still continue to not
     have UniqueConstraint objects associated with it.
     Pull requests courtesy Eloy Felix.

     See also
     ........

     See Oracle Unique, Check constraints now reflected.

     References: #4003(1)

   * `[oracle] [bug]' ¶. Support for two-phase transactions
     has been removed entirely for cx_Oracle when version 6.0b1 or later
     of the DBAPI is in use.  The two- phase feature historically has
     never been usable under cx_Oracle 5.x in any case, and cx_Oracle
     6.x has removed the connection-level “twophase” flag upon which
     this feature relied.

     This change is also `backported' to: 1.1.11

     References: #3997(2)

   * `[oracle] [bug]' ¶. Fixed bug in cx_Oracle dialect
     where version string parsing would fail for cx_Oracle version 6.0b1
     due to the “b” character.  Version string parsing is now via a
     regexp rather than a simple split.

     This change is also `backported' to: 1.1.10

     References: #3975(3)

   * `[oracle] [bug]' ¶. The cx_Oracle dialect now supports
     “sane multi rowcount”, that is, when a series of parameter sets are
     executed via DBAPI ‘cursor.executemany()’, we can make use of
     ‘cursor.rowcount’ to verify the number of rows matched.  This has
     an impact within the ORM when detecting concurrent modification
     scenarios, in that some simple conditions can now be detected even
     when the ORM is batching statements, as well as when the more
     strict versioning feature is used, the ORM can still use statement
     batching.  The flag is enabled for cx_Oracle assuming at least
     version 5.0, which is now commonplace.

     References: #3932(4)

   * `[oracle] [bug]' ¶. Oracle reflection now “normalizes”
     the name given to a foreign key constraint, that is, returns it as
     all lower case for a case insensitive name.  This was already the
     behavior for indexes and primary key constraints as well as all
     table and column names.  This will allow Alembic autogenerate
     scripts to compare and render foreign key constraint names
     correctly when initially specified as case insensitive.

     See also
     ........

     See Oracle foreign key constraint names are now “name normalized”.

     References: #3276(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4003

   (2) http://www.sqlalchemy.org/trac/ticket/3997

   (3) http://www.sqlalchemy.org/trac/ticket/3975

   (4) http://www.sqlalchemy.org/trac/ticket/3932

   (5) http://www.sqlalchemy.org/trac/ticket/3276

8.3.3.141 misc
..............

   * `[feature] [ext]' ¶. Added new flag
     Session.enable_baked_queries to the Session to
     allow baked queries to be disabled session-wide, reducing memory
     use.  Also added new Bakery wrapper so that the bakery
     returned by BakedQuery.bakery can be inspected.

   * `[bug] [ext]' ¶. Protected against testing “None” as a
     class in the case where declarative classes are being garbage
     collected and new automap prepare() operations are taking place
     concurrently, very infrequently hitting a weakref that has not been
     fully acted upon after gc.

     This change is also `backported' to: 1.1.10

     References: #3980(1)

   * `[bug] [ext]' ¶. Fixed bug in
     sqlalchemy.ext.mutable where the Mutable.as_mutable()
     method would not track a type that had been copied using
     ‘TypeEngine.copy()’.  This became more of a regression in 1.1
     compared to 1.0 because the TypeDecorator class is now
     a subclass of SchemaEventTarget, which among other
     things indicates to the parent Column that the type
     should be copied when the Column is.  These copies are
     common when using declarative with mixins or abstract classes.

     This change is also `backported' to: 1.1.8

     References: #3950(2)

   * `[bug] [ext]' ¶. Added support for bound parameters,
     e.g.  those normally set up via Query.params(), to the
     Result.count() method.  Previously, support for
     parameters were omitted.  Pull request courtesy Pat Deegan.

     This change is also `backported' to: 1.1.8

   * `[bug] [ext]' ¶. The ‘AssociationProxy.any()’,
     ‘AssociationProxy.has()’ and ‘AssociationProxy.contains()’
     comparison methods now support linkage to an attribute that is
     itself also an AssociationProxy, recursively.

     See also
     ........

     See AssociationProxy any(), has(), contains() work with chained association proxies.

     References: #3769(3)

   * `[bug] [ext]' ¶. Implemented in-place mutation
     operators ‘__ior__’, ‘__iand__’, ‘__ixor__’ and ‘__isub__’ for
     MutableSet and ‘__iadd__’ for MutableList
     so that change events are fired off when these mutator methods are
     used to alter the collection.

     See also
     ........

     See In-place mutation operators work for MutableSet, MutableList.

     References: #3853(4)

   * `[bug] [declarative]' ¶. A warning is emitted if the
     declared_attr.cascading modifier is used with a
     declarative attribute that is itself declared on a class that is to
     be mapped, as opposed to a declarative mixin class or
     ‘__abstract__’ class.  The declared_attr.cascading
     modifier currently only applies to mixin/abstract classes.

     References: #3847(5)

   * `[bug] [ext]' ¶. Improved the association proxy list
     collection so that premature autoflush against a newly created
     association object can be prevented in the case where
     ‘list.append()’ is being used, and a lazy load would be invoked
     when the association proxy accesses the endpoint collection.  The
     endpoint collection is now accessed first before the creator is
     invoked to produce the association object.

     References: #3941(6)

   * `[bug] [ext]' ¶. The
     sqlalchemy.ext.hybrid.hybrid_property class now supports
     calling mutators like ‘@setter’, ‘@expression’ etc.  multiple times
     across subclasses, and now provides a ‘@getter’ mutator, so that a
     particular hybrid can be repurposed across subclasses or other
     classes.  This now matches the behavior of ‘@property’ in standard
     Python.

     See also
     ........

     See Hybrid attributes support reuse among subclasses, redefinition of @getter.

     References: #3911(7), #3912(8)

   * `[bug] [ext]' ¶. Fixed a bug in the
     ‘sqlalchemy.ext.serializer’ extension whereby an “annotated” SQL
     element (as produced by the ORM for many types of SQL expressions)
     could not be reliably serialized.  Also bumped the default pickle
     level for the serializer to “HIGHEST_PROTOCOL”.

     References: #3918(9)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3980

   (2) http://www.sqlalchemy.org/trac/ticket/3950

   (3) http://www.sqlalchemy.org/trac/ticket/3769

   (4) http://www.sqlalchemy.org/trac/ticket/3853

   (5) http://www.sqlalchemy.org/trac/ticket/3847

   (6) http://www.sqlalchemy.org/trac/ticket/3941

   (7) http://www.sqlalchemy.org/trac/ticket/3911

   (8) http://www.sqlalchemy.org/trac/ticket/3912

   (9) http://www.sqlalchemy.org/trac/ticket/3918

8.3.4.1 1.1.18
..............

Released: March 6, 2018

8.3.4.2 postgresql
..................

   * `[postgresql] [bug] [py3k]' ¶. Fixed bug in PostgreSQL
     COLLATE / ARRAY adjustment first introduced in #4006(1) where new
     behaviors in Python 3.7 regular expressions caused the fix to fail.

     References: #4208(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4006

   (2) http://www.sqlalchemy.org/trac/ticket/4208

8.3.4.3 mysql
.............

   * `[mysql] [bug]' ¶. MySQL dialects now query the server
     version using ‘SELECT @@version’ explicitly to the server to ensure
     we are getting the correct version information back.  Proxy servers
     like MaxScale interfere with the value that is passed to the
     DBAPI’s connection.server_version value so this is no longer
     reliable.

     References: #4205(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4205

8.3.4.4 1.1.17
..............

Released: February 22, 2018

   * `[bug] [ext]' ¶. Repaired regression caused in 1.2.3
     and 1.1.16 regarding association proxy objects, revising the
     approach to #4185(1) when calculating the “owning class” of an
     association proxy to default to choosing the current class if the
     proxy object is not directly associated with a mapped class, such
     as a mixin.

     References: #4185(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4185

   (2) http://www.sqlalchemy.org/trac/ticket/4185

8.3.4.5 1.1.16
..............

Released: February 16, 2018

8.3.4.6 orm
...........

   * `[orm] [bug]' ¶. Fixed issue in post_update feature
     where an UPDATE is emitted when the parent object has been deleted
     but the dependent object is not.  This issue has existed for a long
     time however since 1.2 now asserts rows matched for post_update,
     this was raising an error.

     References: #4187(1)

   * `[orm] [bug]' ¶. Fixed regression caused by fix for
     issue #4116(2) affecting versions 1.2.2 as well as 1.1.15, which
     had the effect of mis-calculation of the “owning class” of an
     AssociationProxy as the ‘NoneType’ class in some declarative
     mixin/inheritance situations as well as if the association proxy
     were accessed off of an un-mapped class.  The “figure out the
     owner” logic has been replaced by an in-depth routine that searches
     through the complete mapper hierarchy assigned to the class or
     subclass to determine the correct (we hope) match; will not assign
     the owner if no match is found.  An exception is now raised if the
     proxy is used against an un-mapped instance.

     References: #4185(3)

   * `[orm] [bug]' ¶. Fixed bug where an object that is
     expunged during a rollback of a nested or subtransaction which also
     had its primary key mutated would not be correctly removed from the
     session, causing subsequent issues in using the session.

     References: #4151(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4187

   (2) http://www.sqlalchemy.org/trac/ticket/4116

   (3) http://www.sqlalchemy.org/trac/ticket/4185

   (4) http://www.sqlalchemy.org/trac/ticket/4151

8.3.4.7 sql
...........

   * `[sql] [bug]' ¶. Added ‘nullsfirst()’ and ‘nullslast()’
     as top level imports in the ‘sqlalchemy.’ and ‘sqlalchemy.sql.’
     namespace.  Pull request courtesy Lele Gaifax.

   * `[sql] [bug]' ¶. Fixed bug in Insert.values()
     where using the “multi-values” format in combination with
     Column objects as keys rather than strings would fail.  Pull
     request courtesy Aubrey Stark-Toller.

     References: #4162(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4162

8.3.4.8 postgresql
..................

   * `[postgresql] [bug]' ¶. Added “SSL SYSCALL error:
     Operation timed out” to the list of messages that trigger a
     “disconnect” scenario for the psycopg2 driver.  Pull request
     courtesy André Cruz.

   * `[postgresql] [bug]' ¶. Added “TRUNCATE” to the list of
     keywords accepted by the PostgreSQL dialect as an
     “autocommit”-triggering keyword.  Pull request courtesy Jacob
     Hayes.

8.3.4.9 mysql
.............

   * `[mysql] [bug]' ¶. Fixed bug where the MySQL “concat”
     and “match” operators failed to propagate kwargs to the left and
     right expressions, causing compiler options such as “literal_binds”
     to fail.

     References: #4136(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4136

8.3.4.10 misc
.............

   * `[bug] [pool]' ¶. Fixed a fairly serious connection
     pool bug where a connection that is acquired after being refreshed
     as a result of a user-defined DisconnectionError or
     due to the 1.2-released “pre_ping” feature would not be correctly
     reset if the connection were returned to the pool by weakref
     cleanup (e.g.  the front-facing object is garbage collected); the
     weakref would still refer to the previously invalidated DBAPI
     connection which would have the reset operation erroneously called
     upon it instead.  This would lead to stack traces in the logs and a
     connection being checked into the pool without being reset, which
     can cause locking issues.

     References: #4184(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4184

8.3.4.11 1.1.15
...............

Released: November 3, 2017

8.3.4.12 orm
............

   * `[orm] [bug] [ext]' ¶. Fixed bug where the association
     proxy would inadvertently link itself to an AliasedClass
     object if it were called first with the AliasedClass
     as a parent, causing errors upon subsequent usage.

     References: #4116(1)

   * `[orm] [bug]' ¶. Fixed bug where ORM relationship would
     warn against conflicting sync targets (e.g.  two relationships
     would both write to the same column) for sibling classes in an
     inheritance hierarchy, where the two relationships would never
     actually conflict during writes.

     References: #4078(2)

   * `[orm] [bug]' ¶. Fixed bug where correlated select used
     against single-table inheritance entity would fail to render
     correctly in the outer query, due to adjustment for single
     inheritance discriminator criteria inappropriately re-applying the
     criteria to the outer query.

     References: #4103(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4116

   (2) http://www.sqlalchemy.org/trac/ticket/4078

   (3) http://www.sqlalchemy.org/trac/ticket/4103

8.3.4.13 orm declarative
........................

   * `[orm] [declarative] [bug]' ¶. Fixed bug where a
     descriptor that is elsewhere a mapped column or relationship within
     a hierarchy based on AbstractConcreteBase would be
     referred towards during a refresh operation, causing an error as
     the attribute is not mapped as a mapper property.  A similar issue
     can arise for other attributes like the “type” column added by
     AbstractConcreteBase if the class fails to include
     “concrete=True” in its mapper, however the check here should also
     prevent that scenario from causing a problem.

     References: #4124(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4124

8.3.4.14 sql
............

   * `[sql] [bug]' ¶. Fixed bug where ‘__repr__’ of
     ColumnDefault would fail if the argument were a tuple.  Pull
     request courtesy Nicolas Caniart.

     References: #4126(1)

   * `[sql] [bug]' ¶. Fixed bug where the recently added
     ColumnOperators.any_() and
     ColumnOperators.all_() methods didn’t work when called as
     methods, as opposed to using the standalone functions any_()
     and all_().  Also added documentation examples for
     these relatively unintuitive SQL operators.

     References: #4093(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4126

   (2) http://www.sqlalchemy.org/trac/ticket/4093

8.3.4.15 postgresql
...................

   * `[postgresql] [bug]' ¶. Made further fixes to the
     ARRAY class in conjunction with COLLATE, as the fix made in
     #4006(1) failed to accommodate for a multidimensional array.

     References: #4006(2)

   * `[postgresql] [bug]' ¶. Fixed bug in array_agg
     function where passing an argument that is already of type
     ARRAY, such as a PostgreSQL array
     construct, would produce a ‘ValueError’, due to the function
     attempting to nest the arrays.

     References: #4107(3)

   * `[postgresql] [bug]' ¶. Fixed bug in PostgreSQL
     ‘Insert.on_conflict_do_update()’ which would prevent the insert
     statement from being used as a CTE, e.g.  via ‘Insert.cte()’,
     within another statement.

     References: #4074(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4006

   (2) http://www.sqlalchemy.org/trac/ticket/4006

   (3) http://www.sqlalchemy.org/trac/ticket/4107

   (4) http://www.sqlalchemy.org/trac/ticket/4074

8.3.4.16 mysql
..............

   * `[mysql] [bug]' ¶. Warning emitted when MariaDB 10.2.8
     or earlier in the 10.2 series is detected as there are major issues
     with CHECK constraints within these versions that were resolved as
     of 10.2.9.

     Note that this changelog message was NOT released with SQLAlchemy
     1.2.0b3 and was added retroactively.

     References: #4097(1)

   * `[mysql] [bug]' ¶. MySQL 5.7.20 now warns for use of
     the @tx_isolation variable; a version check is now performed and
     uses @transaction_isolation instead to prevent this warning.

     References: #4120(2)

   * `[mysql] [bug]' ¶. Fixed issue where CURRENT_TIMESTAMP
     would not reflect correctly in the MariaDB 10.2 series due to a
     syntax change, where the function is now represented as
     ‘current_timestamp()’.

     References: #4096(3)

   * `[mysql] [bug]' ¶. MariaDB 10.2 now supports CHECK
     constraints (warning: use version 10.2.9 or greater due to upstream
     issues noted in #4097(4)).  Reflection now takes these CHECK
     constraints into account when they are present in the ‘SHOW CREATE
     TABLE’ output.

     References: #4098(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4097

   (2) http://www.sqlalchemy.org/trac/ticket/4120

   (3) http://www.sqlalchemy.org/trac/ticket/4096

   (4) http://www.sqlalchemy.org/trac/ticket/4097

   (5) http://www.sqlalchemy.org/trac/ticket/4098

8.3.4.17 sqlite
...............

   * `[sqlite] [bug]' ¶. Fixed bug where SQLite CHECK
     constraint reflection would fail if the referenced table were in a
     remote schema, e.g.  on SQLite a remote database referred to by
     ATTACH.

     References: #4099(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4099

8.3.4.18 mssql
..............

   * `[mssql] [bug]' ¶. Added a full range of “connection
     closed” exception codes to the PyODBC dialect for SQL Server,
     including ‘08S01’, ‘01002’, ‘08003’, ‘08007’, ‘08S02’, ‘08001’,
     ‘HYT00’, ‘HY010’.  Previously, only ‘08S01’ was covered.

     References: #4095(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4095

8.3.4.19 1.1.14
...............

Released: September 5, 2017

8.3.4.20 orm
............

   * `[orm] [bug]' ¶. Fixed bug in Session.merge()
     following along similar lines as that of #4030(1), where an
     internal check for a target object in the identity map could lead
     to an error if it were to be garbage collected immediately before
     the merge routine actually retrieves the object.

     References: #4069(2)

   * `[orm] [bug]' ¶. Fixed bug where an
     undefer_group() option would not be recognized if it extended
     from a relationship that was loading using joined eager loading.
     Additionally, as the bug led to excess work being performed, Python
     function call counts are also improved by 20% within the initial
     calculation of result set columns, complementing the joined eager
     load improvements of #3915(3).

     References: #4048(4)

   * `[orm] [bug]' ¶. Fixed race condition in ORM identity
     map which would cause objects to be inappropriately removed during
     a load operation, causing duplicate object identities to occur,
     particularly under joined eager loading which involves
     deduplication of objects.  The issue is specific to garbage
     collection of weak references and is observed only under the PyPy
     interpreter.

     References: #4068(5)

   * `[orm] [bug]' ¶. Fixed bug in Session.merge()
     where objects in a collection that had the primary key
     attribute set to ‘None’ for a key that is typically
     autoincrementing would be considered to be a database-persisted key
     for part of the internal deduplication process, causing only one
     object to actually be inserted in the database.

     References: #4056(6)

   * `[orm] [bug]' ¶. An InvalidRequestError is
     raised when a synonym() is used against an attribute
     that is not against a MapperProperty, such as an
     association proxy.  Previously, a recursion overflow would occur
     trying to locate non-existent attributes.

     References: #4067(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4030

   (2) http://www.sqlalchemy.org/trac/ticket/4069

   (3) http://www.sqlalchemy.org/trac/ticket/3915

   (4) http://www.sqlalchemy.org/trac/ticket/4048

   (5) http://www.sqlalchemy.org/trac/ticket/4068

   (6) http://www.sqlalchemy.org/trac/ticket/4056

   (7) http://www.sqlalchemy.org/trac/ticket/4067

8.3.4.21 sql
............

   * `[sql] [bug]' ¶. Altered the range specification for
     window functions to allow for two of the same PRECEDING or
     FOLLOWING keywords in a range by allowing for the left side of the
     range to be positive and for the right to be negative, e.g.  (1, 3)
     is “1 FOLLOWING AND 3 FOLLOWING”.

     References: #4053(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4053

8.3.4.22 1.1.13
...............

Released: August 3, 2017

8.3.4.23 oracle
...............

   * `[oracle] [performance] [bug] [py2k]' ¶. Fixed
     performance regression caused by the fix for #3937(1) where
     cx_Oracle as of version 5.3 dropped the ‘.UNICODE’ symbol from its
     namespace, which was interpreted as cx_Oracle’s “WITH_UNICODE” mode
     being turned on unconditionally, which invokes functions on the
     SQLAlchemy side which convert all strings to unicode
     unconditionally and causing a performance impact.  In fact, per
     cx_Oracle’s author the “WITH_UNICODE” mode has been removed
     entirely as of 5.1, so the expensive unicode conversion functions
     are no longer necessary and are disabled if cx_Oracle 5.1 or
     greater is detected under Python 2.  The warning against
     “WITH_UNICODE” mode that was removed under #3937(2) is also
     restored.

     This change is also `backported' to: 1.0.19

     References: #4035(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3937

   (2) http://www.sqlalchemy.org/trac/ticket/3937

   (3) http://www.sqlalchemy.org/trac/ticket/4035

8.3.4.24 1.1.12
...............

Released: July 24, 2017

8.3.4.25 orm
............

   * `[orm] [bug]' ¶. Fixed regression from 1.1.11 where
     adding additional non-entity columns to a query that includes an
     entity with subqueryload relationships would fail, due to an
     inspection added in 1.1.11 as a result of #4011(1).

     References: #4033(2)

   * `[orm] [bug]' ¶. Fixed bug involving JSON NULL
     evaluation logic added in 1.1 as part of #3514(3) where the logic
     would not accommodate ORM mapped attributes named differently from
     the Column that was mapped.

     References: #4031(4)

   * `[orm] [bug]' ¶. Added ‘KeyError’ checks to all methods
     within ‘WeakInstanceDict’ where a check for ‘key in dict’ is
     followed by indexed access to that key, to guard against a race
     against garbage collection that under load can remove the key from
     the dict after the code assumes its present, leading to very
     infrequent ‘KeyError’ raises.

     References: #4030(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4011

   (2) http://www.sqlalchemy.org/trac/ticket/4033

   (3) http://www.sqlalchemy.org/trac/ticket/3514

   (4) http://www.sqlalchemy.org/trac/ticket/4031

   (5) http://www.sqlalchemy.org/trac/ticket/4030

8.3.4.26 oracle
...............

   * `[oracle] [feature] [postgresql]' ¶. Added new keywords
     Sequence.cache and Sequence.order to
     Sequence, to allow rendering of the CACHE parameter
     understood by Oracle and PostgreSQL, and the ORDER parameter
     understood by Oracle.  Pull request courtesy David Moore.

8.3.4.27 misc
.............

   * `[bug] [py3k] [tests]' ¶. Fixed issue in testing
     fixtures which was incompatible with a change made as of Python
     3.6.2 involving context managers.

     This change is also `backported' to: 1.0.18

     References: #4034(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4034

8.3.4.28 1.1.11
...............

Released: Monday, June 19, 2017

8.3.4.29 orm
............

   * `[orm] [bug]' ¶. Fixed issue with subquery eagerloading
     which continues on from the series of issues fixed in #2699(1),
     #3106(2), #3893(3) involving that the “subquery” contains the
     correct FROM clause when beginning from a joined inheritance
     subclass and then subquery eager loading onto a relationship from
     the base class, while the query also includes criteria against the
     subclass.  The fix in the previous tickets did not accommodate for
     additional subqueryload operations loading more deeply from the
     first level, so the fix has been further generalized.

     References: #4011(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2699

   (2) http://www.sqlalchemy.org/trac/ticket/3106

   (3) http://www.sqlalchemy.org/trac/ticket/3893

   (4) http://www.sqlalchemy.org/trac/ticket/4011

8.3.4.30 sql
............

   * `[sql] [bug]' ¶. Fixed AttributeError which would occur
     in WithinGroup construct during an iteration of the
     structure.

     References: #4012(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4012

8.3.4.31 postgresql
...................

   * `[postgresql] [bug]' ¶. Continuing with the fix that
     correctly handles PostgreSQL version string “10devel” released in
     1.1.8, an additional regexp bump to handle version strings of the
     form “10beta1”.  While PostgreSQL now offers better ways to get
     this information, we are sticking w/ the regexp at least through
     1.1.x for the least amount of risk to compatibility w/ older or
     alternate PostgreSQL databases.

     References: #4005(1)

   * `[postgresql] [bug]' ¶. Fixed bug where using
     ARRAY with a string type that features a collation would fail
     to produce the correct syntax within CREATE TABLE.

     References: #4006(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4005

   (2) http://www.sqlalchemy.org/trac/ticket/4006

8.3.4.32 mysql
..............

   * `[mysql] [bug]' ¶. MySQL 5.7 has introduced permission
     limiting for the “SHOW VARIABLES” command; the MySQL dialect will
     now handle when SHOW returns no row, in particular for the initial
     fetch of SQL_MODE, and will emit a warning that user permissions
     should be modified to allow the row to be present.

     References: #4007(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4007

8.3.4.33 mssql
..............

   * `[mssql] [bug]' ¶. Fixed bug where SQL Server
     transaction isolation must be fetched from a different view when
     using Azure data warehouse, the query is now attempted against both
     views and then a NotImplemented is raised unconditionally if
     failure continues to provide the best resiliency against future
     arbitrary API changes in new SQL Server versions.

     References: #3994(1)

   * `[mssql] [bug]' ¶. Added a placeholder type XML
     to the SQL Server dialect, so that a reflected table which
     includes this type can be re-rendered as a CREATE TABLE. The type
     has no special round-trip behavior nor does it currently support
     additional qualifying arguments.

     References: #3973(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3994

   (2) http://www.sqlalchemy.org/trac/ticket/3973

8.3.4.34 oracle
...............

   * `[oracle] [bug]' ¶. Support for two-phase transactions
     has been removed entirely for cx_Oracle when version 6.0b1 or later
     of the DBAPI is in use.  The two- phase feature historically has
     never been usable under cx_Oracle 5.x in any case, and cx_Oracle
     6.x has removed the connection-level “twophase” flag upon which
     this feature relied.

     References: #3997(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3997

8.3.4.35 1.1.10
...............

Released: Friday, May 19, 2017

8.3.4.36 orm
............

   * `[orm] [bug]' ¶. Fixed bug where a cascade such as
     “delete-orphan” (but others as well) would fail to locate an object
     linked to a relationship that itself is local to a subclass in an
     inheritance relationship, thus causing the operation to not take
     place.

     References: #3986(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3986

8.3.4.37 schema
...............

   * `[schema] [bug]' ¶. An ArgumentError is now
     raised if a ForeignKeyConstraint object is created with
     a mismatched number of “local” and “remote” columns, which
     otherwise causes the internal state of the constraint to be
     incorrect.  Note that this also impacts the condition where a
     dialect’s reflection process produces a mismatched set of columns
     for a foreign key constraint.

     References: #3949(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3949

8.3.4.38 postgresql
...................

   * `[postgresql] [bug]' ¶. Added “autocommit” support for
     GRANT, REVOKE keywords.  Pull request courtesy Jacob Hayes.

8.3.4.39 mysql
..............

   * `[mysql] [bug]' ¶. Removed an ancient and unnecessary
     intercept of the UTC_TIMESTAMP MySQL function, which was getting in
     the way of using it with a parameter.

     References: #3966(1)

   * `[mysql] [bug]' ¶. Fixed bug in MySQL dialect regarding
     rendering of table options in conjunction with PARTITION options
     when rendering CREATE TABLE. The PARTITION related options need to
     follow the table options, whereas previously this ordering was not
     enforced.

     References: #3961(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3966

   (2) http://www.sqlalchemy.org/trac/ticket/3961

8.3.4.40 oracle
...............

   * `[oracle] [bug]' ¶. Fixed bug in cx_Oracle dialect
     where version string parsing would fail for cx_Oracle version 6.0b1
     due to the “b” character.  Version string parsing is now via a
     regexp rather than a simple split.

     References: #3975(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3975

8.3.4.41 misc
.............

   * `[bug] [ext]' ¶. Protected against testing “None” as a
     class in the case where declarative classes are being garbage
     collected and new automap prepare() operations are taking place
     concurrently, very infrequently hitting a weakref that has not been
     fully acted upon after gc.

     References: #3980(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3980

8.3.4.42 1.1.9
..............

Released: April 4, 2017

8.3.4.43 sql
............

   * `[sql] [bug]' ¶. Fixed regression released in 1.1.5 due
     to #3859(1) where adjustments to the “right-hand-side” evaluation
     of an expression based on Variant to honor the
     underlying type’s “right-hand-side” rules caused the Variant
     type to be inappropriately lost, in those cases when we `do'
     want the left-hand side type to be transferred directly to the
     right hand side so that bind-level rules can be applied to the
     expression’s argument.

     References: #3952(2)

   * `[sql] [bug] [postgresql]' ¶. Changed the mechanics of
     ‘ResultProxy’ to unconditionally delay the “autoclose” step until
     the Connection is done with the object; in the case
     where PostgreSQL ON CONFLICT with RETURNING returns no rows,
     autoclose was occurring in this previously non-existent use case,
     causing the usual autocommit behavior that occurs unconditionally
     upon INSERT/UPDATE/DELETE to fail.

     References: #3955(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3859

   (2) http://www.sqlalchemy.org/trac/ticket/3952

   (3) http://www.sqlalchemy.org/trac/ticket/3955

8.3.4.44 misc
.............

   * `[bug] [ext]' ¶. Fixed regression released in 1.1.8 due
     to #3950(1) where the deeper search for information about column
     types in the case of a “schema type” or a TypeDecorator
     would produce an attribute error if the mapping also
     contained a column_property.

     References: #3956(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3950

   (2) http://www.sqlalchemy.org/trac/ticket/3956

8.3.4.45 1.1.8
..............

Released: March 31, 2017

8.3.4.46 postgresql
...................

   * `[postgresql] [bug]' ¶. Added support for parsing the
     PostgreSQL version string for a development version like
     “PostgreSQL 10devel”.  Pull request courtesy Sean McCully.

8.3.4.47 misc
.............

   * `[bug] [ext]' ¶. Fixed bug in
     sqlalchemy.ext.mutable where the Mutable.as_mutable()
     method would not track a type that had been copied using
     ‘TypeEngine.copy()’.  This became more of a regression in 1.1
     compared to 1.0 because the TypeDecorator class is now
     a subclass of SchemaEventTarget, which among other
     things indicates to the parent Column that the type
     should be copied when the Column is.  These copies are
     common when using declarative with mixins or abstract classes.

     References: #3950(1)

   * `[bug] [ext]' ¶. Added support for bound parameters,
     e.g.  those normally set up via Query.params(), to the
     Result.count() method.  Previously, support for
     parameters were omitted.  Pull request courtesy Pat Deegan.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3950

8.3.4.48 1.1.7
..............

Released: March 27, 2017

8.3.4.49 orm
............

   * `[orm] [feature]' ¶. An aliased() construct
     can now be passed to the Query.select_entity_from()
     method.  Entities will be pulled from the selectable represented by
     the aliased() construct.  This allows special options
     for aliased() such as aliased.adapt_on_names
     to be used in conjunction with
     Query.select_entity_from().

     References: #3933(1)

   * `[orm] [bug]' ¶. Fixed a race condition which could
     occur under threaded environments as a result of the caching added
     via #3915(2).  An internal collection of ‘Column’ objects could be
     regenerated on an alias object inappropriately, confusing a joined
     eager loader when it attempts to render SQL and collect results and
     resulting in an attribute error.  The collection is now generated
     up front before the alias object is cached and shared among
     threads.

     References: #3947(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3933

   (2) http://www.sqlalchemy.org/trac/ticket/3915

   (3) http://www.sqlalchemy.org/trac/ticket/3947

8.3.4.50 engine
...............

   * `[engine] [bug]' ¶. Added an exception handler that
     will warn for the “cause” exception on Py2K when the “autorollback”
     feature of Connection itself raises an exception.  In
     Py3K, the two exceptions are naturally reported by the interpreter
     as one occurring during the handling of the other.  This is
     continuing with the series of changes for rollback failure handling
     that were last visited as part of #2696(1) in 1.0.12.

     References: #3946(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2696

   (2) http://www.sqlalchemy.org/trac/ticket/3946

8.3.4.51 sql
............

   * `[sql] [bug] [postgresql]' ¶. Added support for the
     Variant and the SchemaType objects to be
     compatible with each other.  That is, a variant can be created
     against a type like Enum, and the instructions to create
     constraints and/or database-specific type objects will propagate
     correctly as per the variant’s dialect mapping.

     References: #2892(1)

   * `[sql] [bug]' ¶. Fixed bug in compiler where the string
     identifier of a savepoint would be cached in the identifier quoting
     dictionary; as these identifiers are arbitrary, a small memory leak
     could occur if a single Connection had an unbounded
     number of savepoints used, as well as if the savepoint clause
     constructs were used directly with an unbounded umber of savepoint
     names.  The memory leak does `not' impact the vast majority of
     cases as normally the Connection, which renders
     savepoint names with a simple counter starting at “1”, is used on a
     per-transaction or per-fixed-number-of-transactions basis before
     being discarded.

     References: #3931(2)

   * `[sql] [bug]' ¶. Fixed bug in new “schema translate”
     feature where the translated schema name would be invoked in terms
     of an alias name when rendered along with a column expression;
     occurred only when the source translate name was “None”.  The
     “schema translate” feature now only takes effect for
     SchemaItem and SchemaType subclasses, that is,
     objects that correspond to a DDL-creatable structure in a database.

     References: #3924(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2892

   (2) http://www.sqlalchemy.org/trac/ticket/3931

   (3) http://www.sqlalchemy.org/trac/ticket/3924

8.3.4.52 oracle
...............

   * `[oracle] [bug]' ¶. A fix to cx_Oracle’s WITH_UNICODE
     mode which was uncovered by the fact that cx_Oracle 5.3 now seems
     to hardcode this flag on in the build; an internal method that uses
     this mode wasn’t using the correct signature.

     This change is also `backported' to: 1.0.18

     References: #3937(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3937

8.3.4.53 1.1.6
..............

Released: February 28, 2017

8.3.4.54 orm
............

   * `[orm] [bug]' ¶. Addressed some long unattended
     performance concerns within the joined eager loader query
     construction system that have accumulated since earlier versions as
     a result of increased abstraction.  The use of ad- hoc
     AliasedClass objects per query, which produces lots of column
     lookup overhead each time, has been replaced with a cached approach
     that makes use of a small pool of AliasedClass objects
     that are reused between invocations of joined eager loading.  Some
     mechanics involving eager join path construction have also been
     optimized.  Callcounts for an end-to-end query construction +
     single row fetch test with a worst-case joined loader scenario have
     been reduced by about 60% vs.  1.1.5 and 42% vs.  that of 0.8.6.

     References: #3915(1)

   * `[orm] [bug]' ¶. Fixed a major inefficiency in the
     “eager_defaults” feature whereby an unnecessary SELECT would be
     emitted for column values where the ORM had explicitly inserted
     NULL, corresponding to attributes that were unset on the object but
     did not have any server default specified, as well as expired
     attributes on update that nevertheless had no server onupdate set
     up.  As these columns are not part of the RETURNING that
     eager_defaults tries to use, they should not be post-SELECTed
     either.

     References: #3909(2)

   * `[orm] [bug]' ¶. Fixed two closely related bugs
     involving the mapper eager_defaults flag in conjunction with
     single-table inheritance; one where the eager defaults logic would
     inadvertently try to access a column that’s part of the mapper’s
     “exclude_properties” list (used by Declarative with single table
     inheritance) during the eager defaults fetch, and the other where
     the full load of the row in order to fetch the defaults would fail
     to use the correct inheriting mapper.

     References: #3908(3)

   * `[orm] [bug]' ¶. Fixed bug first introduced in 0.9.7 as
     a result of #3106(4) which would cause an incorrect query in some
     forms of multi-level subqueryload against aliased entities, with an
     unnecessary extra FROM entity in the innermost subquery.

     References: #3893(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3915

   (2) http://www.sqlalchemy.org/trac/ticket/3909

   (3) http://www.sqlalchemy.org/trac/ticket/3908

   (4) http://www.sqlalchemy.org/trac/ticket/3106

   (5) http://www.sqlalchemy.org/trac/ticket/3893

8.3.4.55 orm declarative
........................

   * `[orm] [declarative] [bug]' ¶. Fixed bug where the
     “automatic exclude” feature of declarative that ensures a column
     local to a single table inheritance subclass does not appear as an
     attribute on other derivations of the base would not take effect
     for multiple levels of subclassing from the base.

     References: #3895(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3895

8.3.4.56 sql
............

   * `[sql] [bug]' ¶. Fixed bug whereby the
     DDLEvents.column_reflect() event would not allow a
     non-textual expression to be passed as the value of the “default”
     for the new column, such as a FetchedValue object to
     indicate a generic triggered default or a text()
     construct.  Clarified the documentation in this regard as well.

     References: #3905(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3905

8.3.4.57 postgresql
...................

   * `[postgresql] [bug]' ¶. Added regular expressions for
     the “IMPORT FOREIGN SCHEMA”, “REFRESH MATERIALIZED VIEW” PostgreSQL
     statements so that they autocommit when invoked via a connection or
     engine without an explicit transaction.  Pull requests courtesy
     Frazer McLean and Paweł Stiasny.

     References: #3804(1)

   * `[postgresql] [bug]' ¶. Fixed bug in PostgreSQL
     ExcludeConstraint where the “whereclause” and “using”
     parameters would not be copied during an operation like
     Table.tometadata().

     References: #3900(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3804

   (2) http://www.sqlalchemy.org/trac/ticket/3900

8.3.4.58 mysql
..............

   * `[mysql] [bug]' ¶. Added new MySQL 8.0 reserved words
     to the MySQL dialect for proper quoting.  Pull request courtesy
     Hanno Schlichting.

8.3.4.59 mssql
..............

   * `[mssql] [bug]' ¶. Added a version check to the
     “get_isolation_level” feature, which is invoked upon first connect,
     so that it skips for SQL Server version 2000, as the necessary
     system view is not available prior to SQL Server 2005.

     References: #3898(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3898

8.3.4.60 misc
.............

   * `[feature] [ext]' ¶. Added Result.scalar().
     and Result.count() to the “baked” query system.

     References: #3896(1)

   * `[bug] [ext]' ¶. Fixed bug in new
     sqlalchemy.ext.indexable extension where setting of a property
     that itself refers to another property would fail.

     References: #3901(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3896

   (2) http://www.sqlalchemy.org/trac/ticket/3901

8.3.4.61 1.1.5
..............

Released: January 17, 2017

8.3.4.62 orm
............

   * `[orm] [bug]' ¶. Fixed bug involving joined eager
     loading against multiple entities when polymorphic inheritance is
     also in use which would throw “‘NoneType’ object has no attribute
     ‘isa’”.  The issue was introduced by the fix for #3611(1).

     This change is also `backported' to: 1.0.17

     References: #3884(2)

   * `[orm] [bug]' ¶. Fixed bug in subquery loading where an
     object encountered as an “existing” row, e.g.  already loaded from
     a different path in the same query, would not invoke subquery
     loaders for unloaded attributes that specified this loading.  This
     issue is in the same area as that of #3431(3), #3811(4) which
     involved similar issues with joined loading.

     References: #3854(5)

   * `[orm] [bug]' ¶. The Session.no_autoflush.
     context manager now ensures that the autoflush flag is reset within
     a “finally” block, so that if an exception is raised within the
     block, the state still resets appropriately.  Pull request courtesy
     Emin Arakelian.

   * `[orm] [bug]' ¶. Fixed bug where the single-table
     inheritance query criteria would not be inserted into the query in
     the case that the Bundle construct were used as the
     selection criteria.

     References: #3874(6)

   * `[orm] [bug]' ¶. Fixed bug related to #3177(7), where a
     UNION or other set operation emitted by a Query would
     apply “single-inheritance” criteria to the outside of the union
     (also referencing the wrong selectable), even though this criteria
     is now expected to be already present on the inside subqueries.
     The single-inheritance criteria is now omitted once union() or
     another set operation is called against Query in the
     same way as Query.from_self().

     References: #3856(8)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3611

   (2) http://www.sqlalchemy.org/trac/ticket/3884

   (3) http://www.sqlalchemy.org/trac/ticket/3431

   (4) http://www.sqlalchemy.org/trac/ticket/3811

   (5) http://www.sqlalchemy.org/trac/ticket/3854

   (6) http://www.sqlalchemy.org/trac/ticket/3874

   (7) http://www.sqlalchemy.org/trac/ticket/3177

   (8) http://www.sqlalchemy.org/trac/ticket/3856

8.3.4.63 engine
...............

   * `[engine] [bug]' ¶. The “extend_existing” option of
     Table reflection would cause indexes and constraints to
     be doubled up in the case that the parameter were used with
     MetaData.reflect(). (as the automap extension does) due to
     tables being reflected both within the foreign key path as well as
     directly.  A new de-duplicating set is passed through within the
     MetaData.reflect() sequence to prevent double
     reflection in this way.

     References: #3861(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3861

8.3.4.64 sql
............

   * `[sql] [bug]' ¶. Fixed bug originally introduced in 0.9
     via #1068(1) where order_by(<some Label()>) would order by the
     label name based on name alone, that is, even if the labeled
     expression were not at all the same expression otherwise present,
     implicitly or explicitly, in the selectable.  The logic that orders
     by label now ensures that the labeled expression is related to the
     one that resolves to that name before ordering by the label name;
     additionally, the name has to resolve to an actual label explicit
     in the expression elsewhere, not just a column name.  This logic is
     carefully kept separate from the order by(textual name) feature
     that has a slightly different purpose.

     References: #3882(2)

   * `[sql] [bug]' ¶. Fixed 1.1 regression where “import
     >>*<<” would not work for sqlalchemy.sql.expression, due to
     mis-spelled ‘any_’ and ‘all_’ functions.

     References: #3878(3)

   * `[sql] [bug]' ¶. The engine URL embedded in the
     exception for “could not reflect” in MetaData.reflect()
     now conceals the password; also the ‘__repr__’ for ‘TLEngine’ now
     acts like that of Engine, concealing the URL password.
     Pull request courtesy Valery Yundin.

   * `[sql] [bug]' ¶. Fixed issue in Variant.
     where the “right hand coercion” logic, inherited from
     TypeDecorator, would coerce the right-hand side into the
     Variant itself, rather than what the default type for
     the Variant would do.  In the case of Variant,
     we want the type to act mostly like the base type so the
     default logic of TypeDecorator is now overridden to
     fall back to the underlying wrapped type’s logic.  Is mostly
     relevant for JSON at the moment.

     References: #3859(4)

   * `[sql] [bg]' ¶. Fixed bug where literal_binds compiler
     flag was not honored by the Insert construct for the
     “multiple values” feature; the subsequent values are now rendered
     as literals.

     References: #3880(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1068

   (2) http://www.sqlalchemy.org/trac/ticket/3882

   (3) http://www.sqlalchemy.org/trac/ticket/3878

   (4) http://www.sqlalchemy.org/trac/ticket/3859

   (5) http://www.sqlalchemy.org/trac/ticket/3880

8.3.4.65 postgresql
...................

   * `[postgresql] [bug]' ¶. Fixed bug in new “ON CONFLICT
     DO UPDATE” feature where the “set” values for the UPDATE clause
     would not be subject to type-level processing, as normally takes
     effect to handle both user-defined type level conversions as well
     as dialect-required conversions, such as those required for JSON
     datatypes.  Additionally, clarified that the keys in the ‘set_’
     dictionary should match the “key” of the column, if distinct from
     the column name.  A warning is emitted for remaining column names
     that don’t match column keys; for compatibility reasons, these are
     emitted as they were previously.

     References: #3888(1)

   * `[postgresql] [bug]' ¶. The ‘TIME’ and ‘TIMESTAMP’
     datatypes now support a setting of zero for “precision”; previously
     a zero would be ignored.  Pull request courtesy Ionuț Ciocîrlan.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3888

8.3.4.66 mysql
..............

   * `[mysql] [feature]' ¶. Added a new parameter
     ‘mysql_prefix’ supported by the Index construct, allows
     specification of MySQL-specific prefixes such as “FULLTEXT”.  Pull
     request courtesy Joseph Schorr.

   * `[mysql] [bug]' ¶. The MySQL dialect now will not warn
     when a reflected column has a “COMMENT” keyword on it, but note
     however the comment is not yet reflected; this is on the roadmap
     for a future release.  Pull request courtesy Lele Long.

     References: #3867(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3867

8.3.4.67 mssql
..............

   * `[mssql] [bug]' ¶. Fixed bug where SQL Server dialects
     would attempt to select the last row identity for an INSERT from
     SELECT, failing in the case when the SELECT has no rows.  For such
     a statement, the inline flag is set to True indicating no last
     primary key should be fetched.

     References: #3876(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3876

8.3.4.68 oracle
...............

   * `[oracle] [bug] [postgresql]' ¶. Fixed bug where an
     INSERT from SELECT where the source table contains an
     autoincrementing Sequence would fail to compile correctly.

     References: #3877(1)

   * `[oracle] [bug]' ¶. Fixed bug where the “COMPRESSION”
     keyword was used in the ALL_TABLES query on Oracle 9.2; even though
     Oracle docs state table compression was introduced in 9i, the
     actual column is not present until 10.1.

     References: #3875(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3877

   (2) http://www.sqlalchemy.org/trac/ticket/3875

8.3.4.69 firebird
.................

   * `[firebird] [bug]' ¶. Ported the fix for Oracle
     quoted-lowercase names to Firebird, so that a table name that is
     quoted as lower case can be reflected properly including when the
     table name comes from the get_table_names() inspection function.

     References: #3548(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3548

8.3.4.70 misc
.............

   * `[bug] [py3k]' ¶. Fixed Python 3.6 DeprecationWarnings
     related to escaped strings without the ‘r’ modifier, and added test
     coverage for Python 3.6.

     This change is also `backported' to: 1.0.17

     References: #3886(1)

   * `[bug] [examples]' ¶. Fixed two issues with the
     versioned_history example, one is that the history table now gets
     autoincrement=False to avoid 1.1’s new errors regarding composite
     primary keys with autoincrement; the other is that the
     sqlite_autoincrement flag is now used to ensure on SQLite, unique
     identifiers are used for the lifespan of a table even if some rows
     are deleted.  Pull request courtesy Carlos García Montoro.

     References: #3872(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3886

   (2) http://www.sqlalchemy.org/trac/ticket/3872

8.3.4.71 1.1.4
..............

Released: November 15, 2016

8.3.4.72 orm
............

   * `[orm] [bug]' ¶. Fixed bug in
     Session.bulk_update_mappings() where an alternate-named
     primary key attribute would not track properly into the UPDATE
     statement.

     This change is also `backported' to: 1.0.16

     References: #3849(1)

   * `[orm] [bug]' ¶. Fixed bug in ‘Session.bulk_save()’
     where an UPDATE would not function correctly in conjunction with a
     mapping that implements a version id counter.

     This change is also `backported' to: 1.0.16

     References: #3781(2)

   * `[orm] [bug]' ¶. Fixed bug where the
     Mapper.attrs, Mapper.all_orm_descriptors and other
     derived attributes would fail to refresh when mapper properties or
     other ORM constructs were added to the mapper/class after these
     accessors were first called.

     This change is also `backported' to: 1.0.16

     References: #3778(3)

   * `[orm] [bug]' ¶. Fixed regression in collections due to
     #3457(4) whereby deserialize during pickle or deepcopy would fail
     to establish all attributes of an ORM collection, causing further
     mutation operations to fail.

     References: #3852(5)

   * `[orm] [bug]' ¶. Fixed long-standing bug where the
     “noload” relationship loading strategy would cause backrefs and/or
     back_populates options to be ignored.

     References: #3845(6)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3849

   (2) http://www.sqlalchemy.org/trac/ticket/3781

   (3) http://www.sqlalchemy.org/trac/ticket/3778

   (4) http://www.sqlalchemy.org/trac/ticket/3457

   (5) http://www.sqlalchemy.org/trac/ticket/3852

   (6) http://www.sqlalchemy.org/trac/ticket/3845

8.3.4.73 engine
...............

   * `[engine] [bug]' ¶. Removed long-broken
     “default_schema_name()” method from Connection.  This
     method was left over from a very old version and was non-working
     (e.g.  would raise).  Pull request courtesy Benjamin Dopplinger.

8.3.4.74 sql
............

   * `[sql] [bug]' ¶. Fixed bug where newly added warning
     for primary key on insert w/o autoincrement setting (see *note The
     .autoincrement directive is no longer implicitly enabled for a
     composite primary key column: 25b2.) would fail to emit correctly
     when invoked upon a lower-case table() construct.

     References: #3842(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3842

8.3.4.75 postgresql
...................

   * `[postgresql] [bug]' ¶. Fixed regression caused by the
     fix in #3807(1) (version 1.1.0) where we ensured that the tablename
     was qualified in the WHERE clause of the DO UPDATE portion of
     PostgreSQL’s ON CONFLICT, however you `cannot' put the table name
     in the WHERE clause in the actual ON CONFLICT itself.  This was an
     incorrect assumption, so that portion of the change in #3807(2) is
     rolled back.

     References: #3807(3), #3846(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3807

   (2) http://www.sqlalchemy.org/trac/ticket/3807

   (3) http://www.sqlalchemy.org/trac/ticket/3807

   (4) http://www.sqlalchemy.org/trac/ticket/3846

8.3.4.76 mysql
..............

   * `[mysql] [feature]' ¶. Added support for server side
     cursors to the mysqlclient and pymysql dialects.  This feature is
     available via the
     Connection.execution_options.stream_results flag as well as
     the ‘server_side_cursors=True’ dialect argument in the same way
     that it has been for psycopg2 on PostgreSQL. Pull request courtesy
     Roman Podoliaka.

   * `[mysql] [bug]' ¶. MySQL’s native ENUM type supports
     any non-valid value being sent, and in response will return a blank
     string.  A hardcoded rule to check for “is returning the blank
     string” has been added to the MySQL implementation for ENUM so that
     this blank string is returned to the application rather than being
     rejected as a non-valid value.  Note that if your MySQL enum is
     linking values to objects, you still get the blank string back.

     References: #3841(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3841

8.3.4.77 sqlite
...............

   * `[sqlite] [bug]' ¶. Added quotes to the PRAGMA
     directives in the pysqlcipher dialect to support additional cipher
     arguments appropriately.  Pull request courtesy Kevin Jurczyk.

   * `[sqlite] [bug] [py3k]' ¶. Added an optional import for
     the pysqlcipher3 DBAPI when using the pysqlcipher dialect.  This
     package will attempt to be imported if the Python-2 only
     pysqlcipher DBAPI is non-present.  Pull request courtesy Kevin
     Jurczyk.

8.3.4.78 mssql
..............

   * `[mssql] [bug]' ¶. Fixed bug in pyodbc dialect (as well
     as in the mostly non-working adodbapi dialect) whereby a semicolon
     present in the password or username fields could be interpreted as
     a separator for another token; the values are now quoted when
     semicolons are present.

     This change is also `backported' to: 1.0.16

     References: #3762(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3762

8.3.4.79 1.1.3
..............

Released: October 27, 2016

8.3.4.80 orm
............

   * `[orm] [bug]' ¶. Fixed regression caused by #2677(1)
     whereby calling Session.delete() on an object that was
     already flushed as deleted in that session would fail to set up the
     object in the identity map (or reject the object), causing flush
     errors as the object were in a state not accommodated by the unit
     of work.  The pre-1.1 behavior in this case has been restored,
     which is that the object is put back into the identity map so that
     the DELETE statement will be attempted again, which emits a warning
     that the number of expected rows was not matched (unless the row
     were restored outside of the session).

     References: #3839(2)

   * `[orm] [bug]' ¶. Fixed regression where some
     Query methods like Query.update() and others
     would fail if the Query were against a series of mapped
     columns, rather than the mapped entity as a whole.

     References: #3836(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2677

   (2) http://www.sqlalchemy.org/trac/ticket/3839

   (3) http://www.sqlalchemy.org/trac/ticket/3836

8.3.4.81 sql
............

   * `[sql] [bug]' ¶. Fixed bug involving new value
     translation and validation feature in Enum whereby
     using the enum object in a string concatenation would maintain the
     Enum type as the type of the expression overall,
     producing missing lookups.  A string concatenation against an
     Enum.-typed column now uses String as the datatype
     of the expression itself.

     References: #3833(1)

   * `[sql] [bug]' ¶. Fixed regression which occurred as a
     side effect of #2919(2), which in the less typical case of a
     user-defined TypeDecorator that was also itself an
     instance of SchemaType. (rather than the implementation
     being such) would cause the column attachment events to be skipped
     for the type itself.

     References: #3832(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3833

   (2) http://www.sqlalchemy.org/trac/ticket/2919

   (3) http://www.sqlalchemy.org/trac/ticket/3832

8.3.4.82 postgresql
...................

   * `[postgresql] [bug]' ¶. PostgreSQL table reflection
     will ensure that the Column.autoincrement flag is set
     to False when reflecting a primary key column that is not of an
     Integer datatype, even if the default is related to an
     integer-generating sequence.  This can happen if a column is
     created as SERIAL and the datatype is changed.  The autoincrement
     flag can only be True if the datatype is of integer affinity in the
     1.1 series.

     References: #3835(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3835

8.3.4.83 1.1.2
..............

Released: October 17, 2016

8.3.4.84 orm
............

   * `[orm] [bug]' ¶. Fixed bug involving the rule to
     disable a joined collection eager loader on the other side of a
     many-to-one lazy loader, first added in #1495(1), where the rule
     would fail if the parent object had some other lazyloader-bound
     query options associated with it.

     References: #3824(2)

   * `[orm] [bug]' ¶. Fixed self-referential entity,
     deferred column loading issue in a similar style as that of
     #3431(3), #3811(4) where an entity is present in multiple positions
     within the row due to self-referential eager loading; when the
     deferred loader only applies to one of the paths, the “present”
     column loader will now override the deferred non- load for that
     entity regardless of row ordering.

     References: #3822(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1495

   (2) http://www.sqlalchemy.org/trac/ticket/3824

   (3) http://www.sqlalchemy.org/trac/ticket/3431

   (4) http://www.sqlalchemy.org/trac/ticket/3811

   (5) http://www.sqlalchemy.org/trac/ticket/3822

8.3.4.85 sql
............

   * `[sql] [bug]' ¶. Fixed a regression caused by a newly
     added function that performs the “wrap callable” function of sql
     DefaultGenerator objects, an attribute error raised
     for ‘__module__’ when the default callable was a
     ‘functools.partial’ or other object that doesn’t have a
     ‘__module__’ attribute.

     References: #3823(1)

   * `[sql] [bug] [postgresql]' ¶. Fixed regression in
     Enum type where event handlers were not transferred in the
     case of the type object being copied, due to a conflicting copy()
     method added as part of #3250(2).  This copy occurs normally in
     situations when the column is copied, such as in tometadata() or
     when using declarative mixins with columns.  The event handler not
     being present would impact the constraint being created for a
     non-native enumerated type, but more critically the ENUM object on
     the PostgreSQL backend.

     References: #3827(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3823

   (2) http://www.sqlalchemy.org/trac/ticket/3250

   (3) http://www.sqlalchemy.org/trac/ticket/3827

8.3.4.86 postgresql
...................

   * `[postgresql] [bug] [sql]' ¶. Changed the naming
     convention used when generating bound parameters for a multi-VALUES
     insert statement, so that the numbered parameter names don’t
     conflict with the anonymized parameters of a WHERE clause, as is
     now common in a PostgreSQL ON CONFLICT construct.

     References: #3828(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3828

8.3.4.87 1.1.1
..............

Released: October 7, 2016

8.3.4.88 mssql
..............

   * `[mssql] [bug]' ¶. The “SELECT SERVERPROPERTY” query
     added in #3810(1) and #3814(2) is failing on unknown combinations
     of Pyodbc and SQL Server.  While failure of this function was
     anticipated, the exception catch was not broad enough so it now
     catches all forms of pyodbc.Error.

     References: #3820(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3810

   (2) http://www.sqlalchemy.org/trac/ticket/3814

   (3) http://www.sqlalchemy.org/trac/ticket/3820

8.3.4.89 misc
.............

   * `[bug] [core]' ¶. Changed the CompileError raised when
     various primary key missing situations are detected to a warning.
     The statement is again passed to the database where it will fail
     and the DBAPI error (usually IntegrityError) raises as usual.

     See also
     ........

     See The .autoincrement directive is no longer implicitly enabled for a composite primary key column.

     References: #3216(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3216

8.3.4.90 1.1.0
..............

Released: October 5, 2016

8.3.4.91 orm
............

   * `[orm] [feature]' ¶. Enhanced the new “raise” lazy
     loader strategy to also include a “raise_on_sql” variant, available
     both via relationship.lazy as well as
     raiseload().  This variant only raises if the lazy load would
     actually emit SQL, vs.  raising if the lazy loader mechanism is
     invoked at all.

     References: #3812(1)

   * `[orm] [feature]' ¶. The Query.group_by().
     method now resets the group by collection if an argument of ‘None’
     is passed, in the same way that Query.order_by() has
     worked for a long time.  Pull request courtesy Iuri Diniz.

   * `[orm] [change]' ¶. Passing False to
     Query.order_by() in order to cancel all order by’s is
     deprecated; there is no longer any difference between calling this
     method with False or with None.

   * `[orm] [bug]' ¶. Fixed bug where joined eager loading
     would fail for a polymorphically- loaded mapper, where the
     polymorphic_on was set to an un-mapped expression such as a CASE
     expression.

     This change is also `backported' to: 1.0.16

     References: #3800(2)

   * `[orm] [bug]' ¶. Fixed bug where the ArgumentError
     raised for an invalid bind sent to a Session via
     Session.bind_mapper(), Session.bind_table(), or the
     constructor would fail to be correctly raised.

     This change is also `backported' to: 1.0.16

     References: #3798(3)

   * `[orm] [bug]' ¶. Fixed bug in subquery eager loading
     where a subqueryload of an “of_type()” object linked to a second
     subqueryload of a plain mapped class, or a longer chain of several
     “of_type()” attributes, would fail to link the joins correctly.

     This change is also `backported' to: 1.0.15

     References: #3773(4), #3774(5)

   * `[orm] [bug]' ¶. ORM attributes can now be assigned any
     object that is has a ‘__clause_element__()’ attribute, which will
     result in inline SQL the way any ClauseElement class
     does.  This covers other mapped attributes not otherwise
     transformed by further expression constructs.

     References: #3802(6)

   * `[orm] [bug]' ¶. Made an adjustment to the bug fix
     first introduced in [ticket:3431] that involves an object appearing
     in multiple contexts in a single result set, such that an eager
     loader that would set the related object value to be None will
     still fire off, thus satisfying the load of that attribute.
     Previously, the adjustment only honored a non-None value arriving
     for an eagerly loaded attribute in a secondary row.

     References: #3811(7)

   * `[orm] [bug]' ¶. Fixed bug in new
     SessionEvents.persistent_to_deleted() event where the target
     object could be garbage collected before the event is fired off.

     References: #3808(8)

   * `[orm] [bug]' ¶. The primaryjoin of a
     relationship() construct can now include a bindparam()
     object that includes a callable function to generate values.
     Previously, the lazy loader strategy would be incompatible with
     this use, and additionally would fail to correctly detect if the
     “use_get” criteria should be used if the primary key were involved
     with the bound parameter.

     References: #3767(9)

   * `[orm] [bug]' ¶. An UPDATE emitted from the ORM flush
     process can now accommodate a SQL expression element for a column
     within the primary key of an object, if the target database
     supports RETURNING in order to provide the new value, or if the PK
     value is set “to itself” for the purposes of bumping some other
     trigger / onupdate on the column.

     References: #3801(10)

   * `[orm] [bug]' ¶. Fixed bug where the “simple
     many-to-one” condition that allows lazy loading to use get() from
     identity map would fail to be invoked if the primaryjoin of the
     relationship had multiple clauses separated by AND which were not
     in the same order as that of the primary key columns being compared
     in each clause.  This ordering difference occurs for a composite
     foreign key where the table-bound columns on the referencing side
     were not in the same order in the .c collection as the primary key
     columns on the referenced side….which in turn occurs a lot if one
     is using declarative mixins and/or declared_attr to set up columns.

     References: #3788(11)

   * `[orm] [bug]' ¶. An exception is raised when two
     ‘@validates’ decorators on a mapping make use of the same name.
     Only one validator of a certain name at a time is supported,
     there’s no mechanism to chain these together, as the order of the
     validators at the level of function decorator can’t be made
     deterministic.

     See also
     ........

     See Same-named @validates decorators will now raise an exception.

     References: #3776(12)

   * `[orm] [bug]' ¶. Mapper errors raised during
     configure_mappers() now explicitly include the name of the
     originating mapper in the exception message to help in those
     situations where the wrapped exception does not itself include the
     source mapper.  Pull request courtesy John Perkins.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3812

   (2) http://www.sqlalchemy.org/trac/ticket/3800

   (3) http://www.sqlalchemy.org/trac/ticket/3798

   (4) http://www.sqlalchemy.org/trac/ticket/3773

   (5) http://www.sqlalchemy.org/trac/ticket/3774

   (6) http://www.sqlalchemy.org/trac/ticket/3802

   (7) http://www.sqlalchemy.org/trac/ticket/3811

   (8) http://www.sqlalchemy.org/trac/ticket/3808

   (9) http://www.sqlalchemy.org/trac/ticket/3767

   (10) http://www.sqlalchemy.org/trac/ticket/3801

   (11) http://www.sqlalchemy.org/trac/ticket/3788

   (12) http://www.sqlalchemy.org/trac/ticket/3776

8.3.4.92 orm declarative
........................

   * `[orm] [declarative] [change]' ¶. Constructing a
     declarative base class that inherits from another class will also
     inherit its docstring.  This means ‘as_declarative()’ acts more
     like a normal class decorator.

8.3.4.93 sql
............

   * `[sql] [bug]' ¶. Fixed bug in Table where
     the internal method ‘_reset_exported()’ would corrupt the state of
     the object.  This method is intended for selectable objects and is
     called by the ORM in some cases; an erroneous mapper configuration
     would could lead the ORM to call this on a Table object.

     This change is also `backported' to: 1.0.15

     References: #3755(1)

   * `[sql] [bug]' ¶. Execution options can now be
     propagated from within a statement at compile time to the outermost
     statement, so that if an embedded element wants to set “autocommit”
     to be True for example, it can propagate this to the enclosing
     statement.  Currently, this feature is enabled for a DML-oriented
     CTE embedded inside of a SELECT statement, e.g.
     INSERT/UPDATE/DELETE inside of SELECT.

     References: #3805(2)

   * `[sql] [bug]' ¶. A string sent as a column default via
     the Column.server_default parameter is now escaped for
     quotes.

     See also
     ........

     See String server_default now literal quoted.

     References: #3809(3)

   * `[sql] [bug] [postgresql]' ¶. Added compiler-level
     flags used by PostgreSQL to place additional parenthesis than would
     normally be generated by precedence rules around operations
     involving JSON, HSTORE indexing operators as well as within their
     operands since it has been observed that PostgreSQL’s precedence
     rules for at least the HSTORE indexing operator is not consistent
     between 9.4 and 9.5.

     References: #3806(4)

   * `[sql] [bug] [mysql]' ¶. The ‘BaseException’ exception
     class is now intercepted by the exception-handling routines of
     Connection, and includes handling by the
     ConnectionEvents.handle_error() event.  The
     Connection is now `invalidated' by default in the case of a
     system level exception that is not a subclass of ‘Exception’,
     including ‘KeyboardInterrupt’ and the greenlet ‘GreenletExit’
     class, to prevent further operations from occurring upon a database
     connection that is in an unknown and possibly corrupted state.  The
     MySQL drivers are most targeted by this change however the change
     is across all DBAPIs.

     See also
     ........

     See Engines now invalidate connections, run error handlers for BaseException.

     References: #3803(5)

   * `[sql] [bug]' ¶. The “eq” and “ne” operators are no
     longer part of the list of “associative” operators, while they
     remain considered to be “commutative”.  This allows an expression
     like ‘(x == y) == z’ to be maintained at the SQL level with
     parenthesis.  Pull request courtesy John Passaro.

     References: #3799(6)

   * `[sql] [bug]' ¶. Stringify of expression with unnamed
     Column objects, as occurs in lots of situations
     including ORM error reporting, will now render the name in string
     context as “<name unknown>” rather than raising a compile error.

     References: #3789(7)

   * `[sql] [bug]' ¶. Raise a more descriptive exception /
     message when ClauseElement or non-SQLAlchemy objects that are not
     “executable” are erroneously passed to ‘.execute()’; a new
     exception ObjectNotExecutableError is raised consistently in all
     cases.

     References: #3786(8)

   * `[sql] [bug] [mysql] [postgresql]' ¶. Fixed regression
     in JSON datatypes where the “literal processor” for a JSON index
     value would not be invoked.  The native String and Integer
     datatypes are now called upon from within the JSONIndexType and
     JSONPathType.  This is applied to the generic, PostgreSQL, and
     MySQL JSON types and also has a dependency on #3766(9).

     References: #3765(10)

   * `[sql] [bug]' ¶. Fixed bug where Index.
     would fail to extract columns from compound SQL expressions if
     those SQL expressions were wrapped inside of an ORM-style
     ‘__clause_element__()’ construct.  This bug exists in 1.0.x as
     well, however in 1.1 is more noticeable as hybrid_property
     @expression now returns a wrapped element.

     References: #3763(11)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3755

   (2) http://www.sqlalchemy.org/trac/ticket/3805

   (3) http://www.sqlalchemy.org/trac/ticket/3809

   (4) http://www.sqlalchemy.org/trac/ticket/3806

   (5) http://www.sqlalchemy.org/trac/ticket/3803

   (6) http://www.sqlalchemy.org/trac/ticket/3799

   (7) http://www.sqlalchemy.org/trac/ticket/3789

   (8) http://www.sqlalchemy.org/trac/ticket/3786

   (9) http://www.sqlalchemy.org/trac/ticket/3766

   (10) http://www.sqlalchemy.org/trac/ticket/3765

   (11) http://www.sqlalchemy.org/trac/ticket/3763

8.3.4.94 postgresql
...................

   * `[postgresql] [bug]' ¶. An adjustment to ON CONFLICT
     such that the “inserted_primary_key” logic is able to accommodate
     the case where there’s no INSERT or UPDATE and there’s no net
     change.  The value comes out as None in this case, rather than
     failing on an exception.

     References: #3813(1)

   * `[postgresql] [bug]' ¶.

          Fixed issue in new PG “on conflict” construct where columns
          including those of the “excluded” namespace would not be
          table-qualified in the WHERE clauses in the statement.

     References: #3807(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3813

   (2) http://www.sqlalchemy.org/trac/ticket/3807

8.3.4.95 mysql
..............

   * `[mysql] [bug]' ¶. Added support for parsing
     MySQL/Connector boolean and integer arguments within the URL query
     string: connection_timeout, connect_timeout, pool_size,
     get_warnings, raise_on_warnings, raw, consume_results,
     ssl_verify_cert, force_ipv6, pool_reset_session, compress,
     allow_local_infile, use_pure.

     This change is also `backported' to: 1.0.15

     References: #3787(1)

   * `[mysql] [bug]' ¶. Fixed bug where the “literal_binds”
     flag would not be propagated to a CAST expression under MySQL.

     References: #3766(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3787

   (2) http://www.sqlalchemy.org/trac/ticket/3766

8.3.4.96 mssql
..............

   * `[mssql] [bug]' ¶. Changed the query used to get
     “default schema name”, from one that queries the database
     principals table to using the “schema_name()” function, as issues
     have been reported that the former system was unavailable on the
     Azure Data Warehouse edition.  It is hoped that this will finally
     work across all SQL Server versions and authentication styles.

     This change is also `backported' to: 1.0.16

     References: #3810(1)

   * `[mssql] [bug]' ¶. Updated the server version info
     scheme for pyodbc to use SQL Server SERVERPROPERTY(), rather than
     relying upon pyodbc.SQL_DBMS_VER, which continues to be unreliable
     particularly with FreeTDS.

     This change is also `backported' to: 1.0.16

     References: #3814(2)

   * `[mssql] [bug]' ¶. Added error code 20017 “unexpected
     EOF from the server” to the list of disconnect exceptions that
     result in a connection pool reset.  Pull request courtesy Ken
     Robbins.

     This change is also `backported' to: 1.0.16

     References: #3791(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3810

   (2) http://www.sqlalchemy.org/trac/ticket/3814

   (3) http://www.sqlalchemy.org/trac/ticket/3791

8.3.4.97 misc
.............

   * `[bug] [orm.declarative]' ¶. Fixed bug where setting up
     a single-table inh subclass of a joined-table subclass which
     included an extra column would corrupt the foreign keys collection
     of the mapped table, thereby interfering with the initialization of
     relationships.

     This change is also `backported' to: 1.0.16

     References: #3797(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3797

8.3.4.98 1.1.0b3
................

Released: July 26, 2016

8.3.4.99 orm
............

   * `[orm] [change]' ¶. Removed a warning that dates back
     to 0.4 which emits when a same-named relationship is placed on two
     mappers that inherits via joined or single table inheritance.  The
     warning does not apply to the current unit of work implementation.

     See also
     ........

     See Same-named relationships on inheriting mappers no longer warn.

     References: #3749(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3749

8.3.4.100 sql
.............

   * `[sql] [bug]' ¶. Fixed bug in new CTE feature for
     update/insert/delete stated as a CTE inside of an enclosing
     statement (typically SELECT) whereby oninsert and onupdate values
     weren’t called upon for the embedded statement.

     References: #3745(1)

   * `[sql] [bug]' ¶. Fixed bug in new CTE feature for
     update/insert/delete whereby an anonymous (e.g.  no name passed)
     CTE construct around the statement would fail.

     References: #3744(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3745

   (2) http://www.sqlalchemy.org/trac/ticket/3744

8.3.4.101 postgresql
....................

   * `[postgresql] [bug]' ¶. Fixed bug whereby
     TypeDecorator and Variant types were not deeply
     inspected enough by the PostgreSQL dialect to determine if
     SMALLSERIAL or BIGSERIAL needed to be rendered rather than SERIAL.

     This change is also `backported' to: 1.0.14

     References: #3739(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3739

8.3.4.102 oracle
................

   * `[oracle] [bug]' ¶. Fixed bug in
     Select.with_for_update.of, where the Oracle “rownum” approach
     to LIMIT/OFFSET would fail to accommodate for the expressions
     inside the “OF” clause, which must be stated at the topmost level
     referring to expression within the subquery.  The expressions are
     now added to the subquery if needed.

     This change is also `backported' to: 1.0.14

     References: #3741(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3741

8.3.4.103 misc
..............

   * `[feature] [ext]' ¶. Added a “default” parameter to the
     new sqlalchemy.ext.indexable extension.

   * `[bug] [ext]' ¶. Fixed bug in ‘sqlalchemy.ext.baked’
     where the unbaking of a subquery eager loader query would fail due
     to a variable scoping issue, when multiple subquery loaders were
     involved.  Pull request courtesy Mark Hahnenberg.

     This change is also `backported' to: 1.0.15

     References: #3743(1)

   * `[bug] [ext]' ¶ sqlalchemy.ext.indexable will
     intercept IndexError as well as KeyError when raising as
     AttributeError.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3743

8.3.4.104 1.1.0b2
.................

Released: July 1, 2016

8.3.4.105 sql
.............

   * `[sql] [bug]' ¶. Fixed issue in SQL math negation
     operator where the type of the expression would no longer be the
     numeric type of the original.  This would cause issues where the
     type determined result set behaviors.

     This change is also `backported' to: 1.0.14

     References: #3735(1)

   * `[sql] [bug]' ¶. Fixed bug whereby the ‘__getstate__’ /
     ‘__setstate__’ methods for sqlalchemy.util.Properties were
     non-working due to the transition in the 1.0 series to ‘__slots__’.
     The issue potentially impacted some third-party applications.  Pull
     request courtesy Pieter Mulder.

     This change is also `backported' to: 1.0.14

     References: #3728(2)

   * `[sql] [bug]' ¶. The processing performed by the
     Boolean datatype for backends that only feature integer types
     has been made consistent between the pure Python and C-extension
     versions, in that the C-extension version will accept any integer
     value from the database as a boolean, not just zero and one;
     additionally, non-boolean integer values being sent to the database
     are coerced to exactly zero or one, instead of being passed as the
     original integer value.

     See also
     ........

     See Non-native boolean integer values coerced to zero/one/None in all cases.

     References: #3730(3)

   * `[sql] [bug]' ¶. Rolled back the validation rules a bit
     in Enum to allow unknown string values to pass through,
     unless the flag ‘validate_string=True’ is passed to the Enum; any
     other kind of object is still of course rejected.  While the
     immediate use is to allow comparisons to enums with LIKE, the fact
     that this use exists indicates there may be more
     unknown-string-comparison use cases than we expected, which hints
     that perhaps there are some unknown string-INSERT cases too.

     References: #3725(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3735

   (2) http://www.sqlalchemy.org/trac/ticket/3728

   (3) http://www.sqlalchemy.org/trac/ticket/3730

   (4) http://www.sqlalchemy.org/trac/ticket/3725

8.3.4.106 postgresql
....................

   * `[postgresql] [bug] [ext]' ¶. Made a slight behavioral
     change in the ‘sqlalchemy.ext.compiler’ extension, whereby the
     existing compilation schemes for an established construct would be
     removed if that construct itself didn’t already have its own
     dedicated ‘__visit_name__’.  This was a rare occurrence in 1.0,
     however in 1.1 ARRAY subclasses ARRAY and
     has this behavior.  As a result, setting up a compilation handler
     for another dialect such as SQLite would render the main
     ARRAY object no longer compilable.

     References: #3732(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3732

8.3.4.107 mysql
...............

   * `[mysql] [bug]' ¶. Dialed back the “order the primary
     key columns per auto-increment” described in *note No more
     generation of an implicit KEY for composite primary key w/
     AUTO_INCREMENT: 265b. a bit, so that if the
     PrimaryKeyConstraint is explicitly defined, the order of
     columns is maintained exactly, allowing control of this behavior
     when necessary.

     References: #3726(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3726

8.3.4.108 1.1.0b1
.................

Released: June 16, 2016

8.3.4.109 orm
.............

   * `[orm] [feature] [ext]' ¶. A new ORM extension
     Indexable is added, which allows construction of Python
     attributes which refer to specific elements of “indexed” structures
     such as arrays and JSON fields.  Pull request courtesy Jeong
     YunWon.

     See also
     ........

     See New Indexable ORM extension.

   * `[orm] [feature]' ¶. Added new flag
     Session.bulk_insert_mappings.render_nulls which allows an ORM
     bulk INSERT to occur with NULL values rendered; this bypasses
     server side defaults, however allows all statements to be formed
     with the same set of columns, allowing them to be batched.  Pull
     request courtesy Tobias Sauerwein.

   * `[orm] [feature]' ¶. Added new event
     AttributeEvents.init_scalar(), as well as a new example suite
     illustrating its use.  This event can be used to provide a
     Core-generated default value to a Python-side attribute before the
     object is persisted.

     See also
     ........

     See New init_scalar() event intercepts default values at ORM level.

     References: #1311(1)

   * `[orm] [feature]' ¶. Added
     AutomapBase.prepare.schema to the
     AutomapBase.prepare() method, to indicate which schema tables
     should be reflected from if not the default schema.  Pull request
     courtesy Josh Marlow.

   * `[orm] [feature]' ¶. Added new parameter
     mapper.passive_deletes to available mapper options.  This
     allows a DELETE to proceed for a joined-table inheritance mapping
     against the base table only, while allowing for ON DELETE CASCADE
     to handle deleting the row from the subclass tables.

     See also
     ........

     See passive_deletes feature for joined-inheritance mappings.

     References: #2349(2)

   * `[orm] [feature]' ¶. Calling str() on a core SQL
     construct has been made more “friendly”, when the construct
     contains non-standard SQL elements such as RETURNING, array index
     operations, or dialect-specific or custom datatypes.  A string is
     now returned in these cases rendering an approximation of the
     construct (typically the PostgreSQL-style version of it) rather
     than raising an error.

     See also
     ........

     See “Friendly” stringification of Core SQL constructs without a dialect.

     References: #3631(3)

   * `[orm] [feature]' ¶. The ‘str()’ call for Query
     will now take into account the Engine to which the
     Session is bound, when generating the string form of the
     SQL, so that the actual SQL that would be emitted to the database
     is shown, if possible.  Previously, only the engine associated with
     the MetaData to which the mappings are associated would
     be used, if present.  If no bind can be located either on the
     Session or on the MetaData to which the mappings
     are associated, then the “default” dialect is used to render the
     SQL, as was the case previously.

     See also
     ........

     See Stringify of Query will consult the Session for the correct dialect.

     References: #3081(4)

   * `[orm] [feature]' ¶. The SessionEvents.
     suite now includes events to allow unambiguous tracking of all
     object lifecycle state transitions in terms of the Session
     itself, e.g.  pending, transient, persistent, detached.  The
     state of the object within each event is also defined.

     See also
     ........

     See New Session lifecycle events.

     References: #2677(5)

   * `[orm] [feature]' ¶. Added a new session lifecycle
     state deleted.  This new state represents an object that has been
     deleted from the persistent state and will move to the detached
     state once the transaction is committed.  This resolves the
     long-standing issue that objects which were deleted existed in a
     gray area between persistent and detached.  The
     InstanceState.persistent accessor will `no longer' report on
     a deleted object as persistent; the InstanceState.deleted
     accessor will instead be True for these objects, until they
     become detached.

     See also
     ........

     See New Session lifecycle events.

     References: #2677(6)

   * `[orm] [feature]' ¶. Added new checks for the common
     error case of passing mapped classes or mapped instances into
     contexts where they are interpreted as SQL bound parameters; a new
     exception is raised for this.

     See also
     ........

     See Specific checks added for passing mapped classes, instances as SQL literals.

     References: #3321(7)

   * `[orm] [feature]' ¶. Added new relationship loading
     strategy raiseload(). (also accessible via
     ‘lazy='raise'’).  This strategy behaves almost like noload()
     but instead of returning ‘None’ it raises an
     InvalidRequestError.  Pull request courtesy Adrian Moennich.

     See also
     ........

     See New “raise” / “raise_on_sql” loader strategies.

     References: #3512(8)

   * `[orm] [change]' ¶. The Mapper.order_by.
     parameter is deprecated.  This is an old parameter no longer
     relevant to how SQLAlchemy works, once the Query object was
     introduced.  By deprecating it we establish that we aren’t
     supporting non-working use cases and that we encourage applications
     to move off of the use of this parameter.

     See also
     ........

     See Mapper.order_by is deprecated.

     References: #3394(9)

   * `[orm] [change]' ¶. The
     Session.weak_identity_map parameter is deprecated.  See the
     new recipe at Session Referencing Behavior for an
     event-based approach to maintaining strong identity map behavior.

     See also
     ........

     See New Session lifecycle events.

     References: #2677(10)

   * `[orm] [bug]' ¶. Fixed an issue where a many-to-one
     change of an object from one parent to another could work
     inconsistently when combined with an un-flushed modification of the
     foreign key attribute.  The attribute move now considers the
     database-committed value of the foreign key in order to locate the
     “previous” parent of the object being moved.  This allows events to
     fire off correctly including backref events.  Previously, these
     events would not always fire.  Applications which may have relied
     on the previously broken behavior may be affected.

     See also
     ........

     See Fix involving many-to-one object moves with user-initiated foreign key manipulations.

     References: #3708(11)

   * `[orm] [bug]' ¶. Fixed bug where deferred columns would
     inadvertently be set up for database load on the next object-wide
     unexpire, when the object were merged into the session with
     ‘session.merge(obj, load=False)’.

     References: #3488(12)

   * `[orm] [bug] [mysql]' ¶. Further continuing on the
     common MySQL exception case of a savepoint being cancelled first
     covered in #2696(13), the failure mode in which the Session
     is placed when a SAVEPOINT vanishes before rollback has been
     improved to allow the Session to still function outside
     of that savepoint.  It is assumed that the savepoint operation
     failed and was cancelled.

     See also
     ........

     See Improved Session state when a SAVEPOINT is cancelled by the database.

     References: #3680(14)

   * `[orm] [bug]' ¶. Fixed bug where a newly inserted
     instance that is rolled back would still potentially cause
     persistence conflicts on the next transaction, because the instance
     would not be checked that it was expired.  This fix will resolve a
     large class of cases that erroneously cause the “New instance with
     identity X conflicts with persistent instance Y” error.

     See also
     ........

     See Erroneous “new instance X conflicts with persistent instance Y” flush errors fixed.

     References: #3677(15)

   * `[orm] [bug]' ¶. An improvement to the workings of
     Query.correlate() such that when a “polymorphic” entity
     is used which represents a straight join of several tables, the
     statement will ensure that all the tables within the join are part
     of what’s correlating.

     See also
     ........

     See Improvements to the Query.correlate method with polymorphic entities.

     References: #3662(16)

   * `[orm] [bug]' ¶. Fixed bug which would cause an eagerly
     loaded many-to-one attribute to not be loaded, if the joined eager
     load were from a row where the same entity were present multiple
     times, some calling for the attribute to be eagerly loaded and
     others not.  The logic here is revised to take in the attribute
     even though a different loader path has handled the parent entity
     already.

     See also
     ........

     See Joined eager loading where the same entity is present multiple times in one row.

     References: #3431(17)

   * `[orm] [bug]' ¶. A refinement to the logic which adds
     columns to the resulting SQL when Query.distinct() is
     combined with Query.order_by() such that columns which
     are already present will not be added a second time, even if they
     are labeled with a different name.  Regardless of this change, the
     extra columns added to the SQL have never been returned in the
     final result, so this change only impacts the string form of the
     statement as well as its behavior when used in a Core execution
     context.  Additionally, columns are no longer added when the
     DISTINCT ON format is used, provided the query is not wrapped
     inside a subquery due to joined eager loading.

     See also
     ........

     See Columns no longer added redundantly with DISTINCT + ORDER BY.

     References: #3641(18)

   * `[orm] [bug]' ¶. Fixed issue where two same-named
     relationships that refer to a base class and a concrete-inherited
     subclass would raise an error if those relationships were set up
     using “backref”, while setting up the identical configuration using
     relationship() instead with the conflicting names would succeed, as
     is allowed in the case of a concrete mapping.

     See also
     ........

     See Same-named backrefs will not raise an error when applied to concrete inheritance subclasses.

     References: #3630(19)

   * `[orm] [bug]' ¶. The Session.merge() method
     now tracks pending objects by primary key before emitting an
     INSERT, and merges distinct objects with duplicate primary keys
     together as they are encountered, which is essentially
     semi-deterministic at best.  This behavior matches what happens
     already with persistent objects.

     See also
     ........

     See Session.merge resolves pending conflicts the same as persistent.

     References: #3601(20)

   * `[orm] [bug]' ¶. Fixed bug where the “single table
     inheritance” criteria would be added onto the end of a query in
     some inappropriate situations, such as when querying from an
     exists() of a single-inheritance subclass.

     See also
     ........

     See Further Fixes to single-table inheritance querying.

     References: #3582(21)

   * `[orm] [bug]' ¶. Added a new type-level modifier
     TypeEngine.evaluates_none() which indicates to the ORM that a
     positive set of None should be persisted as the value NULL, instead
     of omitting the column from the INSERT statement.  This feature is
     used both as part of the implementation for #3514(22) as well as a
     standalone feature available on any type.

     See also
     ........

     See New options allowing explicit persistence of NULL over a default.

     References: #3250(23)

   * `[orm] [bug]' ¶. Internal calls to “bookkeeping”
     functions within Session.bulk_save_objects() and
     related bulk methods have been scaled back to the extent that this
     functionality is not currently used, e.g.  checks for column
     default values to be fetched after an INSERT or UPDATE statement.

     References: #3526(24)

   * `[orm] [bug] [postgresql]' ¶. Additional fixes have
     been made regarding the value of ‘None’ in conjunction with the
     PostgreSQL JSON type.  When the
     JSON.none_as_null flag is left at its default value of
     ‘False’, the ORM will now correctly insert the JSON “‘null’” string
     into the column whenever the value on the ORM object is set to the
     value ‘None’ or when the value ‘None’ is used with
     Session.bulk_insert_mappings(), `including' if the column has
     a default or server default on it.

     See also
     ........

     See JSON “null” is inserted as expected with ORM operations, omitted when not present.

     See New options allowing explicit persistence of NULL over a default.

     References: #3514(25)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1311

   (2) http://www.sqlalchemy.org/trac/ticket/2349

   (3) http://www.sqlalchemy.org/trac/ticket/3631

   (4) http://www.sqlalchemy.org/trac/ticket/3081

   (5) http://www.sqlalchemy.org/trac/ticket/2677

   (6) http://www.sqlalchemy.org/trac/ticket/2677

   (7) http://www.sqlalchemy.org/trac/ticket/3321

   (8) http://www.sqlalchemy.org/trac/ticket/3512

   (9) http://www.sqlalchemy.org/trac/ticket/3394

   (10) http://www.sqlalchemy.org/trac/ticket/2677

   (11) http://www.sqlalchemy.org/trac/ticket/3708

   (12) http://www.sqlalchemy.org/trac/ticket/3488

   (13) http://www.sqlalchemy.org/trac/ticket/2696

   (14) http://www.sqlalchemy.org/trac/ticket/3680

   (15) http://www.sqlalchemy.org/trac/ticket/3677

   (16) http://www.sqlalchemy.org/trac/ticket/3662

   (17) http://www.sqlalchemy.org/trac/ticket/3431

   (18) http://www.sqlalchemy.org/trac/ticket/3641

   (19) http://www.sqlalchemy.org/trac/ticket/3630

   (20) http://www.sqlalchemy.org/trac/ticket/3601

   (21) http://www.sqlalchemy.org/trac/ticket/3582

   (22) http://www.sqlalchemy.org/trac/ticket/3514

   (23) http://www.sqlalchemy.org/trac/ticket/3250

   (24) http://www.sqlalchemy.org/trac/ticket/3526

   (25) http://www.sqlalchemy.org/trac/ticket/3514

8.3.4.110 engine
................

   * `[engine] [feature]' ¶. Added connection pool events
     ‘ConnectionEvents.close()’, ‘ConnectionEvents.detach()’,
     ‘ConnectionEvents.close_detached()’.

   * `[engine] [feature]' ¶. All string formatting of bound
     parameter sets and result rows for logging, exception, and ‘repr()’
     purposes now truncate very large scalar values within each
     collection, including an “N characters truncated” notation, similar
     to how the display for large multiple-parameter sets are themselves
     truncated.

     See also
     ........

     See Large parameter and row values are now truncated in logging and exception displays.

     References: #2837(1)

   * `[engine] [feature]' ¶. Multi-tenancy schema
     translation for Table objects is added.  This supports
     the use case of an application that uses the same set of
     Table objects in many schemas, such as schema-per-user.  A new
     execution option
     Connection.execution_options.schema_translate_map is added.

     See also
     ........

     See Multi-Tenancy Schema Translation for Table objects.

     References: #2685(2)

   * `[engine] [feature]' ¶. Added a new entrypoint system
     to the engine to allow “plugins” to be stated in the query string
     for a URL. Custom plugins can be written which will be given the
     chance up front to alter and/or consume the engine’s URL and
     keyword arguments, and then at engine create time will be given the
     engine itself to allow additional modifications or event
     registration.  Plugins are written as a subclass of
     CreateEnginePlugin; see that class for details.

     References: #3536(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2837

   (2) http://www.sqlalchemy.org/trac/ticket/2685

   (3) http://www.sqlalchemy.org/trac/ticket/3536

8.3.4.111 sql
.............

   * `[sql] [feature]' ¶. Added TABLESAMPLE support via the
     new FromClause.tablesample() method and standalone
     function.  Pull request courtesy Ilja Everilä.

     See also
     ........

     See Support for TABLESAMPLE.

     References: #3718(1)

   * `[sql] [feature]' ¶. Added support for ranges in window
     functions, using the over.range_ and over.rows
     parameters.

     See also
     ........

     See Support for RANGE and ROWS specification within window functions.

     References: #3049(2)

   * `[sql] [feature]' ¶. Implemented reflection of CHECK
     constraints for SQLite and PostgreSQL. This is available via the
     new inspector method Inspector.get_check_constraints()
     as well as when reflecting Table objects in the form of
     CheckConstraint objects present in the constraints
     collection.  Pull request courtesy Alex Grönholm.

   * `[sql] [feature]' ¶. New
     ColumnOperators.is_distinct_from() and
     ColumnOperators.isnot_distinct_from() operators; pull request
     courtesy Sebastian Bank.

     See also
     ........

     See Support for IS DISTINCT FROM and IS NOT DISTINCT FROM.

   * `[sql] [feature]' ¶. Added a hook in
     ‘DDLCompiler.visit_create_table()’ called
     ‘DDLCompiler.create_table_suffix()’, allowing custom dialects to
     add keywords after the “CREATE TABLE” clause.  Pull request
     courtesy Mark Sandan.

   * `[sql] [feature]' ¶. Negative integer indexes are now
     accommodated by rows returned from a ‘ResultProxy’.  Pull request
     courtesy Emanuele Gaifas.

     See also
     ........

     See Negative integer indexes accommodated by Core result rows.

   * `[sql] [feature]' ¶. Added Select.lateral().
     and related constructs to allow for the SQL standard LATERAL
     keyword, currently only supported by PostgreSQL.

     See also
     ........

     See Support for the SQL LATERAL keyword.

     References: #2857(3)

   * `[sql] [feature]' ¶. Added support for rendering “FULL
     OUTER JOIN” to both Core and ORM. Pull request courtesy Stefan
     Urbanek.

     See also
     ........

     See Core and ORM support for FULL OUTER JOIN.

     References: #1957(4)

   * `[sql] [feature]' ¶. CTE functionality has been
     expanded to support all DML, allowing INSERT, UPDATE, and DELETE
     statements to both specify their own WITH clause, as well as for
     these statements themselves to be CTE expressions when they include
     a RETURNING clause.

     See also
     ........

     See CTE Support for INSERT, UPDATE, DELETE.

     References: #2551(5)

   * `[sql] [feature]' ¶. Added support for PEP-435-style
     enumerated classes, namely Python 3’s ‘enum.Enum’ class but also
     including compatible enumeration libraries, to the Enum
     datatype.  The Enum datatype now also performs
     in-Python validation of incoming values, and adds an option to
     forego creating the CHECK constraint Enum.create_constraint.
     Pull request courtesy Alex Grönholm.

     See also
     ........

     See Support for Python’s native enum type and compatible forms.

     See The Enum type now does in-Python validation of values.

     References: #3095(6), #3292(7)

   * `[sql] [feature]' ¶. A deep improvement to the recently
     added TextClause.columns() method, and its interaction
     with result-row processing, now allows the columns passed to the
     method to be positionally matched with the result columns in the
     statement, rather than matching on name alone.  The advantage to
     this includes that when linking a textual SQL statement to an ORM
     or Core table model, no system of labeling or de-duping of common
     column names needs to occur, which also means there’s no need to
     worry about how label names match to ORM columns and so-forth.  In
     addition, the ‘ResultProxy’ has been further enhanced to map column
     and string keys to a row with greater precision in some cases.

     See also
     ........

     See ResultSet column matching enhancements; positional column setup for textual SQL.
     - feature overview

     See TextClause.columns() will match columns positionally, not by name, when passed positionally.
     - backwards compatibility
     remarks

     References: #3501(8)

   * `[sql] [feature]' ¶. Added a new type to core
     JSON.  This is the base of the PostgreSQL JSON
     type as well as that of the new JSON type, so that a
     PG/MySQL-agnostic JSON column may be used.  The type features basic
     index and path searching support.

     See also
     ........

     See JSON support added to Core.

     References: #3619(9)

   * `[sql] [feature]' ¶. Added support for “set-aggregate”
     functions of the form ‘<function> WITHIN GROUP (ORDER BY
     <criteria>)’, using the method
     FunctionElement.within_group().  A series of common
     set-aggregate functions with return types derived from the set have
     been added.  This includes functions like percentile_cont,
     see dense_rank and others.

     See also
     ........

     See New Function features, “WITHIN GROUP”, array_agg and set aggregate functions.

     References: #1370(10)

   * `[sql] [feature] [postgresql]' ¶. Added support for the
     SQL-standard function array_agg, which automatically
     returns an ARRAY of the correct type and supports index
     / slice operations, as well as array_agg(), which
     returns a ARRAY with additional comparison features.
     As arrays are only supported on PostgreSQL at the moment, only
     actually works on PostgreSQL. Also added a new construct
     aggregate_order_by in support of PG’s “ORDER BY” extension.

     See also
     ........

     See New Function features, “WITHIN GROUP”, array_agg and set aggregate functions.

     References: #3132(11)

   * `[sql] [feature]' ¶. Added a new type to core
     ARRAY.  This is the base of the PostgreSQL ARRAY
     type, and is now part of Core to begin supporting various
     SQL-standard array-supporting features including some functions and
     eventual support for native arrays on other databases that have an
     “array” concept, such as DB2 or Oracle.  Additionally, new
     operators any_() and all_() have been
     added.  These support not just array constructs on PostgreSQL, but
     also subqueries that are usable on MySQL (but sadly not on
     PostgreSQL).

     See also
     ........

     See Array support added to Core; new ANY and ALL operators.

     References: #3516(12)

   * `[sql] [change] [mysql]' ¶. The system by which a
     Column considers itself to be an “auto increment” column has
     been changed, such that autoincrement is no longer implicitly
     enabled for a Table that has a composite primary key.
     In order to accommodate being able to enable autoincrement for a
     composite PK member column while at the same time maintaining
     SQLAlchemy’s long standing behavior of enabling implicit
     autoincrement for a single integer primary key, a third state has
     been added to the Column.autoincrement parameter
     ‘"auto"’, which is now the default.

     See also
     ........

     See The .autoincrement directive is no longer implicitly enabled for a composite primary key column.

     See No more generation of an implicit KEY for composite primary key w/ AUTO_INCREMENT.

     References: #3216(13)

   * `[sql] [bug]' ¶. ‘FromClause.count()’ is deprecated.
     This function makes use of an arbitrary column in the table and is
     not reliable; for Core use, ‘func.count()’ should be preferred.

     References: #3724(14)

   * `[sql] [bug]' ¶. Fixed an assertion that would raise
     somewhat inappropriately if a Index were associated
     with a Column that is associated with a lower-case-t
     TableClause; the association should be ignored for the
     purposes of associating the index with a Table.

     References: #3616(15)

   * `[sql] [bug]' ¶. The type_coerce().
     construct is now a fully fledged Core expression element which is
     late-evaluated at compile time.  Previously, the function was only
     a conversion function which would handle different expression
     inputs by returning either a Label of a column-oriented
     expression or a copy of a given BindParameter object,
     which in particular prevented the operation from being logically
     maintained when an ORM-level expression transformation would
     convert a column to a bound parameter (e.g.  for lazy loading).

     See also
     ........

     See The type_coerce function is now a persistent SQL element.

     References: #3531(16)

   * `[sql] [bug]' ¶. The TypeDecorator type
     extender will now work in conjunction with a SchemaType
     implementation, typically Enum or Boolean
     with regards to ensuring that the per-table events are
     propagated from the implementation type to the outer type.  These
     events are used to ensure that the constraints or PostgreSQL types
     (e.g.  ENUM) are correctly created (and possibly dropped) along
     with the parent table.

     See also
     ........

     See TypeDecorator now works with Enum, Boolean, “schema” types automatically.

     References: #2919(17)

   * `[sql] [bug]' ¶. The behavior of the union()
     construct and related constructs such as Query.union()
     now handle the case where the embedded SELECT statements need
     to be parenthesized due to the fact that they include LIMIT, OFFSET
     and/or ORDER BY. These queries `do not work on SQLite', and will
     fail on that backend as they did before, but should now work on all
     other backends.

     See also
     ........

     See A UNION or similar of SELECTs with LIMIT/OFFSET/ORDER BY now parenthesizes the embedded selects.

     References: #2528(18)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3718

   (2) http://www.sqlalchemy.org/trac/ticket/3049

   (3) http://www.sqlalchemy.org/trac/ticket/2857

   (4) http://www.sqlalchemy.org/trac/ticket/1957

   (5) http://www.sqlalchemy.org/trac/ticket/2551

   (6) http://www.sqlalchemy.org/trac/ticket/3095

   (7) http://www.sqlalchemy.org/trac/ticket/3292

   (8) http://www.sqlalchemy.org/trac/ticket/3501

   (9) http://www.sqlalchemy.org/trac/ticket/3619

   (10) http://www.sqlalchemy.org/trac/ticket/1370

   (11) http://www.sqlalchemy.org/trac/ticket/3132

   (12) http://www.sqlalchemy.org/trac/ticket/3516

   (13) http://www.sqlalchemy.org/trac/ticket/3216

   (14) http://www.sqlalchemy.org/trac/ticket/3724

   (15) http://www.sqlalchemy.org/trac/ticket/3616

   (16) http://www.sqlalchemy.org/trac/ticket/3531

   (17) http://www.sqlalchemy.org/trac/ticket/2919

   (18) http://www.sqlalchemy.org/trac/ticket/2528

8.3.4.112 schema
................

   * `[schema] [enhancement]' ¶. The default generation
     functions passed to Column objects are now run through
     “update_wrapper”, or an equivalent function if a callable
     non-function is passed, so that introspection tools preserve the
     name and docstring of the wrapped function.  Pull request courtesy
     hsum.

8.3.4.113 postgresql
....................

   * `[postgresql] [feature]' ¶. Added support for
     PostgreSQL’s INSERT..ON CONFLICT using a new PostgreSQL-specific
     ‘Insert’ object.  Pull request and extensive efforts here by Robin
     Thomas.

     See also
     ........

     See Support for INSERT..ON CONFLICT (DO UPDATE | DO NOTHING).

     References: #3529(1)

   * `[postgresql] [feature]' ¶. The DDL for DROP INDEX will
     emit “CONCURRENTLY” if the ‘postgresql_concurrently’ flag is set
     upon the Index and if the database in use is detected
     as PostgreSQL version 9.2 or greater.  For CREATE INDEX, database
     version detection is also added which will omit the clause if PG
     version is less than 8.2.  Pull request courtesy Iuri de Silvio.

   * `[postgresql] [feature]' ¶. Added new parameter
     PGInspector.get_view_names.include, allowing specification
     for what kinds of views should be returned.  Currently “plain” and
     “materialized” views are included.  Pull request courtesy Sebastian
     Bank.

     References: #3588(2)

   * `[postgresql] [feature]' ¶. Added
     ‘postgresql_tablespace’ as an argument to Index to
     allow specification of TABLESPACE for an index in PostgreSQL.
     Complements the same-named parameter on Table.  Pull
     request courtesy Benjamin Bertrand.

     References: #3720(3)

   * `[postgresql] [feature]' ¶. Added new parameter
     GenerativeSelect.with_for_update.key_share, which will render
     the ‘FOR NO KEY UPDATE’ version of ‘FOR UPDATE’ and ‘FOR KEY SHARE’
     instead of ‘FOR SHARE’ on the PostgreSQL backend.  Pull request
     courtesy Sergey Skopin.

   * `[postgresql] [feature] [oracle]' ¶. Added new
     parameter GenerativeSelect.with_for_update.skip_locked,
     which will render the ‘SKIP LOCKED’ phrase for a ‘FOR UPDATE’ or
     ‘FOR SHARE’ lock on the PostgreSQL and Oracle backends.  Pull
     request courtesy Jack Zhou.

   * `[postgresql] [feature]' ¶. Added a new dialect for the
     PyGreSQL PostgreSQL dialect.  Thanks to Christoph Zwerschke and
     Kaolin Imago Fire for their efforts.

   * `[postgresql] [feature]' ¶. Added a new constant
     ‘JSON.NULL’, indicating that the JSON NULL value should be used for
     a value regardless of other settings.

     See also
     ........

     See New JSON.NULL Constant Added.

     References: #3514(4)

   * `[postgresql] [change]' ¶. The
     ‘sqlalchemy.dialects.postgres’ module, long deprecated, is removed;
     this has emitted a warning for many years and projects should be
     calling upon ‘sqlalchemy.dialects.postgresql’.  Engine URLs of the
     form ‘postgres://’ will still continue to function, however.

   * `[postgresql] [bug]' ¶. Added support for reflecting
     the source of materialized views to the PostgreSQL version of the
     Inspector.get_view_definition() method.

     References: #3587(5)

   * `[postgresql] [bug]' ¶. The use of a ARRAY.
     object that refers to a Enum or ENUM
     subtype will now emit the expected “CREATE TYPE” and “DROP TYPE”
     DDL when the type is used within a “CREATE TABLE” or “DROP TABLE”.

     See also
     ........

     See ARRAY with ENUM will now emit CREATE TYPE for the ENUM.

     References: #2729(6)

   * `[postgresql] [bug]' ¶. The “hashable” flag on special
     datatypes such as ARRAY, JSON and
     HSTORE is now set to False, which allows these types to be
     fetchable in ORM queries that include entities within the row.

     See also
     ........

     See Changes regarding “unhashable” types, impacts deduping of ORM rows.

     See ARRAY and JSON types now correctly specify “unhashable”.

     References: #3499(7)

   * `[postgresql] [bug]' ¶. The PostgreSQL ARRAY
     type now supports multidimensional indexed access, e.g.
     expressions such as ‘somecol[5][6]’ without any need for explicit
     casts or type coercions, provided that the ARRAY.dimensions
     parameter is set to the desired number of dimensions.

     See also
     ........

     See Correct SQL Types are Established from Indexed Access of ARRAY, JSON, HSTORE.

     References: #3487(8)

   * `[postgresql] [bug]' ¶. The return type for the
     JSON and JSONB when using indexed access has
     been fixed to work like PostgreSQL itself, and returns an
     expression that itself is of type JSON or JSONB.
     Previously, the accessor would return NullType
     which disallowed subsequent JSON-like operators to be used.

     See also
     ........

     See Correct SQL Types are Established from Indexed Access of ARRAY, JSON, HSTORE.

     References: #3503(9)

   * `[postgresql] [bug]' ¶. The JSON,
     JSONB and HSTORE datatypes now allow full
     control over the return type from an indexed textual access
     operation, either ‘column[someindex].astext’ for a JSON type or
     ‘column[someindex]’ for an HSTORE type, via the
     JSON.astext_type and HSTORE.text_type
     parameters.

     See also
     ........

     See Correct SQL Types are Established from Indexed Access of ARRAY, JSON, HSTORE.

     References: #3503(10)

   * `[postgresql] [bug]' ¶. The Comparator.astext
     modifier no longer calls upon ColumnElement.cast()
     implicitly, as PG’s JSON/JSONB types allow cross-casting
     between each other as well.  Code that makes use of
     ColumnElement.cast() on JSON indexed access, e.g.
     ‘col[someindex].cast(Integer)’, will need to be changed to call
     Comparator.astext explicitly.

     See also
     ........

     See The JSON cast() operation now requires .astext is called explicitly.

     References: #3503(11)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3529

   (2) http://www.sqlalchemy.org/trac/ticket/3588

   (3) http://www.sqlalchemy.org/trac/ticket/3720

   (4) http://www.sqlalchemy.org/trac/ticket/3514

   (5) http://www.sqlalchemy.org/trac/ticket/3587

   (6) http://www.sqlalchemy.org/trac/ticket/2729

   (7) http://www.sqlalchemy.org/trac/ticket/3499

   (8) http://www.sqlalchemy.org/trac/ticket/3487

   (9) http://www.sqlalchemy.org/trac/ticket/3503

   (10) http://www.sqlalchemy.org/trac/ticket/3503

   (11) http://www.sqlalchemy.org/trac/ticket/3503

8.3.4.114 mysql
...............

   * `[mysql] [feature]' ¶. Added support for “autocommit”
     on MySQL drivers, via the AUTOCOMMIT isolation level setting.  Pull
     request courtesy Roman Podoliaka.

     See also
     ........

     See Added support for AUTOCOMMIT “isolation level”.

     References: #3332(1)

   * `[mysql] [feature]' ¶. Added JSON for
     MySQL 5.7.  The JSON type provides persistence of JSON values in
     MySQL as well as basic operator support of “getitem” and “getpath”,
     making use of the ‘JSON_EXTRACT’ function in order to refer to
     individual paths in a JSON structure.

     See also
     ........

     See MySQL JSON Support.

     References: #3547(2)

   * `[mysql] [change]' ¶. The MySQL dialect no longer
     generates an extra “KEY” directive when generating CREATE TABLE DDL
     for a table using InnoDB with a composite primary key with
     AUTO_INCREMENT on a column that isn’t the first column; to overcome
     InnoDB’s limitation here, the PRIMARY KEY constraint is now
     generated with the AUTO_INCREMENT column placed first in the list
     of columns.

     See also
     ........

     See No more generation of an implicit KEY for composite primary key w/ AUTO_INCREMENT.

     See The .autoincrement directive is no longer implicitly enabled for a composite primary key column.

     References: #3216(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3332

   (2) http://www.sqlalchemy.org/trac/ticket/3547

   (3) http://www.sqlalchemy.org/trac/ticket/3216

8.3.4.115 sqlite
................

   * `[sqlite] [feature]' ¶. The SQLite dialect now reflects
     ON UPDATE and ON DELETE phrases within foreign key constraints.
     Pull request courtesy Michal Petrucha.

   * `[sqlite] [feature]' ¶. The SQLite dialect now reflects
     the names of primary key constraints.  Pull request courtesy Diana
     Clarke.

     See also
     ........

     See Reflection of the name of PRIMARY KEY constraints.

     References: #3629(1)

   * `[sqlite] [change]' ¶. Added support to the SQLite
     dialect for the Inspector.get_schema_names() method to
     work with SQLite; pull request courtesy Brian Van Klaveren.  Also
     repaired support for creation of indexes with schemas as well as
     reflection of foreign key constraints in schema-bound tables.

     See also
     ........

     See Improved Support for Remote Schemas.

   * `[sqlite] [bug]' ¶. The workaround for right-nested
     joins on SQLite, where they are rewritten as subqueries in order to
     work around SQLite’s lack of support for this syntax, is lifted
     when SQLite version 3.7.16 or greater is detected.

     See also
     ........

     See Right-nested join workaround lifted for SQLite version 3.7.16.

     References: #3634(2)

   * `[sqlite] [bug]' ¶. The workaround for SQLite’s
     unexpected delivery of column names as ‘tablename.columnname’ for
     some kinds of queries is now disabled when SQLite version 3.10.0 or
     greater is detected.

     See also
     ........

     See Dotted column names workaround lifted for SQLite version 3.10.0.

     References: #3633(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3629

   (2) http://www.sqlalchemy.org/trac/ticket/3634

   (3) http://www.sqlalchemy.org/trac/ticket/3633

8.3.4.116 mssql
...............

   * `[mssql] [feature]' ¶. The ‘mssql_clustered’ flag
     available on UniqueConstraint,
     PrimaryKeyConstraint, Index now defaults to ‘None’,
     and can be set to False which will render the NONCLUSTERED keyword
     in particular for a primary key, allowing a different index to be
     used as “clustered”.  Pull request courtesy Saulius Žemaitaitis.

   * `[mssql] [feature]' ¶. Added basic isolation level
     support to the SQL Server dialects via
     create_engine.isolation_level and
     Connection.execution_options.isolation_level parameters.

     See also
     ........

     See Added transaction isolation level support for SQL Server.

     References: #3534(1)

   * `[mssql] [change]' ¶. The ‘legacy_schema_aliasing’
     flag, introduced in version 1.0.5 as part of #3424(2) to allow
     disabling of the MSSQL dialect’s attempts to create aliases for
     schema-qualified tables, now defaults to False; the old behavior is
     now disabled unless explicitly turned on.

     See also
     ........

     See The legacy_schema_aliasing flag is now set to False.

     References: #3434(3)

   * `[mssql] [bug]' ¶. Adjustments to the mxODBC dialect to
     make use of the ‘BinaryNull’ symbol when appropriate in conjunction
     with the ‘VARBINARY’ data type.  Pull request courtesy Sheila
     Allen.

   * `[mssql] [bug]' ¶. Fixed issue where the SQL Server
     dialect would reflect a string- or other variable-length column
     type with unbounded length by assigning the token ‘"max"’ to the
     length attribute of the string.  While using the ‘"max"’ token
     explicitly is supported by the SQL Server dialect, it isn’t part of
     the normal contract of the base string types, and instead the
     length should just be left as None.  The dialect now assigns the
     length to None on reflection of the type so that the type behaves
     normally in other contexts.

     See also
     ........

     See String / varlength types no longer represent “max” explicitly on reflection.

     References: #3504(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3534

   (2) http://www.sqlalchemy.org/trac/ticket/3424

   (3) http://www.sqlalchemy.org/trac/ticket/3434

   (4) http://www.sqlalchemy.org/trac/ticket/3504

8.3.4.117 misc
..............

   * `[feature] [ext]' ¶. Added MutableSet and
     MutableList helper classes to the Mutation Tracking
     extension.  Pull request courtesy Jeong YunWon.

     References: #3297(1)

   * `[bug] [ext]' ¶. The docstring specified on a hybrid
     property or method is now honored at the class level, allowing it
     to work with tools like Sphinx autodoc.  The mechanics here
     necessarily involve some wrapping of expressions to occur for
     hybrid properties, which may cause them to appear differently using
     introspection.

     See also
     ........

     See Hybrid properties and methods now propagate the docstring as well as .info.

     References: #3653(2)

   * `[bug] [sybase]' ¶. The unsupported Sybase dialect now
     raises ‘NotImplementedError’ when attempting to compile a query
     that includes “offset”; Sybase has no straightforward “offset”
     feature.

     References: #2278(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3297

   (2) http://www.sqlalchemy.org/trac/ticket/3653

   (3) http://www.sqlalchemy.org/trac/ticket/2278

8.3.5.1 1.0.19
..............

Released: August 3, 2017

8.3.5.2 oracle
..............

   * `[oracle] [performance] [bug] [py2k]' ¶. Fixed
     performance regression caused by the fix for #3937(1) where
     cx_Oracle as of version 5.3 dropped the ‘.UNICODE’ symbol from its
     namespace, which was interpreted as cx_Oracle’s “WITH_UNICODE” mode
     being turned on unconditionally, which invokes functions on the
     SQLAlchemy side which convert all strings to unicode
     unconditionally and causing a performance impact.  In fact, per
     cx_Oracle’s author the “WITH_UNICODE” mode has been removed
     entirely as of 5.1, so the expensive unicode conversion functions
     are no longer necessary and are disabled if cx_Oracle 5.1 or
     greater is detected under Python 2.  The warning against
     “WITH_UNICODE” mode that was removed under #3937(2) is also
     restored.

     References: #4035(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3937

   (2) http://www.sqlalchemy.org/trac/ticket/3937

   (3) http://www.sqlalchemy.org/trac/ticket/4035

8.3.5.3 1.0.18
..............

Released: July 24, 2017

8.3.5.4 oracle
..............

   * `[oracle] [bug]' ¶. A fix to cx_Oracle’s WITH_UNICODE
     mode which was uncovered by the fact that cx_Oracle 5.3 now seems
     to hardcode this flag on in the build; an internal method that uses
     this mode wasn’t using the correct signature.

     References: #3937(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3937

8.3.5.5 misc
............

   * `[bug] [py3k] [tests]' ¶. Fixed issue in testing
     fixtures which was incompatible with a change made as of Python
     3.6.2 involving context managers.

     References: #4034(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4034

8.3.5.6 1.0.17
..............

Released: January 17, 2017

8.3.5.7 orm
...........

   * `[orm] [bug]' ¶. Fixed bug involving joined eager
     loading against multiple entities when polymorphic inheritance is
     also in use which would throw “‘NoneType’ object has no attribute
     ‘isa’”.  The issue was introduced by the fix for #3611(1).

     References: #3884(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3611

   (2) http://www.sqlalchemy.org/trac/ticket/3884

8.3.5.8 misc
............

   * `[bug] [py3k]' ¶. Fixed Python 3.6 DeprecationWarnings
     related to escaped strings without the ‘r’ modifier, and added test
     coverage for Python 3.6.

     References: #3886(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3886

8.3.5.9 1.0.16
..............

Released: November 15, 2016

8.3.5.10 orm
............

   * `[orm] [bug]' ¶. Fixed bug in
     Session.bulk_update_mappings() where an alternate-named
     primary key attribute would not track properly into the UPDATE
     statement.

     References: #3849(1)

   * `[orm] [bug]' ¶. Fixed bug where joined eager loading
     would fail for a polymorphically- loaded mapper, where the
     polymorphic_on was set to an un-mapped expression such as a CASE
     expression.

     References: #3800(2)

   * `[orm] [bug]' ¶. Fixed bug where the ArgumentError
     raised for an invalid bind sent to a Session via
     Session.bind_mapper(), Session.bind_table(), or the
     constructor would fail to be correctly raised.

     References: #3798(3)

   * `[orm] [bug]' ¶. Fixed bug in ‘Session.bulk_save()’
     where an UPDATE would not function correctly in conjunction with a
     mapping that implements a version id counter.

     References: #3781(4)

   * `[orm] [bug]' ¶. Fixed bug where the
     Mapper.attrs, Mapper.all_orm_descriptors and other
     derived attributes would fail to refresh when mapper properties or
     other ORM constructs were added to the mapper/class after these
     accessors were first called.

     References: #3778(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3849

   (2) http://www.sqlalchemy.org/trac/ticket/3800

   (3) http://www.sqlalchemy.org/trac/ticket/3798

   (4) http://www.sqlalchemy.org/trac/ticket/3781

   (5) http://www.sqlalchemy.org/trac/ticket/3778

8.3.5.11 mssql
..............

   * `[mssql] [bug]' ¶. Changed the query used to get
     “default schema name”, from one that queries the database
     principals table to using the “schema_name()” function, as issues
     have been reported that the former system was unavailable on the
     Azure Data Warehouse edition.  It is hoped that this will finally
     work across all SQL Server versions and authentication styles.

     References: #3810(1)

   * `[mssql] [bug]' ¶. Updated the server version info
     scheme for pyodbc to use SQL Server SERVERPROPERTY(), rather than
     relying upon pyodbc.SQL_DBMS_VER, which continues to be unreliable
     particularly with FreeTDS.

     References: #3814(2)

   * `[mssql] [bug]' ¶. Added error code 20017 “unexpected
     EOF from the server” to the list of disconnect exceptions that
     result in a connection pool reset.  Pull request courtesy Ken
     Robbins.

     References: #3791(3)

   * `[mssql] [bug]' ¶. Fixed bug in pyodbc dialect (as well
     as in the mostly non-working adodbapi dialect) whereby a semicolon
     present in the password or username fields could be interpreted as
     a separator for another token; the values are now quoted when
     semicolons are present.

     References: #3762(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3810

   (2) http://www.sqlalchemy.org/trac/ticket/3814

   (3) http://www.sqlalchemy.org/trac/ticket/3791

   (4) http://www.sqlalchemy.org/trac/ticket/3762

8.3.5.12 misc
.............

   * `[bug] [orm.declarative]' ¶. Fixed bug where setting up
     a single-table inh subclass of a joined-table subclass which
     included an extra column would corrupt the foreign keys collection
     of the mapped table, thereby interfering with the initialization of
     relationships.

     References: #3797(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3797

8.3.5.13 1.0.15
...............

Released: September 1, 2016

8.3.5.14 orm
............

   * `[orm] [bug]' ¶. Fixed bug in subquery eager loading
     where a subqueryload of an “of_type()” object linked to a second
     subqueryload of a plain mapped class, or a longer chain of several
     “of_type()” attributes, would fail to link the joins correctly.

     References: #3773(1), #3774(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3773

   (2) http://www.sqlalchemy.org/trac/ticket/3774

8.3.5.15 sql
............

   * `[sql] [bug]' ¶. Fixed bug in Table where
     the internal method ‘_reset_exported()’ would corrupt the state of
     the object.  This method is intended for selectable objects and is
     called by the ORM in some cases; an erroneous mapper configuration
     would could lead the ORM to call this on a Table object.

     References: #3755(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3755

8.3.5.16 mysql
..............

   * `[mysql] [bug]' ¶. Added support for parsing
     MySQL/Connector boolean and integer arguments within the URL query
     string: connection_timeout, connect_timeout, pool_size,
     get_warnings, raise_on_warnings, raw, consume_results,
     ssl_verify_cert, force_ipv6, pool_reset_session, compress,
     allow_local_infile, use_pure.

     References: #3787(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3787

8.3.5.17 misc
.............

   * `[bug] [ext]' ¶. Fixed bug in ‘sqlalchemy.ext.baked’
     where the unbaking of a subquery eager loader query would fail due
     to a variable scoping issue, when multiple subquery loaders were
     involved.  Pull request courtesy Mark Hahnenberg.

     References: #3743(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3743

8.3.5.18 1.0.14
...............

Released: July 6, 2016

8.3.5.19 engine
...............

   * `[engine] [bug] [postgresql]' ¶. Fixed bug in
     cross-schema foreign key reflection in conjunction with the
     MetaData.schema argument, where a referenced table that is
     present in the “default” schema would fail since there would be no
     way to indicate a Table that has “blank” for a schema.
     The special symbol ‘sqlalchemy.schema.BLANK_SCHEMA’ has been added
     as an available value for Table.schema and
     Sequence.schema, indicating that the schema name should be
     forced to be ‘None’ even if MetaData.schema is
     specified.

     References: #3716(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3716

8.3.5.20 sql
............

   * `[sql] [bug]' ¶. Fixed issue in SQL math negation
     operator where the type of the expression would no longer be the
     numeric type of the original.  This would cause issues where the
     type determined result set behaviors.

     References: #3735(1)

   * `[sql] [bug]' ¶. Fixed bug whereby the ‘__getstate__’ /
     ‘__setstate__’ methods for sqlalchemy.util.Properties were
     non-working due to the transition in the 1.0 series to ‘__slots__’.
     The issue potentially impacted some third-party applications.  Pull
     request courtesy Pieter Mulder.

     References: #3728(2)

   * `[sql] [bug]' ¶. ‘FromClause.count()’ is pending
     deprecation for 1.1.  This function makes use of an arbitrary
     column in the table and is not reliable; for Core use,
     ‘func.count()’ should be preferred.

     References: #3724(3)

   * `[sql] [bug]' ¶. Fixed bug in CTE structure
     which would cause it to not clone properly when a union was used,
     as is common in a recursive CTE. The improper cloning would cause
     errors when the CTE is used in various ORM contexts such as that of
     a column_property().

     References: #3722(4)

   * `[sql] [bug]' ¶. Fixed bug whereby
     Table.tometadata() would make a duplicate
     UniqueConstraint for each Column object that
     featured the ‘unique=True’ parameter.

     References: #3721(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3735

   (2) http://www.sqlalchemy.org/trac/ticket/3728

   (3) http://www.sqlalchemy.org/trac/ticket/3724

   (4) http://www.sqlalchemy.org/trac/ticket/3722

   (5) http://www.sqlalchemy.org/trac/ticket/3721

8.3.5.21 postgresql
...................

   * `[postgresql] [bug]' ¶. Fixed bug whereby
     TypeDecorator and Variant types were not deeply
     inspected enough by the PostgreSQL dialect to determine if
     SMALLSERIAL or BIGSERIAL needed to be rendered rather than SERIAL.

     References: #3739(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3739

8.3.5.22 oracle
...............

   * `[oracle] [bug]' ¶. Fixed bug in
     Select.with_for_update.of, where the Oracle “rownum” approach
     to LIMIT/OFFSET would fail to accommodate for the expressions
     inside the “OF” clause, which must be stated at the topmost level
     referring to expression within the subquery.  The expressions are
     now added to the subquery if needed.

     References: #3741(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3741

8.3.5.23 misc
.............

   * `[bug] [examples]' ¶. Fixed a regression that occurred
     in the examples/vertical/dictlike-polymorphic.py example which
     prevented it from running.

     References: #3704(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3704

8.3.5.24 1.0.13
...............

Released: May 16, 2016

8.3.5.25 orm
............

   * `[orm] [bug]' ¶. Fixed bug in “evaluate” strategy of
     Query.update() and Query.delete() which
     would fail to accommodate a bound parameter with a “callable”
     value, as which occurs when filtering by a many-to-one equality
     expression along a relationship.

     References: #3700(1)

   * `[orm] [bug]' ¶. Fixed bug whereby the event listeners
     used for backrefs could be inadvertently applied multiple times,
     when using a deep class inheritance hierarchy in conjunction with
     multiple mapper configuration steps.

     References: #3710(2)

   * `[orm] [bug]' ¶. Fixed bug whereby passing a
     text() construct to the Query.group_by() method
     would raise an error, instead of interpreting the object as a SQL
     fragment.

     References: #3706(3)

   * `[orm] [bug]' ¶. Anonymous labeling is applied to a
     ‘func’ construct that is passed to column_property(), so
     that if the same attribute is referred to as a column expression
     twice the names are de-duped, thus avoiding “ambiguous column”
     errors.  Previously, the ‘.label(None)’ would need to be applied in
     order for the name to be de-anonymized.

     References: #3663(4)

   * `[orm] [bug]' ¶. Fixed regression appearing in the 1.0
     series in ORM loading where the exception raised for an expected
     column missing would incorrectly be a ‘NoneType’ error, rather than
     the expected NoSuchColumnError.

     References: #3658(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3700

   (2) http://www.sqlalchemy.org/trac/ticket/3710

   (3) http://www.sqlalchemy.org/trac/ticket/3706

   (4) http://www.sqlalchemy.org/trac/ticket/3663

   (5) http://www.sqlalchemy.org/trac/ticket/3658

8.3.5.26 sql
............

   * `[sql] [bug]' ¶. Fixed bug where when using
     ‘case_sensitive=False’ with an Engine, the result set
     would fail to correctly accommodate for duplicate column names in
     the result set, causing an error when the statement is executed in
     1.0, and preventing the “ambiguous column” exception from
     functioning in 1.1.

     References: #3690(1)

   * `[sql] [bug]' ¶. Fixed bug where the negation of an
     EXISTS expression would not be properly typed as boolean in the
     result, and also would fail to be anonymously aliased in a SELECT
     list as is the case with a non-negated EXISTS construct.

     References: #3682(2)

   * `[sql] [bug]' ¶. Fixed bug where “unconsumed column
     names” exception would fail to be raised in the case where
     Insert.values() were called with a list of parameter mappings,
     instead of a single mapping of parameters.  Pull request courtesy
     Athena Yao.

     References: #3666(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3690

   (2) http://www.sqlalchemy.org/trac/ticket/3682

   (3) http://www.sqlalchemy.org/trac/ticket/3666

8.3.5.27 postgresql
...................

   * `[postgresql] [bug]' ¶. Added disconnect detection
     support for the error string “SSL error: decryption failed or bad
     record mac”.  Pull request courtesy Iuri de Silvio.

     References: #3715(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3715

8.3.5.28 mssql
..............

   * `[mssql] [bug]' ¶. Fixed bug where by ROW_NUMBER OVER
     clause applied for OFFSET selects in SQL Server would
     inappropriately substitute a plain column from the local statement
     that overlaps with a label name used by the ORDER BY criteria of
     the statement.

     References: #3711(1)

   * `[mssql] [bug] [oracle]' ¶. Fixed regression appearing
     in the 1.0 series which would cause the Oracle and SQL Server
     dialects to incorrectly account for result set columns when these
     dialects would wrap a SELECT in a subquery in order to provide
     LIMIT/OFFSET behavior, and the original SELECT statement referred
     to the same column multiple times, such as a column and a label of
     that same column.  This issue is related to #3658(2) in that when
     the error occurred, it would also cause a ‘NoneType’ error, rather
     than reporting that it couldn’t locate a column.

     References: #3657(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3711

   (2) http://www.sqlalchemy.org/trac/ticket/3658

   (3) http://www.sqlalchemy.org/trac/ticket/3657

8.3.5.29 oracle
...............

   * `[oracle] [bug]' ¶. Fixed a bug in the cx_Oracle
     connect process that caused a TypeError when the either the user,
     password or dsn was empty.  This prevented external authentication
     to Oracle databases, and prevented connecting to the default dsn.
     The connect string oracle:// now logs into the default dsn using
     the Operating System username, equivalent to connecting using ‘/’
     with sqlplus.

     References: #3705(1)

   * `[oracle] [bug]' ¶. Fixed a bug in the result proxy
     used mainly by Oracle when binary and other LOB types are in play,
     such that when query / statement caching were used, the type-level
     result processors, notably that required by the binary type itself
     but also any other processor, would become lost after the first run
     of the statement due to it being removed from the cached result
     metadata.

     References: #3699(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3705

   (2) http://www.sqlalchemy.org/trac/ticket/3699

8.3.5.30 misc
.............

   * `[bug] [examples]' ¶. Changed the “directed graph”
     example to no longer consider integer identifiers of nodes as
     significant; the “higher” / “lower” references now allow mutual
     edges in both directions.

     References: #3698(1)

   * `[bug] [py3k]' ¶. Fixed bug in “to_list” conversion
     where a single bytes object would be turned into a list of
     individual characters.  This would impact among other things using
     the Query.get() method on a primary key that’s a bytes
     object.

     References: #3660(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3698

   (2) http://www.sqlalchemy.org/trac/ticket/3660

8.3.5.31 1.0.12
...............

Released: February 15, 2016

8.3.5.32 orm
............

   * `[orm] [bug]' ¶. Fixed bug in Session.merge()
     where an object with a composite primary key that has values
     for some but not all of the PK fields would emit a SELECT statement
     leaking the internal NEVER_SET symbol into the query, rather than
     detecting that this object does not have a searchable primary key
     and no SELECT should be emitted.

     References: #3647(1)

   * `[orm] [bug]' ¶. Fixed regression since 0.9 where the
     0.9 style loader options system failed to accommodate for multiple
     undefer_group() loader options in a single query.
     Multiple undefer_group() options will now be taken into
     account even against the same entity.

     References: #3623(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3647

   (2) http://www.sqlalchemy.org/trac/ticket/3623

8.3.5.33 engine
...............

   * `[engine] [bug] [mysql]' ¶. Revisiting #2696(1), first
     released in 1.0.10, which attempts to work around Python 2’s lack
     of exception context reporting by emitting a warning for an
     exception that was interrupted by a second exception when
     attempting to roll back the already-failed transaction; this issue
     continues to occur for MySQL backends in conjunction with a
     savepoint that gets unexpectedly lost, which then causes a “no such
     savepoint” error when the rollback is attempted, obscuring what the
     original condition was.

     The approach has been generalized to the Core “safe reraise”
     function which takes place across the ORM and Core in any place
     that a transaction is being rolled back in response to an error
     which occurred trying to commit, including the context managers
     provided by Session and Connection, and
     taking place for operations such as a failure on “RELEASE
     SAVEPOINT”.  Previously, the fix was only in place for a specific
     path within the ORM flush/commit process; it now takes place for
     all transactional context managers as well.

     References: #2696(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2696

   (2) http://www.sqlalchemy.org/trac/ticket/2696

8.3.5.34 sql
............

   * `[sql] [bug]' ¶. Fixed issue where the “literal_binds”
     flag was not propagated for insert(), update()
     or delete() constructs when compiled to string
     SQL. Pull request courtesy Tim Tate.

     References: #3643(1)

   * `[sql] [bug]' ¶. Fixed issue where inadvertent use of
     the Python ‘__contains__’ override with a column expression (e.g.
     by using ‘'x' in col’) would cause an endless loop in the case of
     an ARRAY type, as Python defers this to ‘__getitem__’ access which
     never raises for this type.  Overall, all use of ‘__contains__’ now
     raises NotImplementedError.

     References: #3642(2)

   * `[sql] [bug]' ¶. Fixed bug in Table metadata
     construct which appeared around the 0.9 series where adding columns
     to a Table that was unpickled would fail to correctly
     establish the Column within the ‘c’ collection, leading
     to issues in areas such as ORM configuration.  This could impact
     use cases such as ‘extend_existing’ and others.

     References: #3632(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3643

   (2) http://www.sqlalchemy.org/trac/ticket/3642

   (3) http://www.sqlalchemy.org/trac/ticket/3632

8.3.5.35 postgresql
...................

   * `[postgresql] [bug]' ¶. Fixed bug in text().
     construct where a double-colon expression would not escape
     properly, e.g.  ‘some\:\:expr’, as is most commonly required when
     rendering PostgreSQL-style CAST expressions.

     References: #3644(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3644

8.3.5.36 mssql
..............

   * `[mssql] [bug]' ¶. Fixed the syntax of the
     extract() function when used on MSSQL against a datetime
     value; the quotes around the keyword are removed.  Pull request
     courtesy Guillaume Doumenc.

     References: #3624(1)

   * `[mssql] [bug] [firebird]' ¶. Fixed 1.0 regression
     where the eager fetch of cursor.rowcount was no longer called for
     an UPDATE or DELETE statement emitted via plain text or via the
     text() construct, affecting those drivers that erase
     cursor.rowcount once the cursor is closed such as SQL Server ODBC
     and Firebird drivers.

     References: #3622(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3624

   (2) http://www.sqlalchemy.org/trac/ticket/3622

8.3.5.37 oracle
...............

   * `[oracle] [bug] [jython]' ¶. Fixed a small issue in the
     Jython Oracle compiler involving the rendering of “RETURNING” which
     allows this currently unsupported/untested dialect to work
     rudimentally with the 1.0 series.  Pull request courtesy Carlos
     Rivas.

     References: #3621(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3621

8.3.5.38 misc
.............

   * `[bug] [py3k]' ¶. Fixed bug where some exception
     re-raise scenarios would attach the exception to itself as the
     “cause”; while the Python 3 interpreter is OK with this, it could
     cause endless loops in iPython.

     References: #3625(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3625

8.3.5.39 1.0.11
...............

Released: December 22, 2015

8.3.5.40 orm
............

   * `[orm] [bug]' ¶. Fixed regression caused in 1.0.10 by
     the fix for #3593(1) where the check added for a polymorphic
     joinedload from a poly_subclass->class->poly_baseclass connection
     would fail for the scenario of class->poly_subclass->class.

     References: #3611(2)

   * `[orm] [bug]' ¶. Fixed bug where
     Session.bulk_update_mappings() and related would not bump a
     version id counter when in use.  The experience here is still a
     little rough as the original version id is required in the given
     dictionaries and there’s not clean error reporting on that yet.

     References: #3610(3)

   * `[orm] [bug]' ¶. Major fixes to the
     Mapper.eager_defaults flag, this flag would not be honored
     correctly in the case that multiple UPDATE statements were to be
     emitted, either as part of a flush or a bulk update operation.
     Additionally, RETURNING would be emitted unnecessarily within
     update statements.

     References: #3609(4)

   * `[orm] [bug]' ¶. Fixed bug where use of the
     Query.select_from() method would cause a subsequent call to
     the Query.with_parent() method to fail.

     References: #3606(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3593

   (2) http://www.sqlalchemy.org/trac/ticket/3611

   (3) http://www.sqlalchemy.org/trac/ticket/3610

   (4) http://www.sqlalchemy.org/trac/ticket/3609

   (5) http://www.sqlalchemy.org/trac/ticket/3606

8.3.5.41 sql
............

   * `[sql] [bug]' ¶. Fixed bug in
     ‘Update.return_defaults()’ which would cause all insert-default
     holding columns not otherwise included in the SET clause (such as
     primary key cols) to get rendered into the RETURNING even though
     this is an UPDATE.

     References: #3609(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3609

8.3.5.42 mysql
..............

   * `[mysql] [bug]' ¶. An adjustment to the regular
     expression used to parse MySQL views, such that we no longer assume
     the “ALGORITHM” keyword is present in the reflected view source, as
     some users have reported this not being present in some Amazon RDS
     environments.

     References: #3613(1)

   * `[mysql] [bug]' ¶. Added new reserved words for MySQL
     5.7 to the MySQL dialect, including ‘generated’, ‘optimizer_costs’,
     ‘stored’, ‘virtual’.  Pull request courtesy Hanno Schlichting.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3613

8.3.5.43 misc
.............

   * `[bug] [ext]' ¶. Further fixes to #3605(1), pop method
     on MutableDict, where the “default” argument was not
     included.

     References: #3605(2)

   * `[bug] [ext]' ¶. Fixed bug in baked loader system where
     the systemwide monkeypatch for setting up baked lazy loaders would
     interfere with other loader strategies that rely on lazy loading as
     a fallback, e.g.  joined and subquery eager loaders, leading to
     ‘IndexError’ exceptions at mapper configuration time.

     References: #3612(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3605

   (2) http://www.sqlalchemy.org/trac/ticket/3605

   (3) http://www.sqlalchemy.org/trac/ticket/3612

8.3.5.44 1.0.10
...............

Released: December 11, 2015

8.3.5.45 orm
............

   * `[orm] [bug]' ¶. Fixed issue where post_update on a
     many-to-one relationship would fail to emit an UPDATE in the case
     where the attribute were set to None and not previously loaded.

     References: #3599(1)

   * `[orm] [bug]' ¶. Fixed bug which is actually a
     regression that occurred between versions 0.8.0 and 0.8.1, due
     #2714(2).  The case where joined eager loading needs to join out
     over a subclass-bound relationship when “with_polymorphic” were
     also used would fail to join from the correct entity.

     References: #3593(3)

   * `[orm] [bug]' ¶. Fixed joinedload bug which would occur
     when a.  the query includes limit/offset criteria that forces a
     subquery b.  the relationship uses “secondary” c.  the primaryjoin
     of the relationship refers to a column that is either not part of
     the primary key, or is a PK col in a joined-inheritance subclass
     table that is under a different attribute name than the parent
     table’s primary key column d.  the query defers the columns that
     are present in the primaryjoin, typically via not being included in
     load_only(); the necessary column(s) would not be present in the
     subquery and produce invalid SQL.

     References: #3592(4)

   * `[orm] [bug]' ¶. A rare case which occurs when a
     Session.rollback() fails in the scope of a
     Session.flush() operation that’s raising an exception, as has
     been observed in some MySQL SAVEPOINT cases, prevents the original
     database exception from being observed when it was emitted during
     flush, but only on Py2K because Py2K does not support exception
     chaining; on Py3K the originating exception is chained.  As a
     workaround, a warning is emitted in this specific case showing at
     least the string message of the original database error before we
     proceed to raise the rollback-originating exception.

     References: #2696(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3599

   (2) http://www.sqlalchemy.org/trac/ticket/2714

   (3) http://www.sqlalchemy.org/trac/ticket/3593

   (4) http://www.sqlalchemy.org/trac/ticket/3592

   (5) http://www.sqlalchemy.org/trac/ticket/2696

8.3.5.46 orm declarative
........................

   * `[orm] [declarative] [bug]' ¶. Fixed bug where in Py2K
     a unicode literal would not be accepted as the string name of a
     class or other argument within declarative using backref()
     on relationship().  Pull request courtesy Nils
     Philippsen.

8.3.5.47 sql
............

   * `[sql] [feature]' ¶. Added support for
     parameter-ordered SET clauses in an UPDATE statement.  This feature
     is available by passing the update.preserve_parameter_order
     flag either to the core Update construct or
     alternatively adding it to the Query.update.update_args
     dictionary at the ORM-level, also passing the parameters themselves
     as a list of 2-tuples.  Thanks to Gorka Eguileor for implementation
     and tests.

     See also
     ........

     See Parameter-Ordered Updates.

   * `[sql] [bug]' ¶. Fixed issue within the
     Insert.from_select() construct whereby the Select
     construct would have its ‘._raw_columns’ collection mutated
     in-place when compiling the Insert construct, when the
     target Table has Python-side defaults.  The
     Select construct would compile standalone with the erroneous
     column present subsequent to compilation of the Insert,
     and the Insert statement itself would fail on a second
     compile attempt due to duplicate bound parameters.

     References: #3603(1)

   * `[sql] [bug] [postgresql]' ¶. Fixed bug where CREATE
     TABLE with a no-column table, but a constraint such as a CHECK
     constraint would render an erroneous comma in the definition; this
     scenario can occur such as with a PostgreSQL INHERITS table that
     has no columns of its own.

     References: #3598(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3603

   (2) http://www.sqlalchemy.org/trac/ticket/3598

8.3.5.48 postgresql
...................

   * `[postgresql] [bug]' ¶. Fixed issue where the “FOR
     UPDATE OF” PostgreSQL-specific SELECT modifier would fail if the
     referred table had a schema qualifier; PG needs the schema name to
     be omitted.  Pull request courtesy Diana Clarke.

     References: #3573(1)

   * `[postgresql] [bug]' ¶. Fixed bug where some varieties
     of SQL expression passed to the “where” clause of
     ExcludeConstraint would fail to be accepted correctly.  Pull
     request courtesy aisch.

   * `[postgresql] [bug]' ¶. Fixed the ‘.python_type’
     attribute of INTERVAL to return ‘datetime.timedelta’
     in the same way as that of python_type, rather than
     raising ‘NotImplementedError’.

     References: #3571(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3573

   (2) http://www.sqlalchemy.org/trac/ticket/3571

8.3.5.49 mysql
..............

   * `[mysql] [bug]' ¶. Fixed bug in MySQL reflection where
     the “fractional sections portion” of the DATETIME,
     TIMESTAMP and TIME types would be
     incorrectly placed into the ‘timezone’ attribute, which is unused
     by MySQL, instead of the ‘fsp’ attribute.

     References: #3602(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3602

8.3.5.50 mssql
..............

   * `[mssql] [bug]' ¶. Added the error “20006: Write to the
     server failed” to the list of disconnect errors for the pymssql
     driver, as this has been observed to render a connection unusable.

     References: #3585(1)

   * `[mssql] [bug]' ¶. A descriptive ValueError is now
     raised in the event that SQL server returns an invalid date or time
     format from a DATE or TIME column, rather than failing with a
     NoneType error.  Pull request courtesy Ed Avis.

   * `[mssql] [bug]' ¶. Fixed issue where DDL generated for
     the MSSQL types DATETIME2, TIME and DATETIMEOFFSET with a precision
     of “zero” would not generate the precision field.  Pull request
     courtesy Jacobo de Vera.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3585

8.3.5.51 misc
.............

   * `[change] [tests]' ¶. The ORM and Core tutorials, which
     have always been in doctest format, are now exercised within the
     normal unit test suite in both Python 2 and Python 3.

   * `[bug] [ext]' ¶. Added support for the ‘dict.pop()’ and
     ‘dict.popitem()’ methods to the MutableDict class.

     References: #3605(1)

   * `[bug] [py3k]' ¶. Updates to internal getargspec()
     calls, some py36-related fixture updates, and alterations to two
     iterators to “return” instead of raising StopIteration, to allow
     tests to pass without errors or warnings on Py3.5, Py3.6, pull
     requests courtesy Jacob MacDonald, Luri de Silvio, and Phil Jones.

   * `[bug] [ext]' ¶. Fixed an issue in baked queries where
     the .get() method, used either directly or within lazy loads,
     didn’t consider the mapper’s “get clause” as part of the cache key,
     causing bound parameter mismatches if the clause got re-generated.
     This clause is cached by mappers on the fly but in highly
     concurrent scenarios may be generated more than once when first
     accessed.

     References: #3597(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3605

   (2) http://www.sqlalchemy.org/trac/ticket/3597

8.3.5.52 1.0.9
..............

Released: October 20, 2015

8.3.5.53 orm
............

   * `[orm] [feature]' ¶. Added new method
     Query.one_or_none(); same as Query.one() but
     returns None if no row found.  Pull request courtesy esiegerman.

   * `[orm] [bug] [postgresql]' ¶. Fixed regression in 1.0
     where new feature of using “executemany” for UPDATE statements in
     the ORM (e.g.  see UPDATE statements are now batched with executemany() in a flush)
     would break on PostgreSQL and
     other RETURNING backends when using server-side version generation
     schemes, as the server side value is retrieved via RETURNING which
     is not supported with executemany.

     References: #3556(1)

   * `[orm] [bug]' ¶. Fixed rare TypeError which could occur
     when stringifying certain kinds of internal column loader options
     within internal logging.

     References: #3539(2)

   * `[orm] [bug]' ¶. Fixed bug in
     Session.bulk_save_objects() where a mapped column that had
     some kind of “fetch on update” value and was not locally present in
     the given object would cause an AttributeError within the
     operation.

     References: #3525(3)

   * `[orm] [bug]' ¶. Fixed 1.0 regression where the
     “noload” loader strategy would fail to function for a many-to-one
     relationship.  The loader used an API to place “None” into the
     dictionary which no longer actually writes a value; this is a side
     effect of #3061(4).

     References: #3510(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3556

   (2) http://www.sqlalchemy.org/trac/ticket/3539

   (3) http://www.sqlalchemy.org/trac/ticket/3525

   (4) http://www.sqlalchemy.org/trac/ticket/3061

   (5) http://www.sqlalchemy.org/trac/ticket/3510

8.3.5.54 sql
............

   * `[sql] [bug]' ¶. Fixed regression in 1.0-released
     default-processor for multi-VALUES insert statement, #3288(1),
     where the column type for the default-holding column would not be
     propagated to the compiled statement in the case where the default
     was being used, leading to bind-level type handlers not being
     invoked.

     References: #3520(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3288

   (2) http://www.sqlalchemy.org/trac/ticket/3520

8.3.5.55 postgresql
...................

   * `[postgresql] [bug]' ¶. An adjustment to the new
     PostgreSQL feature of reflecting storage options and USING of
     #3455(1) released in 1.0.6, to disable the feature for PostgreSQL
     versions < 8.2 where the ‘reloptions’ column is not provided; this
     allows Amazon Redshift to again work as it is based on an 8.0.x
     version of PostgreSQL. Fix courtesy Pete Hollobon.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3455

8.3.5.56 oracle
...............

   * `[oracle] [bug] [py3k]' ¶. Fixed support for cx_Oracle
     version 5.2, which was tripping up SQLAlchemy’s version detection
     under Python 3 and inadvertently not using the correct unicode mode
     for Python 3.  This would cause issues such as bound variables
     mis-interpreted as NULL and rows silently not being returned.

     This change is also `backported' to: 0.7.0b1

     References: #3491(1)

   * `[oracle] [bug]' ¶. Fixed bug in Oracle dialect where
     reflection of tables and other symbols with names quoted to force
     all-lower-case would not be identified properly in reflection
     queries.  The quoted_name construct is now applied to
     incoming symbol names that detect as forced into all-lower-case
     within the “name normalize” process.

     References: #3548(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3491

   (2) http://www.sqlalchemy.org/trac/ticket/3548

8.3.5.57 misc
.............

   * `[feature] [ext]' ¶. Added the
     AssociationProxy.info parameter to the
     AssociationProxy constructor, to suit the
     AssociationProxy.info accessor that was added in #2971(1).
     This is possible because AssociationProxy is
     constructed explicitly, unlike a hybrid which is constructed
     implicitly via the decorator syntax.

     References: #3551(2)

   * `[bug] [examples]' ¶. Fixed two issues in the
     “history_meta” example where history tracking could encounter empty
     history, and where a column keyed to an alternate attribute name
     would fail to track properly.  Fixes courtesy Alex Fraser.

   * `[bug] [sybase]' ¶. Fixed two issues regarding Sybase
     reflection, allowing tables without primary keys to be reflected as
     well as ensured that a SQL statement involved in foreign key
     detection is pre-fetched up front to avoid driver issues upon
     nested queries.  Fixes here courtesy Eugene Zapolsky; note that we
     cannot currently test Sybase to locally verify these changes.

     References: #3508(3), #3509(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2971

   (2) http://www.sqlalchemy.org/trac/ticket/3551

   (3) http://www.sqlalchemy.org/trac/ticket/3508

   (4) http://www.sqlalchemy.org/trac/ticket/3509

8.3.5.58 1.0.8
..............

Released: July 22, 2015

8.3.5.59 engine
...............

   * `[engine] [bug]' ¶. Fixed critical issue whereby the
     pool “checkout” event handler may be called against a stale
     connection without the “connect” event handler having been called,
     in the case where the pool attempted to reconnect after being
     invalidated and failed; the stale connection would remain present
     and would be used on a subsequent attempt.  This issue has a
     greater impact in the 1.0 series subsequent to 1.0.2, as it also
     delivers a blanked-out ‘.info’ dictionary to the event handler;
     prior to 1.0.2 the ‘.info’ dictionary is still the previous one.

     This change is also `backported' to: 0.7.0b1

     References: #3497(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3497

8.3.5.60 sqlite
...............

   * `[sqlite] [bug]' ¶. Fixed bug in SQLite dialect where
     reflection of UNIQUE constraints that included non-alphabetic
     characters in the names, like dots or spaces, would not be
     reflected with their name.

     This change is also `backported' to: 0.9.10

     References: #3495(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3495

8.3.5.61 misc
.............

   * `[misc] [bug]' ¶. Fixed an issue where a particular
     base class within utils didn’t implement ‘__slots__’, and therefore
     meant all subclasses of that class didn’t either, negating the
     rationale for ‘__slots__’ to be in use.  Didn’t cause any issue
     except on IronPython which apparently does not implement
     ‘__slots__’ behavior compatibly with cPython.

     References: #3494(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3494

8.3.5.62 1.0.7
..............

Released: July 20, 2015

8.3.5.63 orm
............

   * `[orm] [bug]' ¶. Fixed 1.0 regression where value
     objects that override ‘__eq__()’ to return a non-boolean-capable
     object, such as some geoalchemy types as well as numpy types, were
     being tested for ‘bool()’ during a unit of work update operation,
     where in 0.9 the return value of ‘__eq__()’ was tested against “is
     True” to guard against this.

     References: #3469(1)

   * `[orm] [bug]' ¶. Fixed 1.0 regression where a
     “deferred” attribute would not populate correctly if it were loaded
     within the “optimized inheritance load”, which is a special SELECT
     emitted in the case of joined table inheritance used to populate
     expired or unloaded attributes against a joined table without
     loading the base table.  This is related to the fact that SQLA 1.0
     no longer guesses about loading deferred columns and must be
     directed explicitly.

     References: #3468(2)

   * `[orm] [bug]' ¶. Fixed 1.0 regression where the “parent
     entity” of a synonym- mapped attribute on top of an
     aliased() object would resolve to the original mapper, not
     the aliased() version of it, thereby causing problems
     for a Query that relies on this attribute (e.g.  it’s
     the only representative attribute given in the constructor) to
     figure out the correct FROM clause for the query.

     References: #3466(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3469

   (2) http://www.sqlalchemy.org/trac/ticket/3468

   (3) http://www.sqlalchemy.org/trac/ticket/3466

8.3.5.64 orm declarative
........................

   * `[orm] [declarative] [bug]' ¶. Fixed bug in
     AbstractConcreteBase extension where a column setup on the
     ABC base which had a different attribute name vs.  column name
     would not be correctly mapped on the final base class.  The failure
     on 0.9 would be silent whereas on 1.0 it raised an ArgumentError,
     so may not have been noticed prior to 1.0.

     References: #3480(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3480

8.3.5.65 engine
...............

   * `[engine] [bug]' ¶. Fixed regression where new methods
     on ‘ResultProxy’ used by the ORM Query object (part of
     the performance enhancements of #3175(1)) 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.

     References: #3481(2)

   * `[engine] [bug]' ¶. Fixed regression where
     ‘ResultProxy.keys()’ would return 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 #918.

     References: #3483(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3175

   (2) http://www.sqlalchemy.org/trac/ticket/3481

   (3) http://www.sqlalchemy.org/trac/ticket/3483

8.3.5.66 sql
............

   * `[sql] [feature]' ¶. Added a
     ColumnElement.cast() method which performs the same purpose
     as the standalone cast() function.  Pull request
     courtesy Sebastian Bank.

     References: #3459(1)

   * `[sql] [bug]' ¶. Fixed bug where coercion of literal
     ‘True’ or ‘False’ constant in conjunction with and_() or
     or_() would fail with an AttributeError.

     References: #3490(2)

   * `[sql] [bug]' ¶. Fixed potential issue where a custom
     subclass of FunctionElement or other column element
     that incorrectly states ‘None’ or any other invalid object as the
     ‘.type’ attribute will report this exception instead of recursion
     overflow.

     References: #3485(3)

   * `[sql] [bug]' ¶. Fixed bug where the modulus SQL
     operator wouldn’t work in reverse due to a missing ‘__rmod__’
     method.  Pull request courtesy dan-gittik.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3459

   (2) http://www.sqlalchemy.org/trac/ticket/3490

   (3) http://www.sqlalchemy.org/trac/ticket/3485

8.3.5.67 schema
...............

   * `[schema] [feature]' ¶. Added support for the MINVALUE,
     MAXVALUE, NO MINVALUE, NO MAXVALUE, and CYCLE arguments for CREATE
     SEQUENCE as supported by PostgreSQL and Oracle.  Pull request
     courtesy jakeogh.

8.3.5.68 1.0.6
..............

Released: June 25, 2015

8.3.5.69 orm
............

   * `[orm] [bug]' ¶. Fixed a major regression in the 1.0
     series where the version_id_counter feature would cause an object’s
     version counter to be incremented when there was no net change to
     the object’s row, but instead an object related to it via
     relationship (e.g.  typically many-to-one) were associated or
     de-associated with it, resulting in an UPDATE statement that
     updates the object’s version counter and nothing else.  In the use
     case where the relatively recent “server side” and/or
     “programmatic/conditional” version counter feature were used (e.g.
     setting version_id_generator to False), the bug could cause an
     UPDATE without a valid SET clause to be emitted.

     References: #3465(1)

   * `[orm] [bug]' ¶. Fixed 1.0 regression where the
     enhanced behavior of single-inheritance joins of #3222(2) takes
     place inappropriately for a JOIN along explicit join criteria with
     a single-inheritance subclass that does not make use of any
     discriminator, resulting in an additional “AND NULL” clause.

     References: #3462(3)

   * `[orm] [bug]' ¶. Fixed bug in new
     Session.bulk_update_mappings() feature where the primary key
     columns used in the WHERE clause to locate the row would also be
     included in the SET clause, setting their value to themselves
     unnecessarily.  Pull request courtesy Patrick Hayes.

     References: #3451(4)

   * `[orm] [bug]' ¶. Fixed an unexpected-use regression
     whereby custom Comparator objects that made use of the
     ‘__clause_element__()’ method and returned an object that was an
     ORM-mapped InstrumentedAttribute and not explicitly a
     ColumnElement would fail to be correctly handled when
     passed as an expression to Session.query().  The logic
     in 0.9 happened to succeed on this, so this use case is now
     supported.

     References: #3448(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3465

   (2) http://www.sqlalchemy.org/trac/ticket/3222

   (3) http://www.sqlalchemy.org/trac/ticket/3462

   (4) http://www.sqlalchemy.org/trac/ticket/3451

   (5) http://www.sqlalchemy.org/trac/ticket/3448

8.3.5.70 sql
............

   * `[sql] [bug]' ¶. Fixed a bug where clause adaption as
     applied to a Label object would fail to accommodate the
     labeled SQL expression in all cases, such that any SQL operation
     that made use of Label.self_group() would use the
     original unadapted expression.  One effect of this would be that an
     ORM aliased() construct would not fully accommodate
     attributes mapped by column_property, such that the
     un-aliased table could leak out when the property were used in some
     kinds of SQL comparisons.

     References: #3445(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3445

8.3.5.71 postgresql
...................

   * `[postgresql] [feature]' ¶. Added support for storage
     parameters under CREATE INDEX, using a new keyword argument
     ‘postgresql_with’.  Also added support for reflection to support
     both the ‘postgresql_with’ flag as well as the ‘postgresql_using’
     flag, which will now be set on Index objects that are
     reflected, as well present in a new “dialect_options” dictionary in
     the result of Inspector.get_indexes().  Pull request
     courtesy Pete Hollobon.

     See also
     ........

     See Index Storage Parameters.

     References: #3455(1)

   * `[postgresql] [feature]' ¶. Added new execution option
     ‘max_row_buffer’ which is interpreted by the psycopg2 dialect when
     the ‘stream_results’ option is used, which sets a limit on the size
     of the row buffer that may be allocated.  This value is also
     provided based on the integer value sent to
     Query.yield_per().  Pull request courtesy mcclurem.

   * `[postgresql] [bug] [pypy]' ¶. Re-fixed this issue
     first released in 1.0.5 to fix psycopg2cffi JSONB support once
     again, as they suddenly switched on unconditional decoding of JSONB
     types in version 2.7.1.  Version detection now specifies 2.7.1 as
     where we should expect the DBAPI to do json encoding for us.

     References: #3439(2)

   * `[postgresql] [bug]' ¶. Repaired the
     ExcludeConstraint construct to support common features that
     other objects like Index now do, that the column
     expression may be specified as an arbitrary SQL expression such as
     cast or text.

     References: #3454(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3455

   (2) http://www.sqlalchemy.org/trac/ticket/3439

   (3) http://www.sqlalchemy.org/trac/ticket/3454

8.3.5.72 mssql
..............

   * `[mssql] [bug]' ¶. Fixed issue when using
     VARBINARY type in conjunction with an INSERT of NULL +
     pyodbc; pyodbc requires a special object be passed in order to
     persist NULL. As the VARBINARY type is now usually the
     default for LargeBinary due to #3039(1), this issue is
     partially a regression in 1.0.  The pymssql driver appears to be
     unaffected.

     References: #3464(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3039

   (2) http://www.sqlalchemy.org/trac/ticket/3464

8.3.5.73 misc
.............

   * `[bug] [documentation]' ¶. Fixed an internal
     “memoization” routine for method types such that a Python
     descriptor is no longer used; repairs inspectability of these
     methods including support for Sphinx documentation.

     References: #2077(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2077

8.3.5.74 1.0.5
..............

Released: June 7, 2015

8.3.5.75 orm
............

   * `[orm] [feature]' ¶. Added new event
     InstanceEvents.refresh_flush(), invoked when an INSERT or
     UPDATE level default value fetched via RETURNING or Python-side
     default is invoked within the flush process.  This is to provide a
     hook that is no longer present as a result of #3167(1), where
     attribute and validation events are no longer called within the
     flush process.

     References: #3427(2)

   * `[orm] [bug]' ¶. The “lightweight named tuple” used
     when a Query returns rows failed to implement
     ‘__slots__’ correctly such that it still had a ‘__dict__’.  This is
     resolved, but in the extremely unlikely case someone was assigning
     values to the returned tuples, that will no longer work.

     References: #3420(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3167

   (2) http://www.sqlalchemy.org/trac/ticket/3427

   (3) http://www.sqlalchemy.org/trac/ticket/3420

8.3.5.76 engine
...............

   * `[engine] [feature]' ¶. Added new engine event
     ConnectionEvents.engine_disposed().  Called after the
     Engine.dispose() method is called.

   * `[engine] [feature]' ¶. Adjustments to the engine
     plugin hook, such that the URL.get_dialect() method
     will continue to return the ultimate Dialect object
     when a dialect plugin is used, without the need for the caller to
     be aware of the Dialect.get_dialect_cls() method.

     References: #3379(1)

   * `[engine] [bug]' ¶. Fixed bug where known boolean
     values used by engine_from_config() were not being
     parsed correctly; these included ‘pool_threadlocal’ and the
     psycopg2 argument ‘use_native_unicode’.

     References: #3435(2)

   * `[engine] [bug]' ¶. Added support for the case of the
     misbehaving DBAPI that has pep-249 exception names linked to
     exception classes of an entirely different name, preventing
     SQLAlchemy’s own exception wrapping from wrapping the error
     appropriately.  The SQLAlchemy dialect in use needs to implement a
     new accessor DefaultDialect.dbapi_exception_translation_map
     to support this feature; this is implemented now for the
     py-postgresql dialect.

     References: #3421(3)

   * `[engine] [bug]' ¶. Fixed bug involving the case when
     pool checkout event handlers are used and connection attempts are
     made in the handler itself which fail, the owning connection record
     would not be freed until the stack trace of the connect error
     itself were freed.  For the case where a test pool of only a single
     connection were used, this means the pool would be fully checked
     out until that stack trace were freed.  This mostly impacts very
     specific debugging scenarios and is unlikely to have been
     noticeable in any production application.  The fix applies an
     explicit checkin of the record before re-raising the caught
     exception.

     References: #3419(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3379

   (2) http://www.sqlalchemy.org/trac/ticket/3435

   (3) http://www.sqlalchemy.org/trac/ticket/3421

   (4) http://www.sqlalchemy.org/trac/ticket/3419

8.3.5.77 sql
............

   * `[sql] [feature]' ¶. Added official support for a CTE
     used by the SELECT present inside of Insert.from_select().
     This behavior worked accidentally up until 0.9.9, when it no
     longer worked due to unrelated changes as part of #3248(1).  Note
     that this is the rendering of the WITH clause after the INSERT,
     before the SELECT; the full functionality of CTEs rendered at the
     top level of INSERT, UPDATE, DELETE is a new feature targeted for a
     later release.

     This change is also `backported' to: 0.9.10

     References: #3418(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3248

   (2) http://www.sqlalchemy.org/trac/ticket/3418

8.3.5.78 postgresql
...................

   * `[postgresql] [bug] [pypy]' ¶. Repaired some typing and
     test issues related to the pypy psycopg2cffi dialect, in particular
     that the current 2.7.0 version does not have native support for the
     JSONB type.  The version detection for psycopg2 features has been
     tuned into a specific sub-version for psycopg2cffi.  Additionally,
     test coverage has been enabled for the full series of psycopg2
     features under psycopg2cffi.

     References: #3439(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3439

8.3.5.79 mssql
..............

   * `[mssql] [bug]' ¶. Added a new dialect flag to the
     MSSQL dialect ‘legacy_schema_aliasing’ which when set to False will
     disable a very old and obsolete behavior, that of the compiler’s
     attempt to turn all schema-qualified table names into alias names,
     to work around old and no longer locatable issues where SQL server
     could not parse a multi-part identifier name in all circumstances.
     The behavior prevented more sophisticated statements from working
     correctly, including those which use hints, as well as CRUD
     statements that embed correlated SELECT statements.  Rather than
     continue to repair the feature to work with more complex
     statements, it’s better to just disable it as it should no longer
     be needed for any modern SQL server version.  The flag defaults to
     True for the 1.0.x series, leaving current behavior unchanged for
     this version series.  In the 1.1 series, it will default to False.
     For the 1.0 series, when not set to either value explicitly, a
     warning is emitted when a schema-qualified table is first used in a
     statement, which suggests that the flag be set to False for all
     modern SQL Server versions.

     See also
     ........

     See Legacy Schema Mode.

     References: #3424(1), #3430(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3424

   (2) http://www.sqlalchemy.org/trac/ticket/3430

8.3.5.80 misc
.............

   * `[feature] [ext]' ¶. Added support for ‘*args’ to be
     passed to the baked query initial callable, in the same way that
     ‘*args’ are supported for the BakedQuery.add_criteria()
     and BakedQuery.with_criteria() methods.  Initial PR
     courtesy Naoki INADA.

   * `[feature] [ext]' ¶. Added a new semi-public method to
     MutableBase. ‘MutableBase._get_listen_keys()’.
     Overriding this method is needed in the case where a
     MutableBase subclass needs events to propagate for attribute
     keys other than the key to which the mutable type is associated
     with, when intercepting the InstanceEvents.refresh() or
     InstanceEvents.refresh_flush() events.  The current
     example of this is composites using MutableComposite.

     References: #3427(1)

   * `[bug] [ext]' ¶. Fixed regression in the
     sqlalchemy.ext.mutable extension as a result of the bugfix for
     #3167(2), where attribute and validation events are no longer
     called within the flush process.  The mutable extension was relying
     upon this behavior in the case where a column level Python-side
     default were responsible for generating the new value on INSERT or
     UPDATE, or when a value were fetched from the RETURNING clause for
     “eager defaults” mode.  The new value would not be subject to any
     event when populated and the mutable extension could not establish
     proper coercion or history listening.  A new event
     InstanceEvents.refresh_flush() is added which the mutable
     extension now makes use of for this use case.

     References: #3427(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3427

   (2) http://www.sqlalchemy.org/trac/ticket/3167

   (3) http://www.sqlalchemy.org/trac/ticket/3427

8.3.5.81 1.0.4
..............

Released: May 7, 2015

8.3.5.82 orm
............

   * `[orm] [bug]' ¶. Fixed unexpected-use regression where
     in the odd case that the primaryjoin of a relationship involved
     comparison to an unhashable type such as an HSTORE, lazy loads
     would fail due to a hash-oriented check on the statement
     parameters, modified in 1.0 as a result of #3061(1) to use hashing
     and modified in #3368(2) to occur in cases more common than “load
     on pending”.  The values are now checked for the ‘__hash__’
     attribute beforehand.

     References: #3416(3)

   * `[orm] [bug]' ¶. Liberalized an assertion that was
     added as part of #3347(4) to protect against unknown conditions
     when splicing inner joins together within joined eager loads with
     ‘innerjoin=True’; if some of the joins use a “secondary” table, the
     assertion needs to unwrap further joins in order to pass.

     References: #3347(5), #3412(6)

   * `[orm] [bug]' ¶. Repaired / added to tests yet more
     expressions that were reported as failing with the new ‘entity’ key
     value added to Query.column_descriptions, the logic to
     discover the “from” clause is again reworked to accommodate columns
     from aliased classes, as well as to report the correct value for
     the “aliased” flag in these cases.

     References: #3320(7), #3409(8)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3061

   (2) http://www.sqlalchemy.org/trac/ticket/3368

   (3) http://www.sqlalchemy.org/trac/ticket/3416

   (4) http://www.sqlalchemy.org/trac/ticket/3347

   (5) http://www.sqlalchemy.org/trac/ticket/3347

   (6) http://www.sqlalchemy.org/trac/ticket/3412

   (7) http://www.sqlalchemy.org/trac/ticket/3320

   (8) http://www.sqlalchemy.org/trac/ticket/3409

8.3.5.83 schema
...............

   * `[schema] [bug]' ¶. Fixed bug in enhanced
     constraint-attachment logic introduced in #3341(1) where in the
     unusual case of a constraint that refers to a mixture of
     Column objects and string column names at the same time, the
     auto-attach-on-column-attach logic will be skipped; for the
     constraint to be auto-attached in this case, all columns must be
     assembled on the target table up front.  Added a new section to the
     migration document regarding the original feature as well as this
     change.

     See also
     ........

     See Constraints referring to unattached Columns can auto-attach to the Table when their referred columns are attached.

     References: #3411(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3341

   (2) http://www.sqlalchemy.org/trac/ticket/3411

8.3.5.84 misc
.............

   * `[bug] [ext]' ¶. Fixed bug where when using extended
     attribute instrumentation system, the correct exception would not
     be raised when class_mapper() were called with an
     invalid input that also happened to not be weak referencable, such
     as an integer.

     This change is also `backported' to: 0.9.10

     References: #3408(1)

   * `[bug] [pypy] [tests]' ¶. Fixed an import that
     prevented “pypy setup.py test” from working correctly.

     This change is also `backported' to: 0.9.10

     References: #3406(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3408

   (2) http://www.sqlalchemy.org/trac/ticket/3406

8.3.5.85 1.0.3
..............

Released: April 30, 2015

8.3.5.86 orm
............

   * `[orm] [bug] [pypy]' ¶. Fixed regression from 0.9.10
     prior to release due to #3349(1) where the check for query state on
     Query.update() or Query.delete() compared
     the empty tuple to itself using ‘is’, which fails on PyPy to
     produce ‘True’ in this case; this would erronously emit a warning
     in 0.9 and raise an exception in 1.0.

     References: #3405(2)

   * `[orm] [bug]' ¶. Fixed regression from 0.9.10 prior to
     release where the new addition of ‘entity’ to the
     Query.column_descriptions accessor would fail if the target
     entity was produced from a core selectable such as a Table
     or CTE object.

     References: #3320(3), #3403(4)

   * `[orm] [bug]' ¶. Fixed regression within the flush
     process when an attribute were set to a SQL expression for an
     UPDATE, and the SQL expression when compared to the previous value
     of the attribute would produce a SQL comparison other than ‘==’ or
     ‘!=’, the exception “Boolean value of this clause is not defined”
     would raise.  The fix ensures that the unit of work will not
     interpret the SQL expression in this way.

     References: #3402(5)

   * `[orm] [bug]' ¶. Fixed unexpected use regression due to
     #2992(6) where textual elements placed into the
     Query.order_by() clause in conjunction with joined eager
     loading would be added to the columns clause of the inner query in
     such a way that they were assumed to be table-bound column names,
     in the case where the joined eager load needs to wrap the query in
     a subquery to accommodate for a limit/offset.

     Originally, the behavior here was intentional, in that a query such
     as ‘query(User).order_by('name').limit(1)’ would order by
     ‘user.name’ even if the query was modified by joined eager loading
     to be within a subquery, as ‘'name'’ would be interpreted as a
     symbol to be located within the FROM clauses, in this case
     ‘User.name’, which would then be copied into the columns clause to
     ensure it were present for ORDER BY. However, the feature fails to
     anticipate the case where ‘order_by("name")’ refers to a specific
     label name present in the local columns clause already and not a
     name bound to a selectable in the FROM clause.

     Beyond that, the feature also fails for deprecated cases such as
     ‘order_by("name desc")’, which, while it emits a warning that
     text() should be used here (note that the issue does not
     impact cases where text() is used explicitly), still
     produces a different query than previously where the “name desc”
     expression is copied into the columns clause inappropriately.  The
     resolution is such that the “joined eager loading” aspect of the
     feature will skip over these so-called “label reference”
     expressions when augmenting the inner columns clause, as though
     they were text() constructs already.

     References: #3392(7)

   * `[orm] [bug]' ¶. Fixed a regression regarding the
     MapperEvents.instrument_class() event where its invocation
     was moved to be after the class manager’s instrumentation of the
     class, which is the opposite of what the documentation for the
     event explicitly states.  The rationale for the switch was due to
     Declarative taking the step of setting up the full “instrumentation
     manager” for a class before it was mapped for the purpose of the
     new ‘@declared_attr’ features described in Improvements to declarative mixins, @declared_attr and related features,
     but
     the change was also made against the classical use of
     mapper() for consistency.  However, SQLSoup relies upon the
     instrumentation event happening before any instrumentation under
     classical mapping.  The behavior is reverted in the case of
     classical and declarative mapping, the latter implemented by using
     a simple memoization without using class manager.

     References: #3388(8)

   * `[orm] [bug]' ¶. Fixed issue in new
     QueryEvents.before_compile() event where changes made to the
     Query object’s collection of entities to load within
     the event would render in the SQL, but would not be reflected
     during the loading process.

     References: #3387(9)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3349

   (2) http://www.sqlalchemy.org/trac/ticket/3405

   (3) http://www.sqlalchemy.org/trac/ticket/3320

   (4) http://www.sqlalchemy.org/trac/ticket/3403

   (5) http://www.sqlalchemy.org/trac/ticket/3402

   (6) http://www.sqlalchemy.org/trac/ticket/2992

   (7) http://www.sqlalchemy.org/trac/ticket/3392

   (8) http://www.sqlalchemy.org/trac/ticket/3388

   (9) http://www.sqlalchemy.org/trac/ticket/3387

8.3.5.87 engine
...............

   * `[engine] [feature]' ¶. New features added to support
     engine/pool plugins with advanced functionality.  Added a new “soft
     invalidate” feature to the connection pool at the level of the
     checked out connection wrapper as well as the
     _ConnectionRecord.  This works similarly to a modern pool
     invalidation in that connections aren’t actively closed, but are
     recycled only on next checkout; this is essentially a
     per-connection version of that feature.  A new event
     PoolEvents.soft_invalidate() is added to complement it.

     Also added new flag
     ExceptionContext.invalidate_pool_on_disconnect.  Allows an
     error handler within ConnectionEvents.handle_error()
     to maintain a “disconnect” condition, but to handle calling
     invalidate on individual connections in a specific manner within
     the event.

     References: #3379(1)

   * `[engine] [feature]' ¶. Added new event ‘do_connect’,
     which allows interception / replacement of when the
     Dialect.connect() hook is called to create a DBAPI
     connection.  Also added dialect plugin hooks
     Dialect.get_dialect_cls() and
     Dialect.engine_created() which allow external plugins to add
     events to existing dialects using entry points.

     References: #3355(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3379

   (2) http://www.sqlalchemy.org/trac/ticket/3355

8.3.5.88 sql
............

   * `[sql] [feature]' ¶. Added a placeholder method
     TypeEngine.compare_against_backend() which is now consumed
     by Alembic migrations as of 0.7.6.  User-defined types can
     implement this method to assist in the comparison of a type against
     one reflected from the database.

   * `[sql] [bug]' ¶. Fixed bug where the truncation of long
     labels in SQL could produce a label that overlapped another label
     that is not truncated; this because the length threshold for
     truncation was greater than the portion of the label that remains
     after truncation.  These two values have now been made the same;
     label_length - 6.  The effect here is that shorter column labels
     will be “truncated” where they would not have been truncated
     before.

     References: #3396(1)

   * `[sql] [bug]' ¶. Fixed regression due to #3282(2) where
     the ‘tables’ collection passed as a keyword argument to the
     DDLEvents.before_create(), DDLEvents.after_create(),
     see DDLEvents.before_drop(), and
     DDLEvents.after_drop() events would no longer be a list of
     tables, but instead a list of tuples which contained a second entry
     with foreign keys to be added or dropped.  As the ‘tables’
     collection, while documented as not necessarily stable, has come to
     be relied upon, this change is considered a regression.
     Additionally, in some cases for “drop”, this collection would be an
     iterator that would cause the operation to fail if prematurely
     iterated.  The collection is now a list of table objects in all
     cases and test coverage for the format of this collection is now
     added.

     References: #3391(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3396

   (2) http://www.sqlalchemy.org/trac/ticket/3282

   (3) http://www.sqlalchemy.org/trac/ticket/3391

8.3.5.89 misc
.............

   * `[bug] [ext]' ¶. Fixed bug in association proxy where
     an any()/has() on an relationship->scalar non-object attribute
     comparison would fail, e.g.
     ‘filter(Parent.some_collection_to_attribute.any(Child.attr ==
     'foo'))’

     References: #3397(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3397

8.3.5.90 1.0.2
..............

Released: April 24, 2015

8.3.5.91 orm declarative
........................

   * `[orm] [declarative] [bug]' ¶. Fixed unexpected use
     regression regarding the declarative ‘__declare_first__’ and
     ‘__declare_last__’ accessors where these would no longer be called
     on the superclass of the declarative base.

     References: #3383(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3383

8.3.5.92 sql
............

   * `[sql] [bug]' ¶. Fixed a regression that was
     incorrectly fixed in 1.0.0b4 (hence becoming two regressions);
     reports that SELECT statements would GROUP BY a label name and fail
     was misconstrued that certain backends such as SQL Server should
     not be emitting ORDER BY or GROUP BY on a simple label name at all;
     when in fact, we had forgotten that 0.9 was already emitting ORDER
     BY on a simple label name for all backends, as described in
     Label constructs can now render as their name alone in an ORDER BY,
     even though 1.0 includes a rewrite of this logic as part of
     #2992(1).  As far as emitting GROUP BY against a simple label, even
     PostgreSQL has cases where it will raise an error even though the
     label to group on should be apparent, so it is clear that GROUP BY
     should never be rendered in this way automatically.

     In 1.0.2, SQL Server, Firebird and others will again emit ORDER BY
     on a simple label name when passed a Label construct
     that is also present in the columns clause.  Additionally, no
     backend will emit GROUP BY against the simple label name only when
     passed a Label construct.

     References: #3338(2), #3385(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2992

   (2) http://www.sqlalchemy.org/trac/ticket/3338

   (3) http://www.sqlalchemy.org/trac/ticket/3385

8.3.5.93 1.0.1
..............

Released: April 23, 2015

8.3.5.94 orm
............

   * `[orm] [bug]' ¶. Fixed issue where a query of the form
     ‘query(B).filter(B.a != A(id=7))’ would render the ‘NEVER_SET’
     symbol, when given a transient object.  For a persistent object, it
     would always use the persisted database value and not the currently
     set value.  Assuming autoflush is turned on, this usually would not
     be apparent for persistent values, as any pending changes would be
     flushed first in any case.  However, this is inconsistent vs.  the
     logic used for the non-negated comparison, ‘query(B).filter(B.a ==
     A(id=7))’, which does use the current value and additionally allows
     comparisons to transient objects.  The comparison now uses the
     current value and not the database-persisted value.

     Unlike the other ‘NEVER_SET’ issues that are repaired as
     regressions caused by #3061(1) in this release, this particular
     issue is present at least as far back as 0.8 and possibly earlier,
     however it was discovered as a result of repairing the related
     ‘NEVER_SET’ issues.

     See also
     ........

     See A “negated contains or equals” relationship comparison will use the current value of attributes, not the database value.

     References: #3374(2)

   * `[orm] [bug]' ¶. Fixed unexpected use regression cause
     by #3061(3) where the NEVER_SET symbol could leak into
     relationship-oriented queries, including ‘filter()’ and
     ‘with_parent()’ queries.  The ‘None’ symbol is returned in all
     cases, however many of these queries have never been correctly
     supported in any case, and produce comparisons to NULL without
     using the IS operator.  For this reason, a warning is also added to
     that subset of relationship queries that don’t currently provide
     for ‘IS NULL’.

     See also
     ........

     See Warnings emitted when comparing objects with None values to relationships.

     References: #3371(4)

   * `[orm] [bug]' ¶. Fixed a regression caused by #3061(5)
     where the NEVER_SET symbol could leak into a lazyload query,
     subsequent to the flush of a pending object.  This would occur
     typically for a many-to-one relationship that does not use a simple
     “get” strategy.  The good news is that the fix improves efficiency
     vs.  0.9, because we can now skip the SELECT statement entirely
     when we detect NEVER_SET symbols present in the parameters; prior
     to #3061(6), we couldn’t discern if the None here were set or not.

     References: #3368(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3061

   (2) http://www.sqlalchemy.org/trac/ticket/3374

   (3) http://www.sqlalchemy.org/trac/ticket/3061

   (4) http://www.sqlalchemy.org/trac/ticket/3371

   (5) http://www.sqlalchemy.org/trac/ticket/3061

   (6) http://www.sqlalchemy.org/trac/ticket/3061

   (7) http://www.sqlalchemy.org/trac/ticket/3368

8.3.5.95 engine
...............

   * `[engine] [bug]' ¶. Added the string value ‘"none"’ to
     those accepted by the Pool.reset_on_return parameter
     as a synonym for ‘None’, so that string values can be used for all
     settings, allowing utilities like engine_from_config()
     to be usable without issue.

     This change is also `backported' to: 0.9.10

     References: #3375(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3375

8.3.5.96 sql
............

   * `[sql] [bug]' ¶. Fixed issue where a straight SELECT
     EXISTS query would fail to assign the proper result type of Boolean
     to the result mapping, and instead would leak column types from
     within the query into the result map.  This issue exists in 0.9 and
     earlier as well, however has less of an impact in those versions.
     In 1.0, due to #918(1) this becomes a regression in that we now
     rely upon the result mapping to be very accurate, else we can
     assign result-type processors to the wrong column.  In all
     versions, this issue also has the effect that a simple EXISTS will
     not apply the Boolean type handler, leading to simple 1/0 values
     for backends without native boolean instead of True/False.  The fix
     includes that an EXISTS columns argument will be anon-labeled like
     other column expressions; a similar fix is implemented for
     pure-boolean expressions like ‘not_(True())’.

     References: #3372(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/918

   (2) http://www.sqlalchemy.org/trac/ticket/3372

8.3.5.97 sqlite
...............

   * `[sqlite] [bug]' ¶. Fixed a regression due to #3282(1),
     where due to the fact that we attempt to assume the availability of
     ALTER when creating/dropping schemas, in the case of SQLite we
     simply said to not worry about foreign keys at all, since ALTER is
     not available, when creating and dropping tables.  This meant that
     the sorting of tables was basically skipped in the case of SQLite,
     and for the vast majority of SQLite use cases, this is not an
     issue.

     However, users who were doing DROPs on SQLite with tables that
     contained data and with referential integrity turned on would then
     experience errors, as the dependency sorting `does' matter in the
     case of DROP with enforced constraints, when those tables have data
     (SQLite will still happily let you create foreign keys to
     nonexistent tables and drop tables referring to existing ones with
     constraints enabled, as long as there’s no data being referenced).

     In order to maintain the new feature of #3282(2) while still
     allowing a SQLite DROP operation to maintain ordering, we now do
     the sort with full FKs taken under consideration, and if we
     encounter an unresolvable cycle, only `then' do we forego
     attempting to sort the tables; we instead emit a warning and go
     with the unsorted list.  If an environment needs both ordered DROPs
     `and' has foreign key cycles, then the warning notes they will need
     to restore the ‘use_alter’ flag to their ForeignKey and
     ForeignKeyConstraint objects so that just those objects
     will be omitted from the dependency sort.

     See also
     ........

     See The use_alter flag on ForeignKeyConstraint is (usually) no longer needed.
     - contains an updated note about SQLite.

     References: #3378(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3282

   (2) http://www.sqlalchemy.org/trac/ticket/3282

   (3) http://www.sqlalchemy.org/trac/ticket/3378

8.3.5.98 firebird
.................

   * `[firebird] [bug]' ¶. Fixed a regression due to
     #3034(1) where limit/offset clauses were not properly interpreted
     by the Firebird dialect.  Pull request courtesy effem-git.

     References: #3380(2)

   * `[firebird] [bug]' ¶. Fixed support for “literal_binds”
     mode when using limit/offset with Firebird, so that the values are
     again rendered inline when this is selected.  Related to #3034(3).

     References: #3381(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3034

   (2) http://www.sqlalchemy.org/trac/ticket/3380

   (3) http://www.sqlalchemy.org/trac/ticket/3034

   (4) http://www.sqlalchemy.org/trac/ticket/3381

8.3.5.99 1.0.0
..............

Released: April 16, 2015

8.3.5.100 orm
.............

   * `[orm] [feature]' ¶. Added new argument
     Query.update.update_args which allows kw arguments such as
     ‘mysql_limit’ to be passed to the underlying Update
     construct.  Pull request courtesy Amir Sadoughi.

   * `[orm] [bug]' ¶. Identified an inconsistency when
     handling Query.join() to the same target more than
     once; it implicitly dedupes only in the case of a relationship
     join, and due to #3233(1), in 1.0 a join to the same table twice
     behaves differently than 0.9 in that it no longer erroneously
     aliases.  To help document this change, the verbiage regarding
     #3233(2) in the migration notes has been generalized, and a warning
     has been added when Query.join() is called against the
     same target relationship more than once.

     References: #3367(3)

   * `[orm] [bug]' ¶. Made a small improvement to the
     heuristics of relationship when determining remote side with
     semi-self-referential (e.g.  two joined inh subclasses referring to
     each other), non-simple join conditions such that the parententity
     is taken into account and can reduce the need for using the
     ‘remote()’ annotation; this can restore some cases that might have
     worked without the annotation prior to 0.9.4 via #2948(4).

     References: #3364(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3233

   (2) http://www.sqlalchemy.org/trac/ticket/3233

   (3) http://www.sqlalchemy.org/trac/ticket/3367

   (4) http://www.sqlalchemy.org/trac/ticket/2948

   (5) http://www.sqlalchemy.org/trac/ticket/3364

8.3.5.101 sql
.............

   * `[sql] [feature]' ¶. The topological sorting used to
     sort Table objects and available via the
     MetaData.sorted_tables collection will now produce a
     `deterministic' ordering; that is, the same ordering each time
     given a set of tables with particular names and dependencies.  This
     is to help with comparison of DDL scripts and other use cases.  The
     tables are sent to the topological sort sorted by name, and the
     topological sort itself will process the incoming data in an
     ordered fashion.  Pull request courtesy Sebastian Bank.

     See also
     ........

     See MetaData.sorted_tables accessor is “deterministic”.

     References: #3084(1)

   * `[sql] [bug]' ¶. Fixed issue where a MetaData
     object that used a naming convention would not properly work
     with pickle.  The attribute was skipped leading to inconsistencies
     and failures if the unpickled MetaData object were used
     to base additional tables from.

     This change is also `backported' to: 0.9.10

     References: #3362(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3084

   (2) http://www.sqlalchemy.org/trac/ticket/3362

8.3.5.102 postgresql
....................

   * `[postgresql] [bug]' ¶. Fixed a long-standing bug where
     the Enum type as used with the psycopg2 dialect in
     conjunction with non-ascii values and ‘native_enum=False’ would
     fail to decode return results properly.  This stemmed from when the
     PG ENUM type used to be a standalone type without a
     “non native” option.

     This change is also `backported' to: 0.9.10

     References: #3354(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3354

8.3.5.103 mssql
...............

   * `[mssql] [bug]' ¶. Fixed a regression where the “last
     inserted id” mechanics would fail to store the correct value for
     MSSQL on an INSERT where the primary key value was present in the
     insert params before execution, as well as in the case where an
     INSERT from SELECT would state the target columns as column
     objects, instead of string keys.

     References: #3360(1)

   * `[mssql] [bug]' ¶. Using the ‘Binary’ constructor now
     present in pymssql rather than patching one in.  Pull request
     courtesy Ramiro Morales.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3360

8.3.5.104 misc
..............

   * `[bug] [tests]' ¶. Fixed the pathing used when tests
     run; for sqla_nose.py and py.test, the “./lib” prefix is again
     inserted at the head of sys.path but only if sys.flags.no_user_site
     isn’t set; this makes it act just like the way Python puts “.” in
     the current path by default.  For tox, we are setting the
     PYTHONNOUSERSITE flag now.

     References: #3356(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3356

8.3.5.105 1.0.0b5
.................

Released: April 3, 2015

8.3.5.106 orm
.............

   * `[orm] [bug]' ¶. Fixed bug where the state tracking
     within multiple, nested Session.begin_nested()
     operations would fail to propagate the “dirty” flag for an object
     that had been updated within the inner savepoint, such that if the
     enclosing savepoint were rolled back, the object would not be part
     of the state that was expired and therefore reverted to its
     database state.

     This change is also `backported' to: 0.9.10

     References: #3352(1)

   * `[orm] [bug]' ¶. Query doesn’t support
     joins, subselects, or special FROM clauses when using the
     Query.update() or Query.delete() methods; instead
     of silently ignoring these fields if methods like
     Query.join() or Query.select_from() has been
     called, an error is raised.  In 0.9.10 this only emits a warning.

     References: #3349(2)

   * `[orm] [bug]' ¶. Added a list() call around a weak
     dictionary used within the commit phase of the session, which
     without it could cause a “dictionary changed size during iter”
     error if garbage collection interacted within the process.  Change
     was introduced by #3139.

   * `[orm] [bug]' ¶. Fixed a bug related to “nested” inner
     join eager loading, which exists in 0.9 as well but is more of a
     regression in 1.0 due to #3008(3) which turns on “nested” by
     default, such that a joined eager load that travels across sibling
     paths from a common ancestor using innerjoin=True will correctly
     splice each “innerjoin” sibling into the appropriate part of the
     join, when a series of inner/outer joins are mixed together.

     References: #3347(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3352

   (2) http://www.sqlalchemy.org/trac/ticket/3349

   (3) http://www.sqlalchemy.org/trac/ticket/3008

   (4) http://www.sqlalchemy.org/trac/ticket/3347

8.3.5.107 sql
.............

   * `[sql] [bug]' ¶. The warning emitted by the unicode
     type for a non-unicode type has been liberalized to warn for values
     that aren’t even string values, such as integers; previously, the
     updated warning system of 1.0 made use of string formatting
     operations which would raise an internal TypeError.  While these
     cases should ideally raise totally, some backends like SQLite and
     MySQL do accept them and are potentially in use by legacy code, not
     to mention that they will always pass through if unicode conversion
     is turned off for the target backend.

     References: #3346(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3346

8.3.5.108 postgresql
....................

   * `[postgresql] [bug]' ¶. Fixed bug where updated PG
     index reflection as a result of #3184(1) would cause index
     operations to fail on PostgreSQL versions 8.4 and earlier.  The
     enhancements are now disabled when using an older version of
     PostgreSQL.

     References: #3343(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3184

   (2) http://www.sqlalchemy.org/trac/ticket/3343

8.3.5.109 1.0.0b4
.................

Released: March 29, 2015

8.3.5.110 sql
.............

   * `[sql] [bug]' ¶. Fixed bug in new “label resolution”
     feature of #2992(1) where a label that was anonymous, then labeled
     again with a name, would fail to be locatable via a textual label.
     This situation occurs naturally when a mapped
     column_property() is given an explicit label in a query.

     References: #3340(2)

   * `[sql] [bug]' ¶. Fixed bug in new “label resolution”
     feature of #2992(3) where the string label placed in the order_by()
     or group_by() of a statement would place higher priority on the
     name as found inside the FROM clause instead of a more locally
     available name inside the columns clause.

     References: #3335(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2992

   (2) http://www.sqlalchemy.org/trac/ticket/3340

   (3) http://www.sqlalchemy.org/trac/ticket/2992

   (4) http://www.sqlalchemy.org/trac/ticket/3335

8.3.5.111 schema
................

   * `[schema] [feature]' ¶. The “auto-attach” feature of
     constraints such as UniqueConstraint and
     CheckConstraint has been further enhanced such that when the
     constraint is associated with non-table-bound Column
     objects, the constraint will set up event listeners with the
     columns themselves such that the constraint auto attaches at the
     same time the columns are associated with the table.  This in
     particular helps in some edge cases in declarative but is also of
     general use.

     See also
     ........

     See Constraints referring to unattached Columns can auto-attach to the Table when their referred columns are attached.

     References: #3341(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3341

8.3.5.112 mysql
...............

   * `[mysql] [bug] [pymysql]' ¶. Fixed unicode support for
     PyMySQL when using an “executemany” operation with unicode
     parameters.  SQLAlchemy now passes both the statement as well as
     the bound parameters as unicode objects, as PyMySQL generally uses
     string interpolation internally to produce the final statement, and
     in the case of executemany does the “encode” step only on the final
     statement.

     This change is also `backported' to: 0.9.10

     References: #3337(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3337

8.3.5.113 mssql
...............

   * `[mssql] [bug] [firebird] [oracle] [sybase]' ¶. Turned
     off the “simple order by” flag on the MSSQL, Oracle dialects; this
     is the flag that per #2992(1) causes an order by or group by an
     expression that’s also in the columns clause to be copied by label,
     even if referenced as the expression object.  The behavior for
     MSSQL is now the old behavior that copies the whole expression in
     by default, as MSSQL can be picky on these particularly in GROUP BY
     expressions.  The flag is also turned off defensively for the
     Firebird and Sybase dialects.

          Note: this resolution was incorrect, please see version 1.0.2
          for a rework of this resolution.

     References: #3338(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2992

   (2) http://www.sqlalchemy.org/trac/ticket/3338

8.3.5.114 1.0.0b3
.................

Released: March 20, 2015

8.3.5.115 mysql
...............

   * `[mysql] [bug]' ¶. Repaired the commit for issue #2771
     which was inadvertently commented out.

     References: #2771(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2771

8.3.5.116 1.0.0b2
.................

Released: March 20, 2015

8.3.5.117 orm
.............

   * `[orm] [bug]' ¶. Fixed unexpected use regression from
     pullreq github:137 where Py2K unicode literals (e.g.  ‘u""’) would
     not be accepted by the relationship.cascade option.
     Pull request courtesy Julien Castets.

     References: #3327(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3327

8.3.5.118 orm declarative
.........................

   * `[orm] [declarative] [change]' ¶. Loosened some
     restrictions that were added to ‘@declared_attr’ objects, such that
     they were prevented from being called outside of the declarative
     process; this is related to the enhancements of #3150 which allow
     ‘@declared_attr’ to return a value that is cached based on the
     current class as it’s being configured.  The exception raise has
     been removed, and the behavior changed so that outside of the
     declarative process, the function decorated by ‘@declared_attr’ is
     called every time just like a regular ‘@property’, without using
     any caching, as none is available at this stage.

     References: #3331(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3331

8.3.5.119 engine
................

   * `[engine] [bug]' ¶. The “auto close” for ‘ResultProxy’
     is now a “soft” close.  That is, after exhausting 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 ‘ResultProxy.close()’ is called explicitly will these methods
     raise the “result is closed” error.

     See also
     ........

     See ResultProxy “auto close” is now a “soft” close.

     References: #3329(1), #3330(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3329

   (2) http://www.sqlalchemy.org/trac/ticket/3330

8.3.5.120 mysql
...............

   * `[mysql] [bug] [py3k]' ¶. Fixed the BIT.
     type on Py3K which was not using the ‘ord()’ function correctly.
     Pull request courtesy David Marin.

     This change is also `backported' to: 0.9.10

     References: #3333(1)

   * `[mysql] [bug]' ¶. Fixes to fully support using the
     ‘'utf8mb4'’ MySQL-specific charset with MySQL dialects, in
     particular MySQL-Python and PyMySQL. In addition, MySQL databases
     that report more unusual charsets such as ‘koi8u’ or ‘eucjpms’ will
     also work correctly.  Pull request courtesy Thomas Grainger.

     References: #2771(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3333

   (2) http://www.sqlalchemy.org/trac/ticket/2771

8.3.5.121 1.0.0b1
.................

Released: March 13, 2015

Version 1.0.0b1 is the first release of the 1.0 series.  Many changes
described here are also present in the 0.9 and sometimes the 0.8 series
as well.  For changes that are specific to 1.0 with an emphasis on
compatibility concerns, see What’s New in SQLAlchemy 1.0?.

8.3.5.122 general
.................

   * `[general] [feature]' ¶. Structural memory use has been
     improved via much more significant use of ‘__slots__’ for many
     internal objects.  This optimization is particularly geared towards
     the base memory size of large applications that have lots of tables
     and columns, and greatly reduces memory size for a variety of
     high-volume objects including event listening internals, comparator
     objects and parts of the ORM attribute and loader strategy system.

     See also
     ........

     See Significant Improvements in Structural Memory Use.

   * `[general] [bug]' ¶. The ‘__module__’ attribute is now
     set for all those SQL and ORM functions that are derived as “public
     factory” symbols, which should assist with documentation tools
     being able to report on the target module.

     References: #3218(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3218

8.3.5.123 orm
.............

   * `[orm] [feature]' ¶. Added a new entry ‘"entity"’ to
     the dictionaries returned by Query.column_descriptions.
     This refers to the primary ORM mapped class or aliased class that
     is referred to by the expression.  Compared to the existing entry
     for ‘"type"’, it will always be a mapped entity, even if extracted
     from a column expression, or None if the given expression is a pure
     core expression.  See also #3403(1) which repaired a regression in
     this feature which was unreleased in 0.9.10 but was released in the
     1.0 version.

     This change is also `backported' to: 0.9.10

     References: #3320(2)

   * `[orm] [feature]' ¶. Added new parameter
     Session.connection.execution_options which may be used to set
     up execution options on a Connection when it is first
     checked out, before the transaction has begun.  This is used to set
     up options such as isolation level on the connection before the
     transaction starts.

     See also
     ........

     See Setting Transaction Isolation Levels / DBAPI AUTOCOMMIT.
     - new documentation section detailing best practices for setting
     transaction isolation with sessions.

     This change is also `backported' to: 0.9.9

     References: #3296(3)

   * `[orm] [feature]' ¶. Added new method
     Session.invalidate(), functions similarly to
     Session.close(), except also calls
     Connection.invalidate() on all connections, guaranteeing that
     they will not be returned to the connection pool.  This is useful
     in situations e.g.  dealing with gevent timeouts when it is not
     safe to use the connection further, even for rollbacks.

     This change is also `backported' to: 0.9.9

   * `[orm] [feature]' ¶. The “primaryjoin” model has been
     stretched a bit further to allow a join condition that is strictly
     from a single column to itself, translated through some kind of SQL
     function or expression.  This is kind of experimental, but the
     first proof of concept is a “materialized path” join condition
     where a path string is compared to itself using “like”.  The
     ColumnOperators.like() operator has also been added to the
     list of valid operators to use in a primaryjoin condition.

     This change is also `backported' to: 0.9.5

     References: #3029(4)

   * `[orm] [feature]' ¶. Added new utility function
     make_transient_to_detached() which can be used to manufacture
     objects that behave as though they were loaded from a session, then
     detached.  Attributes that aren’t present are marked as expired,
     and the object can be added to a Session where it will act like a
     persistent one.

     This change is also `backported' to: 0.9.5

     References: #3017(5)

   * `[orm] [feature]' ¶. Added a new event suite
     QueryEvents.  The QueryEvents.before_compile()
     event allows the creation of functions which may place additional
     modifications to Query objects before the construction
     of the SELECT statement.  It is hoped that this event be made much
     more useful via the advent of a new inspection system that will
     allow for detailed modifications to be made against Query
     objects in an automated fashion.

     See also
     ........

     See QueryEvents.

     References: #3317(6)

   * `[orm] [feature]' ¶. The subquery wrapping which occurs
     when joined eager loading is used with a one-to-many query that
     also features LIMIT, OFFSET, or DISTINCT has been disabled in the
     case of a one-to-one relationship, that is a one-to-many with
     relationship.uselist set to False.  This will produce more
     efficient queries in these cases.

     See also
     ........

     See Subqueries no longer applied to uselist=False joined eager loads.

     References: #3249(7)

   * `[orm] [feature]' ¶. Mapped state internals have been
     reworked to allow for a 50% reduction in callcounts specific to the
     “expiration” of objects, as in the “auto expire” feature of
     Session.commit() and for Session.expire_all(), as
     well as in the “cleanup” step which occurs when object states are
     garbage collected.

     References: #3307(8)

   * `[orm] [feature]' ¶. A warning is emitted when the same
     polymorphic identity is assigned to two different mappers in the
     same hierarchy.  This is typically a user error and means that the
     two different mapping types cannot be correctly distinguished at
     load time.  Pull request courtesy Sebastian Bank.

     References: #3262(9)

   * `[orm] [feature]' ¶. A new series of Session.
     methods which provide hooks directly into the unit of work’s
     facility for emitting INSERT and UPDATE statements has been
     created.  When used correctly, this expert-oriented system can
     allow ORM-mappings to be used to generate bulk insert and update
     statements batched into executemany groups, allowing the statements
     to proceed at speeds that rival direct use of the Core.

     See also
     ........

     See Bulk Operations.

     References: #3100(10)

   * `[orm] [feature]' ¶. Added a parameter
     Query.join.isouter which is synonymous with calling
     Query.outerjoin(); this flag is to provide a more consistent
     interface compared to Core FromClause.join().  Pull
     request courtesy Jonathan Vanasco.

     References: #3217(11)

   * `[orm] [feature]' ¶. Added new event handlers
     AttributeEvents.init_collection() and
     AttributeEvents.dispose_collection(), which track when a
     collection is first associated with an instance and when it is
     replaced.  These handlers supersede the ‘collection.linker()’
     annotation.  The old hook remains supported through an event
     adapter.

   * `[orm] [feature]' ¶. The Query will raise
     an exception when Query.yield_per() is used with
     mappings or options where either subquery eager loading, or joined
     eager loading with collections, would take place.  These loading
     strategies are not currently compatible with yield_per, so by
     raising this error, the method is safer to use.  Eager loads can be
     disabled with the ‘lazyload('*')’ option or
     Query.enable_eagerloads().

     See also
     ........

     See Joined/Subquery eager loading explicitly disallowed with yield_per.

   * `[orm] [feature]' ¶. A new implementation for
     ‘KeyedTuple’ used by the Query object offers dramatic
     speed improvements when fetching large numbers of column-oriented
     rows.

     See also
     ........

     See New KeyedTuple implementation dramatically faster.

     References: #3176(12)

   * `[orm] [feature]' ¶. The behavior of
     joinedload.innerjoin as well as relationship.innerjoin
     is now to use “nested” inner joins, that is, right-nested, as
     the default behavior when an inner join joined eager load is
     chained to an outer join eager load.

     See also
     ........

     See Right inner join nesting now the default for joinedload with innerjoin=True.

     References: #3008(13)

   * `[orm] [feature]' ¶. UPDATE statements can now be
     batched within an ORM flush into more performant executemany()
     call, similarly to how INSERT statements can be batched; this will
     be invoked within flush to the degree that subsequent UPDATE
     statements for the same mapping and table involve the identical
     columns within the VALUES clause, that no SET-level SQL expressions
     are embedded, and that the versioning requirements for the mapping
     are compatible with the backend dialect’s ability to return a
     correct rowcount for an executemany operation.

   * `[orm] [feature]' ¶. The ‘info’ parameter has been
     added to the constructor for SynonymProperty and
     ‘ComparableProperty’.

     References: #2963(14)

   * `[orm] [feature]' ¶. The ‘InspectionAttr.info’
     collection is now moved down to InspectionAttr, where in
     addition to being available on all MapperProperty
     objects, it is also now available on hybrid properties, association
     proxies, when accessed via Mapper.all_orm_descriptors.

     References: #2971(15)

   * `[orm] [change]' ¶. Mapped attributes marked as
     deferred without explicit undeferral will now remain “deferred”
     even if their column is otherwise present in the result set in some
     way.  This is a performance enhancement in that an ORM load no
     longer spends time searching for each deferred column when the
     result set is obtained.  However, for an application that has been
     relying upon this, an explicit undefer() or similar
     option should now be used.

   * `[orm] [changed]' ¶. The ‘proc()’ callable passed to
     the ‘create_row_processor()’ method of custom Bundle
     classes now accepts only a single “row” argument.

     See also
     ........

     See API Change for new Bundle feature when custom row loaders are used.

   * `[orm] [changed]' ¶. Deprecated event hooks removed:
     ‘populate_instance’, ‘create_instance’, ‘translate_row’,
     ‘append_result’

     See also
     ........

     See Deprecated ORM Event Hooks Removed.

   * `[orm] [bug]' ¶. Fixed bug in subquery eager loading
     where a long chain of eager loads across a polymorphic-subclass
     boundary in conjunction with polymorphic loading would fail to
     locate the subclass-link in the chain, erroring out with a missing
     property name on an AliasedClass.

     This change is also `backported' to: 0.9.5, 0.8.7

     References: #3055(16)

   * `[orm] [bug]' ¶. Fixed ORM bug where the
     class_mapper() function would mask AttributeErrors or
     KeyErrors that should raise during mapper configuration due to user
     errors.  The catch for attribute/keyerror has been made more
     specific to not include the configuration step.

     This change is also `backported' to: 0.9.5, 0.8.7

     References: #3047(17)

   * `[orm] [bug]' ¶. Fixed bugs in ORM object comparisons
     where comparison of many-to-one ‘!= None’ would fail if the source
     were an aliased class, or if the query needed to apply special
     aliasing to the expression due to aliased joins or polymorphic
     querying; also fixed bug in the case where comparing a many-to-one
     to an object state would fail if the query needed to apply special
     aliasing due to aliased joins or polymorphic querying.

     This change is also `backported' to: 0.9.9

     References: #3310(18)

   * `[orm] [bug]' ¶. Fixed bug where internal assertion
     would fail in the case where an ‘after_rollback()’ handler for a
     Session incorrectly adds state to that Session
     within the handler, and the task to warn and remove this state
     (established by #2389(19)) attempts to proceed.

     This change is also `backported' to: 0.9.9

     References: #3309(20)

   * `[orm] [bug]' ¶. Fixed bug where TypeError raised when
     Query.join() called with unknown kw arguments would
     raise its own TypeError due to broken formatting.  Pull request
     courtesy Malthe Borch.

     This change is also `backported' to: 0.9.9

   * `[orm] [bug]' ¶. Fixed bug in lazy loading SQL
     construction whereby a complex primaryjoin that referred to the
     same “local” column multiple times in the “column that points to
     itself” style of self-referential join would not be substituted in
     all cases.  The logic to determine substitutions here has been
     reworked to be more open-ended.

     This change is also `backported' to: 0.9.9

     References: #3300(21)

   * `[orm] [bug]' ¶. The “wildcard” loader options, in
     particular the one set up by the load_only() option to
     cover all attributes not explicitly mentioned, now takes into
     account the superclasses of a given entity, if that entity is
     mapped with inheritance mapping, so that attribute names within the
     superclasses are also omitted from the load.  Additionally, the
     polymorphic discriminator column is unconditionally included in the
     list, just in the same way that primary key columns are, so that
     even with load_only() set up, polymorphic loading of subtypes
     continues to function correctly.

     This change is also `backported' to: 0.9.9

     References: #3287(22)

   * `[orm] [bug] [pypy]' ¶. Fixed bug where if an exception
     were thrown at the start of a Query before it fetched
     results, particularly when row processors can’t be formed, the
     cursor would stay open with results pending and not actually be
     closed.  This is typically only an issue on an interpreter like
     PyPy where the cursor isn’t immediately GC’ed, and can in some
     circumstances lead to transactions/ locks being open longer than is
     desirable.

     This change is also `backported' to: 0.9.9

     References: #3285(23)

   * `[orm] [bug]' ¶. Fixed a leak which would occur in the
     unsupported and highly non-recommended use case of replacing a
     relationship on a fixed mapped class many times, referring to an
     arbitrarily growing number of target mappers.  A warning is emitted
     when the old relationship is replaced, however if the mapping were
     already used for querying, the old relationship would still be
     referenced within some registries.

     This change is also `backported' to: 0.9.9

     References: #3251(24)

   * `[orm] [bug] [sqlite]' ¶. Fixed bug regarding
     expression mutations which could express itself as a “Could not
     locate column” error when using Query to select from
     multiple, anonymous column entities when querying against SQLite,
     as a side effect of the “join rewriting” feature used by the SQLite
     dialect.

     This change is also `backported' to: 0.9.9

     References: #3241(25)

   * `[orm] [bug]' ¶. Fixed bug where the ON clause for
     Query.join(), and Query.outerjoin() to a
     single-inheritance subclass using ‘of_type()’ would not render the
     “single table criteria” in the ON clause if the
     ‘from_joinpoint=True’ flag were set.

     This change is also `backported' to: 0.9.9

     References: #3232(26)

   * `[orm] [bug] [engine]' ¶. Fixed bug that affected
     generally the same classes of event as that of #3199(27), when the
     ‘named=True’ parameter would be used.  Some events would fail to
     register, and others would not invoke the event arguments
     correctly, generally in the case of when an event was “wrapped” for
     adaption in some other way.  The “named” mechanics have been
     rearranged to not interfere with the argument signature expected by
     internal wrapper functions.

     This change is also `backported' to: 0.9.8

     References: #3197(28)

   * `[orm] [bug]' ¶. Fixed bug that affected many classes
     of event, particularly ORM events but also engine events, where the
     usual logic of “de duplicating” a redundant call to listen()
     with the same arguments would fail, for those events where the
     listener function is wrapped.  An assertion would be hit within
     registry.py.  This assertion has now been integrated into the
     deduplication check, with the added bonus of a simpler means of
     checking deduplication across the board.

     This change is also `backported' to: 0.9.8

     References: #3199(29)

   * `[orm] [bug]' ¶. Fixed warning that would emit when a
     complex self-referential primaryjoin contained functions, while at
     the same time remote_side was specified; the warning would suggest
     setting “remote side”.  It now only emits if remote_side isn’t
     present.

     This change is also `backported' to: 0.9.8

     References: #3194(30)

   * `[orm] [bug] [eagerloading]' ¶. Fixed a regression
     caused by #2976(31) released in 0.9.4 where the “outer join”
     propagation along a chain of joined eager loads would incorrectly
     convert an “inner join” along a sibling join path into an outer
     join as well, when only descendant paths should be receiving the
     “outer join” propagation; additionally, fixed related issue where
     “nested” join propagation would take place inappropriately between
     two sibling join paths.

     This change is also `backported' to: 0.9.7

     References: #3131(32)

   * `[orm] [bug]' ¶. Fixed a regression from 0.9.0 due to
     #2736(33) where the Query.select_from() method no
     longer set up the “from entity” of the Query object
     correctly, so that subsequent Query.filter_by() or
     Query.join() calls would fail to check the appropriate
     “from” entity when searching for attributes by string name.

     This change is also `backported' to: 0.9.7

     References: #2736(34), #3083(35)

   * `[orm] [bug]' ¶. Fixed bug where items that were
     persisted, deleted, or had a primary key change within a savepoint
     block would not participate in being restored to their former state
     (not in session, in session, previous PK) after the outer
     transaction were rolled back.

     This change is also `backported' to: 0.9.7

     References: #3108(36)

   * `[orm] [bug]' ¶. Fixed bug in subquery eager loading in
     conjunction with with_polymorphic(), the targeting of
     entities and columns in the subquery load has been made more
     accurate with respect to this type of entity and others.

     This change is also `backported' to: 0.9.7

     References: #3106(37)

   * `[orm] [bug]' ¶. Additional checks have been added for
     the case where an inheriting mapper is implicitly combining one of
     its column-based attributes with that of the parent, where those
     columns normally don’t necessarily share the same value.  This is
     an extension of an existing check that was added via #1892(38);
     however this new check emits only a warning, instead of an
     exception, to allow for applications that may be relying upon the
     existing behavior.

     See also
     ........

     See I’m getting a warning or error about “Implicitly combining column X under attribute Y”.

     This change is also `backported' to: 0.9.5

     References: #3042(39)

   * `[orm] [bug]' ¶. Modified the behavior of
     load_only() such that primary key columns are always added to
     the list of columns to be “undeferred”; otherwise, the ORM can’t
     load the row’s identity.  Apparently, one can defer the mapped
     primary keys and the ORM will fail, that hasn’t been changed.  But
     as load_only is essentially saying “defer all but X”, it’s more
     critical that PK cols not be part of this deferral.

     This change is also `backported' to: 0.9.5

     References: #3080(40)

   * `[orm] [bug]' ¶. Fixed a few edge cases which arise in
     the so-called “row switch” scenario, where an INSERT/DELETE can be
     turned into an UPDATE. In this situation, a many-to-one
     relationship set to None, or in some cases a scalar attribute set
     to None, may not be detected as a net change in value, and
     therefore the UPDATE would not reset what was on the previous row.
     This is due to some as-yet unresolved side effects of the way
     attribute history works in terms of implicitly assuming None isn’t
     really a “change” for a previously un-set attribute.  See also
     #3061(41).

          Note: This change has been `REVERTED' in 0.9.6.  The full fix
          will be in version 1.0 of SQLAlchemy.

     This change is also `backported' to: 0.9.5

     References: #3060(42)

   * `[orm] [bug]' ¶. Related to #3060(43), an adjustment
     has been made to the unit of work such that loading for related
     many-to-one objects is slightly more aggressive, in the case of a
     graph of self-referential objects that are to be deleted; the load
     of related objects is to help determine the correct order for
     deletion if passive_deletes is not set.

     This change is also `backported' to: 0.9.5

   * `[orm] [bug]' ¶. Fixed bug in SQLite join rewriting
     where anonymized column names due to repeats would not correctly be
     rewritten in subqueries.  This would affect SELECT queries with any
     kind of subquery + join.

     This change is also `backported' to: 0.9.5

     References: #3057(44)

   * `[orm] [bug] [sql]' ¶. Fixes to the newly enhanced
     boolean coercion in #2804(45) where the new rules for “where” and
     “having” woudn’t take effect for the “whereclause” and “having” kw
     arguments of the select() construct, which is also what
     Query uses so wasn’t working in the ORM either.

     This change is also `backported' to: 0.9.5

     References: #3013(46)

   * `[orm] [bug]' ¶. Fixed bug where the session attachment
     error “object is already attached to session X” would fail to
     prevent the object from also being attached to the new session, in
     the case that execution continued after the error raise occurred.

     References: #3301(47)

   * `[orm] [bug]' ¶. The primary Mapper of a
     Query is now passed to the Session.get_bind()
     method when calling upon Query.count(),
     Query.update(), Query.delete(), as well as queries
     against mapped columns, see column_property objects, and
     SQL functions and expressions derived from mapped columns.  This
     allows sessions that rely upon either customized
     Session.get_bind() schemes or “bound” metadata to work in all
     relevant cases.

     See also
     ........

     See Session.get_bind() will receive the Mapper in all relevant Query cases.

     References: #1326(48), #3227(49), #3242(50)

   * `[orm] [bug]' ¶. The PropComparator.of_type()
     modifier has been improved in conjunction with loader
     directives such as joinedload() and
     contains_eager() such that if two
     PropComparator.of_type() modifiers of the same base type/path
     are encountered, they will be joined together into a single
     “polymorphic” entity, rather than replacing the entity of type A
     with the one of type B. E.g.  a joinedload of
     ‘A.b.of_type(BSub1)->BSub1.c’ combined with joinedload of
     ‘A.b.of_type(BSub2)->BSub2.c’ will create a single joinedload of
     ‘A.b.of_type((BSub1, BSub2)) -> BSub1.c, BSub2.c’, without the need
     for the ‘with_polymorphic’ to be explicit in the query.

     See also
     ........

     See Eager Loading of Specific or Polymorphic Subtypes. -
     contains an updated example illustrating the new format.

     References: #3256(51)

   * `[orm] [bug]' ¶. Repaired support of the
     ‘copy.deepcopy()’ call when used by the ‘CascadeOptions’ argument,
     which occurs if ‘copy.deepcopy()’ is being used with
     relationship(). (not an officially supported use case).  Pull
     request courtesy duesenfranz.

   * `[orm] [bug]' ¶. Fixed bug where
     Session.expunge() would not fully detach the given object if
     the object had been subject to a delete operation that was flushed,
     but not committed.  This would also affect related operations like
     make_transient().

     See also
     ........

     See session.expunge() will fully detach an object that’s been deleted.

     References: #3139(52)

   * `[orm] [bug]' ¶. A warning is emitted in the case of
     multiple relationships that ultimately will populate a foreign key
     column in conflict with another, where the relationships are
     attempting to copy values from different source columns.  This
     occurs in the case where composite foreign keys with overlapping
     columns are mapped to relationships that each refer to a different
     referenced column.  A new documentation section illustrates the
     example as well as how to overcome the issue by specifying
     “foreign” columns specifically on a per-relationship basis.

     See also
     ........

     See Overlapping Foreign Keys.

     References: #3230(53)

   * `[orm] [bug]' ¶. The Query.update() method
     will now convert string key names in the given dictionary of values
     into mapped attribute names against the mapped class being updated.
     Previously, string names were taken in directly and passed to the
     core update statement without any means to resolve against the
     mapped entity.  Support for synonyms and hybrid attributes as the
     subject attributes of Query.update() are also
     supported.

     See also
     ........

     See query.update() now resolves string names into mapped attribute names.

     References: #3228(54)

   * `[orm] [bug]' ¶. Improvements to the mechanism used by
     Session to locate “binds” (e.g.  engines to use), such
     engines can be associated with mixin classes, concrete subclasses,
     as well as a wider variety of table metadata such as joined
     inheritance tables.

     See also
     ........

     See Session.get_bind() handles a wider variety of inheritance scenarios.

     References: #3035(55)

   * `[orm] [bug]' ¶. Fixed bug in single table inheritance
     where a chain of joins that included the same single inh entity
     more than once (normally this should raise an error) could, in some
     cases depending on what was being joined “from”, implicitly alias
     the second case of the single inh entity, producing a query that
     “worked”.  But as this implicit aliasing is not intended in the
     case of single table inheritance, it didn’t really “work” fully and
     was very misleading, since it wouldn’t always appear.

     See also
     ........

     See Changes and fixes in handling of duplicate join targets.

     References: #3233(56)

   * `[orm] [bug]' ¶. The ON clause rendered when using
     Query.join(), Query.outerjoin(), or the
     standalone join(). / see outerjoin() functions
     to a single-inheritance subclass will now include the “single table
     criteria” in the ON clause even if the ON clause is otherwise
     hand-rolled; it is now added to the criteria using AND, the same
     way as if joining to a single-table target using relationship or
     similar.

     This is sort of in-between feature and bug.

     See also
     ........

     See single-table-inheritance criteria added to all ON clauses unconditionally.

     References: #3222(57)

   * `[orm] [bug]' ¶. A major rework to the behavior of
     expression labels, most specifically when used with ColumnProperty
     constructs with custom SQL expressions and in conjunction with the
     “order by labels” logic first introduced in 0.9.  Fixes include
     that an ‘order_by(Entity.some_col_prop)’ will now make use of
     “order by label” rules even if Entity has been subject to aliasing,
     either via inheritance rendering or via the use of the ‘aliased()’
     construct; rendering of the same column property multiple times
     with aliasing (e.g.  ‘query(Entity.some_prop,
     entity_alias.some_prop)’) will label each occurrence of the entity
     with a distinct label, and additionally “order by label” rules will
     work for both (e.g.  ‘order_by(Entity.some_prop,
     entity_alias.some_prop)’).  Additional issues that could prevent
     the “order by label” logic from working in 0.9, most notably that
     the state of a Label could change such that “order by label” would
     stop working depending on how things were called, has been fixed.

     See also
     ........

     See ColumnProperty constructs work a lot better with aliases, order_by.

     References: #3148(58), #3188(59)

   * `[orm] [bug]' ¶. Changed the approach by which the
     “single inheritance criterion” is applied, when using
     Query.from_self(), or its common user Query.count().
     The criteria to limit rows to those with a certain type is
     now indicated on the inside subquery, not the outside one, so that
     even if the “type” column is not available in the columns clause,
     we can filter on it on the “inner” query.

     See also
     ........

     See Change to single-table-inheritance criteria when using from_self(), count().

     References: #3177(60)

   * `[orm] [bug]' ¶. Made a small adjustment to the
     mechanics of lazy loading, such that it has less chance of
     interfering with a joinload() in the very rare circumstance that an
     object points to itself; in this scenario, the object refers to
     itself while loading its attributes which can cause a mixup between
     loaders.  The use case of “object points to itself” is not fully
     supported, but the fix also removes some overhead so for now is
     part of testing.

     References: #3145(61)

   * `[orm] [bug]' ¶. The “resurrect” ORM event has been
     removed.  This event hook had no purpose since the old “mutable
     attribute” system was removed in 0.8.

     References: #3171(62)

   * `[orm] [bug]' ¶. Fixed bug where attribute “set” events
     or columns with ‘@validates’ would have events triggered within the
     flush process, when those columns were the targets of a “fetch and
     populate” operation, such as an autoincremented primary key, a
     Python side default, or a server-side default “eagerly” fetched via
     RETURNING.

     References: #3167(63)

   * `[orm] [bug] [py3k]' ¶. The IdentityMap.
     exposed from Session.identity_map now returns lists for
     ‘items()’ and ‘values()’ in Py3K. Early porting to Py3K here had
     these returning iterators, when they technically should be
     “iterable views”..for now, lists are OK.

   * `[orm] [bug]' ¶. The “evaluator” for
     query.update()/delete() won’t work with multi-table updates, and
     needs to be set to ‘synchronize_session=False’ or
     ‘synchronize_session=’fetch’’; this now raises an exception, with a
     message to change the synchronize setting.  This is upgraded from a
     warning emitted as of 0.9.7.

     References: #3117(64)

   * `[orm] [enhancement]' ¶. Adjustment to attribute
     mechanics concerning when a value is implicitly initialized to None
     via first access; this action, which has always resulted in a
     population of the attribute, no longer does so; the None value is
     returned but the underlying attribute receives no set event.  This
     is consistent with how collections work and allows attribute
     mechanics to behave more consistently; in particular, getting an
     attribute with no value does not squash the event that should
     proceed if the value is actually set to None.

     See also
     ........

     See Changes to attribute events and other operations regarding attributes that have no pre-existing value.

     where bound parameters are rendered inline as strings based on a
     compile-time option.  Work on this feature is courtesy of Dobes
     Vandermeer.

          See also
          ........

          See Select/Query LIMIT / OFFSET may be specified as an arbitrary SQL expression.

     References: #3061(65)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3403

   (2) http://www.sqlalchemy.org/trac/ticket/3320

   (3) http://www.sqlalchemy.org/trac/ticket/3296

   (4) http://www.sqlalchemy.org/trac/ticket/3029

   (5) http://www.sqlalchemy.org/trac/ticket/3017

   (6) http://www.sqlalchemy.org/trac/ticket/3317

   (7) http://www.sqlalchemy.org/trac/ticket/3249

   (8) http://www.sqlalchemy.org/trac/ticket/3307

   (9) http://www.sqlalchemy.org/trac/ticket/3262

   (10) http://www.sqlalchemy.org/trac/ticket/3100

   (11) http://www.sqlalchemy.org/trac/ticket/3217

   (12) http://www.sqlalchemy.org/trac/ticket/3176

   (13) http://www.sqlalchemy.org/trac/ticket/3008

   (14) http://www.sqlalchemy.org/trac/ticket/2963

   (15) http://www.sqlalchemy.org/trac/ticket/2971

   (16) http://www.sqlalchemy.org/trac/ticket/3055

   (17) http://www.sqlalchemy.org/trac/ticket/3047

   (18) http://www.sqlalchemy.org/trac/ticket/3310

   (19) http://www.sqlalchemy.org/trac/ticket/2389

   (20) http://www.sqlalchemy.org/trac/ticket/3309

   (21) http://www.sqlalchemy.org/trac/ticket/3300

   (22) http://www.sqlalchemy.org/trac/ticket/3287

   (23) http://www.sqlalchemy.org/trac/ticket/3285

   (24) http://www.sqlalchemy.org/trac/ticket/3251

   (25) http://www.sqlalchemy.org/trac/ticket/3241

   (26) http://www.sqlalchemy.org/trac/ticket/3232

   (27) http://www.sqlalchemy.org/trac/ticket/3199

   (28) http://www.sqlalchemy.org/trac/ticket/3197

   (29) http://www.sqlalchemy.org/trac/ticket/3199

   (30) http://www.sqlalchemy.org/trac/ticket/3194

   (31) http://www.sqlalchemy.org/trac/ticket/2976

   (32) http://www.sqlalchemy.org/trac/ticket/3131

   (33) http://www.sqlalchemy.org/trac/ticket/2736

   (34) http://www.sqlalchemy.org/trac/ticket/2736

   (35) http://www.sqlalchemy.org/trac/ticket/3083

   (36) http://www.sqlalchemy.org/trac/ticket/3108

   (37) http://www.sqlalchemy.org/trac/ticket/3106

   (38) http://www.sqlalchemy.org/trac/ticket/1892

   (39) http://www.sqlalchemy.org/trac/ticket/3042

   (40) http://www.sqlalchemy.org/trac/ticket/3080

   (41) http://www.sqlalchemy.org/trac/ticket/3061

   (42) http://www.sqlalchemy.org/trac/ticket/3060

   (43) http://www.sqlalchemy.org/trac/ticket/3060

   (44) http://www.sqlalchemy.org/trac/ticket/3057

   (45) http://www.sqlalchemy.org/trac/ticket/2804

   (46) http://www.sqlalchemy.org/trac/ticket/3013

   (47) http://www.sqlalchemy.org/trac/ticket/3301

   (48) http://www.sqlalchemy.org/trac/ticket/1326

   (49) http://www.sqlalchemy.org/trac/ticket/3227

   (50) http://www.sqlalchemy.org/trac/ticket/3242

   (51) http://www.sqlalchemy.org/trac/ticket/3256

   (52) http://www.sqlalchemy.org/trac/ticket/3139

   (53) http://www.sqlalchemy.org/trac/ticket/3230

   (54) http://www.sqlalchemy.org/trac/ticket/3228

   (55) http://www.sqlalchemy.org/trac/ticket/3035

   (56) http://www.sqlalchemy.org/trac/ticket/3233

   (57) http://www.sqlalchemy.org/trac/ticket/3222

   (58) http://www.sqlalchemy.org/trac/ticket/3148

   (59) http://www.sqlalchemy.org/trac/ticket/3188

   (60) http://www.sqlalchemy.org/trac/ticket/3177

   (61) http://www.sqlalchemy.org/trac/ticket/3145

   (62) http://www.sqlalchemy.org/trac/ticket/3171

   (63) http://www.sqlalchemy.org/trac/ticket/3167

   (64) http://www.sqlalchemy.org/trac/ticket/3117

   (65) http://www.sqlalchemy.org/trac/ticket/3061

8.3.5.124 orm declarative
.........................

   * `[orm] [declarative] [feature]' ¶. The
     declared_attr construct has newly improved behaviors and
     features in conjunction with declarative.  The decorated function
     will now have access to the final column copies present on the
     local mixin when invoked, and will also be invoked exactly once for
     each mapped class, the returned result being memoized.  A new
     modifier declared_attr.cascading is added as well.

     See also
     ........

     See Improvements to declarative mixins, @declared_attr and related features.

     References: #3150(1)

   * `[orm] [declarative] [bug]' ¶. Fixed “‘NoneType’ object
     has no attribute ‘concrete’” error when using
     AbstractConcreteBase in conjunction with a subclass that
     declares ‘__abstract__’.

     This change is also `backported' to: 0.9.8

     References: #3185(2)

   * `[orm] [declarative] [bug]' ¶. Fixed bug where using an
     ‘__abstract__’ mixin in the middle of a declarative inheritance
     hierarchy would prevent attributes and configuration being
     correctly propagated from the base class to the inheriting class.

     References: #3219(3), #3240(4)

   * `[orm] [declarative] [bug]' ¶. A relationship set up
     with declared_attr on a AbstractConcreteBase
     base class will now be configured on the abstract base mapping
     automatically, in addition to being set up on descendant concrete
     classes as usual.

     See also
     ........

     See Improvements to declarative mixins, @declared_attr and related features.

     References: #2670(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3150

   (2) http://www.sqlalchemy.org/trac/ticket/3185

   (3) http://www.sqlalchemy.org/trac/ticket/3219

   (4) http://www.sqlalchemy.org/trac/ticket/3240

   (5) http://www.sqlalchemy.org/trac/ticket/2670

8.3.5.125 engine
................

   * `[engine] [feature]' ¶. Added new user-space accessors
     for viewing transaction isolation levels; see
     Connection.get_isolation_level(),
     Connection.default_isolation_level.

     This change is also `backported' to: 0.9.9

   * `[engine] [feature]' ¶. Added new event
     ConnectionEvents.handle_error(), a more fully featured and
     comprehensive replacement for ‘ConnectionEvents.dbapi_error()’.

     This change is also `backported' to: 0.9.7

     References: #3076(1)

   * `[engine] [feature]' ¶. A new style of warning can be
     emitted which will “filter” up to N occurrences of a parameterized
     string.  This allows parameterized warnings that can refer to their
     arguments to be delivered a fixed number of times until allowing
     Python warning filters to squelch them, and prevents memory from
     growing unbounded within Python’s warning registries.

     See also
     ........

     See Session.get_bind() handles a wider variety of inheritance scenarios.

     References: #3178(2)

   * `[engine] [bug]' ¶. Fixed bug in Connection.
     and pool where the Connection.invalidate() method, or
     an invalidation due to a database disconnect, would fail if the
     ‘isolation_level’ parameter had been used with
     Connection.execution_options(); the “finalizer” that resets
     the isolation level would be called on the no longer opened
     connection.

     This change is also `backported' to: 0.9.9

     References: #3302(3)

   * `[engine] [bug]' ¶. A warning is emitted if the
     ‘isolation_level’ parameter is used with
     Connection.execution_options() when a Transaction
     is in play; DBAPIs and/or SQLAlchemy dialects such as psycopg2,
     MySQLdb may implicitly rollback or commit the transaction, or not
     change the setting til next transaction, so this is never safe.

     This change is also `backported' to: 0.9.9

     References: #3296(4)

   * `[engine] [bug]' ¶. The execution options passed to an
     Engine either via
     create_engine.execution_options or
     Engine.update_execution_options() are not passed to the
     special Connection used to initialize the dialect
     within the “first connect” event; dialects will usually perform
     their own queries in this phase, and none of the current available
     options should be applied here.  In particular, the “autocommit”
     option was causing an attempt to autocommit within this initial
     connect which would fail with an AttributeError due to the
     non-standard state of the Connection.

     This change is also `backported' to: 0.9.8

     References: #3200(5)

   * `[engine] [bug]' ¶. The string keys that are used to
     determine the columns impacted for an INSERT or UPDATE are now
     sorted when they contribute towards the “compiled cache” cache key.
     These keys were previously not deterministically ordered, meaning
     the same statement could be cached multiple times on equivalent
     keys, costing both in terms of memory as well as performance.

     This change is also `backported' to: 0.9.8

     References: #3165(6)

   * `[engine] [bug]' ¶. Fixed bug which would occur if a
     DBAPI exception occurs when the engine first connects and does its
     initial checks, and the exception is not a disconnect exception,
     yet the cursor raises an error when we try to close it.  In this
     case the real exception would be quashed as we tried to log the
     cursor close exception via the connection pool and failed, as we
     were trying to access the pool’s logger in a way that is
     inappropriate in this very specific scenario.

     This change is also `backported' to: 0.9.5

     References: #3063(7)

   * `[engine] [bug]' ¶. Fixed some “double invalidate”
     situations were detected where a connection invalidation could
     occur within an already critical section like a connection.close();
     ultimately, these conditions are caused by the change in #2907(8),
     in that the “reset on return” feature calls out to the
     Connection/Transaction in order to handle it, where “disconnect
     detection” might be caught.  However, it’s possible that the more
     recent change in #2985(9) made it more likely for this to be seen
     as the “connection invalidate” operation is much quicker, as the
     issue is more reproducible on 0.9.4 than 0.9.3.

     Checks are now added within any section that an invalidate might
     occur to halt further disallowed operations on the invalidated
     connection.  This includes two fixes both at the engine level and
     at the pool level.  While the issue was observed with highly
     concurrent gevent cases, it could in theory occur in any kind of
     scenario where a disconnect occurs within the connection close
     operation.

     This change is also `backported' to: 0.9.5

     References: #3043(10)

   * `[engine] [bug]' ¶. The engine-level error handling and
     wrapping routines will now take effect in all engine connection use
     cases, including when user-custom connect routines are used via the
     create_engine.creator parameter, as well as when the
     Connection encounters a connection error on
     revalidation.

     See also
     ........

     See DBAPI exception wrapping and handle_error() event improvements.

     References: #3266(11)

   * `[engine] [bug]' ¶. Removing (or adding) an event
     listener at the same time that the event is being run itself,
     either from inside the listener or from a concurrent thread, now
     raises a RuntimeError, as the collection used is now an instance of
     ‘collections.deque()’ and does not support changes while being
     iterated.  Previously, a plain Python list was used where removal
     from inside the event itself would produce silent failures.

     References: #3163(12)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3076

   (2) http://www.sqlalchemy.org/trac/ticket/3178

   (3) http://www.sqlalchemy.org/trac/ticket/3302

   (4) http://www.sqlalchemy.org/trac/ticket/3296

   (5) http://www.sqlalchemy.org/trac/ticket/3200

   (6) http://www.sqlalchemy.org/trac/ticket/3165

   (7) http://www.sqlalchemy.org/trac/ticket/3063

   (8) http://www.sqlalchemy.org/trac/ticket/2907

   (9) http://www.sqlalchemy.org/trac/ticket/2985

   (10) http://www.sqlalchemy.org/trac/ticket/3043

   (11) http://www.sqlalchemy.org/trac/ticket/3266

   (12) http://www.sqlalchemy.org/trac/ticket/3163

8.3.5.126 sql
.............

   * `[sql] [feature]' ¶. Liberalized the contract for
     Index a bit in that you can specify a text()
     expression as the target; the index no longer needs to have a
     table-bound column present if the index is to be manually added to
     the table, either via inline declaration or via
     Table.append_constraint().

     This change is also `backported' to: 0.9.5

     References: #3028(1)

   * `[sql] [feature]' ¶. Added new flag
     between.symmetric, when set to True renders “BETWEEN
     SYMMETRIC”.  Also added a new negation operator “notbetween_op”,
     which now allows an expression like ‘~col.between(x, y)’ to render
     as “col NOT BETWEEN x AND y”, rather than a parenthesized NOT
     string.

     This change is also `backported' to: 0.9.5

     References: #2990(2)

   * `[sql] [feature]' ¶. The SQL compiler now generates the
     mapping of expected columns 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 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.

     References: #918(3)

   * `[sql] [feature]' ¶. Literal values within a
     DefaultClause, which is invoked when using the
     Column.server_default parameter, will now be rendered using
     the “inline” compiler, so that they are rendered as-is, rather than
     as bound parameters.

     See also
     ........

     See Column server defaults now render literal values.

     References: #3087(4)

   * `[sql] [feature]' ¶. The type of expression is reported
     when an object passed to a SQL expression unit can’t be interpreted
     as a SQL fragment; pull request courtesy Ryan P. Kelly.

   * `[sql] [feature]' ¶. Added a new parameter
     Table.tometadata.name to the Table.tometadata()
     method.  Similar to Table.tometadata.schema, this
     argument causes the newly copied Table to take on the
     new name instead of the existing one.  An interesting capability
     this adds is that of copying a Table object to the
     `same' MetaData target with a new name.  Pull request
     courtesy n.d.  parker.

   * `[sql] [feature]' ¶. Exception messages have been
     spiffed up a bit.  The SQL statement 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.

     References: #3172(5)

   * `[sql] [feature]' ¶. See Insert.from_select().
     now includes Python and SQL-expression defaults if otherwise
     unspecified; the limitation where non- server column defaults
     aren’t included in an INSERT FROM SELECT is now lifted and these
     expressions are rendered as constants into the SELECT statement.

     See also
     ........

     See INSERT FROM SELECT now includes Python and SQL-expression defaults.

   * `[sql] [feature]' ¶. The UniqueConstraint.
     construct is now included when reflecting a Table
     object, for databases where this is applicable.  In order to
     achieve this with sufficient accuracy, MySQL and PostgreSQL now
     contain features that correct for the duplication of indexes and
     unique constraints when reflecting tables, indexes, and
     constraints.  In the case of MySQL, there is not actually a “unique
     constraint” concept independent of a “unique index”, so for this
     backend UniqueConstraint continues to remain
     non-present for a reflected Table.  For PostgreSQL, the
     query used to detect indexes against ‘pg_index’ has been improved
     to check for the same construct in ‘pg_constraint’, and the
     implicitly constructed unique index is not included with a
     reflected Table.

     In both cases, the Inspector.get_indexes() and the
     Inspector.get_unique_constraints() methods return both
     constructs individually, but include a new token
     ‘duplicates_constraint’ in the case of PostgreSQL or
     ‘duplicates_index’ in the case of MySQL to indicate when this
     condition is detected.  Pull request courtesy Johannes Erdfelt.

     See also
     ........

     See UniqueConstraint is now part of the Table reflection process.

     References: #3184(6)

   * `[sql] [feature]' ¶. Added new method
     Select.with_statement_hint() and ORM method
     Query.with_statement_hint() to support statement-level hints
     that are not specific to a table.

     References: #3206(7)

   * `[sql] [feature]' ¶. The ‘info’ parameter has been
     added as a constructor argument to all schema constructs including
     MetaData, Index, ForeignKey,
     ForeignKeyConstraint, UniqueConstraint,
     PrimaryKeyConstraint, CheckConstraint.

     References: #2963(8)

   * `[sql] [feature]' ¶. The Table.autoload_with.
     flag now implies that Table.autoload should be ‘True’.
     Pull request courtesy Malik Diarra.

     References: #3027(9)

   * `[sql] [feature]' ¶. The Select.limit() and
     Select.offset() methods now accept any SQL expression,
     in addition to integer values, as arguments.  Typically this is
     used to allow a bound parameter to be passed, which can be
     substituted with a value later thus allowing Python-side caching of
     the SQL query.  The implementation here is fully backwards
     compatible with existing third party dialects, however those
     dialects which implement special LIMIT/OFFSET systems will need
     modification in order to take advantage of the new capabilities.
     Limit and offset also support “literal_binds” mode,

     References: #3034(10)

   * `[sql] [changed]' ¶. The column() and
     table() constructs are now importable from the “from
     sqlalchemy” namespace, just like every other Core construct.

   * `[sql] [changed]' ¶. The implicit conversion of strings
     to text() constructs when passed to most builder methods
     of select() as well as 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.

     See also
     ........

     See Warnings emitted when coercing full SQL fragments into text().

     References: #2992(11)

   * `[sql] [bug]' ¶. Fixed bug in Enum and
     other SchemaType subclasses where direct association
     of the type with a MetaData would lead to a hang when
     events (like create events) were emitted on the MetaData.

     This change is also `backported' to: 0.9.7, 0.8.7

     References: #3124(12)

   * `[sql] [bug]' ¶. Fixed a bug within the custom operator
     plus TypeEngine.with_variant() system, whereby using a
     TypeDecorator in conjunction with variant would fail
     with an MRO error when a comparison operator was used.

     This change is also `backported' to: 0.9.7, 0.8.7

     References: #3102(13)

   * `[sql] [bug]' ¶. Fixed bug in INSERT..FROM SELECT
     construct where selecting from a UNION would wrap the union in an
     anonymous (e.g.  unlabeled) subquery.

     This change is also `backported' to: 0.9.5, 0.8.7

     References: #3044(14)

   * `[sql] [bug]' ¶. Fixed bug where Table.update()
     and Table.delete() would produce an empty WHERE
     clause when an empty and_() or or_() or other
     blank expression were applied.  This is now consistent with that of
     select().

     This change is also `backported' to: 0.9.5, 0.8.7

     References: #3045(15)

   * `[sql] [bug]' ¶. Added the ‘native_enum’ flag to the
     ‘__repr__()’ output of Enum, which is mostly important
     when using it with Alembic autogenerate.  Pull request courtesy
     Dimitris Theodorou.

     This change is also `backported' to: 0.9.9

   * `[sql] [bug]' ¶. Fixed bug where using a
     TypeDecorator that implemented a type that was also a
     TypeDecorator would fail with Python’s “Cannot create a
     consistent method resolution order (MRO)” error, when any kind of
     SQL comparison expression were used against an object using this
     type.

     This change is also `backported' to: 0.9.9

     References: #3278(16)

   * `[sql] [bug]' ¶. Fixed issue where the columns from a
     SELECT embedded in an INSERT, either through the values clause or
     as a “from select”, would pollute the column types used in the
     result set produced by the RETURNING clause when columns from both
     statements shared the same name, leading to potential errors or
     mis-adaptation when retrieving the returning rows.

     This change is also `backported' to: 0.9.9

     References: #3248(17)

   * `[sql] [bug]' ¶. Fixed bug where a fair number of SQL
     elements within the sql package would fail to ‘__repr__()’
     successfully, due to a missing ‘description’ attribute that would
     then invoke a recursion overflow when an internal AttributeError
     would then re-invoke ‘__repr__()’.

     This change is also `backported' to: 0.9.8

     References: #3195(18)

   * `[sql] [bug]' ¶. An adjustment to table/index
     reflection such that if an index reports a column that isn’t found
     to be present in the table, a warning is emitted and the column is
     skipped.  This can occur for some special system column situations
     as has been observed with Oracle.

     This change is also `backported' to: 0.9.8

     References: #3180(19)

   * `[sql] [bug]' ¶. Fixed bug in CTE where ‘literal_binds’
     compiler argument would not be always be correctly propagated when
     one CTE referred to another aliased CTE in a statement.

     This change is also `backported' to: 0.9.8

     References: #3154(20)

   * `[sql] [bug]' ¶. Fixed 0.9.7 regression caused by
     #3067(21) in conjunction with a mis-named unit test such that
     so-called “schema” types like Boolean and Enum
     could no longer be pickled.

     This change is also `backported' to: 0.9.8

     References: #3067(22), #3144(23)

   * `[sql] [bug]' ¶. Fix bug in naming convention feature
     where using a check constraint convention that includes
     ‘constraint_name’ would then force all Boolean and
     Enum types to require names as well, as these
     implicitly create a constraint, even if the ultimate target backend
     were one that does not require generation of the constraint such as
     PostgreSQL. The mechanics of naming conventions for these
     particular constraints has been reorganized such that the naming
     determination is done at DDL compile time, rather than at
     constraint/table construction time.

     This change is also `backported' to: 0.9.7

     References: #3067(24)

   * `[sql] [bug]' ¶. Fixed bug in common table expressions
     whereby positional bound parameters could be expressed in the wrong
     final order when CTEs were nested in certain ways.

     This change is also `backported' to: 0.9.7

     References: #3090(25)

   * `[sql] [bug]' ¶. Fixed bug where multi-valued
     Insert construct would fail to check subsequent values entries
     beyond the first one given for literal SQL expressions.

     This change is also `backported' to: 0.9.7

     References: #3069(26)

   * `[sql] [bug]' ¶. Added a “str()” step to the
     dialect_kwargs iteration for Python version < 2.6.5, working around
     the “no unicode keyword arg” bug as these args are passed along as
     keyword args within some reflection processes.

     This change is also `backported' to: 0.9.7

     References: #3123(27)

   * `[sql] [bug]' ¶. The TypeEngine.with_variant()
     method will now accept a type class as an argument which is
     internally converted to an instance, using the same convention long
     established by other constructs such as Column.

     This change is also `backported' to: 0.9.7

     References: #3122(28)

   * `[sql] [bug]' ¶. The Column.nullable flag is
     implicitly set to ‘False’ when that Column is referred
     to in an explicit PrimaryKeyConstraint for that table.
     This behavior now matches that of when the Column itself
     has the Column.primary_key flag set to ‘True’, which is
     intended to be an exactly equivalent case.

     This change is also `backported' to: 0.9.5

     References: #3023(29)

   * `[sql] [bug]' ¶. Fixed bug where the
     Operators.__and__(), Operators.__or__() and
     Operators.__invert__() operator overload methods could not be
     overridden within a custom Comparator implementation.

     This change is also `backported' to: 0.9.5

     References: #3012(30)

   * `[sql] [bug]' ¶. Fixed bug in new
     DialectKWArgs.argument_for() method where adding an argument
     for a construct not previously included for any special arguments
     would fail.

     This change is also `backported' to: 0.9.5

     References: #3024(31)

   * `[sql] [bug]' ¶. Fixed regression introduced in 0.9
     where new “ORDER BY <labelname>” feature from #1068(32) would not
     apply quoting rules to the label name as rendered in the ORDER BY.

     This change is also `backported' to: 0.9.5

     References: #1068(33), #3020(34)

   * `[sql] [bug]' ¶. Restored the import for
     Function to the ‘sqlalchemy.sql.expression’ import namespace,
     which was removed at the beginning of 0.9.

     This change is also `backported' to: 0.9.5

   * `[sql] [bug]' ¶. The multi-values version of
     Insert.values() has been repaired to work more usefully with
     tables that have Python- side default values and/or functions, as
     well as server-side defaults.  The feature will now work with a
     dialect that uses “positional” parameters; a Python callable will
     also be invoked individually for each row just as is the case with
     an “executemany” style invocation; a server- side default column
     will no longer implicitly receive the value explicitly specified
     for the first row, instead refusing to invoke without an explicit
     value.

     See also
     ........

     See Python-side defaults invoked for each row individually when using a multivalued insert.

     References: #3288(35)

   * `[sql] [bug]' ¶. Fixed bug in Table.tometadata()
     method where the CheckConstraint associated with
     a Boolean or Enum type object would be
     doubled in the target table.  The copy process now tracks the
     production of this constraint object as local to a type object.

     References: #3260(36)

   * `[sql] [bug]' ¶. The behavioral contract of the
     ForeignKeyConstraint.columns collection has been made
     consistent; this attribute is now a ColumnCollection
     like that of all other constraints and is initialized at the point
     when the constraint is associated with a Table.

     See also
     ........

     See ForeignKeyConstraint.columns is now a ColumnCollection.

     References: #3243(37)

   * `[sql] [bug]' ¶. The ‘Column.key’ attribute is now used
     as the source of anonymous bound parameter names within
     expressions, to match the existing use of this value as the key
     when rendered in an INSERT or UPDATE statement.  This allows
     ‘Column.key’ to be used as a “substitute” string to work around a
     difficult column name that doesn’t translate well into a bound
     parameter name.  Note that the paramstyle is configurable on
     create_engine() in any case, and most DBAPIs today support a
     named and positional style.

     References: #3245(38)

   * `[sql] [bug]' ¶. Fixed the name of the
     PoolEvents.reset.dbapi_connection parameter as passed to
     this event; in particular this affects usage of the “named”
     argument style for this event.  Pull request courtesy Jason
     Goldberger.

   * `[sql] [bug]' ¶. Reversing a change that was made in
     0.9, the “singleton” nature of the “constants” null(),
     true(), and false() has been reverted.
     These functions returning a “singleton” object had the effect that
     different instances would be treated as the same regardless of
     lexical use, which in particular would impact the rendering of the
     columns clause of a SELECT statement.

     See also
     ........

     See null(), false() and true() constants are no longer singletons.

     References: #3170(39)

   * `[sql] [bug] [engine]' ¶. Fixed bug where a “branched”
     connection, that is the kind you get when you call
     Connection.connect(), would not share invalidation status
     with the parent.  The architecture of branching has been tweaked a
     bit so that the branched connection defers to the parent for all
     invalidation status and operations.

     References: #3215(40)

   * `[sql] [bug] [engine]' ¶. Fixed bug where a “branched”
     connection, that is the kind you get when you call
     Connection.connect(), would not share transaction status with
     the parent.  The architecture of branching has been tweaked a bit
     so that the branched connection defers to the parent for all
     transactional status and operations.

     References: #3190(41)

   * `[sql] [bug]' ¶. Using Insert.from_select().
     now implies ‘inline=True’ on 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 variable numbers of rows, the
     ‘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 Insert.returning() should be
     used to return variable numbers of result rows if inserted data is
     needed.

     References: #3169(42)

   * `[sql] [enhancement]' ¶. Custom dialects that implement
     GenericTypeCompiler can now be constructed such that
     the visit methods receive an indication of the owning expression
     object, if any.  Any visit method that accepts keyword arguments
     (e.g.  ‘**kw’) will in most cases receive a keyword argument
     ‘type_expression’, referring to the expression object that the type
     is contained within.  For columns in DDL, the dialect’s compiler
     class may need to alter its ‘get_column_specification()’ method to
     support this as well.  The ‘UserDefinedType.get_col_spec()’ method
     will also receive ‘type_expression’ if it provides ‘**kw’ in its
     argument signature.

     References: #3074(43)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3028

   (2) http://www.sqlalchemy.org/trac/ticket/2990

   (3) http://www.sqlalchemy.org/trac/ticket/918

   (4) http://www.sqlalchemy.org/trac/ticket/3087

   (5) http://www.sqlalchemy.org/trac/ticket/3172

   (6) http://www.sqlalchemy.org/trac/ticket/3184

   (7) http://www.sqlalchemy.org/trac/ticket/3206

   (8) http://www.sqlalchemy.org/trac/ticket/2963

   (9) http://www.sqlalchemy.org/trac/ticket/3027

   (10) http://www.sqlalchemy.org/trac/ticket/3034

   (11) http://www.sqlalchemy.org/trac/ticket/2992

   (12) http://www.sqlalchemy.org/trac/ticket/3124

   (13) http://www.sqlalchemy.org/trac/ticket/3102

   (14) http://www.sqlalchemy.org/trac/ticket/3044

   (15) http://www.sqlalchemy.org/trac/ticket/3045

   (16) http://www.sqlalchemy.org/trac/ticket/3278

   (17) http://www.sqlalchemy.org/trac/ticket/3248

   (18) http://www.sqlalchemy.org/trac/ticket/3195

   (19) http://www.sqlalchemy.org/trac/ticket/3180

   (20) http://www.sqlalchemy.org/trac/ticket/3154

   (21) http://www.sqlalchemy.org/trac/ticket/3067

   (22) http://www.sqlalchemy.org/trac/ticket/3067

   (23) http://www.sqlalchemy.org/trac/ticket/3144

   (24) http://www.sqlalchemy.org/trac/ticket/3067

   (25) http://www.sqlalchemy.org/trac/ticket/3090

   (26) http://www.sqlalchemy.org/trac/ticket/3069

   (27) http://www.sqlalchemy.org/trac/ticket/3123

   (28) http://www.sqlalchemy.org/trac/ticket/3122

   (29) http://www.sqlalchemy.org/trac/ticket/3023

   (30) http://www.sqlalchemy.org/trac/ticket/3012

   (31) http://www.sqlalchemy.org/trac/ticket/3024

   (32) http://www.sqlalchemy.org/trac/ticket/1068

   (33) http://www.sqlalchemy.org/trac/ticket/1068

   (34) http://www.sqlalchemy.org/trac/ticket/3020

   (35) http://www.sqlalchemy.org/trac/ticket/3288

   (36) http://www.sqlalchemy.org/trac/ticket/3260

   (37) http://www.sqlalchemy.org/trac/ticket/3243

   (38) http://www.sqlalchemy.org/trac/ticket/3245

   (39) http://www.sqlalchemy.org/trac/ticket/3170

   (40) http://www.sqlalchemy.org/trac/ticket/3215

   (41) http://www.sqlalchemy.org/trac/ticket/3190

   (42) http://www.sqlalchemy.org/trac/ticket/3169

   (43) http://www.sqlalchemy.org/trac/ticket/3074

8.3.5.127 schema
................

   * `[schema] [feature]' ¶. The DDL generation system of
     MetaData.create_all() and MetaData.drop_all()
     has been enhanced to in most cases automatically handle the case of
     mutually dependent foreign key constraints; the need for the
     ForeignKeyConstraint.use_alter flag is greatly reduced.  The
     system also works for constraints which aren’t given a name up
     front; only in the case of DROP is a name required for at least one
     of the constraints involved in the cycle.

     See also
     ........

     See The use_alter flag on ForeignKeyConstraint is (usually) no longer needed.

     References: #3282(1)

   * `[schema] [feature]' ¶. Added a new accessor
     Table.foreign_key_constraints to complement the
     Table.foreign_keys collection, as well as
     ForeignKeyConstraint.referred_table.

   * `[schema] [bug]' ¶. The CheckConstraint.
     construct now supports naming conventions that include the token
     ‘%(column_0_name)s’; the constraint expression is scanned for
     columns.  Additionally, naming conventions for check constraints
     that don’t include the ‘%(constraint_name)s’ token will now work
     for SchemaType.- generated constraints, such as those
     of Boolean and Enum; this stopped working
     in 0.9.7 due to #3067(2).

     See also
     ........

     See Naming CHECK Constraints.

     See Configuring Naming for Boolean, Enum, and other schema types.

     References: #3067(3), #3299(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3282

   (2) http://www.sqlalchemy.org/trac/ticket/3067

   (3) http://www.sqlalchemy.org/trac/ticket/3067

   (4) http://www.sqlalchemy.org/trac/ticket/3299

8.3.5.128 postgresql
....................

   * `[postgresql] [feature]' ¶. Added support for the
     ‘CONCURRENTLY’ keyword with PostgreSQL indexes, established using
     ‘postgresql_concurrently’.  Pull request courtesy Iuri de Silvio.

     See also
     ........

     See Indexes with CONCURRENTLY.

     This change is also `backported' to: 0.9.9

   * `[postgresql] [feature] [pg8000]' ¶. Support is added
     for “sane multi row count” with the pg8000 driver, which applies
     mostly to when using versioning with the ORM. The feature is
     version-detected based on pg8000 1.9.14 or greater in use.  Pull
     request courtesy Tony Locke.

     This change is also `backported' to: 0.9.8

   * `[postgresql] [feature]' ¶. Added kw argument
     ‘postgresql_regconfig’ to the ColumnOperators.match()
     operator, allows the “reg config” argument to be specified to the
     ‘to_tsquery()’ function emitted.  Pull request courtesy Jonathan
     Vanasco.

     This change is also `backported' to: 0.9.7

     References: #3078(1)

   * `[postgresql] [feature]' ¶. Added support for
     PostgreSQL JSONB via JSONB.  Pull request courtesy
     Damian Dimmich.

     This change is also `backported' to: 0.9.7

   * `[postgresql] [feature]' ¶. Added support for
     AUTOCOMMIT isolation level when using the pg8000 DBAPI. Pull
     request courtesy Tony Locke.

     This change is also `backported' to: 0.9.5

   * `[postgresql] [feature]' ¶. Added a new flag
     ARRAY.zero_indexes to the PostgreSQL ARRAY type.
     When set to ‘True’, a value of one will be added to all array index
     values before passing to the database, allowing better
     interoperability between Python style zero-based indexes and
     PostgreSQL one-based indexes.  Pull request courtesy Alexey
     Terentev.

     This change is also `backported' to: 0.9.5

     References: #2785(2)

   * `[postgresql] [feature]' ¶. The PG8000 dialect now
     supports the create_engine.encoding parameter, by
     setting up the client encoding on the connection which is then
     intercepted by pg8000.  Pull request courtesy Tony Locke.

   * `[postgresql] [feature]' ¶. Added support for PG8000’s
     native JSONB feature.  Pull request courtesy Tony Locke.

   * `[postgresql] [feature] [pypy]' ¶. Added support for
     the psycopg2cffi DBAPI on pypy.  Pull request courtesy shauns.

     See also
     ........

     See sqlalchemy.dialects.postgresql.psycopg2cffi.

     References: #3052(3)

   * `[postgresql] [feature]' ¶. Added support for the
     FILTER keyword as applied to aggregate functions, supported by
     PostgreSQL 9.4.  Pull request courtesy Ilja Everilä.

     See also
     ........

     See PostgreSQL FILTER keyword.

   * `[postgresql] [feature]' ¶. Support has been added for
     reflection of materialized views and foreign tables, as well as
     support for materialized views within
     Inspector.get_view_names(), and a new method
     PGInspector.get_foreign_table_names() available on the
     PostgreSQL version of Inspector.  Pull request courtesy
     Rodrigo Menezes.

     See also
     ........

     See PostgreSQL Dialect reflects Materialized Views, Foreign Tables.

     References: #2891(4)

   * `[postgresql] [feature]' ¶. Added support for PG table
     options TABLESPACE, ON COMMIT, WITH(OUT) OIDS, and INHERITS, when
     rendering DDL via the Table construct.  Pull request
     courtesy malikdiarra.

     See also
     ........

     See PostgreSQL Table Options.

     References: #2051(5)

   * `[postgresql] [feature]' ¶. Added new method
     PGInspector.get_enums(), when using the inspector for
     PostgreSQL will provide a list of ENUM types.  Pull request
     courtesy Ilya Pekelny.

   * `[postgresql] [bug]' ¶. Added the ‘hashable=False’ flag
     to the PG HSTORE type, which is needed to allow the ORM
     to skip over trying to “hash” an ORM-mapped HSTORE column when
     requesting it in a mixed column/entity list.  Patch courtesy
     Gunnlaugur Þór Briem.

     This change is also `backported' to: 0.9.5, 0.8.7

     References: #3053(6)

   * `[postgresql] [bug]' ¶. Added a new “disconnect”
     message “connection has been closed unexpectedly”.  This appears to
     be related to newer versions of SSL. Pull request courtesy Antti
     Haapala.

     This change is also `backported' to: 0.9.5, 0.8.7

   * `[postgresql] [bug]' ¶. Repaired support for PostgreSQL
     UUID types in conjunction with the ARRAY type when using psycopg2.
     The psycopg2 dialect now employs use of the
     psycopg2.extras.register_uuid() hook so that UUID values are always
     passed to/from the DBAPI as UUID() objects.  The
     UUID.as_uuid flag is still honored, except with psycopg2 we
     need to convert returned UUID objects back into strings when this
     is disabled.

     This change is also `backported' to: 0.9.9

     References: #2940(7)

   * `[postgresql] [bug]' ¶. Added support for the
     ‘postgresql.JSONB’ datatype when using psycopg2 2.5.4 or greater,
     which features native conversion of JSONB data so that SQLAlchemy’s
     converters must be disabled; additionally, the newly added psycopg2
     extension ‘extras.register_default_jsonb’ is used to establish a
     JSON deserializer passed to the dialect via the ‘json_deserializer’
     argument.  Also repaired the PostgreSQL integration tests which
     weren’t actually round-tripping the JSONB type as opposed to the
     JSON type.  Pull request courtesy Mateusz Susik.

     This change is also `backported' to: 0.9.9

   * `[postgresql] [bug]' ¶. Repaired the use of the
     “array_oid” flag when registering the HSTORE type with older
     psycopg2 versions < 2.4.3, which does not support this flag, as
     well as use of the native json serializer hook
     “register_default_json” with user-defined ‘json_deserializer’ on
     psycopg2 versions < 2.5, which does not include native json.

     This change is also `backported' to: 0.9.9

   * `[postgresql] [bug]' ¶. Fixed bug where PostgreSQL
     dialect would fail to render an expression in an Index
     that did not correspond directly to a table-bound column; typically
     when a text() construct was one of the expressions
     within the index; or could misinterpret the list of expressions if
     one or more of them were such an expression.

     This change is also `backported' to: 0.9.9

     References: #3174(8)

   * `[postgresql] [bug]' ¶. A revisit to this issue first
     patched in 0.9.5, apparently psycopg2’s ‘.closed’ accessor is not
     as reliable as we assumed, so we have added an explicit check for
     the exception messages “SSL SYSCALL error: Bad file descriptor” and
     “SSL SYSCALL error: EOF detected” when detecting an is-disconnect
     scenario.  We will continue to consult psycopg2’s connection.closed
     as a first check.

     This change is also `backported' to: 0.9.8

     References: #3021(9)

   * `[postgresql] [bug]' ¶. Fixed bug where PostgreSQL JSON
     type was not able to persist or otherwise render a SQL NULL column
     value, rather than a JSON-encoded ‘'null'’.  To support this case,
     changes are as follows:

        * The value null() can now be specified, which will
          always result in a NULL value resulting in the statement.

        * A new parameter JSON.none_as_null is added, which
          when True indicates that the Python ‘None’ value should be
          persisted as SQL NULL, rather than JSON-encoded ‘'null'’.

     Retrieval of NULL as None is also repaired for DBAPIs other than
     psycopg2, namely pg8000.

     This change is also `backported' to: 0.9.8

     References: #3159(10)

   * `[postgresql] [bug]' ¶. The exception wrapping system
     for DBAPI errors can now accommodate non-standard DBAPI exceptions,
     such as the psycopg2 TransactionRollbackError.  These exceptions
     will now be raised using the closest available subclass in
     ‘sqlalchemy.exc’, in the case of TransactionRollbackError,
     ‘sqlalchemy.exc.OperationalError’.

     This change is also `backported' to: 0.9.8

     References: #3075(11)

   * `[postgresql] [bug]' ¶. Fixed bug in array.
     object where comparison to a plain Python list would fail to use
     the correct array constructor.  Pull request courtesy Andrew.

     This change is also `backported' to: 0.9.8

     References: #3141(12)

   * `[postgresql] [bug]' ¶. Added a supported
     FunctionElement.alias() method to functions, e.g.  the ‘func’
     construct.  Previously, behavior for this method was undefined.
     The current behavior mimics that of pre-0.9.4, which is that the
     function is turned into a single-column FROM clause with the given
     alias name, where the column itself is anonymously named.

     This change is also `backported' to: 0.9.8

     References: #3137(13)

   * `[postgresql] [bug] [pg8000]' ¶. Fixed bug introduced
     in 0.9.5 by new pg8000 isolation level feature where engine-level
     isolation level parameter would raise an error on connect.

     This change is also `backported' to: 0.9.7

     References: #3134(14)

   * `[postgresql] [bug]' ¶. The psycopg2 ‘.closed’ accessor
     is now consulted when determining if an exception is a “disconnect”
     error; ideally, this should remove the need for any other
     inspection of the exception message to detect disconnect, however
     we will leave those existing messages in place as a fallback.  This
     should be able to handle newer cases like “SSL EOF” conditions.
     Pull request courtesy Dirk Mueller.

     This change is also `backported' to: 0.9.5

     References: #3021(15)

   * `[postgresql] [bug]' ¶. The PostgreSQL ENUM
     type will emit a DROP TYPE instruction when a plain
     ‘table.drop()’ is called, assuming the object is not associated
     directly with a MetaData object.  In order to
     accommodate the use case of an enumerated type shared between
     multiple tables, the type should be associated directly with the
     MetaData object; in this case the type will only be
     created at the metadata level, or if created directly.  The rules
     for create/drop of PostgreSQL enumerated types have been highly
     reworked in general.

     See also
     ........

     See Overhaul of ENUM type create/drop rules.

     References: #3319(16)

   * `[postgresql] [bug]' ¶. The ‘PGDialect.has_table()’
     method will now query against
     ‘pg_catalog.pg_table_is_visible(c.oid)’, rather than testing for an
     exact schema match, when the schema name is None; this so that the
     method will also illustrate that temporary tables are present.
     Note that this is a behavioral change, as PostgreSQL allows a
     non-temporary table to silently overwrite an existing temporary
     table of the same name, so this changes the behavior of
     ‘checkfirst’ in that unusual scenario.

     See also
     ........

     See PostgreSQL has_table() now works for temporary tables.

     References: #3264(17)

   * `[postgresql] [enhancement]' ¶. Added a new type
     OID to the PostgreSQL dialect.  While “oid” is generally a
     private type within PG that is not exposed in modern versions,
     there are some PG use cases such as large object support where
     these types might be exposed, as well as within some user-reported
     schema reflection use cases.

     This change is also `backported' to: 0.9.5

     References: #3002(18)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3078

   (2) http://www.sqlalchemy.org/trac/ticket/2785

   (3) http://www.sqlalchemy.org/trac/ticket/3052

   (4) http://www.sqlalchemy.org/trac/ticket/2891

   (5) http://www.sqlalchemy.org/trac/ticket/2051

   (6) http://www.sqlalchemy.org/trac/ticket/3053

   (7) http://www.sqlalchemy.org/trac/ticket/2940

   (8) http://www.sqlalchemy.org/trac/ticket/3174

   (9) http://www.sqlalchemy.org/trac/ticket/3021

   (10) http://www.sqlalchemy.org/trac/ticket/3159

   (11) http://www.sqlalchemy.org/trac/ticket/3075

   (12) http://www.sqlalchemy.org/trac/ticket/3141

   (13) http://www.sqlalchemy.org/trac/ticket/3137

   (14) http://www.sqlalchemy.org/trac/ticket/3134

   (15) http://www.sqlalchemy.org/trac/ticket/3021

   (16) http://www.sqlalchemy.org/trac/ticket/3319

   (17) http://www.sqlalchemy.org/trac/ticket/3264

   (18) http://www.sqlalchemy.org/trac/ticket/3002

8.3.5.129 mysql
...............

   * `[mysql] [feature]' ¶. The MySQL dialect now renders
     TIMESTAMP with NULL / NOT NULL in all cases, so that MySQL 5.6.6
     with the ‘explicit_defaults_for_timestamp’ flag enabled will will
     allow TIMESTAMP to continue to work as expected when
     ‘nullable=False’.  Existing applications are unaffected as
     SQLAlchemy has always emitted NULL for a TIMESTAMP column that is
     ‘nullable=True’.

     See also
     ........

     See MySQL TIMESTAMP Type now renders NULL / NOT NULL in all cases.

     See TIMESTAMP Columns and NULL.

     References: #3155(1)

   * `[mysql] [feature]' ¶. Updated the
     “supports_unicode_statements” flag to True for MySQLdb and Pymysql
     under Python 2.  This refers to the SQL statements themselves, not
     the parameters, and affects issues such as table and column names
     using non-ASCII characters.  These drivers both appear to support
     Python 2 Unicode objects without issue in modern versions.

     References: #3121(2)

   * `[mysql] [change]' ¶. The ‘gaerdbms’ dialect is no
     longer necessary, and emits a deprecation warning.  Google now
     recommends using the MySQLdb dialect directly.

     This change is also `backported' to: 0.9.9

     References: #3275(3)

   * `[mysql] [bug]' ¶. MySQL error 2014 “commands out of
     sync” appears to be raised as a ProgrammingError, not
     OperationalError, in modern MySQL-Python versions; all MySQL error
     codes that are tested for “is disconnect” are now checked within
     OperationalError and ProgrammingError regardless.

     This change is also `backported' to: 0.9.7, 0.8.7

     References: #3101(4)

   * `[mysql] [bug]' ¶. Fixed bug where column names added
     to ‘mysql_length’ parameter on an index needed to have the same
     quoting for quoted names in order to be recognized.  The fix makes
     the quotes optional but also provides the old behavior for
     backwards compatibility with those using the workaround.

     This change is also `backported' to: 0.9.5, 0.8.7

     References: #3085(5)

   * `[mysql] [bug]' ¶. Added support for reflecting tables
     where an index includes KEY_BLOCK_SIZE using an equal sign.  Pull
     request courtesy Sean McGivern.

     This change is also `backported' to: 0.9.5, 0.8.7

   * `[mysql] [bug]' ¶. Added a version check to the MySQLdb
     dialect surrounding the check for ‘utf8_bin’ collation, as this
     fails on MySQL server < 5.0.

     This change is also `backported' to: 0.9.9

     References: #3274(6)

   * `[mysql] [bug] [mysqlconnector]' ¶. Mysqlconnector as
     of version 2.0, probably as a side effect of 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 ‘%’.

     This change is also `backported' to: 0.9.8

   * `[mysql] [bug] [mysqlconnector]' ¶. Unicode SQL is now
     passed for MySQLconnector version 2.0 and above; for Py2k and MySQL
     < 2.0, strings are encoded.

     This change is also `backported' to: 0.9.8

   * `[mysql] [bug]' ¶. The MySQL dialect now supports CAST
     on types that are constructed as TypeDecorator
     objects.

   * `[mysql] [bug]' ¶. A warning is emitted when
     cast() is used with the MySQL dialect on a type where MySQL
     does not support CAST; MySQL only supports CAST on a subset of
     datatypes.  SQLAlchemy has for a long time just omitted the CAST
     for unsupported types in the case of MySQL. While we don’t want to
     change this now, we emit a warning to show that it’s taken place.
     A warning is also emitted when a CAST is used with an older MySQL
     version (< 4) that doesn’t support CAST at all, it’s skipped in
     this case as well.

     References: #3237(7)

   * `[mysql] [bug]' ¶. The SET type has been
     overhauled to no longer assume that the empty string, or a set with
     a single empty string value, is in fact a set with a single empty
     string; instead, this is by default treated as the empty set.  In
     order to handle persistence of a SET that actually
     wants to include the blank value ‘''’ as a legitimate value, a new
     bitwise operational mode is added which is enabled by the
     SET.retrieve_as_bitwise flag, which will persist and
     retrieve values unambiguously using their bitflag positioning.
     Storage and retrieval of unicode values for driver configurations
     that aren’t converting unicode natively is also repaired.

     See also
     ........

     See MySQL SET Type Overhauled to support empty sets, unicode, blank value handling.

     References: #3283(8)

   * `[mysql] [bug]' ¶. The ColumnOperators.match()
     operator is now handled such that the return type is not
     strictly assumed to be boolean; it now returns a Boolean
     subclass called MatchType.  The type will still
     produce boolean behavior when used in Python expressions, however
     the dialect can override its behavior at result time.  In the case
     of MySQL, while the MATCH operator is typically used in a boolean
     context within an expression, if one actually queries for the value
     of a match expression, a floating point value is returned; this
     value is not compatible with SQLAlchemy’s C-based boolean
     processor, so MySQL’s result-set behavior now follows that of the
     Float type.  A new operator object ‘notmatch_op’ is
     also added to better allow dialects to define the negation of a
     match operation.

     See also
     ........

     See The match() operator now returns an agnostic MatchType compatible with MySQL’s floating point return value.

     References: #3263(9)

   * `[mysql] [bug]' ¶. MySQL boolean symbols “true”,
     “false” work again.  0.9’s change in #2682(10) disallowed the MySQL
     dialect from making use of the “true” and “false” symbols in the
     context of “IS” / “IS NOT”, but MySQL supports this syntax even
     though it has no boolean type.  MySQL remains “non native boolean”,
     but the true() and false() symbols again
     produce the keywords “true” and “false”, so that an expression like
     ‘column.is_(true())’ again works on MySQL.

     See also
     ........

     See MySQL boolean symbols “true”, “false” work again.

     References: #3186(11)

   * `[mysql] [bug]' ¶. The MySQL dialect will now disable
     ConnectionEvents.handle_error() events from firing for
     those statements which it uses internally to detect if a table
     exists or not.  This is achieved using an execution option
     ‘skip_user_error_events’ that disables the handle error event for
     the scope of that execution.  In this way, user code that rewrites
     exceptions doesn’t need to worry about the MySQL dialect or other
     dialects that occasionally need to catch SQLAlchemy specific
     exceptions.

   * `[mysql] [bug]' ¶. Changed the default value of
     “raise_on_warnings” to False for MySQLconnector.  This was set at
     True for some reason.  The “buffered” flag unfortunately must stay
     at True as MySQLconnector does not allow a cursor to be closed
     unless all results are fully fetched.

     References: #2515(12)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3155

   (2) http://www.sqlalchemy.org/trac/ticket/3121

   (3) http://www.sqlalchemy.org/trac/ticket/3275

   (4) http://www.sqlalchemy.org/trac/ticket/3101

   (5) http://www.sqlalchemy.org/trac/ticket/3085

   (6) http://www.sqlalchemy.org/trac/ticket/3274

   (7) http://www.sqlalchemy.org/trac/ticket/3237

   (8) http://www.sqlalchemy.org/trac/ticket/3283

   (9) http://www.sqlalchemy.org/trac/ticket/3263

   (10) http://www.sqlalchemy.org/trac/ticket/2682

   (11) http://www.sqlalchemy.org/trac/ticket/3186

   (12) http://www.sqlalchemy.org/trac/ticket/2515

8.3.5.130 sqlite
................

   * `[sqlite] [feature]' ¶. Added support for partial
     indexes (e.g.  with a WHERE clause) on SQLite.  Pull request
     courtesy Kai Groner.

     See also
     ........

     See Partial Indexes.

     This change is also `backported' to: 0.9.9

   * `[sqlite] [feature]' ¶. Added a new SQLite backend for
     the SQLCipher backend.  This backend provides for encrypted SQLite
     databases using the pysqlcipher Python driver, which is very
     similar to the pysqlite driver.

     See also
     ........

     See pysqlcipher.

     This change is also `backported' to: 0.9.9

   * `[sqlite] [bug]' ¶. When selecting from a UNION using
     an attached database file, the pysqlite driver reports column names
     in cursor.description as ‘dbname.tablename.colname’, instead of
     ‘tablename.colname’ as it normally does for a UNION (note that it’s
     supposed to just be ‘colname’ for both, but we work around it).
     The column translation logic here has been adjusted to retrieve the
     rightmost token, rather than the second token, so it works in both
     cases.  Workaround courtesy Tony Roberts.

     This change is also `backported' to: 0.9.8

     References: #3211(1)

   * `[sqlite] [bug]' ¶. Fixed a SQLite join rewriting issue
     where a subquery that is embedded as a scalar subquery such as
     within an IN would receive inappropriate substitutions from the
     enclosing query, if the same table were present inside the subquery
     as were in the enclosing query such as in a joined inheritance
     scenario.

     This change is also `backported' to: 0.9.7

     References: #3130(2)

   * `[sqlite] [bug]' ¶. UNIQUE and FOREIGN KEY constraints
     are now fully reflected on SQLite both with and without names.
     Previously, foreign key names were ignored and unnamed unique
     constraints were skipped.  Thanks to Jon Nelson for assistance with
     this.

     References: #3244(3), #3261(4)

   * `[sqlite] [bug]' ¶. The SQLite dialect, when using the
     DATE, TIME, or DATETIME types,
     and given a ‘storage_format’ that only renders numbers, will render
     the types in DDL as ‘DATE_CHAR’, ‘TIME_CHAR’, and ‘DATETIME_CHAR’,
     so that despite the lack of alpha characters in the values, the
     column will still deliver the “text affinity”.  Normally this is
     not needed, as the textual values within the default storage
     formats already imply text.

     See also
     ........

     See Date and Time Types.

     References: #3257(5)

   * `[sqlite] [bug]' ¶. SQLite now supports reflection of
     unique constraints from temp tables; previously, this would fail
     with a TypeError.  Pull request courtesy Johannes Erdfelt.

     See also
     ........

     See SQLite/Oracle have distinct methods for temporary table/view name reporting.
     - changes regarding SQLite temporary table
     and view reflection.

     References: #3203(6)

   * `[sqlite] [bug]' ¶. Added
     Inspector.get_temp_table_names() and
     Inspector.get_temp_view_names(); currently, only the SQLite
     and Oracle dialects support these methods.  The return of temporary
     table and view names has been `removed' from SQLite and Oracle’s
     version of Inspector.get_table_names() and
     Inspector.get_view_names(); other database backends cannot
     support this information (such as MySQL), and the scope of
     operation is different in that the tables can be local to a session
     and typically aren’t supported in remote schemas.

     See also
     ........

     See SQLite/Oracle have distinct methods for temporary table/view name reporting.

     References: #3204(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3211

   (2) http://www.sqlalchemy.org/trac/ticket/3130

   (3) http://www.sqlalchemy.org/trac/ticket/3244

   (4) http://www.sqlalchemy.org/trac/ticket/3261

   (5) http://www.sqlalchemy.org/trac/ticket/3257

   (6) http://www.sqlalchemy.org/trac/ticket/3203

   (7) http://www.sqlalchemy.org/trac/ticket/3204

8.3.5.131 mssql
...............

   * `[mssql] [feature]' ¶. Enabled “multivalues insert” for
     SQL Server 2008.  Pull request courtesy Albert Cervin.  Also
     expanded the checks for “IDENTITY INSERT” mode to include when the
     identity key is present in the VALUEs clause of the statement.

     This change is also `backported' to: 0.9.7

   * `[mssql] [feature]' ¶. SQL Server 2012 now recommends
     VARCHAR(max), NVARCHAR(max), VARBINARY(max) for large text/binary
     types.  The MSSQL dialect will now respect this based on version
     detection, as well as the new ‘deprecate_large_types’ flag.

     See also
     ........

     See Large Text/Binary Type Deprecation.

     References: #3039(1)

   * `[mssql] [changed]' ¶. The hostname-based connection
     format for SQL Server when using pyodbc will no longer specify a
     default “driver name”, and a warning is emitted if this is missing.
     The optimal driver name for SQL Server changes frequently and is
     per-platform, so hostname based connections need to specify this.
     DSN-based connections are preferred.

     See also
     ........

     See PyODBC driver name is required with hostname-based SQL Server connections.

     References: #3182(2)

   * `[mssql] [bug]' ¶. Added statement encoding to the “SET
     IDENTITY_INSERT” statements which operate when an explicit INSERT
     is being interjected into an IDENTITY column, to support non-ascii
     table identifiers on drivers such as pyodbc + unix + py2k that
     don’t support unicode statements.

     This change is also `backported' to: 0.9.7, 0.8.7

   * `[mssql] [bug]' ¶. In the SQL Server pyodbc dialect,
     repaired the implementation for the ‘description_encoding’ dialect
     parameter, which when not explicitly set was preventing
     cursor.description from being parsed correctly in the case of
     result sets that contained names in alternate encodings.  This
     parameter shouldn’t be needed going forward.

     This change is also `backported' to: 0.9.7, 0.8.7

     References: #3091(3)

   * `[mssql] [bug]' ¶. Fixed the version string detection
     in the pymssql dialect to work with Microsoft SQL Azure, which
     changes the word “SQL Server” to “SQL Azure”.

     This change is also `backported' to: 0.9.8

     References: #3151(4)

   * `[mssql] [bug]' ¶. Revised the query used to determine
     the current default schema name to use the
     ‘database_principal_id()’ function in conjunction with the
     ‘sys.database_principals’ view so that we can determine the default
     schema independently of the type of login in progress (e.g., SQL
     Server, Windows, etc).

     This change is also `backported' to: 0.9.5

     References: #3025(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3039

   (2) http://www.sqlalchemy.org/trac/ticket/3182

   (3) http://www.sqlalchemy.org/trac/ticket/3091

   (4) http://www.sqlalchemy.org/trac/ticket/3151

   (5) http://www.sqlalchemy.org/trac/ticket/3025

8.3.5.132 oracle
................

   * `[oracle] [feature]' ¶. Added support for cx_oracle
     connections to a specific service name, as opposed to a tns name,
     by passing ‘?service_name=<name>’ to the URL. Pull request courtesy
     Sławomir Ehlert.

   * `[oracle] [feature]' ¶. New Oracle DDL features for
     tables, indexes: COMPRESS, BITMAP. Patch courtesy Gabor Gombas.

   * `[oracle] [feature]' ¶. Added support for CTEs under
     Oracle.  This includes some tweaks to the aliasing syntax, as well
     as a new CTE feature ‘CTE.suffix_with()’, which is useful for
     adding in special Oracle-specific directives to the CTE.

     See also
     ........

     See Improved support for CTEs in Oracle.

     References: #3220(1)

   * `[oracle] [feature]' ¶. Added support for the Oracle
     table option ON COMMIT.

   * `[oracle] [bug]' ¶. Fixed long-standing bug in Oracle
     dialect where bound parameter names that started with numbers would
     not be quoted, as Oracle doesn’t like numerics in bound parameter
     names.

     This change is also `backported' to: 0.9.8

     References: #2138(2)

   * `[oracle] [bug] [tests]' ¶. Fixed bug in oracle dialect
     test suite where in one test, ‘username’ was assumed to be in the
     database URL, even though this might not be the case.

     This change is also `backported' to: 0.9.7

     References: #3128(3)

   * `[oracle] [bug]' ¶. An alias name will be properly
     quoted when referred to using the ‘%(name)s’ token inside the
     Select.with_hint() method.  Previously, the Oracle backend
     hadn’t implemented this quoting.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3220

   (2) http://www.sqlalchemy.org/trac/ticket/2138

   (3) http://www.sqlalchemy.org/trac/ticket/3128

8.3.5.133 misc
..............

   * `[feature] [examples]' ¶. Added a new example
     illustrating materialized paths, using the latest relationship
     features.  Example courtesy Jack Zhou.

     This change is also `backported' to: 0.9.5

   * `[feature] [ext]' ¶. Added a new extension suite
     sqlalchemy.ext.baked.  This simple but unusual system allows
     for a dramatic savings in Python overhead for the construction and
     processing of orm Query objects, from query
     construction up through rendering of a string SQL statement.

     See also
     ........

     See Baked Queries.

     References: #3054(1)

   * `[feature] [examples]' ¶. A new suite of examples
     dedicated to providing a detailed study into performance of
     SQLAlchemy ORM and Core, as well as the DBAPI, from multiple
     perspectives.  The suite runs within a container that provides
     built in profiling displays both through console output as well as
     graphically via the RunSnake tool.

     See also
     ........

     See Performance.

   * `[feature] [ext]' ¶. The sqlalchemy.ext.automap
     extension will now set ‘cascade="all, delete-orphan"’
     automatically on a one-to-many relationship/backref where the
     foreign key is detected as containing one or more non-nullable
     columns.  This argument is present in the keywords passed to
     generate_relationship() in this case and can still be
     overridden.  Additionally, if the ForeignKeyConstraint
     specifies ‘ondelete="CASCADE"’ for a non-nullable or ‘ondelete="SET
     NULL"’ for a nullable set of columns, the argument
     ‘passive_deletes=True’ is also added to the relationship.  Note
     that not all backends support reflection of ondelete, but backends
     that do include PostgreSQL and MySQL.

     References: #3210(2)

   * `[bug] [declarative]' ¶. The ‘__mapper_args__’
     dictionary is copied from a declarative mixin or abstract class
     when accessed, so that modifications made to this dictionary by
     declarative itself won’t conflict with that of other mappings.  The
     dictionary is modified regarding the ‘version_id_col’ and
     ‘polymorphic_on’ arguments, replacing the column within with the
     one that is officially mapped to the local class/table.

     This change is also `backported' to: 0.9.5, 0.8.7

     References: #3062(3)

   * `[bug] [ext]' ¶. Fixed bug in mutable extension where
     MutableDict did not report change events for the
     ‘setdefault()’ dictionary operation.

     This change is also `backported' to: 0.9.5, 0.8.7

     References: #3051(4), #3093(5)

   * `[bug] [ext]' ¶. Fixed bug where
     MutableDict.setdefault() didn’t return the existing or new
     value (this bug was not released in any 0.8 version).  Pull request
     courtesy Thomas Hervé.

     This change is also `backported' to: 0.9.5, 0.8.7

     References: #3051(6), #3093(7)

   * `[bug] [ext] [py3k]' ¶. Fixed bug where the association
     proxy list class would not interpret slices correctly under Py3K.
     Pull request courtesy Gilles Dartiguelongue.

     This change is also `backported' to: 0.9.9

   * `[bug] [examples]' ¶. Updated the Versioning with a History Table
     example such that mapped columns are
     re-mapped to match column names as well as grouping of columns; in
     particular, this allows columns that are explicitly grouped in a
     same-column-named joined inheritance scenario to be mapped in the
     same way in the history mappings, avoiding warnings added in the
     0.9 series regarding this pattern and allowing the same view of
     attribute keys.

     This change is also `backported' to: 0.9.9

   * `[bug] [examples]' ¶. Fixed a bug in the
     examples/generic_associations/discriminator_on_association.py
     example, where the subclasses of AddressAssociation were not being
     mapped as “single table inheritance”, leading to problems when
     trying to use the mappings further.

     This change is also `backported' to: 0.9.9

   * `[bug] [declarative]' ¶. Fixed an unlikely race
     condition observed in some exotic end-user setups, where the
     attempt to check for “duplicate class name” in declarative would
     hit upon a not-totally-cleaned-up weak reference related to some
     other class being removed; the check here now ensures the weakref
     still references an object before calling upon it further.

     This change is also `backported' to: 0.9.8

     References: #3208(8)

   * `[bug] [ext]' ¶. Fixed bug in ordering list where the
     order of items would be thrown off during a collection replace
     event, if the reorder_on_append flag were set to True.  The fix
     ensures that the ordering list only impacts the list that is
     explicitly associated with the object.

     This change is also `backported' to: 0.9.8

     References: #3191(9)

   * `[bug] [ext]' ¶. Fixed bug where MutableDict
     failed to implement the ‘update()’ dictionary method, thus not
     catching changes.  Pull request courtesy Matt Chisholm.

     This change is also `backported' to: 0.9.8

   * `[bug] [ext]' ¶. Fixed bug where a custom subclass of
     MutableDict would not show up in a “coerce” operation,
     and would instead return a plain MutableDict.  Pull
     request courtesy Matt Chisholm.

     This change is also `backported' to: 0.9.8

   * `[bug] [pool]' ¶. Fixed bug in connection pool logging
     where the “connection checked out” debug logging message would not
     emit if the logging were set up using ‘logging.setLevel()’, rather
     than using the ‘echo_pool’ flag.  Tests to assert this logging have
     been added.  This is a regression that was introduced in 0.9.0.

     This change is also `backported' to: 0.9.8

     References: #3168(10)

   * `[bug] [tests]' ¶. Fixed bug where “python setup.py
     test” wasn’t calling into distutils appropriately, and errors would
     be emitted at the end of the test suite.

     This change is also `backported' to: 0.9.7

   * `[bug] [declarative]' ¶. Fixed bug when the declarative
     ‘__abstract__’ flag was not being distinguished for when it was
     actually the value ‘False’.  The ‘__abstract__’ flag needs to
     actually evaluate to a True value at the level being tested.

     This change is also `backported' to: 0.9.7

     References: #3097(11)

   * `[bug] [testsuite]' ¶. In public test suite, changed to
     use of ‘String(40)’ from less-supported ‘Text’ in
     ‘StringTest.test_literal_backslashes’.  Pullreq courtesy Jan.

     This change is also `backported' to: 0.9.5

   * `[bug] [py3k] [tests]' ¶. Corrected for some
     deprecation warnings involving the ‘imp’ module and Python 3.3 or
     greater, when running tests.  Pull request courtesy Matt Chisholm.

     This change is also `backported' to: 0.9.5

     References: #2830(12)

   * `[removed]' ¶. The Drizzle dialect has been removed
     from the Core; it is now available as sqlalchemy-drizzle(13), an
     independent, third party dialect.  The dialect is still based
     almost entirely off of the MySQL dialect present in SQLAlchemy.

     See also
     ........

     See Drizzle Dialect is now an External Dialect.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3054

   (2) http://www.sqlalchemy.org/trac/ticket/3210

   (3) http://www.sqlalchemy.org/trac/ticket/3062

   (4) http://www.sqlalchemy.org/trac/ticket/3051

   (5) http://www.sqlalchemy.org/trac/ticket/3093

   (6) http://www.sqlalchemy.org/trac/ticket/3051

   (7) http://www.sqlalchemy.org/trac/ticket/3093

   (8) http://www.sqlalchemy.org/trac/ticket/3208

   (9) http://www.sqlalchemy.org/trac/ticket/3191

   (10) http://www.sqlalchemy.org/trac/ticket/3168

   (11) http://www.sqlalchemy.org/trac/ticket/3097

   (12) http://www.sqlalchemy.org/trac/ticket/2830

   (13) https://bitbucket.org/zzzeek/sqlalchemy-drizzle

8.3.6 0.9 Changelog
-------------------

8.3.6.1 0.9.10
..............

Released: July 22, 2015

8.3.6.2 orm
...........

   * `[orm] [feature]' ¶. Added a new entry ‘"entity"’ to
     the dictionaries returned by Query.column_descriptions.
     This refers to the primary ORM mapped class or aliased class that
     is referred to by the expression.  Compared to the existing entry
     for ‘"type"’, it will always be a mapped entity, even if extracted
     from a column expression, or None if the given expression is a pure
     core expression.  See also #3403(1) which repaired a regression in
     this feature which was unreleased in 0.9.10 but was released in the
     1.0 version.

     References: #3320(2)

   * `[orm] [bug]' ¶. Query doesn’t support
     joins, subselects, or special FROM clauses when using the
     Query.update() or Query.delete() methods; instead
     of silently ignoring these fields if methods like
     Query.join() or Query.select_from() has been
     called, a warning is emitted.  As of 1.0.0b5 this will raise an
     error.

     References: #3349(3)

   * `[orm] [bug]' ¶. Fixed bug where the state tracking
     within multiple, nested Session.begin_nested()
     operations would fail to propagate the “dirty” flag for an object
     that had been updated within the inner savepoint, such that if the
     enclosing savepoint were rolled back, the object would not be part
     of the state that was expired and therefore reverted to its
     database state.

     References: #3352(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3403

   (2) http://www.sqlalchemy.org/trac/ticket/3320

   (3) http://www.sqlalchemy.org/trac/ticket/3349

   (4) http://www.sqlalchemy.org/trac/ticket/3352

8.3.6.3 engine
..............

   * `[engine] [bug]' ¶. Added the string value ‘"none"’ to
     those accepted by the Pool.reset_on_return parameter
     as a synonym for ‘None’, so that string values can be used for all
     settings, allowing utilities like engine_from_config()
     to be usable without issue.

     References: #3375(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3375

8.3.6.4 sql
...........

   * `[sql] [feature]' ¶. Added official support for a CTE
     used by the SELECT present inside of Insert.from_select().
     This behavior worked accidentally up until 0.9.9, when it no
     longer worked due to unrelated changes as part of #3248(1).  Note
     that this is the rendering of the WITH clause after the INSERT,
     before the SELECT; the full functionality of CTEs rendered at the
     top level of INSERT, UPDATE, DELETE is a new feature targeted for a
     later release.

     References: #3418(2)

   * `[sql] [bug]' ¶. Fixed issue where a MetaData
     object that used a naming convention would not properly work
     with pickle.  The attribute was skipped leading to inconsistencies
     and failures if the unpickled MetaData object were used
     to base additional tables from.

     References: #3362(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3248

   (2) http://www.sqlalchemy.org/trac/ticket/3418

   (3) http://www.sqlalchemy.org/trac/ticket/3362

8.3.6.5 postgresql
..................

   * `[postgresql] [bug]' ¶. Fixed a long-standing bug where
     the Enum type as used with the psycopg2 dialect in
     conjunction with non-ascii values and ‘native_enum=False’ would
     fail to decode return results properly.  This stemmed from when the
     PG ENUM type used to be a standalone type without a
     “non native” option.

     References: #3354(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3354

8.3.6.6 mysql
.............

   * `[mysql] [bug] [pymysql]' ¶. Fixed unicode support for
     PyMySQL when using an “executemany” operation with unicode
     parameters.  SQLAlchemy now passes both the statement as well as
     the bound parameters as unicode objects, as PyMySQL generally uses
     string interpolation internally to produce the final statement, and
     in the case of executemany does the “encode” step only on the final
     statement.

     References: #3337(1)

   * `[mysql] [bug] [py3k]' ¶. Fixed the BIT.
     type on Py3K which was not using the ‘ord()’ function correctly.
     Pull request courtesy David Marin.

     References: #3333(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3337

   (2) http://www.sqlalchemy.org/trac/ticket/3333

8.3.6.7 sqlite
..............

   * `[sqlite] [bug]' ¶. Fixed bug in SQLite dialect where
     reflection of UNIQUE constraints that included non-alphabetic
     characters in the names, like dots or spaces, would not be
     reflected with their name.

     References: #3495(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3495

8.3.6.8 misc
............

   * `[bug] [ext]' ¶. Fixed bug where when using extended
     attribute instrumentation system, the correct exception would not
     be raised when class_mapper() were called with an
     invalid input that also happened to not be weak referencable, such
     as an integer.

     References: #3408(1)

   * `[bug] [pypy] [tests]' ¶. Fixed an import that
     prevented “pypy setup.py test” from working correctly.

     References: #3406(2)

   * `[bug] [ext]' ¶. Fixed regression from 0.9.9 where the
     as_declarative() symbol was removed from the
     ‘sqlalchemy.ext.declarative’ namespace.

     References: #3324(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3408

   (2) http://www.sqlalchemy.org/trac/ticket/3406

   (3) http://www.sqlalchemy.org/trac/ticket/3324

8.3.6.9 0.9.9
.............

Released: March 10, 2015

8.3.6.10 orm
............

   * `[orm] [feature]' ¶. Added new parameter
     Session.connection.execution_options which may be used to set
     up execution options on a Connection when it is first
     checked out, before the transaction has begun.  This is used to set
     up options such as isolation level on the connection before the
     transaction starts.

     See also
     ........

     See Setting Transaction Isolation Levels / DBAPI AUTOCOMMIT.
     - new documentation section detailing best practices for setting
     transaction isolation with sessions.

     References: #3296(1)

   * `[orm] [feature]' ¶. Added new method
     Session.invalidate(), functions similarly to
     Session.close(), except also calls
     Connection.invalidate() on all connections, guaranteeing that
     they will not be returned to the connection pool.  This is useful
     in situations e.g.  dealing with gevent timeouts when it is not
     safe to use the connection further, even for rollbacks.

   * `[orm] [bug]' ¶. Fixed bugs in ORM object comparisons
     where comparison of many-to-one ‘!= None’ would fail if the source
     were an aliased class, or if the query needed to apply special
     aliasing to the expression due to aliased joins or polymorphic
     querying; also fixed bug in the case where comparing a many-to-one
     to an object state would fail if the query needed to apply special
     aliasing due to aliased joins or polymorphic querying.

     References: #3310(2)

   * `[orm] [bug]' ¶. Fixed bug where internal assertion
     would fail in the case where an ‘after_rollback()’ handler for a
     Session incorrectly adds state to that Session
     within the handler, and the task to warn and remove this state
     (established by #2389(3)) attempts to proceed.

     References: #3309(4)

   * `[orm] [bug]' ¶. Fixed bug where TypeError raised when
     Query.join() called with unknown kw arguments would
     raise its own TypeError due to broken formatting.  Pull request
     courtesy Malthe Borch.

   * `[orm] [bug]' ¶. Fixed bug in lazy loading SQL
     construction whereby a complex primaryjoin that referred to the
     same “local” column multiple times in the “column that points to
     itself” style of self-referential join would not be substituted in
     all cases.  The logic to determine substitutions here has been
     reworked to be more open-ended.

     References: #3300(5)

   * `[orm] [bug]' ¶. The “wildcard” loader options, in
     particular the one set up by the load_only() option to
     cover all attributes not explicitly mentioned, now takes into
     account the superclasses of a given entity, if that entity is
     mapped with inheritance mapping, so that attribute names within the
     superclasses are also omitted from the load.  Additionally, the
     polymorphic discriminator column is unconditionally included in the
     list, just in the same way that primary key columns are, so that
     even with load_only() set up, polymorphic loading of subtypes
     continues to function correctly.

     References: #3287(6)

   * `[orm] [bug] [pypy]' ¶. Fixed bug where if an exception
     were thrown at the start of a Query before it fetched
     results, particularly when row processors can’t be formed, the
     cursor would stay open with results pending and not actually be
     closed.  This is typically only an issue on an interpreter like
     PyPy where the cursor isn’t immediately GC’ed, and can in some
     circumstances lead to transactions/ locks being open longer than is
     desirable.

     References: #3285(7)

   * `[orm] [bug]' ¶. Fixed a leak which would occur in the
     unsupported and highly non-recommended use case of replacing a
     relationship on a fixed mapped class many times, referring to an
     arbitrarily growing number of target mappers.  A warning is emitted
     when the old relationship is replaced, however if the mapping were
     already used for querying, the old relationship would still be
     referenced within some registries.

     References: #3251(8)

   * `[orm] [bug] [sqlite]' ¶. Fixed bug regarding
     expression mutations which could express itself as a “Could not
     locate column” error when using Query to select from
     multiple, anonymous column entities when querying against SQLite,
     as a side effect of the “join rewriting” feature used by the SQLite
     dialect.

     References: #3241(9)

   * `[orm] [bug]' ¶. Fixed bug where the ON clause for
     Query.join(), and Query.outerjoin() to a
     single-inheritance subclass using ‘of_type()’ would not render the
     “single table criteria” in the ON clause if the
     ‘from_joinpoint=True’ flag were set.

     References: #3232(10)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3296

   (2) http://www.sqlalchemy.org/trac/ticket/3310

   (3) http://www.sqlalchemy.org/trac/ticket/2389

   (4) http://www.sqlalchemy.org/trac/ticket/3309

   (5) http://www.sqlalchemy.org/trac/ticket/3300

   (6) http://www.sqlalchemy.org/trac/ticket/3287

   (7) http://www.sqlalchemy.org/trac/ticket/3285

   (8) http://www.sqlalchemy.org/trac/ticket/3251

   (9) http://www.sqlalchemy.org/trac/ticket/3241

   (10) http://www.sqlalchemy.org/trac/ticket/3232

8.3.6.11 engine
...............

   * `[engine] [feature]' ¶. Added new user-space accessors
     for viewing transaction isolation levels; see
     Connection.get_isolation_level(),
     Connection.default_isolation_level.

   * `[engine] [bug]' ¶. Fixed bug in Connection.
     and pool where the Connection.invalidate() method, or
     an invalidation due to a database disconnect, would fail if the
     ‘isolation_level’ parameter had been used with
     Connection.execution_options(); the “finalizer” that resets
     the isolation level would be called on the no longer opened
     connection.

     References: #3302(1)

   * `[engine] [bug]' ¶. A warning is emitted if the
     ‘isolation_level’ parameter is used with
     Connection.execution_options() when a Transaction
     is in play; DBAPIs and/or SQLAlchemy dialects such as psycopg2,
     MySQLdb may implicitly rollback or commit the transaction, or not
     change the setting til next transaction, so this is never safe.

     References: #3296(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3302

   (2) http://www.sqlalchemy.org/trac/ticket/3296

8.3.6.12 sql
............

   * `[sql] [bug]' ¶. Added the ‘native_enum’ flag to the
     ‘__repr__()’ output of Enum, which is mostly important
     when using it with Alembic autogenerate.  Pull request courtesy
     Dimitris Theodorou.

   * `[sql] [bug]' ¶. Fixed bug where using a
     TypeDecorator that implemented a type that was also a
     TypeDecorator would fail with Python’s “Cannot create a
     consistent method resolution order (MRO)” error, when any kind of
     SQL comparison expression were used against an object using this
     type.

     References: #3278(1)

   * `[sql] [bug]' ¶. Fixed issue where the columns from a
     SELECT embedded in an INSERT, either through the values clause or
     as a “from select”, would pollute the column types used in the
     result set produced by the RETURNING clause when columns from both
     statements shared the same name, leading to potential errors or
     mis-adaptation when retrieving the returning rows.

     References: #3248(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3278

   (2) http://www.sqlalchemy.org/trac/ticket/3248

8.3.6.13 schema
...............

   * `[schema] [bug]' ¶. Fixed bug in 0.9’s foreign key
     setup system, such that the logic used to link a ForeignKey
     to its parent could fail when the foreign key used
     “link_to_name=True” in conjunction with a target Table
     that would not receive its parent column until later, such as
     within a reflection + “useexisting” scenario, if the target column
     in fact had a key value different from its name, as would occur in
     reflection if column reflect events were used to alter the .key of
     reflected Column objects so that the link_to_name
     becomes significant.  Also repaired support for column type via FK
     transmission in a similar way when target columns had a different
     key and were referenced using link_to_name.

     References: #1765(1), #3298(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1765

   (2) http://www.sqlalchemy.org/trac/ticket/3298

8.3.6.14 postgresql
...................

   * `[postgresql] [feature]' ¶. Added support for the
     ‘CONCURRENTLY’ keyword with PostgreSQL indexes, established using
     ‘postgresql_concurrently’.  Pull request courtesy Iuri de Silvio.

     See also
     ........

     See Indexes with CONCURRENTLY.

   * `[postgresql] [bug]' ¶. Repaired support for PostgreSQL
     UUID types in conjunction with the ARRAY type when using psycopg2.
     The psycopg2 dialect now employs use of the
     psycopg2.extras.register_uuid() hook so that UUID values are always
     passed to/from the DBAPI as UUID() objects.  The
     UUID.as_uuid flag is still honored, except with psycopg2 we
     need to convert returned UUID objects back into strings when this
     is disabled.

     References: #2940(1)

   * `[postgresql] [bug]' ¶. Added support for the
     ‘postgresql.JSONB’ datatype when using psycopg2 2.5.4 or greater,
     which features native conversion of JSONB data so that SQLAlchemy’s
     converters must be disabled; additionally, the newly added psycopg2
     extension ‘extras.register_default_jsonb’ is used to establish a
     JSON deserializer passed to the dialect via the ‘json_deserializer’
     argument.  Also repaired the PostgreSQL integration tests which
     weren’t actually round-tripping the JSONB type as opposed to the
     JSON type.  Pull request courtesy Mateusz Susik.

   * `[postgresql] [bug]' ¶. Repaired the use of the
     “array_oid” flag when registering the HSTORE type with older
     psycopg2 versions < 2.4.3, which does not support this flag, as
     well as use of the native json serializer hook
     “register_default_json” with user-defined ‘json_deserializer’ on
     psycopg2 versions < 2.5, which does not include native json.

   * `[postgresql] [bug]' ¶. Fixed bug where PostgreSQL
     dialect would fail to render an expression in an Index
     that did not correspond directly to a table-bound column; typically
     when a text() construct was one of the expressions
     within the index; or could misinterpret the list of expressions if
     one or more of them were such an expression.

     References: #3174(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2940

   (2) http://www.sqlalchemy.org/trac/ticket/3174

8.3.6.15 mysql
..............

   * `[mysql] [change]' ¶. The ‘gaerdbms’ dialect is no
     longer necessary, and emits a deprecation warning.  Google now
     recommends using the MySQLdb dialect directly.

     References: #3275(1)

   * `[mysql] [bug]' ¶. Added a version check to the MySQLdb
     dialect surrounding the check for ‘utf8_bin’ collation, as this
     fails on MySQL server < 5.0.

     References: #3274(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3275

   (2) http://www.sqlalchemy.org/trac/ticket/3274

8.3.6.16 sqlite
...............

   * `[sqlite] [feature]' ¶. Added support for partial
     indexes (e.g.  with a WHERE clause) on SQLite.  Pull request
     courtesy Kai Groner.

     See also
     ........

     See Partial Indexes.

   * `[sqlite] [feature]' ¶. Added a new SQLite backend for
     the SQLCipher backend.  This backend provides for encrypted SQLite
     databases using the pysqlcipher Python driver, which is very
     similar to the pysqlite driver.

     See also
     ........

     See pysqlcipher.

8.3.6.17 misc
.............

   * `[bug] [ext] [py3k]' ¶. Fixed bug where the association
     proxy list class would not interpret slices correctly under Py3K.
     Pull request courtesy Gilles Dartiguelongue.

   * `[bug] [examples]' ¶. Updated the Versioning with a History Table
     example such that mapped columns are
     re-mapped to match column names as well as grouping of columns; in
     particular, this allows columns that are explicitly grouped in a
     same-column-named joined inheritance scenario to be mapped in the
     same way in the history mappings, avoiding warnings added in the
     0.9 series regarding this pattern and allowing the same view of
     attribute keys.

   * `[bug] [examples]' ¶. Fixed a bug in the
     examples/generic_associations/discriminator_on_association.py
     example, where the subclasses of AddressAssociation were not being
     mapped as “single table inheritance”, leading to problems when
     trying to use the mappings further.

8.3.6.18 0.9.8
..............

Released: October 13, 2014

8.3.6.19 orm
............

   * `[orm] [bug] [engine]' ¶. Fixed bug that affected
     generally the same classes of event as that of #3199(1), when the
     ‘named=True’ parameter would be used.  Some events would fail to
     register, and others would not invoke the event arguments
     correctly, generally in the case of when an event was “wrapped” for
     adaption in some other way.  The “named” mechanics have been
     rearranged to not interfere with the argument signature expected by
     internal wrapper functions.

     References: #3197(2)

   * `[orm] [bug]' ¶. Fixed bug that affected many classes
     of event, particularly ORM events but also engine events, where the
     usual logic of “de duplicating” a redundant call to listen()
     with the same arguments would fail, for those events where the
     listener function is wrapped.  An assertion would be hit within
     registry.py.  This assertion has now been integrated into the
     deduplication check, with the added bonus of a simpler means of
     checking deduplication across the board.

     References: #3199(3)

   * `[orm] [bug]' ¶. Fixed warning that would emit when a
     complex self-referential primaryjoin contained functions, while at
     the same time remote_side was specified; the warning would suggest
     setting “remote side”.  It now only emits if remote_side isn’t
     present.

     References: #3194(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3199

   (2) http://www.sqlalchemy.org/trac/ticket/3197

   (3) http://www.sqlalchemy.org/trac/ticket/3199

   (4) http://www.sqlalchemy.org/trac/ticket/3194

8.3.6.20 orm declarative
........................

   * `[orm] [declarative] [bug]' ¶. Fixed “‘NoneType’ object
     has no attribute ‘concrete’” error when using
     AbstractConcreteBase in conjunction with a subclass that
     declares ‘__abstract__’.

     References: #3185(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3185

8.3.6.21 engine
...............

   * `[engine] [bug]' ¶. The execution options passed to an
     Engine either via
     create_engine.execution_options or
     Engine.update_execution_options() are not passed to the
     special Connection used to initialize the dialect
     within the “first connect” event; dialects will usually perform
     their own queries in this phase, and none of the current available
     options should be applied here.  In particular, the “autocommit”
     option was causing an attempt to autocommit within this initial
     connect which would fail with an AttributeError due to the
     non-standard state of the Connection.

     References: #3200(1)

   * `[engine] [bug]' ¶. The string keys that are used to
     determine the columns impacted for an INSERT or UPDATE are now
     sorted when they contribute towards the “compiled cache” cache key.
     These keys were previously not deterministically ordered, meaning
     the same statement could be cached multiple times on equivalent
     keys, costing both in terms of memory as well as performance.

     References: #3165(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3200

   (2) http://www.sqlalchemy.org/trac/ticket/3165

8.3.6.22 sql
............

   * `[sql] [bug]' ¶. Fixed bug where a fair number of SQL
     elements within the sql package would fail to ‘__repr__()’
     successfully, due to a missing ‘description’ attribute that would
     then invoke a recursion overflow when an internal AttributeError
     would then re-invoke ‘__repr__()’.

     References: #3195(1)

   * `[sql] [bug]' ¶. An adjustment to table/index
     reflection such that if an index reports a column that isn’t found
     to be present in the table, a warning is emitted and the column is
     skipped.  This can occur for some special system column situations
     as has been observed with Oracle.

     References: #3180(2)

   * `[sql] [bug]' ¶. Fixed bug in CTE where ‘literal_binds’
     compiler argument would not be always be correctly propagated when
     one CTE referred to another aliased CTE in a statement.

     References: #3154(3)

   * `[sql] [bug]' ¶. Fixed 0.9.7 regression caused by
     #3067(4) in conjunction with a mis-named unit test such that
     so-called “schema” types like Boolean and Enum
     could no longer be pickled.

     References: #3067(5), #3144(6)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3195

   (2) http://www.sqlalchemy.org/trac/ticket/3180

   (3) http://www.sqlalchemy.org/trac/ticket/3154

   (4) http://www.sqlalchemy.org/trac/ticket/3067

   (5) http://www.sqlalchemy.org/trac/ticket/3067

   (6) http://www.sqlalchemy.org/trac/ticket/3144

8.3.6.23 postgresql
...................

   * `[postgresql] [feature] [pg8000]' ¶. Support is added
     for “sane multi row count” with the pg8000 driver, which applies
     mostly to when using versioning with the ORM. The feature is
     version-detected based on pg8000 1.9.14 or greater in use.  Pull
     request courtesy Tony Locke.

   * `[postgresql] [bug]' ¶. A revisit to this issue first
     patched in 0.9.5, apparently psycopg2’s ‘.closed’ accessor is not
     as reliable as we assumed, so we have added an explicit check for
     the exception messages “SSL SYSCALL error: Bad file descriptor” and
     “SSL SYSCALL error: EOF detected” when detecting an is-disconnect
     scenario.  We will continue to consult psycopg2’s connection.closed
     as a first check.

     References: #3021(1)

   * `[postgresql] [bug]' ¶. Fixed bug where PostgreSQL JSON
     type was not able to persist or otherwise render a SQL NULL column
     value, rather than a JSON-encoded ‘'null'’.  To support this case,
     changes are as follows:

        * The value null() can now be specified, which will
          always result in a NULL value resulting in the statement.

        * A new parameter JSON.none_as_null is added, which
          when True indicates that the Python ‘None’ value should be
          persisted as SQL NULL, rather than JSON-encoded ‘'null'’.

     Retrieval of NULL as None is also repaired for DBAPIs other than
     psycopg2, namely pg8000.

     References: #3159(2)

   * `[postgresql] [bug]' ¶. The exception wrapping system
     for DBAPI errors can now accommodate non-standard DBAPI exceptions,
     such as the psycopg2 TransactionRollbackError.  These exceptions
     will now be raised using the closest available subclass in
     ‘sqlalchemy.exc’, in the case of TransactionRollbackError,
     ‘sqlalchemy.exc.OperationalError’.

     References: #3075(3)

   * `[postgresql] [bug]' ¶. Fixed bug in array.
     object where comparison to a plain Python list would fail to use
     the correct array constructor.  Pull request courtesy Andrew.

     References: #3141(4)

   * `[postgresql] [bug]' ¶. Added a supported
     FunctionElement.alias() method to functions, e.g.  the ‘func’
     construct.  Previously, behavior for this method was undefined.
     The current behavior mimics that of pre-0.9.4, which is that the
     function is turned into a single-column FROM clause with the given
     alias name, where the column itself is anonymously named.

     References: #3137(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3021

   (2) http://www.sqlalchemy.org/trac/ticket/3159

   (3) http://www.sqlalchemy.org/trac/ticket/3075

   (4) http://www.sqlalchemy.org/trac/ticket/3141

   (5) http://www.sqlalchemy.org/trac/ticket/3137

8.3.6.24 mysql
..............

   * `[mysql] [bug] [mysqlconnector]' ¶. Mysqlconnector as
     of version 2.0, probably as a side effect of 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 ‘%’.

   * `[mysql] [bug] [mysqlconnector]' ¶. Unicode SQL is now
     passed for MySQLconnector version 2.0 and above; for Py2k and MySQL
     < 2.0, strings are encoded.

8.3.6.25 sqlite
...............

   * `[sqlite] [bug]' ¶. When selecting from a UNION using
     an attached database file, the pysqlite driver reports column names
     in cursor.description as ‘dbname.tablename.colname’, instead of
     ‘tablename.colname’ as it normally does for a UNION (note that it’s
     supposed to just be ‘colname’ for both, but we work around it).
     The column translation logic here has been adjusted to retrieve the
     rightmost token, rather than the second token, so it works in both
     cases.  Workaround courtesy Tony Roberts.

     References: #3211(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3211

8.3.6.26 mssql
..............

   * `[mssql] [bug]' ¶. Fixed the version string detection
     in the pymssql dialect to work with Microsoft SQL Azure, which
     changes the word “SQL Server” to “SQL Azure”.

     References: #3151(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3151

8.3.6.27 oracle
...............

   * `[oracle] [bug]' ¶. Fixed long-standing bug in Oracle
     dialect where bound parameter names that started with numbers would
     not be quoted, as Oracle doesn’t like numerics in bound parameter
     names.

     References: #2138(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2138

8.3.6.28 misc
.............

   * `[bug] [declarative]' ¶. Fixed an unlikely race
     condition observed in some exotic end-user setups, where the
     attempt to check for “duplicate class name” in declarative would
     hit upon a not-totally-cleaned-up weak reference related to some
     other class being removed; the check here now ensures the weakref
     still references an object before calling upon it further.

     References: #3208(1)

   * `[bug] [ext]' ¶. Fixed bug in ordering list where the
     order of items would be thrown off during a collection replace
     event, if the reorder_on_append flag were set to True.  The fix
     ensures that the ordering list only impacts the list that is
     explicitly associated with the object.

     References: #3191(2)

   * `[bug] [ext]' ¶. Fixed bug where MutableDict
     failed to implement the ‘update()’ dictionary method, thus not
     catching changes.  Pull request courtesy Matt Chisholm.

   * `[bug] [ext]' ¶. Fixed bug where a custom subclass of
     MutableDict would not show up in a “coerce” operation,
     and would instead return a plain MutableDict.  Pull
     request courtesy Matt Chisholm.

   * `[bug] [pool]' ¶. Fixed bug in connection pool logging
     where the “connection checked out” debug logging message would not
     emit if the logging were set up using ‘logging.setLevel()’, rather
     than using the ‘echo_pool’ flag.  Tests to assert this logging have
     been added.  This is a regression that was introduced in 0.9.0.

     References: #3168(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3208

   (2) http://www.sqlalchemy.org/trac/ticket/3191

   (3) http://www.sqlalchemy.org/trac/ticket/3168

8.3.6.29 0.9.7
..............

Released: July 22, 2014

8.3.6.30 orm
............

   * `[orm] [bug] [eagerloading]' ¶. Fixed a regression
     caused by #2976(1) released in 0.9.4 where the “outer join”
     propagation along a chain of joined eager loads would incorrectly
     convert an “inner join” along a sibling join path into an outer
     join as well, when only descendant paths should be receiving the
     “outer join” propagation; additionally, fixed related issue where
     “nested” join propagation would take place inappropriately between
     two sibling join paths.

     References: #3131(2)

   * `[orm] [bug]' ¶. Fixed a regression from 0.9.0 due to
     #2736(3) where the Query.select_from() method no longer
     set up the “from entity” of the Query object correctly,
     so that subsequent Query.filter_by() or
     Query.join() calls would fail to check the appropriate “from”
     entity when searching for attributes by string name.

     References: #2736(4), #3083(5)

   * `[orm] [bug]' ¶. The “evaluator” for
     query.update()/delete() won’t work with multi-table updates, and
     needs to be set to ‘synchronize_session=False’ or
     ‘synchronize_session=’fetch’’; a warning is now emitted.  In 1.0
     this will be promoted to a full exception.

     References: #3117(6)

   * `[orm] [bug]' ¶. Fixed bug where items that were
     persisted, deleted, or had a primary key change within a savepoint
     block would not participate in being restored to their former state
     (not in session, in session, previous PK) after the outer
     transaction were rolled back.

     References: #3108(7)

   * `[orm] [bug]' ¶. Fixed bug in subquery eager loading in
     conjunction with with_polymorphic(), the targeting of
     entities and columns in the subquery load has been made more
     accurate with respect to this type of entity and others.

     References: #3106(8)

   * `[orm] [bug]' ¶. Fixed bug involving dynamic
     attributes, that was again a regression of #3060(9) from version
     0.9.5.  A self-referential relationship with lazy=’dynamic’ would
     raise a TypeError within a flush operation.

     References: #3099(10)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2976

   (2) http://www.sqlalchemy.org/trac/ticket/3131

   (3) http://www.sqlalchemy.org/trac/ticket/2736

   (4) http://www.sqlalchemy.org/trac/ticket/2736

   (5) http://www.sqlalchemy.org/trac/ticket/3083

   (6) http://www.sqlalchemy.org/trac/ticket/3117

   (7) http://www.sqlalchemy.org/trac/ticket/3108

   (8) http://www.sqlalchemy.org/trac/ticket/3106

   (9) http://www.sqlalchemy.org/trac/ticket/3060

   (10) http://www.sqlalchemy.org/trac/ticket/3099

8.3.6.31 engine
...............

   * `[engine] [feature]' ¶. Added new event
     ConnectionEvents.handle_error(), a more fully featured and
     comprehensive replacement for ‘ConnectionEvents.dbapi_error()’.

     References: #3076(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3076

8.3.6.32 sql
............

   * `[sql] [bug]' ¶. Fixed bug in Enum and
     other SchemaType subclasses where direct association
     of the type with a MetaData would lead to a hang when
     events (like create events) were emitted on the MetaData.

     This change is also `backported' to: 0.8.7

     References: #3124(1)

   * `[sql] [bug]' ¶. Fixed a bug within the custom operator
     plus TypeEngine.with_variant() system, whereby using a
     TypeDecorator in conjunction with variant would fail
     with an MRO error when a comparison operator was used.

     This change is also `backported' to: 0.8.7

     References: #3102(2)

   * `[sql] [bug]' ¶. Fix bug in naming convention feature
     where using a check constraint convention that includes
     ‘constraint_name’ would then force all Boolean and
     Enum types to require names as well, as these
     implicitly create a constraint, even if the ultimate target backend
     were one that does not require generation of the constraint such as
     PostgreSQL. The mechanics of naming conventions for these
     particular constraints has been reorganized such that the naming
     determination is done at DDL compile time, rather than at
     constraint/table construction time.

     References: #3067(3)

   * `[sql] [bug]' ¶. Fixed bug in common table expressions
     whereby positional bound parameters could be expressed in the wrong
     final order when CTEs were nested in certain ways.

     References: #3090(4)

   * `[sql] [bug]' ¶. Fixed bug where multi-valued
     Insert construct would fail to check subsequent values entries
     beyond the first one given for literal SQL expressions.

     References: #3069(5)

   * `[sql] [bug]' ¶. Added a “str()” step to the
     dialect_kwargs iteration for Python version < 2.6.5, working around
     the “no unicode keyword arg” bug as these args are passed along as
     keyword args within some reflection processes.

     References: #3123(6)

   * `[sql] [bug]' ¶. The TypeEngine.with_variant()
     method will now accept a type class as an argument which is
     internally converted to an instance, using the same convention long
     established by other constructs such as Column.

     References: #3122(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3124

   (2) http://www.sqlalchemy.org/trac/ticket/3102

   (3) http://www.sqlalchemy.org/trac/ticket/3067

   (4) http://www.sqlalchemy.org/trac/ticket/3090

   (5) http://www.sqlalchemy.org/trac/ticket/3069

   (6) http://www.sqlalchemy.org/trac/ticket/3123

   (7) http://www.sqlalchemy.org/trac/ticket/3122

8.3.6.33 postgresql
...................

   * `[postgresql] [feature]' ¶. Added kw argument
     ‘postgresql_regconfig’ to the ColumnOperators.match()
     operator, allows the “reg config” argument to be specified to the
     ‘to_tsquery()’ function emitted.  Pull request courtesy Jonathan
     Vanasco.

     References: #3078(1)

   * `[postgresql] [feature]' ¶. Added support for
     PostgreSQL JSONB via JSONB.  Pull request courtesy
     Damian Dimmich.

   * `[postgresql] [bug] [pg8000]' ¶. Fixed bug introduced
     in 0.9.5 by new pg8000 isolation level feature where engine-level
     isolation level parameter would raise an error on connect.

     References: #3134(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3078

   (2) http://www.sqlalchemy.org/trac/ticket/3134

8.3.6.34 mysql
..............

   * `[mysql] [bug]' ¶. MySQL error 2014 “commands out of
     sync” appears to be raised as a ProgrammingError, not
     OperationalError, in modern MySQL-Python versions; all MySQL error
     codes that are tested for “is disconnect” are now checked within
     OperationalError and ProgrammingError regardless.

     This change is also `backported' to: 0.8.7

     References: #3101(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3101

8.3.6.35 sqlite
...............

   * `[sqlite] [bug]' ¶. Fixed a SQLite join rewriting issue
     where a subquery that is embedded as a scalar subquery such as
     within an IN would receive inappropriate substitutions from the
     enclosing query, if the same table were present inside the subquery
     as were in the enclosing query such as in a joined inheritance
     scenario.

     References: #3130(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3130

8.3.6.36 mssql
..............

   * `[mssql] [feature]' ¶. Enabled “multivalues insert” for
     SQL Server 2008.  Pull request courtesy Albert Cervin.  Also
     expanded the checks for “IDENTITY INSERT” mode to include when the
     identity key is present in the VALUEs clause of the statement.

   * `[mssql] [bug]' ¶. Added statement encoding to the “SET
     IDENTITY_INSERT” statements which operate when an explicit INSERT
     is being interjected into an IDENTITY column, to support non-ascii
     table identifiers on drivers such as pyodbc + unix + py2k that
     don’t support unicode statements.

     This change is also `backported' to: 0.8.7

   * `[mssql] [bug]' ¶. In the SQL Server pyodbc dialect,
     repaired the implementation for the ‘description_encoding’ dialect
     parameter, which when not explicitly set was preventing
     cursor.description from being parsed correctly in the case of
     result sets that contained names in alternate encodings.  This
     parameter shouldn’t be needed going forward.

     This change is also `backported' to: 0.8.7

     References: #3091(1)

   * `[mssql] [bug]' ¶. Fixed a regression from 0.9.5 caused
     by #3025(2) where the query used to determine “default schema” is
     invalid in SQL Server 2000.  For SQL Server 2000 we go back to
     defaulting to the “schema name” parameter of the dialect, which is
     configurable but defaults to ‘dbo’.

     References: #3025(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3091

   (2) http://www.sqlalchemy.org/trac/ticket/3025

   (3) http://www.sqlalchemy.org/trac/ticket/3025

8.3.6.37 oracle
...............

   * `[oracle] [bug] [tests]' ¶. Fixed bug in oracle dialect
     test suite where in one test, ‘username’ was assumed to be in the
     database URL, even though this might not be the case.

     References: #3128(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3128

8.3.6.38 misc
.............

   * `[bug] [tests]' ¶. Fixed bug where “python setup.py
     test” wasn’t calling into distutils appropriately, and errors would
     be emitted at the end of the test suite.

   * `[bug] [declarative]' ¶. Fixed bug when the declarative
     ‘__abstract__’ flag was not being distinguished for when it was
     actually the value ‘False’.  The ‘__abstract__’ flag needs to
     actually evaluate to a True value at the level being tested.

     References: #3097(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3097

8.3.6.39 0.9.6
..............

Released: June 23, 2014

8.3.6.40 orm
............

   * `[orm] [bug]' ¶. Reverted the change for #3060(1) -
     this is a unit of work fix that is updated more comprehensively in
     1.0 via #3061(2).  The fix in #3060(3) unfortunately produces a new
     issue whereby an eager load of a many-to-one attribute can produce
     an event that is interpreted into an attribute change.

     References: #3060(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3060

   (2) http://www.sqlalchemy.org/trac/ticket/3061

   (3) http://www.sqlalchemy.org/trac/ticket/3060

   (4) http://www.sqlalchemy.org/trac/ticket/3060

8.3.6.41 0.9.5
..............

Released: June 23, 2014

8.3.6.42 orm
............

   * `[orm] [feature]' ¶. The “primaryjoin” model has been
     stretched a bit further to allow a join condition that is strictly
     from a single column to itself, translated through some kind of SQL
     function or expression.  This is kind of experimental, but the
     first proof of concept is a “materialized path” join condition
     where a path string is compared to itself using “like”.  The
     ColumnOperators.like() operator has also been added to the
     list of valid operators to use in a primaryjoin condition.

     References: #3029(1)

   * `[orm] [feature]' ¶. Added new utility function
     make_transient_to_detached() which can be used to manufacture
     objects that behave as though they were loaded from a session, then
     detached.  Attributes that aren’t present are marked as expired,
     and the object can be added to a Session where it will act like a
     persistent one.

     References: #3017(2)

   * `[orm] [bug]' ¶. Fixed bug in subquery eager loading
     where a long chain of eager loads across a polymorphic-subclass
     boundary in conjunction with polymorphic loading would fail to
     locate the subclass-link in the chain, erroring out with a missing
     property name on an AliasedClass.

     This change is also `backported' to: 0.8.7

     References: #3055(3)

   * `[orm] [bug]' ¶. Fixed ORM bug where the
     class_mapper() function would mask AttributeErrors or
     KeyErrors that should raise during mapper configuration due to user
     errors.  The catch for attribute/keyerror has been made more
     specific to not include the configuration step.

     This change is also `backported' to: 0.8.7

     References: #3047(4)

   * `[orm] [bug]' ¶. Additional checks have been added for
     the case where an inheriting mapper is implicitly combining one of
     its column-based attributes with that of the parent, where those
     columns normally don’t necessarily share the same value.  This is
     an extension of an existing check that was added via #1892(5);
     however this new check emits only a warning, instead of an
     exception, to allow for applications that may be relying upon the
     existing behavior.

     See also
     ........

     See I’m getting a warning or error about “Implicitly combining column X under attribute Y”.

     References: #3042(6)

   * `[orm] [bug]' ¶. Modified the behavior of
     load_only() such that primary key columns are always added to
     the list of columns to be “undeferred”; otherwise, the ORM can’t
     load the row’s identity.  Apparently, one can defer the mapped
     primary keys and the ORM will fail, that hasn’t been changed.  But
     as load_only is essentially saying “defer all but X”, it’s more
     critical that PK cols not be part of this deferral.

     References: #3080(7)

   * `[orm] [bug]' ¶. Fixed a few edge cases which arise in
     the so-called “row switch” scenario, where an INSERT/DELETE can be
     turned into an UPDATE. In this situation, a many-to-one
     relationship set to None, or in some cases a scalar attribute set
     to None, may not be detected as a net change in value, and
     therefore the UPDATE would not reset what was on the previous row.
     This is due to some as-yet unresolved side effects of the way
     attribute history works in terms of implicitly assuming None isn’t
     really a “change” for a previously un-set attribute.  See also
     #3061(8).

          Note: This change has been `REVERTED' in 0.9.6.  The full fix
          will be in version 1.0 of SQLAlchemy.

     References: #3060(9)

   * `[orm] [bug]' ¶. Related to #3060(10), an adjustment
     has been made to the unit of work such that loading for related
     many-to-one objects is slightly more aggressive, in the case of a
     graph of self-referential objects that are to be deleted; the load
     of related objects is to help determine the correct order for
     deletion if passive_deletes is not set.

   * `[orm] [bug]' ¶. Fixed bug in SQLite join rewriting
     where anonymized column names due to repeats would not correctly be
     rewritten in subqueries.  This would affect SELECT queries with any
     kind of subquery + join.

     References: #3057(11)

   * `[orm] [bug] [sql]' ¶. Fixes to the newly enhanced
     boolean coercion in #2804(12) where the new rules for “where” and
     “having” woudn’t take effect for the “whereclause” and “having” kw
     arguments of the select() construct, which is also what
     Query uses so wasn’t working in the ORM either.

     References: #3013(13)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3029

   (2) http://www.sqlalchemy.org/trac/ticket/3017

   (3) http://www.sqlalchemy.org/trac/ticket/3055

   (4) http://www.sqlalchemy.org/trac/ticket/3047

   (5) http://www.sqlalchemy.org/trac/ticket/1892

   (6) http://www.sqlalchemy.org/trac/ticket/3042

   (7) http://www.sqlalchemy.org/trac/ticket/3080

   (8) http://www.sqlalchemy.org/trac/ticket/3061

   (9) http://www.sqlalchemy.org/trac/ticket/3060

   (10) http://www.sqlalchemy.org/trac/ticket/3060

   (11) http://www.sqlalchemy.org/trac/ticket/3057

   (12) http://www.sqlalchemy.org/trac/ticket/2804

   (13) http://www.sqlalchemy.org/trac/ticket/3013

8.3.6.43 engine
...............

   * `[engine] [bug]' ¶. Fixed bug which would occur if a
     DBAPI exception occurs when the engine first connects and does its
     initial checks, and the exception is not a disconnect exception,
     yet the cursor raises an error when we try to close it.  In this
     case the real exception would be quashed as we tried to log the
     cursor close exception via the connection pool and failed, as we
     were trying to access the pool’s logger in a way that is
     inappropriate in this very specific scenario.

     References: #3063(1)

   * `[engine] [bug]' ¶. Fixed some “double invalidate”
     situations were detected where a connection invalidation could
     occur within an already critical section like a connection.close();
     ultimately, these conditions are caused by the change in #2907(2),
     in that the “reset on return” feature calls out to the
     Connection/Transaction in order to handle it, where “disconnect
     detection” might be caught.  However, it’s possible that the more
     recent change in #2985(3) made it more likely for this to be seen
     as the “connection invalidate” operation is much quicker, as the
     issue is more reproducible on 0.9.4 than 0.9.3.

     Checks are now added within any section that an invalidate might
     occur to halt further disallowed operations on the invalidated
     connection.  This includes two fixes both at the engine level and
     at the pool level.  While the issue was observed with highly
     concurrent gevent cases, it could in theory occur in any kind of
     scenario where a disconnect occurs within the connection close
     operation.

     References: #3043(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3063

   (2) http://www.sqlalchemy.org/trac/ticket/2907

   (3) http://www.sqlalchemy.org/trac/ticket/2985

   (4) http://www.sqlalchemy.org/trac/ticket/3043

8.3.6.44 sql
............

   * `[sql] [feature]' ¶. Liberalized the contract for
     Index a bit in that you can specify a text()
     expression as the target; the index no longer needs to have a
     table-bound column present if the index is to be manually added to
     the table, either via inline declaration or via
     Table.append_constraint().

     References: #3028(1)

   * `[sql] [feature]' ¶. Added new flag
     between.symmetric, when set to True renders “BETWEEN
     SYMMETRIC”.  Also added a new negation operator “notbetween_op”,
     which now allows an expression like ‘~col.between(x, y)’ to render
     as “col NOT BETWEEN x AND y”, rather than a parenthesized NOT
     string.

     References: #2990(2)

   * `[sql] [bug]' ¶. Fixed bug in INSERT..FROM SELECT
     construct where selecting from a UNION would wrap the union in an
     anonymous (e.g.  unlabeled) subquery.

     This change is also `backported' to: 0.8.7

     References: #3044(3)

   * `[sql] [bug]' ¶. Fixed bug where Table.update()
     and Table.delete() would produce an empty WHERE
     clause when an empty and_() or or_() or other
     blank expression were applied.  This is now consistent with that of
     select().

     This change is also `backported' to: 0.8.7

     References: #3045(4)

   * `[sql] [bug]' ¶. The Column.nullable flag is
     implicitly set to ‘False’ when that Column is referred
     to in an explicit PrimaryKeyConstraint for that table.
     This behavior now matches that of when the Column itself
     has the Column.primary_key flag set to ‘True’, which is
     intended to be an exactly equivalent case.

     References: #3023(5)

   * `[sql] [bug]' ¶. Fixed bug where the
     Operators.__and__(), Operators.__or__() and
     Operators.__invert__() operator overload methods could not be
     overridden within a custom Comparator implementation.

     References: #3012(6)

   * `[sql] [bug]' ¶. Fixed bug in new
     DialectKWArgs.argument_for() method where adding an argument
     for a construct not previously included for any special arguments
     would fail.

     References: #3024(7)

   * `[sql] [bug]' ¶. Fixed regression introduced in 0.9
     where new “ORDER BY <labelname>” feature from #1068(8) would not
     apply quoting rules to the label name as rendered in the ORDER BY.

     References: #1068(9), #3020(10)

   * `[sql] [bug]' ¶. Restored the import for
     Function to the ‘sqlalchemy.sql.expression’ import namespace,
     which was removed at the beginning of 0.9.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3028

   (2) http://www.sqlalchemy.org/trac/ticket/2990

   (3) http://www.sqlalchemy.org/trac/ticket/3044

   (4) http://www.sqlalchemy.org/trac/ticket/3045

   (5) http://www.sqlalchemy.org/trac/ticket/3023

   (6) http://www.sqlalchemy.org/trac/ticket/3012

   (7) http://www.sqlalchemy.org/trac/ticket/3024

   (8) http://www.sqlalchemy.org/trac/ticket/1068

   (9) http://www.sqlalchemy.org/trac/ticket/1068

   (10) http://www.sqlalchemy.org/trac/ticket/3020

8.3.6.45 postgresql
...................

   * `[postgresql] [feature]' ¶. Added support for
     AUTOCOMMIT isolation level when using the pg8000 DBAPI. Pull
     request courtesy Tony Locke.

   * `[postgresql] [feature]' ¶. Added a new flag
     ARRAY.zero_indexes to the PostgreSQL ARRAY type.
     When set to ‘True’, a value of one will be added to all array index
     values before passing to the database, allowing better
     interoperability between Python style zero-based indexes and
     PostgreSQL one-based indexes.  Pull request courtesy Alexey
     Terentev.

     References: #2785(1)

   * `[postgresql] [bug]' ¶. Added the ‘hashable=False’ flag
     to the PG HSTORE type, which is needed to allow the ORM
     to skip over trying to “hash” an ORM-mapped HSTORE column when
     requesting it in a mixed column/entity list.  Patch courtesy
     Gunnlaugur Þór Briem.

     This change is also `backported' to: 0.8.7

     References: #3053(2)

   * `[postgresql] [bug]' ¶. Added a new “disconnect”
     message “connection has been closed unexpectedly”.  This appears to
     be related to newer versions of SSL. Pull request courtesy Antti
     Haapala.

     This change is also `backported' to: 0.8.7

   * `[postgresql] [bug]' ¶. The psycopg2 ‘.closed’ accessor
     is now consulted when determining if an exception is a “disconnect”
     error; ideally, this should remove the need for any other
     inspection of the exception message to detect disconnect, however
     we will leave those existing messages in place as a fallback.  This
     should be able to handle newer cases like “SSL EOF” conditions.
     Pull request courtesy Dirk Mueller.

     References: #3021(3)

   * `[postgresql] [enhancement]' ¶. Added a new type
     OID to the PostgreSQL dialect.  While “oid” is generally a
     private type within PG that is not exposed in modern versions,
     there are some PG use cases such as large object support where
     these types might be exposed, as well as within some user-reported
     schema reflection use cases.

     References: #3002(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2785

   (2) http://www.sqlalchemy.org/trac/ticket/3053

   (3) http://www.sqlalchemy.org/trac/ticket/3021

   (4) http://www.sqlalchemy.org/trac/ticket/3002

8.3.6.46 mysql
..............

   * `[mysql] [bug]' ¶. Fixed bug where column names added
     to ‘mysql_length’ parameter on an index needed to have the same
     quoting for quoted names in order to be recognized.  The fix makes
     the quotes optional but also provides the old behavior for
     backwards compatibility with those using the workaround.

     This change is also `backported' to: 0.8.7

     References: #3085(1)

   * `[mysql] [bug]' ¶. Added support for reflecting tables
     where an index includes KEY_BLOCK_SIZE using an equal sign.  Pull
     request courtesy Sean McGivern.

     This change is also `backported' to: 0.8.7

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3085

8.3.6.47 mssql
..............

   * `[mssql] [bug]' ¶. Revised the query used to determine
     the current default schema name to use the
     ‘database_principal_id()’ function in conjunction with the
     ‘sys.database_principals’ view so that we can determine the default
     schema independently of the type of login in progress (e.g., SQL
     Server, Windows, etc).

     References: #3025(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3025

8.3.6.48 firebird
.................

   * `[firebird] [bug]' ¶. Fixed bug where the combination
     of “limit” rendering as “SELECT FIRST n ROWS” using a bound
     parameter (only firebird has both), combined with column-level
     subqueries which also feature “limit” as well as “positional” bound
     parameters (e.g.  qmark style) would erroneously assign the
     subquery-level positions before that of the enclosing SELECT, thus
     returning parameters which are out of order.

     References: #3038(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3038

8.3.6.49 misc
.............

   * `[feature] [examples]' ¶. Added a new example
     illustrating materialized paths, using the latest relationship
     features.  Example courtesy Jack Zhou.

   * `[bug] [declarative]' ¶. The ‘__mapper_args__’
     dictionary is copied from a declarative mixin or abstract class
     when accessed, so that modifications made to this dictionary by
     declarative itself won’t conflict with that of other mappings.  The
     dictionary is modified regarding the ‘version_id_col’ and
     ‘polymorphic_on’ arguments, replacing the column within with the
     one that is officially mapped to the local class/table.

     This change is also `backported' to: 0.8.7

     References: #3062(1)

   * `[bug] [ext]' ¶. Fixed bug in mutable extension where
     MutableDict did not report change events for the
     ‘setdefault()’ dictionary operation.

     This change is also `backported' to: 0.8.7

     References: #3051(2), #3093(3)

   * `[bug] [ext]' ¶. Fixed bug where
     MutableDict.setdefault() didn’t return the existing or new
     value (this bug was not released in any 0.8 version).  Pull request
     courtesy Thomas Hervé.

     This change is also `backported' to: 0.8.7

     References: #3051(4), #3093(5)

   * `[bug] [testsuite]' ¶. In public test suite, changed to
     use of ‘String(40)’ from less-supported ‘Text’ in
     ‘StringTest.test_literal_backslashes’.  Pullreq courtesy Jan.

   * `[bug] [py3k] [tests]' ¶. Corrected for some
     deprecation warnings involving the ‘imp’ module and Python 3.3 or
     greater, when running tests.  Pull request courtesy Matt Chisholm.

     References: #2830(6)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3062

   (2) http://www.sqlalchemy.org/trac/ticket/3051

   (3) http://www.sqlalchemy.org/trac/ticket/3093

   (4) http://www.sqlalchemy.org/trac/ticket/3051

   (5) http://www.sqlalchemy.org/trac/ticket/3093

   (6) http://www.sqlalchemy.org/trac/ticket/2830

8.3.6.50 0.9.4
..............

Released: March 28, 2014

8.3.6.51 general
................

   * `[general] [feature]' ¶. Support has been added for
     pytest to run tests.  This runner 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 multiple 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.

   * `[general] [bug]' ¶. Adjusted ‘setup.py’ file to
     support the possible future removal of the ‘setuptools.Feature’
     extension from setuptools.  If this keyword isn’t present, the
     setup will still succeed with setuptools rather than falling back
     to distutils.  C extension building can be disabled now also by
     setting the DISABLE_SQLALCHEMY_CEXT environment variable.  This
     variable works whether or not setuptools is even available.

     This change is also `backported' to: 0.8.6

     References: #2986(1)

   * `[general] [bug]' ¶. Fixed some test/feature failures
     occurring in Python 3.4, in particular the logic used to wrap
     “column default” callables wouldn’t work properly for Python
     built-ins.

     References: #2979(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2986

   (2) http://www.sqlalchemy.org/trac/ticket/2979

8.3.6.52 orm
............

   * `[orm] [feature]' ¶. Added new parameter
     mapper.confirm_deleted_rows.  Defaults to True, indicates that
     a series of DELETE statements should confirm that the cursor
     rowcount matches the number of primary keys that should have
     matched; this behavior had been taken off in most cases (except
     when version_id is used) to support the unusual edge case of
     self-referential ON DELETE CASCADE; to accommodate this, the
     message is now just a warning, not an exception, and the flag can
     be used to indicate a mapping that expects self-referential
     cascaded deletes of this nature.  See also #2403(1) for background
     on the original change.

     References: #3007(2)

   * `[orm] [feature]' ¶. A warning is emitted if the
     MapperEvents.before_configured() or
     MapperEvents.after_configured() events are applied to a
     specific mapper or mapped class, as the events are only invoked for
     the Mapper target at the general level.

   * `[orm] [feature]' ¶. Added a new keyword argument
     ‘once=True’ to listen() and listens_for().
     This is a convenience feature which will wrap the given listener
     such that it is only invoked once.

   * `[orm] [feature]' ¶. Added a new option to
     relationship.innerjoin which is to specify the string
     ‘"nested"’.  When set to ‘"nested"’ as opposed to ‘True’, the
     “chaining” of joins will parenthesize the inner join on the right
     side of an existing outer join, instead of chaining as a string of
     outer joins.  This possibly should have been the default behavior
     when 0.9 was released, as we introduced the feature of right-nested
     joins in the ORM, however we are keeping it as a non-default for
     now to avoid further surprises.

     See also
     ........

     See Right-nested inner joins available in joined eager loads.

     References: #2976(3)

   * `[orm] [bug]' ¶. Fixed ORM bug where changing the
     primary key of an object, then marking it for DELETE would fail to
     target the correct row for DELETE.

     This change is also `backported' to: 0.8.6

     References: #3006(4)

   * `[orm] [bug]' ¶. Fixed regression from 0.8.3 as a
     result of #2818(5) where Query.exists() wouldn’t work
     on a query that only had a Query.select_from() entry
     but no other entities.

     This change is also `backported' to: 0.8.6

     References: #2995(6)

   * `[orm] [bug]' ¶. Improved an error message which would
     occur if a query() were made against a non-selectable, such as a
     literal_column(), and then an attempt was made to use
     Query.join() such that the “left” side would be
     determined as ‘None’ and then fail.  This condition is now detected
     explicitly.

     This change is also `backported' to: 0.8.6

   * `[orm] [bug]' ¶. Removed stale names from
     ‘sqlalchemy.orm.interfaces.__all__’ and refreshed with current
     names, so that an ‘import *’ from this module again works.

     This change is also `backported' to: 0.8.6

     References: #2975(7)

   * `[orm] [bug]' ¶. Fixed a very old behavior where the
     lazy load emitted for a one-to-many could inappropriately pull in
     the parent table, and also return results inconsistent based on
     what’s in the parent table, when the primaryjoin includes some kind
     of discriminator against the parent table, such as ‘and_(parent.id
     == child.parent_id, parent.deleted == False)’.  While this
     primaryjoin doesn’t make that much sense for a one-to-many, it is
     slightly more common when applied to the many-to-one side, and the
     one-to-many comes as a result of a backref.  Loading rows from
     ‘child’ in this case would keep ‘parent.deleted == False’ as is
     within the query, thereby yanking it into the FROM clause and doing
     a cartesian product.  The new behavior will now substitute the
     value of the local “parent.deleted” for that parameter as is
     appropriate.  Though typically, a real-world app probably wants to
     use a different primaryjoin for the o2m side in any case.

     References: #2948(8)

   * `[orm] [bug]' ¶. Improved the check for “how to join
     from A to B” such that when a table has multiple, composite foreign
     keys targeting a parent table, the relationship.foreign_keys
     argument will be properly interpreted in order to resolve the
     ambiguity; previously this condition would raise that there were
     multiple FK paths when in fact the foreign_keys argument should be
     establishing which one is expected.

     References: #2965(9)

   * `[orm] [bug]' ¶. Added support for the
     not-quite-yet-documented ‘insert=True’ flag for listen()
     to work with mapper / instance events.

   * `[orm] [bug] [engine]' ¶. Fixed bug where events set to
     listen at the class level (e.g.  on the Mapper or
     ClassManager level, as opposed to on an individual mapped
     class, and also on Connection) that also made use of
     internal argument conversion (which is most within those
     categories) would fail to be removable.

     References: #2973(10)

   * `[orm] [bug]' ¶. Fixed regression from 0.8 where using
     an option like lazyload() with the “wildcard”
     expression, e.g.  ‘"*"’, would raise an assertion error in the case
     where the query didn’t contain any actual entities.  This assertion
     is meant for other cases and was catching this one inadvertently.

   * `[orm] [bug] [sqlite]' ¶. More fixes to SQLite “join
     rewriting”; the fix from #2967(11) implemented right before the
     release of 0.9.3 affected the case where a UNION contained nested
     joins in it.  “Join rewriting” is a feature with a wide range of
     possibilities and is the first intricate “SQL rewriting” feature
     we’ve introduced in years, so we’re sort of going through a lot of
     iterations with it (not unlike eager loading back in the 0.2/0.3
     series, polymorphic loading in 0.4/0.5).  We should be there soon
     so thanks for bearing with us :).

     References: #2969(12)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2403

   (2) http://www.sqlalchemy.org/trac/ticket/3007

   (3) http://www.sqlalchemy.org/trac/ticket/2976

   (4) http://www.sqlalchemy.org/trac/ticket/3006

   (5) http://www.sqlalchemy.org/trac/ticket/2818

   (6) http://www.sqlalchemy.org/trac/ticket/2995

   (7) http://www.sqlalchemy.org/trac/ticket/2975

   (8) http://www.sqlalchemy.org/trac/ticket/2948

   (9) http://www.sqlalchemy.org/trac/ticket/2965

   (10) http://www.sqlalchemy.org/trac/ticket/2973

   (11) http://www.sqlalchemy.org/trac/ticket/2967

   (12) http://www.sqlalchemy.org/trac/ticket/2969

8.3.6.53 engine
...............

   * `[engine] [feature]' ¶. Added some new event mechanics
     for dialect-level events; the initial implementation allows an
     event handler to redefine the specific mechanics by which an
     arbitrary dialect invokes execute() or executemany() on a DBAPI
     cursor.  The new events, at this point semi-public and
     experimental, are in support of some upcoming transaction-related
     extensions.

   * `[engine] [feature]' ¶. An event listener can now be
     associated with a Engine, after one or more
     Connection objects have been created (such as by an orm
     Session or via explicit connect) and the listener will pick up
     events from those connections.  Previously, performance concerns
     pushed the event transfer from Engine to
     Connection at init-time only, but we’ve inlined a bunch of
     conditional checks to make this possible without any additional
     function calls.

     References: #2978(1)

   * `[engine] [bug]' ¶. A major improvement made to the
     mechanics by which the Engine recycles the connection
     pool when a “disconnect” condition is detected; instead of
     discarding the pool and explicitly closing out connections, the
     pool is retained and a “generational” timestamp is updated to
     reflect the current time, thereby causing all existing connections
     to be recycled when they are next checked out.  This greatly
     simplifies the recycle process, removes the need for “waking up”
     connect attempts waiting on the old pool and eliminates the race
     condition that many immediately-discarded “pool” objects could be
     created during the recycle operation.

     References: #2985(2)

   * `[engine] [bug]' ¶. The
     ConnectionEvents.after_cursor_execute() event is now emitted
     for the “_cursor_execute()” method of Connection; this
     is the “quick” executor that is used for things like when a
     sequence is executed ahead of an INSERT statement, as well as for
     dialect startup checks like unicode returns, charset, etc.  the
     ConnectionEvents.before_cursor_execute() event was
     already invoked here.  The “executemany” flag is now always set to
     False here, as this event always corresponds to a single execution.
     Previously the flag could be True if we were acting on behalf of an
     executemany INSERT statement.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2978

   (2) http://www.sqlalchemy.org/trac/ticket/2985

8.3.6.54 sql
............

   * `[sql] [feature]' ¶. Added support for literal
     rendering of boolean values, e.g.  “true” / “false” or “1” / “0”.

   * `[sql] [feature]' ¶. Added a new feature conv(),
     the purpose of which is to mark a constraint name as already
     having had a naming convention applied.  This token will be used by
     Alembic migrations as of Alembic 0.6.4 in order to render
     constraints in migration scripts with names marked as already
     having been subject to a naming convention.

   * `[sql] [feature]' ¶. The new dialect-level keyword
     argument system for schema-level constructs has been enhanced in
     order to assist with existing schemes that rely upon addition of
     ad-hoc keyword arguments to constructs.

     E.g., a construct such as Index will again accept
     ad-hoc keyword arguments within the Index.kwargs
     collection, after construction:

          idx = Index('a', 'b')
          idx.kwargs['mysql_someargument'] = True

     To suit the use case of allowing custom arguments at construction
     time, the DialectKWArgs.argument_for() method now
     allows this registration:

          Index.argument_for('mysql', 'someargument', False)

          idx = Index('a', 'b', mysql_someargument=True)

     See also
     ........

     See DialectKWArgs.argument_for().

     References: #2866(1), #2962(2)

   * `[sql] [bug]' ¶. Fixed bug in tuple_().
     construct where the “type” of essentially the first SQL expression
     would be applied as the “comparison type” to a compared tuple
     value; this has the effect in some cases of an inappropriate “type
     coercion” occurring, such as when a tuple that has a mix of String
     and Binary values improperly coerces target values to Binary even
     though that’s not what they are on the left side.  tuple_()
     now expects heterogeneous types within its list of values.

     This change is also `backported' to: 0.8.6

     References: #2977(3)

   * `[sql] [bug]' ¶. Fixed an 0.9 regression where a
     Table that failed to reflect correctly wouldn’t be removed
     from the parent MetaData, even though in an invalid
     state.  Pullreq courtesy Roman Podoliaka.

     References: #2988(4)

   * `[sql] [bug]' ¶. MetaData.naming_convention
     feature will now also apply to CheckConstraint
     objects that are associated directly with a Column
     instead of just on the Table.

   * `[sql] [bug]' ¶. Fixed bug in new
     MetaData.naming_convention feature where the name of a check
     constraint making use of the ‘“%(constraint_name)s”’ token would
     get doubled up for the constraint generated by a boolean or enum
     type, and overall duplicate events would cause the
     ‘“%(constraint_name)s”’ token to keep compounding itself.

     References: #2991(5)

   * `[sql] [bug]' ¶. Adjusted the logic which applies names
     to the .c collection when a no-name BindParameter is
     received, e.g.  via literal() or similar; the “key” of
     the bind param is used as the key within .c.  rather than the
     rendered name.  Since these binds have “anonymous” names in any
     case, this allows individual bound parameters to have their own
     name within a selectable if they are otherwise unlabeled.

     References: #2974(6)

   * `[sql] [bug]' ¶. Some changes to how the
     FromClause.c collection behaves when presented with duplicate
     columns.  The behavior of emitting a warning and replacing the old
     column with the same name still remains to some degree; the
     replacement in particular is to maintain backwards compatibility.
     However, the replaced column still remains associated with the ‘c’
     collection now in a collection ‘._all_columns’, which is used by
     constructs such as aliases and unions, to deal with the set of
     columns in ‘c’ more towards what is actually in the list of columns
     rather than the unique set of key names.  This helps with
     situations where SELECT statements with same-named columns are used
     in unions and such, so that the union can match the columns up
     positionally and also there’s some chance of
     ‘FromClause.corresponding_column()’ still being usable here (it can
     now return a column that is only in selectable.c._all_columns and
     not otherwise named).  The new collection is underscored as we
     still need to decide where this list might end up.  Theoretically
     it would become the result of iter(selectable.c), however this
     would mean that the length of the iteration would no longer match
     the length of keys(), and that behavior needs to be checked out.

     References: #2974(7)

   * `[sql] [bug]' ¶. Fixed issue in new
     TextClause.columns() method where the ordering of columns
     given positionally would not be preserved.  This could have
     potential impact in positional situations such as applying the
     resulting ‘TextAsFrom’ object to a union.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2866

   (2) http://www.sqlalchemy.org/trac/ticket/2962

   (3) http://www.sqlalchemy.org/trac/ticket/2977

   (4) http://www.sqlalchemy.org/trac/ticket/2988

   (5) http://www.sqlalchemy.org/trac/ticket/2991

   (6) http://www.sqlalchemy.org/trac/ticket/2974

   (7) http://www.sqlalchemy.org/trac/ticket/2974

8.3.6.55 postgresql
...................

   * `[postgresql] [feature]' ¶. Enabled “sane multi-row
     count” checking for the psycopg2 DBAPI, as this seems to be
     supported as of psycopg2 2.0.9.

     This change is also `backported' to: 0.8.6

   * `[postgresql] [bug]' ¶. Fixed regression caused by
     release 0.8.5 / 0.9.3’s compatibility enhancements where index
     reflection on PostgreSQL versions specific to only the 8.1, 8.2
     series again broke, surrounding the ever problematic int2vector
     type.  While int2vector supports array operations as of 8.1,
     apparently it only supports CAST to a varchar as of 8.3.

     This change is also `backported' to: 0.8.6

     References: #3000(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3000

8.3.6.56 mysql
..............

   * `[mysql] [bug]' ¶. Tweaked the settings for
     mysql-connector-python; in Py2K, the “supports unicode statements”
     flag is now False, so that SQLAlchemy will encode the `SQL string'
     (note: `not' the parameters) to bytes before sending to the
     database.  This seems to allow all unicode-related tests to pass
     for mysql-connector, including those that use non-ascii
     table/column names, as well as some tests for the TEXT type using
     unicode under cursor.executemany().

8.3.6.57 oracle
...............

   * `[oracle] [feature]' ¶. Added a new engine option
     ‘coerce_to_unicode=True’ to the cx_Oracle dialect, which restores
     the cx_Oracle outputtypehandler approach to Python unicode
     conversion under Python 2, which was removed in 0.9.2 as a result
     of #2911(1).  Some use cases would prefer that unicode coercion is
     unconditional for all string values, despite performance concerns.
     Pull request courtesy Christoph Zwerschke.

     References: #2911(2)

   * `[oracle] [bug]' ¶. Added new datatype DATE,
     which is a subclass of DateTime.  As Oracle has no
     “datetime” type per se, it instead has only ‘DATE’, it is
     appropriate here that the ‘DATE’ type as present in the Oracle
     dialect be an instance of DateTime.  This issue doesn’t
     change anything as far as the behavior of the type, as data
     conversion is handled by the DBAPI in any case, however the
     improved subclass layout will help the use cases of inspecting
     types for cross-database compatibility.  Also removed uppercase
     ‘DATETIME’ from the Oracle dialect as this type isn’t functional in
     that context.

     References: #2987(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2911

   (2) http://www.sqlalchemy.org/trac/ticket/2911

   (3) http://www.sqlalchemy.org/trac/ticket/2987

8.3.6.58 misc
.............

   * `[bug] [ext]' ¶. Fixed bug in mutable extension as well
     as flag_modified() where the change event would not be
     propagated if the attribute had been reassigned to itself.

     This change is also `backported' to: 0.8.6

     References: #2997(1)

   * `[bug] [automap] [ext]' ¶. Added support to automap for
     the case where a relationship should not be created between two
     classes that are in a joined inheritance relationship, for those
     foreign keys that link the subclass back to the superclass.

     References: #3004(2)

   * `[bug] [tests]' ¶. Fixed a few errant ‘u''’ strings
     that would prevent tests from passing in Py3.2.  Patch courtesy
     Arfrever Frehtes Taifersar Arahesis.

     References: #2980(3)

   * `[bug] [pool]' ¶. Fixed small issue in
     SingletonThreadPool where the current connection to be
     returned might get inadvertently cleaned out during the “cleanup”
     process.  Patch courtesy jd23.

   * `[bug] [ext] [py3k]' ¶. Fixed bug in association proxy
     where assigning an empty slice (e.g.  ‘x[:] = [...]’) would fail on
     Py3k.

   * `[bug] [ext]' ¶. Fixed a regression in association
     proxy caused by #2810(4) which caused a user-provided “getter” to
     no longer receive values of ‘None’ when fetching scalar values from
     a target that is non-present.  The check for None introduced by
     this change is now moved into the default getter, so a
     user-provided getter will also again receive values of None.

     References: #2810(5)

   * `[bug] [examples]' ¶. Fixed bug in the
     versioned_history example where column-level INSERT defaults would
     prevent history values of NULL from being written.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2997

   (2) http://www.sqlalchemy.org/trac/ticket/3004

   (3) http://www.sqlalchemy.org/trac/ticket/2980

   (4) http://www.sqlalchemy.org/trac/ticket/2810

   (5) http://www.sqlalchemy.org/trac/ticket/2810

8.3.6.59 0.9.3
..............

Released: February 19, 2014

8.3.6.60 orm
............

   * `[orm] [feature]' ¶. Added new
     MapperEvents.before_configured() event which allows an event
     at the start of configure_mappers(), as well as
     ‘__declare_first__()’ hook within declarative to complement
     ‘__declare_last__()’.

   * `[orm] [bug]' ¶. Fixed bug where Query.get()
     would fail to consistently raise the
     InvalidRequestError that invokes when called on a query with
     existing criterion, when the given identity is already present in
     the identity map.

     This change is also `backported' to: 0.8.5

     References: #2951(1)

   * `[orm] [bug] [sqlite]' ¶. Fixed bug in SQLite “join
     rewriting” where usage of an exists() construct would fail to be
     rewritten properly, such as when the exists is mapped to a
     column_property in an intricate nested-join scenario.  Also fixed a
     somewhat related issue where join rewriting would fail on the
     columns clause of the SELECT statement if the targets were aliased
     tables, as opposed to individual aliased columns.

     References: #2967(2)

   * `[orm] [bug]' ¶. Fixed an 0.9 regression where ORM
     instance or mapper events applied to a base class such as a
     declarative base with the propagate=True flag would fail to apply
     to existing mapped classes which also used inheritance due to an
     assertion.  Additionally, repaired an attribute error which could
     occur during removal of such an event, depending on how it was
     first assigned.

     References: #2949(3)

   * `[orm] [bug]' ¶. Improved the initialization logic of
     composite attributes such that calling ‘MyClass.attribute’ will not
     require that the configure mappers step has occurred, e.g.  it will
     just work without throwing any error.

     References: #2935(4)

   * `[orm] [bug]' ¶. More issues with [ticket:2932] first
     resolved in 0.9.2 where 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 ‘TextAsFrom’ construct or with literal columns.

     References: #2932(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2951

   (2) http://www.sqlalchemy.org/trac/ticket/2967

   (3) http://www.sqlalchemy.org/trac/ticket/2949

   (4) http://www.sqlalchemy.org/trac/ticket/2935

   (5) http://www.sqlalchemy.org/trac/ticket/2932

8.3.6.61 orm declarative
........................

   * `[orm] [declarative] [bug]' ¶. Fixed bug where
     AbstractConcreteBase would fail to be fully usable within
     declarative relationship configuration, as its string classname
     would not be available in the registry of classnames at mapper
     configuration time.  The class now explicitly adds itself to the
     class registry, and additionally both AbstractConcreteBase
     as well as ConcreteBase set themselves up `before'
     mappers are configured within the configure_mappers()
     setup, using the new MapperEvents.before_configured()
     event.

     References: #2950(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2950

8.3.6.62 engine
...............

   * `[engine] [bug] [pool]' ¶. Fixed a critical regression
     caused by #2880(1) where the newly concurrent ability to return
     connections from the pool means that the “first_connect” event is
     now no longer synchronized either, thus leading to dialect
     mis-configurations under even minimal concurrency situations.

     This change is also `backported' to: 0.8.5

     References: #2880(2), #2964(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2880

   (2) http://www.sqlalchemy.org/trac/ticket/2880

   (3) http://www.sqlalchemy.org/trac/ticket/2964

8.3.6.63 sql
............

   * `[sql] [bug]' ¶. Fixed bug where calling
     Insert.values() with an empty list or tuple would raise an
     IndexError.  It now produces an empty insert construct as would be
     the case with an empty dictionary.

     This change is also `backported' to: 0.8.5

     References: #2944(1)

   * `[sql] [bug]' ¶. Fixed bug where
     ColumnOperators.in_() would go into an endless loop if
     erroneously passed a column expression whose comparator included
     the ‘__getitem__()’ method, such as a column that uses the
     ARRAY type.

     This change is also `backported' to: 0.8.5

     References: #2957(2)

   * `[sql] [bug]' ¶. Fixed regression in new “naming
     convention” feature where conventions would fail if the referred
     table in a foreign key contained a schema name.  Pull request
     courtesy Thomas Farvour.

   * `[sql] [bug]' ¶. Fixed bug where so-called “literal
     render” of bindparam() constructs would fail if the bind
     were constructed with a callable, rather than a direct value.  This
     prevented ORM expressions from being rendered with the
     “literal_binds” compiler flag.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2944

   (2) http://www.sqlalchemy.org/trac/ticket/2957

8.3.6.64 postgresql
...................

   * `[postgresql] [feature]' ¶. Added the
     TypeEngine.python_type convenience accessor onto the
     ARRAY type.  Pull request courtesy Alexey Terentev.

   * `[postgresql] [bug]' ¶. Added an additional message to
     psycopg2 disconnect detection, “could not send data to server”,
     which complements the existing “could not receive data from server”
     and has been observed by users.

     This change is also `backported' to: 0.8.5

     References: #2936(1)

   * `[postgresql] [bug]' ¶.

          Support has been improved for PostgreSQL reflection behavior
          on very old (pre 8.1) versions of PostgreSQL, and potentially
          other PG engines such as Redshift (assuming Redshift reports
          the version as < 8.1).  The query for “indexes” as well as
          “primary keys” relies upon inspecting a so-called “int2vector”
          datatype, which refuses to coerce to an array prior to 8.1
          causing failures regarding the “ANY()” operator used in the
          query.  Extensive googling has located the very hacky, but
          recommended-by-PG-core-developer query to use when PG version
          < 8.1 is in use, so index and primary key constraint
          reflection now work on these versions.

     This change is also `backported' to: 0.8.5

   * `[postgresql] [bug]' ¶. Revised this very old issue
     where the PostgreSQL “get primary key” reflection query were
     updated to take into account primary key constraints that were
     renamed; the newer query fails on very old versions of PostgreSQL
     such as version 7, so the old query is restored in those cases when
     server_version_info < (8, 0) is detected.

     This change is also `backported' to: 0.8.5

     References: #2291(2)

   * `[postgresql] [bug]' ¶. Added server version detection
     to the newly added dialect startup query for “show
     standard_conforming_strings”; as this variable was added as of PG
     8.2, we skip the query for PG versions who report a version string
     earlier than that.

     References: #2946(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2936

   (2) http://www.sqlalchemy.org/trac/ticket/2291

   (3) http://www.sqlalchemy.org/trac/ticket/2946

8.3.6.65 mysql
..............

   * `[mysql] [feature]' ¶. Added new MySQL-specific
     DATETIME which includes fractional seconds support; also
     added fractional seconds support to TIMESTAMP.  DBAPI
     support is limited, though fractional seconds are known to be
     supported by MySQL Connector/Python.  Patch courtesy Geert JM
     Vanderkelen.

     This change is also `backported' to: 0.8.5

     References: #2941(1)

   * `[mysql] [bug]' ¶. Added support for the ‘PARTITION BY’
     and ‘PARTITIONS’ MySQL table keywords, specified as
     ‘mysql_partition_by='value'’ and ‘mysql_partitions='value'’ to
     Table.  Pull request courtesy Marcus McCurdy.

     This change is also `backported' to: 0.8.5

     References: #2966(2)

   * `[mysql] [bug]' ¶. Fixed bug which prevented
     MySQLdb-based dialects (e.g.  pymysql) from working in Py3K, where
     a check for “connection charset” would fail due to Py3K’s more
     strict value comparison rules.  The call in question wasn’t taking
     the database version into account in any case as the server version
     was still None at that point, so the method overall has been
     simplified to rely upon connection.character_set_name().

     This change is also `backported' to: 0.8.5

     References: #2933(3)

   * `[mysql] [bug] [cymysql]' ¶. Fixed bug in cymysql
     dialect where a version string such as ‘'33a-MariaDB'’ would fail
     to parse properly.  Pull request courtesy Matt Schmidt.

     References: #2934(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2941

   (2) http://www.sqlalchemy.org/trac/ticket/2966

   (3) http://www.sqlalchemy.org/trac/ticket/2933

   (4) http://www.sqlalchemy.org/trac/ticket/2934

8.3.6.66 sqlite
...............

   * `[sqlite] [bug]' ¶. The SQLite dialect will now skip
     unsupported arguments when reflecting types; such as if it
     encounters a string like ‘INTEGER(5)’, the INTEGER
     type will be instantiated without the “5” being included, based on
     detecting a ‘TypeError’ on the first attempt.

   * `[sqlite] [bug]' ¶. Support has been added to SQLite
     type reflection to fully support the “type affinity” contract
     specified at ‘http://www.sqlite.org/datatype3.html’.  In this
     scheme, keywords like ‘INT’, ‘CHAR’, ‘BLOB’ or ‘REAL’ located in
     the type name generically associate the type with one of five
     affinities.  Pull request courtesy Erich Blume.

     See also
     ........

     See Type Reflection.

8.3.6.67 misc
.............

   * `[feature] [examples]' ¶. Added optional “changed”
     column to the versioned rows example, as well as support for when
     the versioned Table has an explicit Table.schema
     argument.  Pull request courtesy jplaverdure.

   * `[bug] [ext]' ¶. Fixed bug where the AutomapBase
     class of the new automap extension would fail if classes were
     pre-arranged in single or potentially joined inheritance patterns.
     The repaired joined inheritance issue could also potentially apply
     when using DeferredReflection as well.

8.3.6.68 0.9.2
..............

Released: February 2, 2014

8.3.6.69 orm
............

   * `[orm] [feature]' ¶. Added a new parameter
     Operators.op.is_comparison.  This flag allows a custom op from
     Operators.op() to be considered as a “comparison”
     operator, thus usable for custom relationship.primaryjoin
     conditions.

     See also
     ........

     See Using custom operators in join conditions.

   * `[orm] [feature]' ¶. Support is improved for supplying
     a join() construct as the target of
     relationship.secondary for the purposes of creating very
     complex relationship() join conditions.  The change
     includes adjustments to query joining, joined eager loading to not
     render a SELECT subquery, changes to lazy loading such that the
     “secondary” target is properly included in the SELECT, and changes
     to declarative to better support specification of a join() object
     with classes as targets.

     The new use case is somewhat experimental, but a new documentation
     section has been added.

     See also
     ........

     See Composite “Secondary” Joins.

   * `[orm] [bug]' ¶. Fixed error message when an iterator
     object is passed to class_mapper() or similar, where
     the error would fail to render on string formatting.  Pullreq
     courtesy Kyle Stark.

     This change is also `backported' to: 0.8.5

   * `[orm] [bug]' ¶. Fixed bug in new ‘TextAsFrom’
     construct where Column.- oriented row lookups were not
     matching up to the ad-hoc ColumnClause objects that
     ‘TextAsFrom’ generates, thereby making it not usable as a target in
     Query.from_statement().  Also fixed
     Query.from_statement() mechanics to not mistake a
     ‘TextAsFrom’ for a Select construct.  This bug is also
     an 0.9 regression as the TextClause.columns() method is
     called to accommodate the text.typemap argument.

     References: #2932(1)

   * `[orm] [bug]' ¶. Added a new directive used within the
     scope of an attribute “set” operation to disable autoflush, in the
     case that the attribute needs to lazy-load the “old” value, as in
     when replacing one-to-one values or some kinds of many-to-one.  A
     flush at this point otherwise occurs at the point that the
     attribute is None and can cause NULL violations.

     References: #2921(2)

   * `[orm] [bug]' ¶. Fixed an 0.9 regression where the
     automatic aliasing applied by Query and in other
     situations where selects or joins were aliased (such as joined
     table inheritance) could fail if a user-defined Column
     subclass were used in the expression.  In this case, the subclass
     would fail to propagate ORM-specific “annotations” along needed by
     the adaptation.  The “expression annotations” system has been
     corrected to account for this case.

     References: #2918(3)

   * `[orm] [bug]' ¶. Fixed a bug involving the new
     flattened JOIN structures which are used with joinedload().
     (thereby causing a regression in joined eager loading) as well
     as aliased() in conjunction with the ‘flat=True’ flag
     and joined-table inheritance; basically multiple joins across a
     “parent JOIN sub” entity using different paths to get to a target
     class wouldn’t form the correct ON conditions.  An adjustment /
     simplification made in the mechanics of figuring out the “left
     side” of the join in the case of an aliased, joined-inh class
     repairs the issue.

     References: #2908(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2932

   (2) http://www.sqlalchemy.org/trac/ticket/2921

   (3) http://www.sqlalchemy.org/trac/ticket/2918

   (4) http://www.sqlalchemy.org/trac/ticket/2908

8.3.6.70 engine
...............

   * `[engine] [feature] [pool]' ¶. Added a new pool event
     PoolEvents.invalidate().  Called when a DBAPI
     connection is to be marked as “invalidated” and discarded from the
     pool.

8.3.6.71 sql
............

   * `[sql] [feature]' ¶. Added
     MetaData.reflect.**dialect_kwargs to support dialect-level
     reflection options for all Table objects reflected.

   * `[sql] [feature]' ¶. Added a new feature which allows
     automated naming conventions to be applied to Constraint
     and Index objects.  Based on a recipe in the wiki, the
     new feature uses schema-events to set up names as various schema
     objects are associated with each other.  The events then expose a
     configuration system through a new argument
     MetaData.naming_convention.  This system allows production of
     both simple and custom naming schemes for constraints and indexes
     on a per-see MetaData basis.

     See also
     ........

     See Configuring Constraint Naming Conventions.

     References: #2923(1)

   * `[sql] [feature]' ¶. Options can now be specified on a
     PrimaryKeyConstraint object independently of the
     specification of columns in the table with the ‘primary_key=True’
     flag; use a PrimaryKeyConstraint object with no columns
     in it to achieve this result.

     Previously, an explicit PrimaryKeyConstraint would have
     the effect of those columns marked as ‘primary_key=True’ being
     ignored; since this is no longer the case, the
     PrimaryKeyConstraint will now assert that either one style or
     the other is used to specify the columns, or if both are present,
     that the column lists match exactly.  If an inconsistent set of
     columns in the PrimaryKeyConstraint and within the
     Table marked as ‘primary_key=True’ are present, a warning is
     emitted, and the list of columns is taken only from the
     PrimaryKeyConstraint alone as was the case in previous
     releases.

     See also
     ........

     See PrimaryKeyConstraint.

     References: #2910(2)

   * `[sql] [feature]' ¶. The system by which schema
     constructs and certain SQL constructs accept dialect-specific
     keyword arguments has been enhanced.  This system includes commonly
     the Table and Index constructs, which accept
     a wide variety of dialect-specific arguments such as ‘mysql_engine’
     and ‘postgresql_where’, as well as the constructs
     PrimaryKeyConstraint, UniqueConstraint,
     Update, Insert and Delete, and also newly
     added kwarg capability to ForeignKeyConstraint and
     ForeignKey.  The change is that participating dialects can now
     specify acceptable argument lists for these constructs, allowing an
     argument error to be raised if an invalid keyword is specified for
     a particular dialect.  If the dialect portion of the keyword is
     unrecognized, a warning is emitted only; while the system will
     actually make use of setuptools entrypoints in order to locate
     non-local dialects, the use case where certain dialect-specific
     arguments are used in an environment where that third-party dialect
     is uninstalled remains supported.  Dialects also have to explicitly
     opt-in to this system, so that external dialects which aren’t
     making use of this system will remain unaffected.

     References: #2866(3)

   * `[sql] [bug]' ¶. The behavior of
     Table.tometadata() has been adjusted such that the schema
     target of a ForeignKey will not be changed unless that
     schema matches that of the parent table.  That is, if a table
     “schema_a.user” has a foreign key to “schema_b.order.id”, the
     “schema_b” target will be maintained whether or not the “schema”
     argument is passed to Table.tometadata().  However if a
     table “schema_a.user” refers to “schema_a.order.id”, the presence
     of “schema_a” will be updated on both the parent and referred
     tables.  This is a behavioral change hence isn’t likely to be
     backported to 0.8; it is assumed that the previous behavior is
     pretty buggy however and that it’s unlikely anyone was relying upon
     it.

     Additionally, a new parameter has been added
     Table.tometadata.referred_schema_fn.  This refers to a
     callable function which will be used to determine the new referred
     schema for any ForeignKeyConstraint encountered in the
     tometadata operation.  This callable can be used to revert to the
     previous behavior or to customize how referred schemas are treated
     on a per-constraint basis.

     References: #2913(4)

   * `[sql] [bug]' ¶. Fixed bug whereby binary type would
     fail in some cases if used with a “test” dialect, such as a
     DefaultDialect or other dialect with no DBAPI.

   * `[sql] [bug] [py3k]' ¶. Fixed bug where “literal binds”
     wouldn’t work with a bound parameter that’s a binary type.  A
     similar, but different, issue is fixed in 0.8.

   * `[sql] [bug]' ¶. Fixed regression whereby the
     “annotation” system used by the ORM was leaking into the names used
     by standard functions in sqlalchemy.sql.functions, such
     as ‘func.coalesce()’ and ‘func.max()’.  Using these functions in
     ORM attributes and thus producing annotated versions of them could
     corrupt the actual function name rendered in the SQL.

     References: #2927(5)

   * `[sql] [bug]' ¶. Fixed 0.9 regression where the new
     sortable support for ‘RowProxy’ 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 ‘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.

     References: #2848(6), #2924(7)

   * `[sql] [bug]' ¶. A UniqueConstraint.
     created inline with a Table that has no columns within
     it will be skipped.  Pullreq courtesy Derek Harland.

   * `[sql] [bug] [orm]' ¶. Fixed the multiple-table
     “UPDATE..FROM” construct, only usable on MySQL, to correctly render
     the SET clause among multiple columns with the same name across
     tables.  This also changes the name used for the bound parameter in
     the SET clause to “<tablename>_<colname>” for the non-primary table
     only; as this parameter is typically specified using the
     Column object directly this should not have an impact on
     applications.  The fix takes effect for both Table.update()
     as well as Query.update() in the ORM.

     References: #2912(8)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2923

   (2) http://www.sqlalchemy.org/trac/ticket/2910

   (3) http://www.sqlalchemy.org/trac/ticket/2866

   (4) http://www.sqlalchemy.org/trac/ticket/2913

   (5) http://www.sqlalchemy.org/trac/ticket/2927

   (6) http://www.sqlalchemy.org/trac/ticket/2848

   (7) http://www.sqlalchemy.org/trac/ticket/2924

   (8) http://www.sqlalchemy.org/trac/ticket/2912

8.3.6.72 schema
...............

   * `[schema] [bug]' ¶. Restored
     ‘sqlalchemy.schema.SchemaVisitor’ to the ‘.schema’ module.  Pullreq
     courtesy Sean Dague.

8.3.6.73 postgresql
...................

   * `[postgresql] [feature]' ¶. Added a new dialect-level
     argument ‘postgresql_ignore_search_path’; this argument is accepted
     by both the Table constructor as well as by the
     MetaData.reflect() method.  When in use against PostgreSQL, a
     foreign-key referenced table which specifies a remote schema name
     will retain that schema name even if the name is present in the
     ‘search_path’; the default behavior since 0.7.3 has been that
     schemas present in ‘search_path’ would not be copied to reflected
     ForeignKey objects.  The documentation has been updated
     to describe in detail the behavior of the ‘pg_get_constraintdef()’
     function and how the ‘postgresql_ignore_search_path’ feature
     essentially determines if we will honor the schema qualification
     reported by this function or not.

     See also
     ........

     See Remote-Schema Table Introspection and PostgreSQL search_path.

     References: #2922(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2922

8.3.6.74 mysql
..............

   * `[mysql] [bug]' ¶. Some missing methods added to the
     cymysql dialect, including _get_server_version_info() and
     _detect_charset().  Pullreq courtesy Hajime Nakagami.

     This change is also `backported' to: 0.8.5

   * `[mysql] [bug] [sql]' ¶. Added new test coverage for
     so-called “down adaptions” of SQL types, where a more specific type
     is adapted to a more generic one - this use case is needed by some
     third party tools such as ‘sqlacodegen’.  The specific cases that
     needed repair within this test suite were that of ENUM
     being downcast into a Enum, and that of SQLite date
     types being cast into generic date types.  The ‘adapt()’ method
     needed to become more specific here to counteract the removal of a
     “catch all” ‘**kwargs’ collection on the base TypeEngine
     class that was removed in 0.9.

     References: #2917(1)

   * `[mysql] [bug]' ¶. The MySQL CAST compilation now takes
     into account aspects of a string type such as “charset” and
     “collation”.  While MySQL wants all character- based CAST calls to
     use the CHAR type, we now create a real CHAR object at CAST time
     and copy over all the parameters it has, so that an expression like
     ‘cast(x, mysql.TEXT(charset='utf8'))’ will render ‘CAST(t.col AS
     CHAR CHARACTER SET utf8)’.

   * `[mysql] [bug]' ¶. Added new “unicode returns”
     detection to the MySQL dialect and to the default dialect system
     overall, such that any dialect can add extra “tests” to the
     on-first-connect “does this DBAPI return unicode directly?”
     detection.  In this case, we are adding a check specifically
     against the “utf8” encoding with an explicit “utf8_bin” collation
     type (after checking that this collation is available) to test for
     some buggy unicode behavior observed with MySQLdb version 1.2.3.
     While MySQLdb has resolved this issue as of 1.2.4, the check here
     should guard against regressions.  The change also allows the
     “unicode” checks to log in the engine logs, which was not
     previously the case.

     References: #2906(2)

   * `[mysql] [bug] [engine] [pool]' ¶. Connection
     now associates a new RootTransaction or
     TwoPhaseTransaction with its immediate
     _ConnectionFairy as a “reset handler” for the span of that
     transaction, which takes over the task of calling commit() or
     rollback() for the “reset on return” behavior of Pool
     if the transaction was not otherwise completed.  This resolves the
     issue that a picky transaction like that of MySQL two-phase will be
     properly closed out when the connection is closed without an
     explicit rollback or commit (e.g.  no longer raises “XAER_RMFAIL”
     in this case - note this only shows up in logging as the exception
     is not propagated within pool reset).  This issue would arise e.g.
     when using an orm Session with ‘twophase’ set, and then
     Session.close() is called without an explicit rollback
     or commit.  The change also has the effect that you will now see an
     explicit “ROLLBACK” in the logs when using a Session
     object in non-autocommit mode regardless of how that session was
     discarded.  Thanks to Jeff Dairiki and Laurence Rowe for isolating
     the issue here.

     References: #2907(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2917

   (2) http://www.sqlalchemy.org/trac/ticket/2906

   (3) http://www.sqlalchemy.org/trac/ticket/2907

8.3.6.75 sqlite
...............

   * `[sqlite] [bug]' ¶. Fixed bug whereby SQLite compiler
     failed to propagate compiler arguments such as “literal binds” into
     a CAST expression.

8.3.6.76 mssql
..............

   * `[mssql] [feature]' ¶. Added an option
     ‘mssql_clustered’ to the UniqueConstraint and
     PrimaryKeyConstraint constructs; on SQL Server, this adds the
     ‘CLUSTERED’ keyword to the constraint construct within DDL. Pullreq
     courtesy Derek Harland.

8.3.6.77 oracle
...............

   * `[oracle] [bug]' ¶. It’s been observed that the usage
     of a cx_Oracle “outputtypehandler” in Python 2.xx in order to
     coerce string values to Unicode is inordinately expensive; even
     though cx_Oracle is written in C, when you pass the Python
     ‘unicode’ primitive to cursor.var() and associate with an output
     handler, the library counts every conversion as a Python function
     call with all the requisite overhead being recorded; this `despite'
     the fact when running in Python 3, all strings are also
     unconditionally coerced to unicode but it does `not' incur this
     overhead, meaning that cx_Oracle is failing to use performant
     techniques in Py2K. As SQLAlchemy cannot easily select for this
     style of type handler on a per-column basis, the handler was
     assembled unconditionally thereby adding the overhead to all string
     access.

     So this logic has been replaced with SQLAlchemy’s own unicode
     conversion system, which now only takes effect in Py2K for columns
     that are requested as unicode.  When C extensions are used,
     SQLAlchemy’s system appears to be 2-3x faster than cx_Oracle’s.
     Additionally, SQLAlchemy’s unicode conversion has been enhanced
     such that when the “conditional” converter is required (now needed
     for the Oracle backend), the check for “already unicode” is now
     performed in C and no longer introduces significant overhead.

     This change has two impacts on the cx_Oracle backend.  One is that
     string values in Py2K which aren’t specifically requested with the
     Unicode type or convert_unicode=True will now come back as ‘str’,
     not ‘unicode’ - this behavior is similar to a backend such as
     MySQL. Additionally, when unicode values are requested with the
     cx_Oracle backend, if the C extensions are `not' used, there is now
     an additional overhead of an isinstance() check per column.  This
     tradeoff has been made as it can be worked around and no longer
     places a performance burden on the likely majority of Oracle result
     columns that are non-unicode strings.

     References: #2911(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2911

8.3.6.78 misc
.............

   * `[bug] [examples]' ¶. Added a tweak to the
     “history_meta” example where the check for “history” on a
     relationship-bound attribute will now no longer emit any SQL if the
     relationship is unloaded.

   * `[bug] [pool]' ¶. The argument names for the
     PoolEvents.reset() event have been renamed to
     ‘dbapi_connection’ and ‘connection_record’ in order to maintain
     consistency with all the other pool events.  It is expected that
     any existing listeners for this relatively new and seldom-used
     event are using positional style to receive arguments in any case.

   * `[bug] [cextensions] [py3k]' ¶. Fixed an issue where
     the C extensions in Py3K are using the wrong API to specify the
     top-level module function, which breaks in Python 3.4b2.  Py3.4b2
     changes PyMODINIT_FUNC to return “void” instead of ‘PyObject *’, so
     we now make sure to use “PyMODINIT_FUNC” instead of ‘PyObject *’
     directly.  Pull request courtesy cgohlke.

8.3.6.79 0.9.1
..............

Released: January 5, 2014

8.3.6.80 orm
............

   * `[orm] [feature] [extensions]' ¶. A new, `experimental'
     extension sqlalchemy.ext.automap is added.  This
     extension expands upon the functionality of Declarative as well as
     the DeferredReflection class to produce a base class
     which automatically generates mapped classes `and relationships'
     based on table metadata.

     See also
     ........

     See Automap Extension.

     See Automap.

   * `[orm] [bug] [events]' ¶. Fixed regression where using
     a ‘functools.partial()’ with the event system would cause a
     recursion overflow due to usage of inspect.getargspec() on it in
     order to detect a legacy calling signature for certain events, and
     apparently there’s no way to do this with a partial object.
     Instead we skip the legacy check and assume the modern style; the
     check itself now only occurs for the
     SessionEvents.after_bulk_update and SessionEvents.after_bulk_delete
     events.  Those two events will require the new signature style if
     assigned to a “partial” event listener.

     References: #2905(1)

   * `[orm] [bug]' ¶. Fixed bug where using new
     Session.info attribute would fail if the ‘.info’ argument
     were only passed to the sessionmaker creation call but
     not to the object itself.  Courtesy Robin Schoonover.

   * `[orm] [bug]' ¶. Fixed regression where we don’t check
     the given name against the correct string class when setting up a
     backref based on a name, therefore causing the error “too many
     values to unpack”.  This was related to the Py3k conversion.

     References: #2901(2)

   * `[orm] [bug]' ¶. Fixed regression where we apparently
     still create an implicit alias when saying query(B).join(B.cs),
     where “C” is a joined inh class; however, this implicit alias was
     created only considering the immediate left side, and not a longer
     chain of joins along different joined-inh subclasses of the same
     base.  As long as we’re still implicitly aliasing in this case, the
     behavior is dialed back a bit so that it will alias the right side
     in a wider variety of cases.

     References: #2903(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2905

   (2) http://www.sqlalchemy.org/trac/ticket/2901

   (3) http://www.sqlalchemy.org/trac/ticket/2903

8.3.6.81 orm declarative
........................

   * `[orm] [declarative] [bug]' ¶. Fixed an extremely
     unlikely memory issue where when using DeferredReflection
     to define classes pending for reflection, if some subset of
     those classes were discarded before the
     DeferredReflection.prepare() method were called to reflect
     and map the class, a strong reference to the class would remain
     held within the declarative internals.  This internal collection of
     “classes to map” now uses weak references against the classes
     themselves.

   * `[orm] [declarative] [bug]' ¶. A quasi-regression where
     apparently in 0.8 you can set a class-level attribute on
     declarative to simply refer directly to an
     InstrumentedAttribute on a superclass or on the class itself,
     and it acts more or less like a synonym; in 0.9, this fails to set
     up enough bookkeeping to keep up with the more liberalized backref
     logic from #2789(1).  Even though this use case was never directly
     considered, it is now detected by declarative at the “setattr()”
     level as well as when setting up a subclass, and the
     mirrored/renamed attribute is now set up as a synonym()
     instead.

     References: #2900(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2789

   (2) http://www.sqlalchemy.org/trac/ticket/2900

8.3.6.82 sql
............

   * `[sql] [feature]' ¶. Conjunctions like and_()
     and or_() can now accept Python generators as a
     single argument, e.g.:

          and_(x == y for x, y in tuples)

     The logic here looks for a single argument ‘*args’ where the first
     element is an instance of ‘types.GeneratorType’.

8.3.6.83 schema
...............

   * `[schema] [feature]' ¶. The
     Table.extend_existing and Table.autoload_replace
     parameters are now available on the MetaData.reflect()
     method.

8.3.6.84 0.9.0
..............

Released: December 30, 2013

8.3.6.85 orm
............

   * `[orm] [feature]' ¶. The StatementError or
     DBAPI-related subclass now can accommodate additional information
     about the “reason” for the exception; the Session now
     adds some detail to it when the exception occurs within an
     autoflush.  This approach is taken as opposed to combining
     FlushError with a Python 3 style “chained exception” approach
     so as to maintain compatibility both with Py2K code as well as code
     that already catches ‘IntegrityError’ or similar.

   * `[orm] [feature] [backrefs]' ¶. Added new argument
     ‘include_backrefs=True’ to the validates() function;
     when set to False, a validation event will not be triggered if the
     event was initiated as a backref to an attribute operation from the
     other side.

     See also
     ........

     See include_backrefs=False option for @validates.

     References: #1535(1)

   * `[orm] [feature]' ¶. A new API for specifying the ‘FOR
     UPDATE’ clause of a ‘SELECT’ is added with the new
     Query.with_for_update() method, to complement the new
     GenerativeSelect.with_for_update() method.  Pull request
     courtesy Mario Lassnig.

     See also
     ........

     See New FOR UPDATE support on select(), Query().

   * `[orm] [bug]' ¶. An adjustment to the
     subqueryload() strategy which ensures that the query runs
     after the loading process has begun; this is so that the
     subqueryload takes precedence over other loaders that may be
     hitting the same attribute due to other eager/noload situations at
     the wrong time.

     This change is also `backported' to: 0.8.5

     References: #2887(2)

   * `[orm] [bug]' ¶. Fixed bug when using joined table
     inheritance from a table to a select/alias on the base, where the
     PK columns were also not same named; the persistence system would
     fail to copy primary key values from the base table to the
     inherited table upon INSERT.

     This change is also `backported' to: 0.8.5

     References: #2885(3)

   * `[orm] [bug]' ¶. composite() will raise an
     informative error message when the columns/attribute (names) passed
     don’t resolve to a Column or mapped attribute (such as an erroneous
     tuple); previously raised an unbound local.

     This change is also `backported' to: 0.8.5

     References: #2889(4)

   * `[orm] [bug]' ¶. Fixed a regression introduced by
     #2818(5) where the EXISTS query being generated would produce a
     “columns being replaced” warning for a statement with two
     same-named columns, as the internal SELECT wouldn’t have use_labels
     set.

     This change is also `backported' to: 0.8.4

     References: #2818(6)

   * `[orm] [bug] [collections] [py3k]' ¶. Added support for
     the Python 3 method ‘list.clear()’ within the ORM collection
     instrumentation system; pull request courtesy Eduardo Schettino.

   * `[orm] [bug]' ¶. Some refinements to the
     AliasedClass construct with regards to descriptors, like
     hybrids, synonyms, composites, user-defined descriptors, etc.  The
     attribute adaptation which goes on has been made more robust, such
     that if a descriptor returns another instrumented attribute, rather
     than a compound SQL expression element, the operation will still
     proceed.  Additionally, the “adapted” operator will retain its
     class; previously, a change in class from ‘InstrumentedAttribute’
     to ‘QueryableAttribute’ (a superclass) would interact with Python’s
     operator system such that an expression like ‘aliased(MyClass.x) >
     MyClass.x’ would reverse itself to read ‘myclass.x < myclass_1.x’.
     The adapted attribute will also refer to the new
     AliasedClass as its parent which was not always the case
     before.

     References: #2872(7)

   * `[orm] [bug]' ¶. The ‘viewonly’ flag on
     relationship() will now prevent attribute history from being
     written on behalf of the target attribute.  This has the effect of
     the object not being written to the Session.dirty list if it is
     mutated.  Previously, the object would be present in Session.dirty,
     but no change would take place on behalf of the modified attribute
     during flush.  The attribute still emits events such as backref
     events and user-defined events and will still receive mutations
     from backrefs.

     See also
     ........

     See viewonly=True on relationship() prevents history from taking effect.

     References: #2833(8)

   * `[orm] [bug]' ¶. Added support for new
     Session.info attribute to scoped_session.

   * `[orm] [bug]' ¶. Fixed bug where usage of new
     Bundle object would cause the
     Query.column_descriptions attribute to fail.

   * `[orm] [bug] [sql] [sqlite]' ¶. Fixed a regression
     introduced by the join rewriting feature of #2369(9) and #2587(10)
     where a nested join with one side already an aliased select would
     fail to translate the ON clause on the outside correctly; in the
     ORM this could be seen when using a SELECT statement as a
     “secondary” table.

     References: #2858(11)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1535

   (2) http://www.sqlalchemy.org/trac/ticket/2887

   (3) http://www.sqlalchemy.org/trac/ticket/2885

   (4) http://www.sqlalchemy.org/trac/ticket/2889

   (5) http://www.sqlalchemy.org/trac/ticket/2818

   (6) http://www.sqlalchemy.org/trac/ticket/2818

   (7) http://www.sqlalchemy.org/trac/ticket/2872

   (8) http://www.sqlalchemy.org/trac/ticket/2833

   (9) http://www.sqlalchemy.org/trac/ticket/2369

   (10) http://www.sqlalchemy.org/trac/ticket/2587

   (11) http://www.sqlalchemy.org/trac/ticket/2858

8.3.6.86 orm declarative
........................

   * `[orm] [declarative] [bug]' ¶. Declarative does an
     extra check to detect if the same Column is mapped
     multiple times under different properties (which typically should
     be a synonym() instead) or if two or more Column
     objects are given the same name, raising a warning if this
     condition is detected.

     References: #2828(1)

   * `[orm] [declarative] [bug]' ¶. The
     DeferredReflection class has been enhanced to provide
     automatic reflection support for the “secondary” table referred to
     by a relationship().  “secondary”, when specified either
     as a string table name, or as a Table object with only a
     name and MetaData object will also be included in the
     reflection process when DeferredReflection.prepare() is
     called.

     References: #2865(2)

   * `[orm] [declarative] [bug]' ¶. Fixed bug where in Py2K
     a unicode literal would not be accepted as the string name of a
     class or other argument within declarative using
     relationship().

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2828

   (2) http://www.sqlalchemy.org/trac/ticket/2865

8.3.6.87 engine
...............

   * `[engine] [feature]' ¶. The engine_from_config()
     function has been improved so that we will be able to parse
     dialect-specific arguments from string configuration dictionaries.
     Dialect classes can now provide their own list of parameter types
     and string-conversion routines.  The feature is not yet used by the
     built-in dialects, however.

     References: #2875(1)

   * `[engine] [bug]' ¶. A DBAPI that raises an error on
     ‘connect()’ which is not a subclass of dbapi.Error (such as
     ‘TypeError’, ‘NotImplementedError’, etc.)  will propagate the
     exception unchanged.  Previously, the error handling specific to
     the ‘connect()’ routine would both inappropriately run the
     exception through the dialect’s Dialect.is_disconnect()
     routine as well as wrap it in a
     sqlalchemy.exc.DBAPIError.  It is now propagated unchanged in
     the same way as occurs within the execute process.

     This change is also `backported' to: 0.8.4

     References: #2881(2)

   * `[engine] [bug] [pool]' ¶. The QueuePool.
     has been enhanced to not block new connection attempts when an
     existing connection attempt is blocking.  Previously, the
     production of new connections was serialized within the block that
     monitored overflow; the overflow counter is now altered within its
     own critical section outside of the connection process itself.

     This change is also `backported' to: 0.8.4

     References: #2880(3)

   * `[engine] [bug] [pool]' ¶. Made a slight adjustment to
     the logic which waits for a pooled connection to be available, such
     that for a connection pool with no timeout specified, it will every
     half a second break out of the wait to check for the so-called
     “abort” flag, which allows the waiter to break out in case the
     whole connection pool was dumped; normally the waiter should break
     out due to a notify_all() but it’s possible this notify_all() is
     missed in very slim cases.  This is an extension of logic first
     introduced in 0.8.0, and the issue has only been observed
     occasionally in stress tests.

     This change is also `backported' to: 0.8.4

     References: #2522(4)

   * `[engine] [bug]' ¶. Fixed bug where SQL statement would
     be improperly ASCII-encoded when a pre-DBAPI StatementError
     were raised within Connection.execute(), causing
     encoding errors for non-ASCII statements.  The stringification now
     remains within Python unicode thus avoiding encoding errors.

     This change is also `backported' to: 0.8.4

     References: #2871(5)

   * `[engine] [bug]' ¶. The create_engine().
     routine and the related make_url() function no longer
     considers the ‘+’ sign to be a space within the password field.
     The parsing has been adjusted to match RFC 1738 exactly, in that
     both ‘username’ and ‘password’ expect only ‘:’, ‘@’, and ‘/’ to be
     encoded.

     See also
     ........

     See The “password” portion of a create_engine() no longer considers the + sign as an encoded space.

     References: #2873(6)

   * `[engine] [bug]' ¶. The ‘RowProxy’ object is now
     sortable in Python as a regular 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.

     See also
     ........

     See RowProxy now has tuple-sorting behavior.

     References: #2848(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2875

   (2) http://www.sqlalchemy.org/trac/ticket/2881

   (3) http://www.sqlalchemy.org/trac/ticket/2880

   (4) http://www.sqlalchemy.org/trac/ticket/2522

   (5) http://www.sqlalchemy.org/trac/ticket/2871

   (6) http://www.sqlalchemy.org/trac/ticket/2873

   (7) http://www.sqlalchemy.org/trac/ticket/2848

8.3.6.88 sql
............

   * `[sql] [feature]' ¶. New improvements to the
     text() construct, including more flexible ways to set up bound
     parameters and return types; in particular, a text() can
     now be turned into a full FROM-object, embeddable in other
     statements as an alias or CTE using the new method
     TextClause.columns().  The text() construct can
     also render “inline” bound parameters when the construct is
     compiled in a “literal bound” context.

     See also
     ........

     See New text() Capabilities.

     References: #2877(1), #2882(2)

   * `[sql] [feature]' ¶. A new API for specifying the ‘FOR
     UPDATE’ clause of a ‘SELECT’ is added with the new
     GenerativeSelect.with_for_update() method.  This method
     supports a more straightforward system of setting dialect-specific
     options compared to the ‘for_update’ keyword argument of
     select(), and also includes support for the SQL standard ‘FOR
     UPDATE OF’ clause.  The ORM also includes a new corresponding
     method Query.with_for_update().  Pull request courtesy
     Mario Lassnig.

     See also
     ........

     See New FOR UPDATE support on select(), Query().

   * `[sql] [feature]' ¶. The precision used when coercing a
     returned floating point value to Python ‘Decimal’ via string is now
     configurable.  The flag ‘decimal_return_scale’ is now supported by
     all Numeric and Float types, which will
     ensure this many digits are taken from the native floating point
     value when it is converted to string.  If not present, the type
     will make use of the value of ‘.scale’, if the type supports this
     setting and it is non-None.  Otherwise the original default length
     of 10 is used.

     See also
     ........

     See Floating Point String-Conversion Precision Configurable for Native Floating Point Types.

     References: #2867(3)

   * `[sql] [bug]' ¶. Fixed issue where a primary key column
     that has a Sequence on it, yet the column is not the “auto
     increment” column, either because it has a foreign key constraint
     or ‘autoincrement=False’ set, would attempt to fire the Sequence on
     INSERT for backends that don’t support sequences, when presented
     with an INSERT missing the primary key value.  This would take
     place on non-sequence backends like SQLite, MySQL.

     This change is also `backported' to: 0.8.5

     References: #2896(4)

   * `[sql] [bug]' ¶. Fixed bug with
     Insert.from_select() method where the order of the given names
     would not be taken into account when generating the INSERT
     statement, thus producing a mismatch versus the column names in the
     given SELECT statement.  Also noted that
     Insert.from_select() implies that Python-side insert defaults
     cannot be used, since the statement has no VALUES clause.

     This change is also `backported' to: 0.8.5

     References: #2895(5)

   * `[sql] [bug]' ¶. The cast() function, when
     given a plain literal value, will now apply the given type to the
     given literal value on the bind parameter side according to the
     type given to the cast, in the same manner as that of the
     type_coerce() function.  However unlike type_coerce(),
     this only takes effect if a non-clauseelement value is passed
     to cast(); an existing typed construct will retain its
     type.

   * `[sql] [bug]' ¶. The ForeignKey class more
     aggressively checks the given column argument.  If not a string, it
     checks that the object is at least a ColumnClause, or an
     object that resolves to one, and that the ‘.table’ attribute, if
     present, refers to a TableClause or subclass, and not
     something like an Alias.  Otherwise, a
     ArgumentError is raised.

     References: #2883(6)

   * `[sql] [bug]' ¶. The precedence rules for the
     ColumnOperators.collate() operator have been modified, such
     that the COLLATE operator is now of lower precedence than the
     comparison operators.  This has the effect that a COLLATE applied
     to a comparison will not render parenthesis around the comparison,
     which is not parsed by backends such as MSSQL. The change is
     backwards incompatible for those setups that were working around
     the issue by applying ‘Operators.collate()’ to an individual
     element of the comparison expression, rather than the comparison
     expression as a whole.

     See also
     ........

     See The precedence rules for COLLATE have been changed.

     References: #2879(7)

   * `[sql] [enhancement]' ¶. The exception raised when a
     BindParameter is present in a compiled statement
     without a value now includes the key name of the bound parameter in
     the error message.

     This change is also `backported' to: 0.8.5

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2877

   (2) http://www.sqlalchemy.org/trac/ticket/2882

   (3) http://www.sqlalchemy.org/trac/ticket/2867

   (4) http://www.sqlalchemy.org/trac/ticket/2896

   (5) http://www.sqlalchemy.org/trac/ticket/2895

   (6) http://www.sqlalchemy.org/trac/ticket/2883

   (7) http://www.sqlalchemy.org/trac/ticket/2879

8.3.6.89 schema
...............

   * `[schema] [bug]' ¶. Fixed a regression caused by
     #2812(1) where the repr() for table and column names would fail if
     the name contained non-ascii characters.

     References: #2868(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2812

   (2) http://www.sqlalchemy.org/trac/ticket/2868

8.3.6.90 postgresql
...................

   * `[postgresql] [feature]' ¶. Support for PostgreSQL JSON
     has been added, using the new JSON type.  Huge thanks
     to Nathan Rice for implementing and testing this.

     References: #2581(1)

   * `[postgresql] [feature]' ¶. Added support for
     PostgreSQL TSVECTOR via the TSVECTOR type.  Pull
     request courtesy Noufal Ibrahim.

   * `[postgresql] [bug]' ¶. Fixed bug where index
     reflection would mis-interpret indkey values when using the
     pypostgresql adapter, which returns these values as lists vs.
     psycopg2’s return type of string.

     This change is also `backported' to: 0.8.4

     References: #2855(2)

   * `[postgresql] [bug]' ¶. Now using psycopg2 UNICODEARRAY
     extension for handling unicode arrays with psycopg2 + normal
     “native unicode” mode, in the same way the UNICODE extension is
     used.

   * `[postgresql] [bug]' ¶. Fixed bug where values within
     an ENUM weren’t escaped for single quote signs.  Note that this is
     backwards-incompatible for existing workarounds that manually
     escape the single quotes.

     See also
     ........

     See PostgreSQL CREATE TYPE <x> AS ENUM now applies quoting to values.

     References: #2878(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2581

   (2) http://www.sqlalchemy.org/trac/ticket/2855

   (3) http://www.sqlalchemy.org/trac/ticket/2878

8.3.6.91 mysql
..............

   * `[mysql] [bug]' ¶. Improvements to the system by which
     SQL types generate within ‘__repr__()’, particularly with regards
     to the MySQL integer/numeric/ character types which feature a wide
     variety of keyword arguments.  The ‘__repr__()’ is important for
     use with Alembic autogenerate for when Python code is rendered in a
     migration script.

     References: #2893(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2893

8.3.6.92 mssql
..............

   * `[mssql] [bug] [firebird]' ¶. The “asdecimal” flag used
     with the Float type will now work with Firebird as
     well as the mssql+pyodbc dialects; previously the decimal
     conversion was not occurring.

     This change is also `backported' to: 0.8.5

   * `[mssql] [bug] [pymssql]' ¶. Added “Net-Lib error
     during Connection reset by peer” message to the list of messages
     checked for “disconnect” within the pymssql dialect.  Courtesy John
     Anderson.

     This change is also `backported' to: 0.8.5

   * `[mssql] [bug]' ¶. Fixed bug introduced in 0.8.0 where
     the ‘DROP INDEX’ statement for an index in MSSQL would render
     incorrectly if the index were in an alternate schema; the
     schemaname/tablename would be reversed.  The format has been also
     been revised to match current MSSQL documentation.  Courtesy Derek
     Harland.

     This change is also `backported' to: 0.8.4

8.3.6.93 oracle
...............

   * `[oracle] [bug]' ¶. Added ORA-02396 “maximum idle time”
     error code to list of “is disconnect” codes with cx_oracle.

     This change is also `backported' to: 0.8.4

     References: #2864(1)

   * `[oracle] [bug]' ¶. Fixed bug where Oracle ‘VARCHAR’
     types given with no length (e.g.  for a ‘CAST’ or similar) would
     incorrectly render ‘None CHAR’ or similar.

     This change is also `backported' to: 0.8.4

     References: #2870(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2864

   (2) http://www.sqlalchemy.org/trac/ticket/2870

8.3.6.94 firebird
.................

   * `[firebird] [bug]' ¶. The firebird dialect will quote
     identifiers which begin with an underscore.  Courtesy Treeve
     Jelbert.

     This change is also `backported' to: 0.8.5

     References: #2897(1)

   * `[firebird] [bug]' ¶. Fixed bug in Firebird index
     reflection where the columns within the index were not sorted
     correctly; they are now sorted in order of RDB$FIELD_POSITION.

     This change is also `backported' to: 0.8.5

   * `[firebird] [bug]' ¶. Changed the queries used by
     Firebird to list table and view names to query from the
     ‘rdb$relations’ view instead of the ‘rdb$relation_fields’ and
     ‘rdb$view_relations’ views.  Variants of both the old and new
     queries are mentioned on many FAQ and blogs, however the new
     queries are taken straight from the “Firebird FAQ” which appears to
     be the most official source of info.

     References: #2898(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2897

   (2) http://www.sqlalchemy.org/trac/ticket/2898

8.3.6.95 misc
.............

   * `[bug] [declarative]' ¶. Error message when a string
     arg sent to relationship() which doesn’t resolve to a
     class or mapper has been corrected to work the same way as when a
     non-string arg is received, which indicates the name of the
     relationship which had the configurational error.

     This change is also `backported' to: 0.8.5

     References: #2888(1)

   * `[bug] [ext]' ¶. Fixed bug which prevented the
     ‘serializer’ extension from working correctly with table or column
     names that contain non-ASCII characters.

     This change is also `backported' to: 0.8.4

     References: #2869(2)

   * `[bug] [examples]' ¶. Fixed bug which prevented
     history_meta recipe from working with joined inheritance schemes
     more than one level deep.

   * `[removed]' ¶. The “informix” and “informixdb” dialects
     have been removed; the code is now available as a separate
     repository on Bitbucket.  The IBM-DB project has provided
     production-level Informix support since the informixdb dialect was
     first added.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2888

   (2) http://www.sqlalchemy.org/trac/ticket/2869

8.3.6.96 0.9.0b1
................

Released: October 26, 2013

8.3.6.97 general
................

   * `[general] [feature] [py3k]' ¶. The C extensions are
     ported to Python 3 and will build under any supported CPython 2 or
     3 environment.

     References: #2161(1)

   * `[general] [feature] [py3k]' ¶. The codebase is now
     “in-place” for Python 2 and 3, the need to run 2to3 has been
     removed.  Compatibility is now against Python 2.6 on forward.

     References: #2671(2)

   * `[general]' ¶. A large refactoring of packages has
     reorganized the import structure of many Core modules as well as
     some aspects of the ORM modules.  In particular ‘sqlalchemy.sql’
     has been broken out into several more modules than before so that
     the very large size of ‘sqlalchemy.sql.expression’ is now pared
     down.  The effort has focused on a large reduction in import
     cycles.  Additionally, the system of API functions in
     ‘sqlalchemy.sql.expression’ and ‘sqlalchemy.orm’ has been
     reorganized to eliminate redundancy in documentation between the
     functions vs.  the objects they produce.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2161

   (2) http://www.sqlalchemy.org/trac/ticket/2671

8.3.6.98 orm
............

   * `[orm] [feature]' ¶. Added new option to
     relationship(). ‘distinct_target_key’.  This enables the
     subquery eager loader strategy to apply a DISTINCT to the innermost
     SELECT subquery, to assist in the case where duplicate rows are
     generated by the innermost query which corresponds to this
     relationship (there’s not yet a general solution to the issue of
     dupe rows within subquery eager loading, however, when joins
     outside of the innermost subquery produce dupes).  When the flag is
     set to ‘True’, the DISTINCT is rendered unconditionally, and when
     it is set to ‘None’, DISTINCT is rendered if the innermost
     relationship targets columns that do not comprise a full primary
     key.  The option defaults to False in 0.8 (e.g.  off by default in
     all cases), None in 0.9 (e.g.  automatic by default).  Thanks to
     Alexander Koval for help with this.

     See also
     ........

     See Subquery Eager Loading will apply DISTINCT to the innermost SELECT for some queries.

     This change is also `backported' to: 0.8.3

     References: #2836(1)

   * `[orm] [feature]' ¶. The association proxy now returns
     ‘None’ when fetching a scalar attribute off of a scalar
     relationship, where the scalar relationship itself points to
     ‘None’, instead of raising an ‘AttributeError’.

     See also
     ........

     See Association Proxy Missing Scalar returns None.

     References: #2810(2)

   * `[orm] [feature]' ¶. Added new method
     AttributeState.load_history(), works like
     AttributeState.history but also fires loader callables.

     See also
     ........

     See attributes.get_history() will query from the DB by default if value not present.

     References: #2787(3)

   * `[orm] [feature]' ¶. Added a new load option
     load_only().  This allows a series of column names to be
     specified as loading “only” those attributes, deferring the rest.

     References: #1418(4)

   * `[orm] [feature]' ¶. The system of loader options has
     been entirely rearchitected to build upon a much more comprehensive
     base, the Load object.  This base allows any common
     loader option like joinedload(), defer(),
     etc.  to be used in a “chained” style for the purpose of specifying
     options down a path, such as
     ‘joinedload("foo").subqueryload("bar")’.  The new system supersedes
     the usage of dot-separated path names, multiple attributes within
     options, and the usage of ‘_all()’ options.

     See also
     ........

     See New Query Options API; load_only() option.

     References: #1418(5)

   * `[orm] [feature]' ¶. The composite().
     construct now maintains the return object when used in a
     column-oriented Query, rather than expanding out into
     individual columns.  This makes use of the new Bundle
     feature internally.  This behavior is backwards incompatible; to
     select from a composite column which will expand out, use
     ‘MyClass.some_composite.clauses’.

     See also
     ........

     See Composite attributes are now returned as their object form when queried on a per-attribute basis.

     References: #2824(6)

   * `[orm] [feature]' ¶. A new construct Bundle.
     is added, which allows for specification of groups of column
     expressions to a Query construct.  The group of columns
     are returned as a single tuple by default.  The behavior of
     Bundle can be overridden however to provide any sort of
     result processing to the returned row.  The behavior of
     Bundle is also embedded into composite attributes now when
     they are used in a column-oriented Query.

     See also
     ........

     See Column Bundles for ORM queries.

     See Composite attributes are now returned as their object form when queried on a per-attribute basis.

     References: #2824(7)

   * `[orm] [feature]' ¶. The ‘version_id_generator’
     parameter of ‘Mapper’ can now be specified to rely upon server
     generated version identifiers, using triggers or other
     database-provided versioning features, or via an optional
     programmatic value, by setting ‘version_id_generator=False’.  When
     using a server-generated version identifier, the ORM will use
     RETURNING when available to immediately load the new version value,
     else it will emit a second SELECT.

     References: #2793(8)

   * `[orm] [feature]' ¶. The ‘eager_defaults’ flag of
     Mapper will now allow the newly generated default values to
     be fetched using an inline RETURNING clause, rather than a second
     SELECT statement, for backends that support RETURNING.

     References: #2793(9)

   * `[orm] [feature]' ¶. Added a new attribute
     Session.info to Session; this is a dictionary
     where applications can store arbitrary data local to a
     Session.  The contents of Session.info can be also
     be initialized using the ‘info’ argument of Session or
     sessionmaker.

   * `[orm] [feature]' ¶. Removal of event listeners is now
     implemented.  The feature is provided via the remove()
     function.

     See also
     ........

     See Event Removal API.

     References: #2268(10)

   * `[orm] [feature]' ¶. The mechanism by which attribute
     events pass along an ‘AttributeImpl’ as an “initiator” token has
     been changed; the object is now an event-specific object called
     ‘Event’.  Additionally, the attribute system no longer halts events
     based on a matching “initiator” token; this logic has been moved to
     be specific to ORM backref event handlers, which are the typical
     source of the re-propagation of an attribute event onto subsequent
     append/set/remove operations.  End user code which emulates the
     behavior of backrefs must now ensure that recursive event
     propagation schemes are halted, if the scheme does not use the
     backref handlers.  Using this new system, backref handlers can now
     perform a “two-hop” operation when an object is appended to a
     collection, associated with a new many-to-one, de-associated with
     the previous many-to-one, and then removed from a previous
     collection.  Before this change, the last step of removal from the
     previous collection would not occur.

     See also
     ........

     See Backref handlers can now propagate more than one level deep.

     References: #2789(11)

   * `[orm] [feature]' ¶. A major change regarding how the
     ORM constructs joins where the right side is itself a join or left
     outer join.  The ORM is now configured to allow simple nesting of
     joins of the form ‘a JOIN (b JOIN c ON b.id=c.id) ON a.id=b.id’,
     rather than forcing the right side into a ‘SELECT’ subquery.  This
     should allow significant performance improvements on most backends,
     most particularly MySQL. The one database backend that has for many
     years held back this change, SQLite, is now addressed by moving the
     production of the ‘SELECT’ subquery from the ORM to the SQL
     compiler; so that a right-nested join on SQLite will still
     ultimately render with a ‘SELECT’, while all other backends are no
     longer impacted by this workaround.

     As part of this change, a new argument ‘flat=True’ has been added
     to the aliased(), Join.alias(), and
     with_polymorphic() functions, which allows an “alias” of a
     JOIN to be produced which applies an anonymous alias to each
     component table within the join, rather than producing a subquery.

     See also
     ........

     See Many JOIN and LEFT OUTER JOIN expressions will no longer be wrapped in (SELECT * FROM ..) AS ANON_1.

     References: #2587(12)

   * `[orm] [bug]' ¶. Fixed bug where using an annotation
     such as remote() or foreign() on a
     Column before association with a parent Table could
     produce issues related to the parent table not rendering within
     joins, due to the inherent copy operation performed by an
     annotation.

     This change is also `backported' to: 0.8.3

     References: #2813(13)

   * `[orm] [bug]' ¶. Fixed bug where Query.exists()
     failed to work correctly without any WHERE criterion.
     Courtesy Vladimir Magamedov.

     This change is also `backported' to: 0.8.3

     References: #2818(14)

   * `[orm] [bug]' ¶. Fixed a potential issue in an ordered
     sequence implementation used by the ORM to iterate mapper
     hierarchies; under the Jython interpreter this implementation
     wasn’t ordered, even though cPython and PyPy maintained ordering.

     This change is also `backported' to: 0.8.3

     References: #2794(15)

   * `[orm] [bug]' ¶. Fixed bug in ORM-level event
     registration where the “raw” or “propagate” flags could potentially
     be mis-configured in some “unmapped base class” configurations.

     This change is also `backported' to: 0.8.3

     References: #2786(16)

   * `[orm] [bug]' ¶. A performance fix related to the usage
     of the defer() option when loading mapped entities.
     The function overhead of applying a per-object deferred callable to
     an instance at load time was significantly higher than that of just
     loading the data from the row (note that ‘defer()’ is meant to
     reduce DB/network overhead, not necessarily function call count);
     the function call overhead is now less than that of loading data
     from the column in all cases.  There is also a reduction in the
     number of “lazy callable” objects created per load from N (total
     deferred values in the result) to 1 (total number of deferred
     cols).

     This change is also `backported' to: 0.8.3

     References: #2778(17)

   * `[orm] [bug]' ¶. Fixed bug whereby attribute history
     functions would fail when an object we moved from “persistent” to
     “pending” using the make_transient() function, for
     operations involving collection-based backrefs.

     This change is also `backported' to: 0.8.3

     References: #2773(18)

   * `[orm] [bug]' ¶. A warning is emitted when trying to
     flush an object of an inherited class where the polymorphic
     discriminator has been assigned to a value that is invalid for the
     class.

     This change is also `backported' to: 0.8.2

     References: #2750(19)

   * `[orm] [bug]' ¶. Fixed bug in polymorphic SQL
     generation where multiple joined-inheritance entities against the
     same base class joined to each other as well would not track
     columns on the base table independently of each other if the string
     of joins were more than two entities long.

     This change is also `backported' to: 0.8.2

     References: #2759(20)

   * `[orm] [bug]' ¶. Fixed bug where sending a composite
     attribute into Query.order_by() would produce a
     parenthesized expression not accepted by some databases.

     This change is also `backported' to: 0.8.2

     References: #2754(21)

   * `[orm] [bug]' ¶. Fixed the interaction between
     composite attributes and the aliased() function.
     Previously, composite attributes wouldn’t work correctly in
     comparison operations when aliasing was applied.

     This change is also `backported' to: 0.8.2

     References: #2755(22)

   * `[orm] [bug] [ext]' ¶. Fixed bug where
     MutableDict didn’t report a change event when ‘clear()’ was
     called.

     This change is also `backported' to: 0.8.2

     References: #2730(23)

   * `[orm] [bug]' ¶. Fixed bug where list instrumentation
     would fail to represent a setslice of ‘[0:0]’ correctly, which in
     particular could occur when using ‘insert(0, item)’ with the
     association proxy.  Due to some quirk in Python collections, the
     issue was much more likely with Python 3 rather than 2.

     This change is also `backported' to: 0.8.3, 0.8.0b1

     References: #2807(24)

   * `[orm] [bug]' ¶. get_history() when used
     with a scalar column-mapped attribute will now honor the “passive”
     flag passed to it; as this defaults to ‘PASSIVE_OFF’, the function
     will by default query the database if the value is not present.
     This is a behavioral change vs.  0.8.

     See also
     ........

     See attributes.get_history() will query from the DB by default if value not present.

     References: #2787(25)

   * `[orm] [bug] [associationproxy]' ¶. Added additional
     criterion to the ==, != comparators, used with scalar values, for
     comparisons to None to also take into account the association
     record itself being non-present, in addition to the existing test
     for the scalar endpoint on the association record being NULL.
     Previously, comparing ‘Cls.scalar == None’ would return records for
     which ‘Cls.associated’ were present and ‘Cls.associated.scalar’ is
     None, but not rows for which ‘Cls.associated’ is non-present.  More
     significantly, the inverse operation ‘Cls.scalar != None’ `would'
     return ‘Cls’ rows for which ‘Cls.associated’ was non-present.

     The case for ‘Cls.scalar != 'somevalue'’ is also modified to act
     more like a direct SQL comparison; only rows for which
     ‘Cls.associated’ is present and ‘Associated.scalar’ is non-NULL and
     not equal to ‘'somevalue'’ are returned.  Previously, this would be
     a simple ‘NOT EXISTS’.

     Also added a special use case where you can call ‘Cls.scalar.has()’
     with no arguments, when ‘Cls.scalar’ is a column-based value - this
     returns whether or not ‘Cls.associated’ has any rows present,
     regardless of whether or not ‘Cls.associated.scalar’ is NULL or
     not.

     See also
     ........

     See Association Proxy SQL Expression Improvements and Fixes.

     References: #2751(26)

   * `[orm] [bug]' ¶. Fixed an obscure bug where the wrong
     results would be fetched when joining/joinedloading across a
     many-to-many relationship to a single-table-inheriting subclass
     with a specific discriminator value, due to “secondary” rows that
     would come back.  The “secondary” and right-side tables are now
     inner joined inside of parenthesis for all ORM joins on
     many-to-many relationships so that the left->right join can
     accurately filtered.  This change was made possible by finally
     addressing the issue with right-nested joins outlined in #2587(27).

     See also
     ........

     See Many JOIN and LEFT OUTER JOIN expressions will no longer be wrapped in (SELECT * FROM ..) AS ANON_1.

     References: #2369(28)

   * `[orm] [bug]' ¶. The “auto-aliasing” behavior of the
     Query.select_from() method has been turned off.  The
     specific behavior is now available via a new method
     Query.select_entity_from().  The auto-aliasing behavior here
     was never well documented and is generally not what’s desired, as
     Query.select_from() has become more oriented towards
     controlling how a JOIN is rendered.
     Query.select_entity_from() will also be made available in 0.8
     so that applications which rely on the auto-aliasing can shift
     their applications to use this method.

     See also
     ........

     See _query.Query.select_from() no longer applies the clause to corresponding entities.

     References: #2736(29)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2836

   (2) http://www.sqlalchemy.org/trac/ticket/2810

   (3) http://www.sqlalchemy.org/trac/ticket/2787

   (4) http://www.sqlalchemy.org/trac/ticket/1418

   (5) http://www.sqlalchemy.org/trac/ticket/1418

   (6) http://www.sqlalchemy.org/trac/ticket/2824

   (7) http://www.sqlalchemy.org/trac/ticket/2824

   (8) http://www.sqlalchemy.org/trac/ticket/2793

   (9) http://www.sqlalchemy.org/trac/ticket/2793

   (10) http://www.sqlalchemy.org/trac/ticket/2268

   (11) http://www.sqlalchemy.org/trac/ticket/2789

   (12) http://www.sqlalchemy.org/trac/ticket/2587

   (13) http://www.sqlalchemy.org/trac/ticket/2813

   (14) http://www.sqlalchemy.org/trac/ticket/2818

   (15) http://www.sqlalchemy.org/trac/ticket/2794

   (16) http://www.sqlalchemy.org/trac/ticket/2786

   (17) http://www.sqlalchemy.org/trac/ticket/2778

   (18) http://www.sqlalchemy.org/trac/ticket/2773

   (19) http://www.sqlalchemy.org/trac/ticket/2750

   (20) http://www.sqlalchemy.org/trac/ticket/2759

   (21) http://www.sqlalchemy.org/trac/ticket/2754

   (22) http://www.sqlalchemy.org/trac/ticket/2755

   (23) http://www.sqlalchemy.org/trac/ticket/2730

   (24) http://www.sqlalchemy.org/trac/ticket/2807

   (25) http://www.sqlalchemy.org/trac/ticket/2787

   (26) http://www.sqlalchemy.org/trac/ticket/2751

   (27) http://www.sqlalchemy.org/trac/ticket/2587

   (28) http://www.sqlalchemy.org/trac/ticket/2369

   (29) http://www.sqlalchemy.org/trac/ticket/2736

8.3.6.99 orm declarative
........................

   * `[orm] [declarative] [feature]' ¶. Added a convenience
     class decorator as_declarative(), is a wrapper for
     declarative_base() which allows an existing base class to be
     applied using a nifty class-decorated approach.

     This change is also `backported' to: 0.8.3

   * `[orm] [declarative] [feature]' ¶. ORM descriptors such
     as hybrid properties can now be referenced by name in a string
     argument used with ‘order_by’, ‘primaryjoin’, or similar in
     relationship(), in addition to column-bound attributes.

     This change is also `backported' to: 0.8.2

     References: #2761(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2761

8.3.6.100 engine
................

   * `[engine] [feature]' ¶. ‘repr()’ for the URL
     of an Engine will now conceal the password using
     asterisks.  Courtesy Gunnlaugur Þór Briem.

     This change is also `backported' to: 0.8.3

     References: #2821(1)

   * `[engine] [feature]' ¶. New events added to
     ConnectionEvents:

        * ConnectionEvents.engine_connect().

        * ConnectionEvents.set_connection_execution_options().

        * ConnectionEvents.set_engine_execution_options().

     References: #2770(2)

   * `[engine] [bug] [oracle]' ¶. Dialect.initialize() is
     not called a second time if an Engine is recreated, due
     to a disconnect error.  This fixes a particular issue in the Oracle
     8 dialect, but in general the dialect.initialize() phase should
     only be once per dialect.

     This change is also `backported' to: 0.8.3

     References: #2776(3)

   * `[engine] [bug] [pool]' ¶. Fixed bug where
     QueuePool would lose the correct checked out count if an
     existing pooled connection failed to reconnect after an invalidate
     or recycle event.

     This change is also `backported' to: 0.8.3

     References: #2772(4)

   * `[engine] [bug]' ¶. Fixed bug where the
     ‘reset_on_return’ argument to various Pool
     implementations would not be propagated when the pool was
     regenerated.  Courtesy Eevee.

     This change is also `backported' to: 0.8.2

   * `[engine] [bug]' ¶. The regexp used by the ‘make_url()’
     function now parses ipv6 addresses, e.g.  surrounded by brackets.

     This change is also `backported' to: 0.8.3, 0.8.0b1

     References: #2851(5)

   * `[engine] [bug]' ¶. The method signature of
     ‘Dialect.reflecttable()’, which in all known cases is provided by
     DefaultDialect, has been tightened to expect
     ‘include_columns’ and ‘exclude_columns’ arguments without any kw
     option, reducing ambiguity - previously ‘exclude_columns’ was
     missing.

     References: #2748(6)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2821

   (2) http://www.sqlalchemy.org/trac/ticket/2770

   (3) http://www.sqlalchemy.org/trac/ticket/2776

   (4) http://www.sqlalchemy.org/trac/ticket/2772

   (5) http://www.sqlalchemy.org/trac/ticket/2851

   (6) http://www.sqlalchemy.org/trac/ticket/2748

8.3.6.101 sql
.............

   * `[sql] [feature]' ¶. Added support for “unique
     constraint” reflection, via the
     Inspector.get_unique_constraints() method.  Thanks for Roman
     Podolyaka for the patch.

     This change is also `backported' to: 0.8.4

     References: #1443(1)

   * `[sql] [feature]' ¶. The update(),
     insert(), and delete() constructs will now
     interpret ORM entities as target tables to be operated upon, e.g.:

          from sqlalchemy import insert, update, delete

          ins = insert(SomeMappedClass).values(x=5)

          del_ = delete(SomeMappedClass).where(SomeMappedClass.id == 5)

          upd = update(SomeMappedClass).where(SomeMappedClass.id == 5).values(name='ed')

     This change is also `backported' to: 0.8.3

   * `[sql] [feature] [mysql] [postgresql]' ¶. The
     PostgreSQL and MySQL dialects now support reflection/inspection of
     foreign key options, including ON UPDATE, ON DELETE. PostgreSQL
     also reflects MATCH, DEFERRABLE, and INITIALLY. Courtesy ijl.

     References: #2183(2)

   * `[sql] [feature]' ¶. A bindparam() construct
     with a “null” type (e.g.  no type specified) is now copied when
     used in a typed expression, and the new copy is assigned the actual
     type of the compared column.  Previously, this logic would occur on
     the given bindparam() in place.  Additionally, a similar
     process now occurs for bindparam() constructs passed to
     ValuesBase.values() for an Insert or
     Update construct, within the compilation phase of the
     construct.

     These are both subtle behavioral changes which may impact some
     usages.

     See also
     ........

     See A bindparam() construct with no type gets upgraded via copy when a type is available.

     References: #2850(3)

   * `[sql] [feature]' ¶. An overhaul of expression handling
     for special symbols particularly with conjunctions, e.g.  ‘None’
     null(). See true(). See false(), including
     consistency in rendering NULL in conjunctions, “short-circuiting”
     of and_() and or_() expressions which contain
     boolean constants, and rendering of boolean constants and
     expressions as compared to “1” or “0” for backends that don’t
     feature ‘true’/‘false’ constants.

     See also
     ........

     See Improved rendering of Boolean constants, NULL constants, conjunctions.

     References: #2734(4), #2804(5), #2823(6)

   * `[sql] [feature]' ¶. The typing system now handles the
     task of rendering “literal bind” values, e.g.  values that are
     normally bound parameters but due to context must be rendered as
     strings, typically within DDL constructs such as CHECK constraints
     and indexes (note that “literal bind” values become used by DDL as
     of #2742(7)).  A new method TypeEngine.literal_processor()
     serves as the base, and
     TypeDecorator.process_literal_param() is added to allow
     wrapping of a native literal rendering method.

     See also
     ........

     See The typing system now handles the task of rendering “literal bind” values.

     References: #2838(8)

   * `[sql] [feature]' ¶. The Table.tometadata()
     method now produces copies of all SchemaItem.info
     dictionaries from all SchemaItem objects within the
     structure including columns, constraints, foreign keys, etc.  As
     these dictionaries are copies, they are independent of the original
     dictionary.  Previously, only the ‘.info’ dictionary of
     Column was transferred within this operation, and it was only
     linked in place, not copied.

     References: #2716(9)

   * `[sql] [feature]' ¶. The ‘default’ argument of
     Column now accepts a class or object method as an argument, in
     addition to a standalone function; will properly detect if the
     “context” argument is accepted or not.

   * `[sql] [feature]' ¶. Added new method to the
     insert() construct Insert.from_select().  Given a
     list of columns and a selectable, renders ‘INSERT INTO (table)
     (columns) SELECT ..’.  While this feature is highlighted as part of
     0.9 it is also backported to 0.8.3.

     See also
     ........

     See INSERT from SELECT.

     References: #722(10)

   * `[sql] [feature]' ¶. Provided a new attribute for
     TypeDecorator called TypeDecorator.coerce_to_is_types,
     to make it easier to control how comparisons using ‘==’ or
     ‘!=’ to ‘None’ and boolean types goes about producing an ‘IS’
     expression, or a plain equality expression with a bound parameter.

     References: #2734(11), #2744(12)

   * `[sql] [feature]' ¶. A label() construct
     will now render as its name alone in an ‘ORDER BY’ clause, if that
     label is also referred to in the columns clause of the select,
     instead of rewriting the full expression.  This gives the database
     a better chance to optimize the evaluation of the same expression
     in two different contexts.

     See also
     ........

     See Label constructs can now render as their name alone in an ORDER BY.

     References: #1068(13)

   * `[sql] [bug]' ¶. Fixed bug where type_coerce()
     would not interpret ORM elements with a ‘__clause_element__()’
     method properly.

     This change is also `backported' to: 0.8.3

     References: #2849(14)

   * `[sql] [bug]' ¶. The Enum and
     Boolean types now bypass any custom (e.g.  TypeDecorator)
     type in use when producing the CHECK constraint for the “non
     native” type.  This so that the custom type isn’t involved in the
     expression within the CHECK, since this expression is against the
     “impl” value and not the “decorated” value.

     This change is also `backported' to: 0.8.3

     References: #2842(15)

   * `[sql] [bug]' ¶. The ‘.unique’ flag on Index
     could be produced as ‘None’ if it was generated from a
     Column that didn’t specify ‘unique’ (where it defaults to
     ‘None’).  The flag will now always be ‘True’ or ‘False’.

     This change is also `backported' to: 0.8.3

     References: #2825(16)

   * `[sql] [bug]' ¶. Fixed bug in default compiler plus
     those of postgresql, mysql, and mssql to ensure that any literal
     SQL expression values are rendered directly as literals, instead of
     as bound parameters, within a CREATE INDEX statement.  This also
     changes the rendering scheme for other DDL such as constraints.

     This change is also `backported' to: 0.8.3

     References: #2742(17)

   * `[sql] [bug]' ¶. A select() that is made to
     refer to itself in its FROM clause, typically via in-place
     mutation, will raise an informative error message rather than
     causing a recursion overflow.

     This change is also `backported' to: 0.8.3

     References: #2815(18)

   * `[sql] [bug]' ¶. Fixed bug where using the
     ‘column_reflect’ event to change the ‘.key’ of the incoming
     Column would prevent primary key constraints, indexes, and
     foreign key constraints from being correctly reflected.

     This change is also `backported' to: 0.8.3

     References: #2811(19)

   * `[sql] [bug]' ¶. The ColumnOperators.notin_()
     operator added in 0.8 now properly produces the negation of
     the expression “IN” returns when used against an empty collection.

     This change is also `backported' to: 0.8.3

   * `[sql] [bug] [postgresql]' ¶. Fixed bug where the
     expression system relied upon the ‘str()’ form of a some
     expressions when referring to the ‘.c’ collection on a ‘select()’
     construct, but the ‘str()’ form isn’t available since the element
     relies on dialect-specific compilation constructs, notably the
     ‘__getitem__()’ operator as used with a PostgreSQL ‘ARRAY’ element.
     The fix also adds a new exception class
     UnsupportedCompilationError which is raised in those cases
     where a compiler is asked to compile something it doesn’t know how
     to.

     This change is also `backported' to: 0.8.3

     References: #2780(20)

   * `[sql] [bug]' ¶. Multiple fixes to the correlation
     behavior of Select constructs, first introduced in
     0.8.0:

        * To satisfy the use case where FROM entries should be
          correlated outwards to a SELECT that encloses another, which
          then encloses this one, correlation now works across multiple
          levels when explicit correlation is established via
          Select.correlate(), provided that the target select is
          somewhere along the chain contained by a WHERE/ORDER
          BY/columns clause, not just nested FROM clauses.  This makes
          Select.correlate() act more compatibly to that of
          0.7 again while still maintaining the new “smart” correlation.

        * When explicit correlation is not used, the usual “implicit”
          correlation limits its behavior to just the immediate
          enclosing SELECT, to maximize compatibility with 0.7
          applications, and also prevents correlation across nested
          FROMs in this case, maintaining compatibility with
          0.8.0/0.8.1.

        * The Select.correlate_except() method was not
          preventing the given FROM clauses from correlation in all
          cases, and also would cause FROM clauses to be incorrectly
          omitted entirely (more like what 0.7 would do), this has been
          fixed.

        * Calling ‘select.correlate_except(None)’ will enter all FROM
          clauses into correlation as would be expected.

     This change is also `backported' to: 0.8.2

     References: #2668(21), #2746(22)

   * `[sql] [bug]' ¶. Fixed bug whereby joining a select()
     of a table “A” with multiple foreign key paths to a table “B”, to
     that table “B”, would fail to produce the “ambiguous join
     condition” error that would be reported if you join table “A”
     directly to “B”; it would instead produce a join condition with
     multiple criteria.

     This change is also `backported' to: 0.8.2

     References: #2738(23)

   * `[sql] [bug] [reflection]' ¶. Fixed bug whereby using
     MetaData.reflect() across a remote schema as well as a
     local schema could produce wrong results in the case where both
     schemas had a table of the same name.

     This change is also `backported' to: 0.8.2

     References: #2728(24)

   * `[sql] [bug]' ¶. Removed the “not implemented”
     ‘__iter__()’ call from the base ColumnOperators class,
     while this was introduced in 0.8.0 to prevent an endless,
     memory-growing loop when one also implements a ‘__getitem__()’
     method on a custom operator and then calls erroneously ‘list()’ on
     that object, it had the effect of causing column elements to report
     that they were in fact iterable types which then throw an error
     when you try to iterate.  There’s no real way to have both sides
     here so we stick with Python best practices.  Careful with
     implementing ‘__getitem__()’ on your custom operators!

     This change is also `backported' to: 0.8.2

     References: #2726(25)

   * `[sql] [bug]' ¶. Fixed regression dating back to 0.7.9
     whereby the name of a CTE might not be properly quoted if it was
     referred to in multiple FROM clauses.

     This change is also `backported' to: 0.8.3, 0.8.0b1

     References: #2801(26)

   * `[sql] [bug] [cte]' ¶. Fixed bug in common table
     expression system where if the CTE were used only as an ‘alias()’
     construct, it would not render using the WITH keyword.

     This change is also `backported' to: 0.8.3, 0.8.0b1

     References: #2783(27)

   * `[sql] [bug]' ¶. Fixed bug in CheckConstraint.
     DDL where the “quote” flag from a Column object
     would not be propagated.

     This change is also `backported' to: 0.8.3, 0.8.0b1

     References: #2784(28)

   * `[sql] [bug]' ¶. The “name” attribute is set on
     Index before the “attach” events are called, so that
     attachment events can be used to dynamically generate a name for
     the index based on the parent table and/or columns.

     References: #2835(29)

   * `[sql] [bug]' ¶. The erroneous kw arg “schema” has been
     removed from the ForeignKey object.  this was an
     accidental commit that did nothing; a warning is raised in 0.8.3
     when this kw arg is used.

     References: #2831(30)

   * `[sql] [bug]' ¶. A rework to the way that “quoted”
     identifiers are handled, in that instead of relying upon various
     ‘quote=True’ flags being passed around, these flags are converted
     into rich string objects with quoting information included at the
     point at which they are passed to common schema constructs like
     Table, Column, etc.  This solves the issue of
     various methods that don’t correctly honor the “quote” flag such as
     Engine.has_table() and related methods.  The
     quoted_name object is a string subclass that can also be used
     explicitly if needed; the object will hold onto the quoting
     preferences passed and will also bypass the “name normalization”
     performed by dialects that standardize on uppercase symbols, such
     as Oracle, Firebird and DB2.  The upshot is that the “uppercase”
     backends can now work with force-quoted names, such as
     lowercase-quoted names and new reserved words.

     See also
     ........

     See Schema identifiers now carry along their own quoting information.

     References: #2812(31)

   * `[sql] [bug]' ¶. The resolution of ForeignKey
     objects to their target Column has been reworked to
     be as immediate as possible, based on the moment that the target
     Column is associated with the same MetaData
     as this ForeignKey, rather than waiting for the first
     time a join is constructed, or similar.  This along with other
     improvements allows earlier detection of some foreign key
     configuration issues.  Also included here is a rework of the
     type-propagation system, so that it should be reliable now to set
     the type as ‘None’ on any Column that refers to another
     via ForeignKey. - the type will be copied from the target
     column as soon as that other column is associated, and now works
     for composite foreign keys as well.

     See also
     ........

     See Columns can reliably get their type from a column referred to via ForeignKey.

     References: #1765(32)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1443

   (2) http://www.sqlalchemy.org/trac/ticket/2183

   (3) http://www.sqlalchemy.org/trac/ticket/2850

   (4) http://www.sqlalchemy.org/trac/ticket/2734

   (5) http://www.sqlalchemy.org/trac/ticket/2804

   (6) http://www.sqlalchemy.org/trac/ticket/2823

   (7) http://www.sqlalchemy.org/trac/ticket/2742

   (8) http://www.sqlalchemy.org/trac/ticket/2838

   (9) http://www.sqlalchemy.org/trac/ticket/2716

   (10) http://www.sqlalchemy.org/trac/ticket/722

   (11) http://www.sqlalchemy.org/trac/ticket/2734

   (12) http://www.sqlalchemy.org/trac/ticket/2744

   (13) http://www.sqlalchemy.org/trac/ticket/1068

   (14) http://www.sqlalchemy.org/trac/ticket/2849

   (15) http://www.sqlalchemy.org/trac/ticket/2842

   (16) http://www.sqlalchemy.org/trac/ticket/2825

   (17) http://www.sqlalchemy.org/trac/ticket/2742

   (18) http://www.sqlalchemy.org/trac/ticket/2815

   (19) http://www.sqlalchemy.org/trac/ticket/2811

   (20) http://www.sqlalchemy.org/trac/ticket/2780

   (21) http://www.sqlalchemy.org/trac/ticket/2668

   (22) http://www.sqlalchemy.org/trac/ticket/2746

   (23) http://www.sqlalchemy.org/trac/ticket/2738

   (24) http://www.sqlalchemy.org/trac/ticket/2728

   (25) http://www.sqlalchemy.org/trac/ticket/2726

   (26) http://www.sqlalchemy.org/trac/ticket/2801

   (27) http://www.sqlalchemy.org/trac/ticket/2783

   (28) http://www.sqlalchemy.org/trac/ticket/2784

   (29) http://www.sqlalchemy.org/trac/ticket/2835

   (30) http://www.sqlalchemy.org/trac/ticket/2831

   (31) http://www.sqlalchemy.org/trac/ticket/2812

   (32) http://www.sqlalchemy.org/trac/ticket/1765

8.3.6.102 postgresql
....................

   * `[postgresql] [feature]' ¶. Support for PostgreSQL 9.2
     range types has been added.  Currently, no type translation is
     provided, so works directly with strings or psycopg2 2.5 range
     extension types at the moment.  Patch courtesy Chris Withers.

     This change is also `backported' to: 0.8.2

   * `[postgresql] [feature]' ¶. Added support for
     “AUTOCOMMIT” isolation when using the psycopg2 DBAPI. The keyword
     is available via the ‘isolation_level’ execution option.  Patch
     courtesy Roman Podolyaka.

     This change is also `backported' to: 0.8.2

     References: #2072(1)

   * `[postgresql] [feature]' ¶. Added support for rendering
     ‘SMALLSERIAL’ when a SmallInteger type is used on a
     primary key autoincrement column, based on server version detection
     of PostgreSQL version 9.2 or greater.

     References: #2840(2)

   * `[postgresql] [bug]' ¶. Removed a 128-character
     truncation from the reflection of the server default for a column;
     this code was original from PG system views which truncated the
     string for readability.

     This change is also `backported' to: 0.8.3

     References: #2844(3)

   * `[postgresql] [bug]' ¶. Parenthesis will be applied to
     a compound SQL expression as rendered in the column list of a
     CREATE INDEX statement.

     This change is also `backported' to: 0.8.3

     References: #2742(4)

   * `[postgresql] [bug]' ¶. Fixed bug where PostgreSQL
     version strings that had a prefix preceding the words “PostgreSQL”
     or “EnterpriseDB” would not parse.  Courtesy Scott Schaefer.

     This change is also `backported' to: 0.8.3

     References: #2819(5)

   * `[postgresql] [bug]' ¶. The behavior of
     extract() has been simplified on the PostgreSQL dialect to no
     longer inject a hardcoded ‘::timestamp’ or similar cast into the
     given expression, as this interfered with types such as
     timezone-aware datetimes, but also does not appear to be at all
     necessary with modern versions of psycopg2.

     This change is also `backported' to: 0.8.2

     References: #2740(6)

   * `[postgresql] [bug]' ¶. Fixed bug in HSTORE type where
     keys/values that contained backslashed quotes would not be escaped
     correctly when using the “non native” (i.e.  non-psycopg2) means of
     translating HSTORE data.  Patch courtesy Ryan Kelly.

     This change is also `backported' to: 0.8.2

     References: #2766(7)

   * `[postgresql] [bug]' ¶. Fixed bug where the order of
     columns in a multi-column PostgreSQL index would be reflected in
     the wrong order.  Courtesy Roman Podolyaka.

     This change is also `backported' to: 0.8.2

     References: #2767(8)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2072

   (2) http://www.sqlalchemy.org/trac/ticket/2840

   (3) http://www.sqlalchemy.org/trac/ticket/2844

   (4) http://www.sqlalchemy.org/trac/ticket/2742

   (5) http://www.sqlalchemy.org/trac/ticket/2819

   (6) http://www.sqlalchemy.org/trac/ticket/2740

   (7) http://www.sqlalchemy.org/trac/ticket/2766

   (8) http://www.sqlalchemy.org/trac/ticket/2767

8.3.6.103 mysql
...............

   * `[mysql] [feature]' ¶. The ‘mysql_length’ parameter
     used with Index can now be passed as a dictionary of
     column names/lengths, for use with composite indexes.  Big thanks
     to Roman Podolyaka for the patch.

     This change is also `backported' to: 0.8.2

     References: #2704(1)

   * `[mysql] [feature]' ¶. The MySQL SET type
     now features the same auto-quoting behavior as that of ENUM.
     Quotes are not required when setting up the value, but
     quotes that are present will be auto-detected along with a warning.
     This also helps with Alembic where the SET type doesn’t render with
     quotes.

     References: #2817(2)

   * `[mysql] [bug]' ¶. The change in #2721(3), which is
     that the ‘deferrable’ keyword of ForeignKeyConstraint is
     silently ignored on the MySQL backend, will be reverted as of 0.9;
     this keyword will now render again, raising errors on MySQL as it
     is not understood - the same behavior will also apply to the
     ‘initially’ keyword.  In 0.8, the keywords will remain ignored but
     a warning is emitted.  Additionally, the ‘match’ keyword now raises
     a CompileError on 0.9 and emits a warning on 0.8; this
     keyword is not only silently ignored by MySQL but also breaks the
     ON UPDATE/ON DELETE options.

     To use a ForeignKeyConstraint that does not render or
     renders differently on MySQL, use a custom compilation option.  An
     example of this usage has been added to the documentation, see
     MySQL / MariaDB Foreign Keys.

     This change is also `backported' to: 0.8.3

     References: #2721(4), #2839(5)

   * `[mysql] [bug]' ¶. MySQL-connector dialect now allows
     options in the create_engine query string to override those
     defaults set up in the connect, including “buffered” and
     “raise_on_warnings”.

     This change is also `backported' to: 0.8.3

     References: #2515(6)

   * `[mysql] [bug]' ¶. Fixed bug when using multi-table
     UPDATE where a supplemental table is a SELECT with its own bound
     parameters, where the positioning of the bound parameters would be
     reversed versus the statement itself when using MySQL’s special
     syntax.

     This change is also `backported' to: 0.8.2

     References: #2768(7)

   * `[mysql] [bug]' ¶. Added another conditional to the
     ‘mysql+gaerdbms’ dialect to detect so-called “development” mode,
     where we should use the ‘rdbms_mysqldb’ DBAPI. Patch courtesy Brett
     Slatkin.

     This change is also `backported' to: 0.8.2

     References: #2715(8)

   * `[mysql] [bug]' ¶. The ‘deferrable’ keyword argument on
     ForeignKey and ForeignKeyConstraint will not
     render the ‘DEFERRABLE’ keyword on the MySQL dialect.  For a long
     time we left this in place because a non-deferrable foreign key
     would act very differently than a deferrable one, but some
     environments just disable FKs on MySQL, so we’ll be less
     opinionated here.

     This change is also `backported' to: 0.8.2

     References: #2721(9)

   * `[mysql] [bug]' ¶. Updates to MySQL reserved words for
     versions 5.5, 5.6, courtesy Hanno Schlichting.

     This change is also `backported' to: 0.8.3, 0.8.0b1

     References: #2791(10)

   * `[mysql] [bug]' ¶. Fix and test parsing of MySQL
     foreign key options within reflection; this complements the work in
     #2183(11) where we begin to support reflection of foreign key
     options such as ON UPDATE/ON DELETE cascade.

     References: #2839(12)

   * `[mysql] [bug]' ¶. Improved support for the cymysql
     driver, supporting version 0.6.5, courtesy Hajime Nakagami.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2704

   (2) http://www.sqlalchemy.org/trac/ticket/2817

   (3) http://www.sqlalchemy.org/trac/ticket/2721

   (4) http://www.sqlalchemy.org/trac/ticket/2721

   (5) http://www.sqlalchemy.org/trac/ticket/2839

   (6) http://www.sqlalchemy.org/trac/ticket/2515

   (7) http://www.sqlalchemy.org/trac/ticket/2768

   (8) http://www.sqlalchemy.org/trac/ticket/2715

   (9) http://www.sqlalchemy.org/trac/ticket/2721

   (10) http://www.sqlalchemy.org/trac/ticket/2791

   (11) http://www.sqlalchemy.org/trac/ticket/2183

   (12) http://www.sqlalchemy.org/trac/ticket/2839

8.3.6.104 sqlite
................

   * `[sqlite] [bug]' ¶. The newly added SQLite DATETIME
     arguments storage_format and regexp apparently were not fully
     implemented correctly; while the arguments were accepted, in
     practice they would have no effect; this has been fixed.

     This change is also `backported' to: 0.8.3

     References: #2781(1)

   * `[sqlite] [bug]' ¶. Added
     sqlalchemy.types.BIGINT to the list of type names that can
     be reflected by the SQLite dialect; courtesy Russell Stuart.

     This change is also `backported' to: 0.8.2

     References: #2764(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2781

   (2) http://www.sqlalchemy.org/trac/ticket/2764

8.3.6.105 mssql
...............

   * `[mssql] [bug]' ¶. When querying the information schema
     on SQL Server 2000, removed a CAST call that was added in 0.8.1 to
     help with driver issues, which apparently is not compatible on
     2000.  The CAST remains in place for SQL Server 2005 and greater.

     This change is also `backported' to: 0.8.2

     References: #2747(1)

   * `[mssql] [bug] [pyodbc]' ¶. Fixes to MSSQL with Python
     3 + pyodbc, including that statements are passed correctly.

     References: #2355(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2747

   (2) http://www.sqlalchemy.org/trac/ticket/2355

8.3.6.106 oracle
................

   * `[oracle] [feature] [py3k]' ¶. The Oracle unit tests
     with cx_oracle now pass fully under Python 3.

   * `[oracle] [bug]' ¶. Fixed bug where Oracle table
     reflection using synonyms would fail if the synonym and the table
     were in different remote schemas.  Patch to fix courtesy Kyle Derr.

     This change is also `backported' to: 0.8.3

     References: #2853(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2853

8.3.6.107 firebird
..................

   * `[firebird] [feature]' ¶. Added new flag
     ‘retaining=True’ to the kinterbasdb and fdb dialects.  This
     controls the value of the ‘retaining’ flag sent to the ‘commit()’
     and ‘rollback()’ methods of the DBAPI connection.  Due to
     historical concerns, this flag defaults to ‘True’ in 0.8.2, however
     in 0.9.0b1 this flag defaults to ‘False’.

     This change is also `backported' to: 0.8.2

     References: #2763(1)

   * `[firebird] [feature]' ¶. The ‘fdb’ dialect is now the
     default dialect when specified without a dialect qualifier, i.e.
     ‘firebird://’, per the Firebird project publishing ‘fdb’ as their
     official Python driver.

     References: #2504(2)

   * `[firebird] [bug]' ¶. Type lookup when reflecting the
     Firebird types LONG and INT64 has been fixed so that LONG is
     treated as INTEGER, INT64 treated as BIGINT, unless the type has a
     “precision” in which case it’s treated as NUMERIC. Patch courtesy
     Russell Stuart.

     This change is also `backported' to: 0.8.2

     References: #2757(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2763

   (2) http://www.sqlalchemy.org/trac/ticket/2504

   (3) http://www.sqlalchemy.org/trac/ticket/2757

8.3.6.108 misc
..............

   * `[feature]' ¶. Added a new flag ‘system=True’ to
     Column, which marks the column as a “system” column which is
     automatically made present by the database (such as PostgreSQL
     ‘oid’ or ‘xmin’).  The column will be omitted from the ‘CREATE
     TABLE’ statement but will otherwise be available for querying.  In
     addition, the CreateColumn construct can be applied to
     a custom compilation rule which allows skipping of columns, by
     producing a rule that returns ‘None’.

     This change is also `backported' to: 0.8.3

   * `[feature] [examples]' ¶. Improved the examples in
     ‘examples/generic_associations’, including that
     ‘discriminator_on_association.py’ makes use of single table
     inheritance do the work with the “discriminator”.  Also added a
     true “generic foreign key” example, which works similarly to other
     popular frameworks in that it uses an open-ended integer to point
     to any other table, foregoing traditional referential integrity.
     While we don’t recommend this pattern, information wants to be
     free.

     This change is also `backported' to: 0.8.3

   * `[feature] [core]' ¶. Added a new variant to
     UpdateBase.returning() called
     ValuesBase.return_defaults(); this allows arbitrary columns
     to be added to the RETURNING clause of the statement without
     interfering with the compilers usual “implicit returning” feature,
     which is used to efficiently fetch newly generated primary key
     values.  For supporting backends, a dictionary of all fetched
     values is present at ‘ResultProxy.returned_defaults’.

     References: #2793(1)

   * `[feature] [pool]' ¶. Added pool logging for
     “rollback-on-return” and the less used “commit-on-return”.  This is
     enabled with the rest of pool “debug” logging.

     References: #2752(2)

   * `[bug] [examples]' ¶. Added “autoincrement=False” to
     the history table created in the versioning example, as this table
     shouldn’t have autoinc on it in any case, courtesy Patrick Schmid.

     This change is also `backported' to: 0.8.3

   * `[bug] [ext]' ¶. Fixed bug whereby if a composite type
     were set up with a function instead of a class, the mutable
     extension would trip up when it tried to check that column for
     being a MutableComposite. (which it isn’t).  Courtesy
     asldevi.

     This change is also `backported' to: 0.8.2

   * `[bug] [examples]' ¶. Fixed an issue with the
     “versioning” recipe whereby a many-to-one reference could produce a
     meaningless version for the target, even though it was not changed,
     when backrefs were present.  Patch courtesy Matt Chisholm.

     This change is also `backported' to: 0.8.2

   * `[requirements]' ¶. The Python mock(3) library is now
     required in order to run the unit test suite.  While part of the
     standard library as of Python 3.3, previous Python installations
     will need to install this in order to run unit tests or to use the
     ‘sqlalchemy.testing’ package for external dialects.

     This change is also `backported' to: 0.8.2

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2793

   (2) http://www.sqlalchemy.org/trac/ticket/2752

   (3) https://pypi.python.org/pypi/mock

8.3.7 0.8 Changelog
-------------------

8.3.7.1 0.8.7
.............

Released: July 22, 2014

8.3.7.2 orm
...........

   * `[orm] [bug]' ¶. Fixed bug in subquery eager loading
     where a long chain of eager loads across a polymorphic-subclass
     boundary in conjunction with polymorphic loading would fail to
     locate the subclass-link in the chain, erroring out with a missing
     property name on an AliasedClass.

     References: #3055(1)

   * `[orm] [bug]' ¶. Fixed ORM bug where the
     class_mapper() function would mask AttributeErrors or
     KeyErrors that should raise during mapper configuration due to user
     errors.  The catch for attribute/keyerror has been made more
     specific to not include the configuration step.

     References: #3047(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3055

   (2) http://www.sqlalchemy.org/trac/ticket/3047

8.3.7.3 sql
...........

   * `[sql] [bug]' ¶. Fixed bug in Enum and
     other SchemaType subclasses where direct association
     of the type with a MetaData would lead to a hang when
     events (like create events) were emitted on the MetaData.

     References: #3124(1)

   * `[sql] [bug]' ¶. Fixed a bug within the custom operator
     plus TypeEngine.with_variant() system, whereby using a
     TypeDecorator in conjunction with variant would fail
     with an MRO error when a comparison operator was used.

     References: #3102(2)

   * `[sql] [bug]' ¶. Fixed bug in INSERT..FROM SELECT
     construct where selecting from a UNION would wrap the union in an
     anonymous (e.g.  unlabeled) subquery.

     References: #3044(3)

   * `[sql] [bug]' ¶. Fixed bug where Table.update()
     and Table.delete() would produce an empty WHERE
     clause when an empty and_() or or_() or other
     blank expression were applied.  This is now consistent with that of
     select().

     References: #3045(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3124

   (2) http://www.sqlalchemy.org/trac/ticket/3102

   (3) http://www.sqlalchemy.org/trac/ticket/3044

   (4) http://www.sqlalchemy.org/trac/ticket/3045

8.3.7.4 postgresql
..................

   * `[postgresql] [bug]' ¶. Added the ‘hashable=False’ flag
     to the PG HSTORE type, which is needed to allow the ORM
     to skip over trying to “hash” an ORM-mapped HSTORE column when
     requesting it in a mixed column/entity list.  Patch courtesy
     Gunnlaugur Þór Briem.

     References: #3053(1)

   * `[postgresql] [bug]' ¶. Added a new “disconnect”
     message “connection has been closed unexpectedly”.  This appears to
     be related to newer versions of SSL. Pull request courtesy Antti
     Haapala.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3053

8.3.7.5 mysql
.............

   * `[mysql] [bug]' ¶. MySQL error 2014 “commands out of
     sync” appears to be raised as a ProgrammingError, not
     OperationalError, in modern MySQL-Python versions; all MySQL error
     codes that are tested for “is disconnect” are now checked within
     OperationalError and ProgrammingError regardless.

     References: #3101(1)

   * `[mysql] [bug]' ¶. Fixed bug where column names added
     to ‘mysql_length’ parameter on an index needed to have the same
     quoting for quoted names in order to be recognized.  The fix makes
     the quotes optional but also provides the old behavior for
     backwards compatibility with those using the workaround.

     References: #3085(2)

   * `[mysql] [bug]' ¶. Added support for reflecting tables
     where an index includes KEY_BLOCK_SIZE using an equal sign.  Pull
     request courtesy Sean McGivern.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3101

   (2) http://www.sqlalchemy.org/trac/ticket/3085

8.3.7.6 mssql
.............

   * `[mssql] [bug]' ¶. Added statement encoding to the “SET
     IDENTITY_INSERT” statements which operate when an explicit INSERT
     is being interjected into an IDENTITY column, to support non-ascii
     table identifiers on drivers such as pyodbc + unix + py2k that
     don’t support unicode statements.

   * `[mssql] [bug]' ¶. In the SQL Server pyodbc dialect,
     repaired the implementation for the ‘description_encoding’ dialect
     parameter, which when not explicitly set was preventing
     cursor.description from being parsed correctly in the case of
     result sets that contained names in alternate encodings.  This
     parameter shouldn’t be needed going forward.

     References: #3091(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3091

8.3.7.7 misc
............

   * `[bug] [declarative]' ¶. The ‘__mapper_args__’
     dictionary is copied from a declarative mixin or abstract class
     when accessed, so that modifications made to this dictionary by
     declarative itself won’t conflict with that of other mappings.  The
     dictionary is modified regarding the ‘version_id_col’ and
     ‘polymorphic_on’ arguments, replacing the column within with the
     one that is officially mapped to the local class/table.

     References: #3062(1)

   * `[bug] [ext]' ¶. Fixed bug in mutable extension where
     MutableDict did not report change events for the
     ‘setdefault()’ dictionary operation.

     References: #3051(2), #3093(3)

   * `[bug] [ext]' ¶. Fixed bug where
     MutableDict.setdefault() didn’t return the existing or new
     value (this bug was not released in any 0.8 version).  Pull request
     courtesy Thomas Hervé.

     References: #3051(4), #3093(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3062

   (2) http://www.sqlalchemy.org/trac/ticket/3051

   (3) http://www.sqlalchemy.org/trac/ticket/3093

   (4) http://www.sqlalchemy.org/trac/ticket/3051

   (5) http://www.sqlalchemy.org/trac/ticket/3093

8.3.7.8 0.8.6
.............

Released: March 28, 2014

8.3.7.9 general
...............

   * `[general] [bug]' ¶. Adjusted ‘setup.py’ file to
     support the possible future removal of the ‘setuptools.Feature’
     extension from setuptools.  If this keyword isn’t present, the
     setup will still succeed with setuptools rather than falling back
     to distutils.  C extension building can be disabled now also by
     setting the DISABLE_SQLALCHEMY_CEXT environment variable.  This
     variable works whether or not setuptools is even available.

     References: #2986(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2986

8.3.7.10 orm
............

   * `[orm] [bug]' ¶. Fixed ORM bug where changing the
     primary key of an object, then marking it for DELETE would fail to
     target the correct row for DELETE.

     References: #3006(1)

   * `[orm] [bug]' ¶. Fixed regression from 0.8.3 as a
     result of #2818(2) where Query.exists() wouldn’t work
     on a query that only had a Query.select_from() entry
     but no other entities.

     References: #2995(3)

   * `[orm] [bug]' ¶. Improved an error message which would
     occur if a query() were made against a non-selectable, such as a
     literal_column(), and then an attempt was made to use
     Query.join() such that the “left” side would be
     determined as ‘None’ and then fail.  This condition is now detected
     explicitly.

   * `[orm] [bug]' ¶. Removed stale names from
     ‘sqlalchemy.orm.interfaces.__all__’ and refreshed with current
     names, so that an ‘import *’ from this module again works.

     References: #2975(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3006

   (2) http://www.sqlalchemy.org/trac/ticket/2818

   (3) http://www.sqlalchemy.org/trac/ticket/2995

   (4) http://www.sqlalchemy.org/trac/ticket/2975

8.3.7.11 sql
............

   * `[sql] [bug]' ¶. Fixed bug in tuple_().
     construct where the “type” of essentially the first SQL expression
     would be applied as the “comparison type” to a compared tuple
     value; this has the effect in some cases of an inappropriate “type
     coercion” occurring, such as when a tuple that has a mix of String
     and Binary values improperly coerces target values to Binary even
     though that’s not what they are on the left side.  tuple_()
     now expects heterogeneous types within its list of values.

     References: #2977(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2977

8.3.7.12 postgresql
...................

   * `[postgresql] [feature]' ¶. Enabled “sane multi-row
     count” checking for the psycopg2 DBAPI, as this seems to be
     supported as of psycopg2 2.0.9.

   * `[postgresql] [bug]' ¶. Fixed regression caused by
     release 0.8.5 / 0.9.3’s compatibility enhancements where index
     reflection on PostgreSQL versions specific to only the 8.1, 8.2
     series again broke, surrounding the ever problematic int2vector
     type.  While int2vector supports array operations as of 8.1,
     apparently it only supports CAST to a varchar as of 8.3.

     References: #3000(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3000

8.3.7.13 misc
.............

   * `[bug] [ext]' ¶. Fixed bug in mutable extension as well
     as flag_modified() where the change event would not be
     propagated if the attribute had been reassigned to itself.

     References: #2997(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2997

8.3.7.14 0.8.5
..............

Released: February 19, 2014

8.3.7.15 orm
............

   * `[orm] [bug]' ¶. Fixed bug where Query.get()
     would fail to consistently raise the
     InvalidRequestError that invokes when called on a query with
     existing criterion, when the given identity is already present in
     the identity map.

     References: #2951(1)

   * `[orm] [bug]' ¶. Fixed error message when an iterator
     object is passed to class_mapper() or similar, where
     the error would fail to render on string formatting.  Pullreq
     courtesy Kyle Stark.

   * `[orm] [bug]' ¶. An adjustment to the
     subqueryload() strategy which ensures that the query runs
     after the loading process has begun; this is so that the
     subqueryload takes precedence over other loaders that may be
     hitting the same attribute due to other eager/noload situations at
     the wrong time.

     References: #2887(2)

   * `[orm] [bug]' ¶. Fixed bug when using joined table
     inheritance from a table to a select/alias on the base, where the
     PK columns were also not same named; the persistence system would
     fail to copy primary key values from the base table to the
     inherited table upon INSERT.

     References: #2885(3)

   * `[orm] [bug]' ¶. composite() will raise an
     informative error message when the columns/attribute (names) passed
     don’t resolve to a Column or mapped attribute (such as an erroneous
     tuple); previously raised an unbound local.

     References: #2889(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2951

   (2) http://www.sqlalchemy.org/trac/ticket/2887

   (3) http://www.sqlalchemy.org/trac/ticket/2885

   (4) http://www.sqlalchemy.org/trac/ticket/2889

8.3.7.16 engine
...............

   * `[engine] [bug] [pool]' ¶. Fixed a critical regression
     caused by #2880(1) where the newly concurrent ability to return
     connections from the pool means that the “first_connect” event is
     now no longer synchronized either, thus leading to dialect
     mis-configurations under even minimal concurrency situations.

     References: #2880(2), #2964(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2880

   (2) http://www.sqlalchemy.org/trac/ticket/2880

   (3) http://www.sqlalchemy.org/trac/ticket/2964

8.3.7.17 sql
............

   * `[sql] [bug]' ¶. Fixed bug where calling
     Insert.values() with an empty list or tuple would raise an
     IndexError.  It now produces an empty insert construct as would be
     the case with an empty dictionary.

     References: #2944(1)

   * `[sql] [bug]' ¶. Fixed bug where
     ColumnOperators.in_() would go into an endless loop if
     erroneously passed a column expression whose comparator included
     the ‘__getitem__()’ method, such as a column that uses the
     ARRAY type.

     References: #2957(2)

   * `[sql] [bug]' ¶. Fixed issue where a primary key column
     that has a Sequence on it, yet the column is not the “auto
     increment” column, either because it has a foreign key constraint
     or ‘autoincrement=False’ set, would attempt to fire the Sequence on
     INSERT for backends that don’t support sequences, when presented
     with an INSERT missing the primary key value.  This would take
     place on non-sequence backends like SQLite, MySQL.

     References: #2896(3)

   * `[sql] [bug]' ¶. Fixed bug with
     Insert.from_select() method where the order of the given names
     would not be taken into account when generating the INSERT
     statement, thus producing a mismatch versus the column names in the
     given SELECT statement.  Also noted that
     Insert.from_select() implies that Python-side insert defaults
     cannot be used, since the statement has no VALUES clause.

     References: #2895(4)

   * `[sql] [enhancement]' ¶. The exception raised when a
     BindParameter is present in a compiled statement
     without a value now includes the key name of the bound parameter in
     the error message.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2944

   (2) http://www.sqlalchemy.org/trac/ticket/2957

   (3) http://www.sqlalchemy.org/trac/ticket/2896

   (4) http://www.sqlalchemy.org/trac/ticket/2895

8.3.7.18 postgresql
...................

   * `[postgresql] [bug]' ¶. Added an additional message to
     psycopg2 disconnect detection, “could not send data to server”,
     which complements the existing “could not receive data from server”
     and has been observed by users.

     References: #2936(1)

   * `[postgresql] [bug]' ¶.

          Support has been improved for PostgreSQL reflection behavior
          on very old (pre 8.1) versions of PostgreSQL, and potentially
          other PG engines such as Redshift (assuming Redshift reports
          the version as < 8.1).  The query for “indexes” as well as
          “primary keys” relies upon inspecting a so-called “int2vector”
          datatype, which refuses to coerce to an array prior to 8.1
          causing failures regarding the “ANY()” operator used in the
          query.  Extensive googling has located the very hacky, but
          recommended-by-PG-core-developer query to use when PG version
          < 8.1 is in use, so index and primary key constraint
          reflection now work on these versions.

   * `[postgresql] [bug]' ¶. Revised this very old issue
     where the PostgreSQL “get primary key” reflection query were
     updated to take into account primary key constraints that were
     renamed; the newer query fails on very old versions of PostgreSQL
     such as version 7, so the old query is restored in those cases when
     server_version_info < (8, 0) is detected.

     References: #2291(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2936

   (2) http://www.sqlalchemy.org/trac/ticket/2291

8.3.7.19 mysql
..............

   * `[mysql] [feature]' ¶. Added new MySQL-specific
     DATETIME which includes fractional seconds support; also
     added fractional seconds support to TIMESTAMP.  DBAPI
     support is limited, though fractional seconds are known to be
     supported by MySQL Connector/Python.  Patch courtesy Geert JM
     Vanderkelen.

     References: #2941(1)

   * `[mysql] [bug]' ¶. Added support for the ‘PARTITION BY’
     and ‘PARTITIONS’ MySQL table keywords, specified as
     ‘mysql_partition_by='value'’ and ‘mysql_partitions='value'’ to
     Table.  Pull request courtesy Marcus McCurdy.

     References: #2966(2)

   * `[mysql] [bug]' ¶. Fixed bug which prevented
     MySQLdb-based dialects (e.g.  pymysql) from working in Py3K, where
     a check for “connection charset” would fail due to Py3K’s more
     strict value comparison rules.  The call in question wasn’t taking
     the database version into account in any case as the server version
     was still None at that point, so the method overall has been
     simplified to rely upon connection.character_set_name().

     References: #2933(3)

   * `[mysql] [bug]' ¶. Some missing methods added to the
     cymysql dialect, including _get_server_version_info() and
     _detect_charset().  Pullreq courtesy Hajime Nakagami.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2941

   (2) http://www.sqlalchemy.org/trac/ticket/2966

   (3) http://www.sqlalchemy.org/trac/ticket/2933

8.3.7.20 sqlite
...............

   * `[sqlite] [bug]' ¶. Restored a change that was missed
     in the backport of unique constraint reflection to 0.8, where
     UniqueConstraint with SQLite would fail if reserved keywords
     were included in the names of columns.  Pull request courtesy Roman
     Podolyaka.

8.3.7.21 mssql
..............

   * `[mssql] [bug] [firebird]' ¶. The “asdecimal” flag used
     with the Float type will now work with Firebird as
     well as the mssql+pyodbc dialects; previously the decimal
     conversion was not occurring.

   * `[mssql] [bug] [pymssql]' ¶. Added “Net-Lib error
     during Connection reset by peer” message to the list of messages
     checked for “disconnect” within the pymssql dialect.  Courtesy John
     Anderson.

8.3.7.22 firebird
.................

   * `[firebird] [bug]' ¶. The firebird dialect will quote
     identifiers which begin with an underscore.  Courtesy Treeve
     Jelbert.

     References: #2897(1)

   * `[firebird] [bug]' ¶. Fixed bug in Firebird index
     reflection where the columns within the index were not sorted
     correctly; they are now sorted in order of RDB$FIELD_POSITION.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2897

8.3.7.23 misc
.............

   * `[bug] [py3k]' ¶. Fixed Py3K bug where a missing import
     would cause “literal binary” mode to fail to import
     “util.binary_type” when rendering a bound parameter.  0.9 handles
     this differently.  Pull request courtesy Andreas Zeidler.

   * `[bug] [declarative]' ¶. Error message when a string
     arg sent to relationship() which doesn’t resolve to a
     class or mapper has been corrected to work the same way as when a
     non-string arg is received, which indicates the name of the
     relationship which had the configurational error.

     References: #2888(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2888

8.3.7.24 0.8.4
..............

Released: December 8, 2013

8.3.7.25 orm
............

   * `[orm] [bug]' ¶. Fixed a regression introduced by
     #2818(1) where the EXISTS query being generated would produce a
     “columns being replaced” warning for a statement with two
     same-named columns, as the internal SELECT wouldn’t have use_labels
     set.

     References: #2818(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2818

   (2) http://www.sqlalchemy.org/trac/ticket/2818

8.3.7.26 engine
...............

   * `[engine] [bug]' ¶. A DBAPI that raises an error on
     ‘connect()’ which is not a subclass of dbapi.Error (such as
     ‘TypeError’, ‘NotImplementedError’, etc.)  will propagate the
     exception unchanged.  Previously, the error handling specific to
     the ‘connect()’ routine would both inappropriately run the
     exception through the dialect’s Dialect.is_disconnect()
     routine as well as wrap it in a
     sqlalchemy.exc.DBAPIError.  It is now propagated unchanged in
     the same way as occurs within the execute process.

     References: #2881(1)

   * `[engine] [bug] [pool]' ¶. The QueuePool.
     has been enhanced to not block new connection attempts when an
     existing connection attempt is blocking.  Previously, the
     production of new connections was serialized within the block that
     monitored overflow; the overflow counter is now altered within its
     own critical section outside of the connection process itself.

     References: #2880(2)

   * `[engine] [bug] [pool]' ¶. Made a slight adjustment to
     the logic which waits for a pooled connection to be available, such
     that for a connection pool with no timeout specified, it will every
     half a second break out of the wait to check for the so-called
     “abort” flag, which allows the waiter to break out in case the
     whole connection pool was dumped; normally the waiter should break
     out due to a notify_all() but it’s possible this notify_all() is
     missed in very slim cases.  This is an extension of logic first
     introduced in 0.8.0, and the issue has only been observed
     occasionally in stress tests.

     References: #2522(3)

   * `[engine] [bug]' ¶. Fixed bug where SQL statement would
     be improperly ASCII-encoded when a pre-DBAPI StatementError
     were raised within Connection.execute(), causing
     encoding errors for non-ASCII statements.  The stringification now
     remains within Python unicode thus avoiding encoding errors.

     References: #2871(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2881

   (2) http://www.sqlalchemy.org/trac/ticket/2880

   (3) http://www.sqlalchemy.org/trac/ticket/2522

   (4) http://www.sqlalchemy.org/trac/ticket/2871

8.3.7.27 sql
............

   * `[sql] [feature]' ¶. Added support for “unique
     constraint” reflection, via the
     Inspector.get_unique_constraints() method.  Thanks for Roman
     Podolyaka for the patch.

     References: #1443(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1443

8.3.7.28 postgresql
...................

   * `[postgresql] [bug]' ¶. Fixed bug where index
     reflection would mis-interpret indkey values when using the
     pypostgresql adapter, which returns these values as lists vs.
     psycopg2’s return type of string.

     References: #2855(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2855

8.3.7.29 mssql
..............

   * `[mssql] [bug]' ¶. Fixed bug introduced in 0.8.0 where
     the ‘DROP INDEX’ statement for an index in MSSQL would render
     incorrectly if the index were in an alternate schema; the
     schemaname/tablename would be reversed.  The format has been also
     been revised to match current MSSQL documentation.  Courtesy Derek
     Harland.

8.3.7.30 oracle
...............

   * `[oracle] [bug]' ¶. Added ORA-02396 “maximum idle time”
     error code to list of “is disconnect” codes with cx_oracle.

     References: #2864(1)

   * `[oracle] [bug]' ¶. Fixed bug where Oracle ‘VARCHAR’
     types given with no length (e.g.  for a ‘CAST’ or similar) would
     incorrectly render ‘None CHAR’ or similar.

     References: #2870(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2864

   (2) http://www.sqlalchemy.org/trac/ticket/2870

8.3.7.31 misc
.............

   * `[bug] [ext]' ¶. Fixed bug which prevented the
     ‘serializer’ extension from working correctly with table or column
     names that contain non-ASCII characters.

     References: #2869(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2869

8.3.7.32 0.8.3
..............

Released: October 26, 2013

8.3.7.33 orm
............

   * `[orm] [feature]' ¶. Added new option to
     relationship(). ‘distinct_target_key’.  This enables the
     subquery eager loader strategy to apply a DISTINCT to the innermost
     SELECT subquery, to assist in the case where duplicate rows are
     generated by the innermost query which corresponds to this
     relationship (there’s not yet a general solution to the issue of
     dupe rows within subquery eager loading, however, when joins
     outside of the innermost subquery produce dupes).  When the flag is
     set to ‘True’, the DISTINCT is rendered unconditionally, and when
     it is set to ‘None’, DISTINCT is rendered if the innermost
     relationship targets columns that do not comprise a full primary
     key.  The option defaults to False in 0.8 (e.g.  off by default in
     all cases), None in 0.9 (e.g.  automatic by default).  Thanks to
     Alexander Koval for help with this.

     See also
     ........

     See Subquery Eager Loading will apply DISTINCT to the innermost SELECT for some queries.

     References: #2836(1)

   * `[orm] [bug]' ¶. Fixed bug where using an annotation
     such as remote() or foreign() on a
     Column before association with a parent Table could
     produce issues related to the parent table not rendering within
     joins, due to the inherent copy operation performed by an
     annotation.

     References: #2813(2)

   * `[orm] [bug]' ¶. Fixed bug where Query.exists()
     failed to work correctly without any WHERE criterion.
     Courtesy Vladimir Magamedov.

     References: #2818(3)

   * `[orm] [bug]' ¶. Backported a change from 0.9 whereby
     the iteration of a hierarchy of mappers used in polymorphic
     inheritance loads is sorted, which allows the SELECT statements
     generated for polymorphic queries to have deterministic rendering,
     which in turn helps with caching schemes that cache on the SQL
     string itself.

     References: #2779(4)

   * `[orm] [bug]' ¶. Fixed a potential issue in an ordered
     sequence implementation used by the ORM to iterate mapper
     hierarchies; under the Jython interpreter this implementation
     wasn’t ordered, even though cPython and PyPy maintained ordering.

     References: #2794(5)

   * `[orm] [bug]' ¶. Fixed bug in ORM-level event
     registration where the “raw” or “propagate” flags could potentially
     be mis-configured in some “unmapped base class” configurations.

     References: #2786(6)

   * `[orm] [bug]' ¶. A performance fix related to the usage
     of the defer() option when loading mapped entities.
     The function overhead of applying a per-object deferred callable to
     an instance at load time was significantly higher than that of just
     loading the data from the row (note that ‘defer()’ is meant to
     reduce DB/network overhead, not necessarily function call count);
     the function call overhead is now less than that of loading data
     from the column in all cases.  There is also a reduction in the
     number of “lazy callable” objects created per load from N (total
     deferred values in the result) to 1 (total number of deferred
     cols).

     References: #2778(7)

   * `[orm] [bug]' ¶. Fixed bug whereby attribute history
     functions would fail when an object we moved from “persistent” to
     “pending” using the make_transient() function, for
     operations involving collection-based backrefs.

     References: #2773(8)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2836

   (2) http://www.sqlalchemy.org/trac/ticket/2813

   (3) http://www.sqlalchemy.org/trac/ticket/2818

   (4) http://www.sqlalchemy.org/trac/ticket/2779

   (5) http://www.sqlalchemy.org/trac/ticket/2794

   (6) http://www.sqlalchemy.org/trac/ticket/2786

   (7) http://www.sqlalchemy.org/trac/ticket/2778

   (8) http://www.sqlalchemy.org/trac/ticket/2773

8.3.7.34 orm declarative
........................

   * `[orm] [declarative] [feature]' ¶. Added a convenience
     class decorator as_declarative(), is a wrapper for
     declarative_base() which allows an existing base class to be
     applied using a nifty class-decorated approach.

8.3.7.35 engine
...............

   * `[engine] [feature]' ¶. ‘repr()’ for the URL
     of an Engine will now conceal the password using
     asterisks.  Courtesy Gunnlaugur Þór Briem.

     References: #2821(1)

   * `[engine] [bug] [oracle]' ¶. Dialect.initialize() is
     not called a second time if an Engine is recreated, due
     to a disconnect error.  This fixes a particular issue in the Oracle
     8 dialect, but in general the dialect.initialize() phase should
     only be once per dialect.

     References: #2776(2)

   * `[engine] [bug] [pool]' ¶. Fixed bug where
     QueuePool would lose the correct checked out count if an
     existing pooled connection failed to reconnect after an invalidate
     or recycle event.

     References: #2772(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2821

   (2) http://www.sqlalchemy.org/trac/ticket/2776

   (3) http://www.sqlalchemy.org/trac/ticket/2772

8.3.7.36 sql
............

   * `[sql] [feature]' ¶. Added new method to the
     insert() construct Insert.from_select().  Given a
     list of columns and a selectable, renders ‘INSERT INTO (table)
     (columns) SELECT ..’.

     References: #722(1)

   * `[sql] [feature]' ¶. The update(),
     insert(), and delete() constructs will now
     interpret ORM entities as target tables to be operated upon, e.g.:

          from sqlalchemy import insert, update, delete

          ins = insert(SomeMappedClass).values(x=5)

          del_ = delete(SomeMappedClass).where(SomeMappedClass.id == 5)

          upd = update(SomeMappedClass).where(SomeMappedClass.id == 5).values(name='ed')

   * `[sql] [bug]' ¶. Fixed bug where type_coerce()
     would not interpret ORM elements with a ‘__clause_element__()’
     method properly.

     References: #2849(2)

   * `[sql] [bug]' ¶. The Enum and
     Boolean types now bypass any custom (e.g.  TypeDecorator)
     type in use when producing the CHECK constraint for the “non
     native” type.  This so that the custom type isn’t involved in the
     expression within the CHECK, since this expression is against the
     “impl” value and not the “decorated” value.

     References: #2842(3)

   * `[sql] [bug]' ¶. The ‘.unique’ flag on Index
     could be produced as ‘None’ if it was generated from a
     Column that didn’t specify ‘unique’ (where it defaults to
     ‘None’).  The flag will now always be ‘True’ or ‘False’.

     References: #2825(4)

   * `[sql] [bug]' ¶. Fixed bug in default compiler plus
     those of postgresql, mysql, and mssql to ensure that any literal
     SQL expression values are rendered directly as literals, instead of
     as bound parameters, within a CREATE INDEX statement.  This also
     changes the rendering scheme for other DDL such as constraints.

     References: #2742(5)

   * `[sql] [bug]' ¶. A select() that is made to
     refer to itself in its FROM clause, typically via in-place
     mutation, will raise an informative error message rather than
     causing a recursion overflow.

     References: #2815(6)

   * `[sql] [bug]' ¶. Non-working “schema” argument on
     ForeignKey is deprecated; raises a warning.  Removed in 0.9.

     References: #2831(7)

   * `[sql] [bug]' ¶. Fixed bug where using the
     ‘column_reflect’ event to change the ‘.key’ of the incoming
     Column would prevent primary key constraints, indexes, and
     foreign key constraints from being correctly reflected.

     References: #2811(8)

   * `[sql] [bug]' ¶. The ColumnOperators.notin_()
     operator added in 0.8 now properly produces the negation of
     the expression “IN” returns when used against an empty collection.

   * `[sql] [bug] [postgresql]' ¶. Fixed bug where the
     expression system relied upon the ‘str()’ form of a some
     expressions when referring to the ‘.c’ collection on a ‘select()’
     construct, but the ‘str()’ form isn’t available since the element
     relies on dialect-specific compilation constructs, notably the
     ‘__getitem__()’ operator as used with a PostgreSQL ‘ARRAY’ element.
     The fix also adds a new exception class
     UnsupportedCompilationError which is raised in those cases
     where a compiler is asked to compile something it doesn’t know how
     to.

     References: #2780(9)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/722

   (2) http://www.sqlalchemy.org/trac/ticket/2849

   (3) http://www.sqlalchemy.org/trac/ticket/2842

   (4) http://www.sqlalchemy.org/trac/ticket/2825

   (5) http://www.sqlalchemy.org/trac/ticket/2742

   (6) http://www.sqlalchemy.org/trac/ticket/2815

   (7) http://www.sqlalchemy.org/trac/ticket/2831

   (8) http://www.sqlalchemy.org/trac/ticket/2811

   (9) http://www.sqlalchemy.org/trac/ticket/2780

8.3.7.37 postgresql
...................

   * `[postgresql] [bug]' ¶. Removed a 128-character
     truncation from the reflection of the server default for a column;
     this code was original from PG system views which truncated the
     string for readability.

     References: #2844(1)

   * `[postgresql] [bug]' ¶. Parenthesis will be applied to
     a compound SQL expression as rendered in the column list of a
     CREATE INDEX statement.

     References: #2742(2)

   * `[postgresql] [bug]' ¶. Fixed bug where PostgreSQL
     version strings that had a prefix preceding the words “PostgreSQL”
     or “EnterpriseDB” would not parse.  Courtesy Scott Schaefer.

     References: #2819(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2844

   (2) http://www.sqlalchemy.org/trac/ticket/2742

   (3) http://www.sqlalchemy.org/trac/ticket/2819

8.3.7.38 mysql
..............

   * `[mysql] [bug]' ¶. The change in #2721(1), which is
     that the ‘deferrable’ keyword of ForeignKeyConstraint is
     silently ignored on the MySQL backend, will be reverted as of 0.9;
     this keyword will now render again, raising errors on MySQL as it
     is not understood - the same behavior will also apply to the
     ‘initially’ keyword.  In 0.8, the keywords will remain ignored but
     a warning is emitted.  Additionally, the ‘match’ keyword now raises
     a CompileError on 0.9 and emits a warning on 0.8; this
     keyword is not only silently ignored by MySQL but also breaks the
     ON UPDATE/ON DELETE options.

     To use a ForeignKeyConstraint that does not render or
     renders differently on MySQL, use a custom compilation option.  An
     example of this usage has been added to the documentation, see
     MySQL / MariaDB Foreign Keys.

     References: #2721(2), #2839(3)

   * `[mysql] [bug]' ¶. MySQL-connector dialect now allows
     options in the create_engine query string to override those
     defaults set up in the connect, including “buffered” and
     “raise_on_warnings”.

     References: #2515(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2721

   (2) http://www.sqlalchemy.org/trac/ticket/2721

   (3) http://www.sqlalchemy.org/trac/ticket/2839

   (4) http://www.sqlalchemy.org/trac/ticket/2515

8.3.7.39 sqlite
...............

   * `[sqlite] [bug]' ¶. The newly added SQLite DATETIME
     arguments storage_format and regexp apparently were not fully
     implemented correctly; while the arguments were accepted, in
     practice they would have no effect; this has been fixed.

     References: #2781(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2781

8.3.7.40 oracle
...............

   * `[oracle] [bug]' ¶. Fixed bug where Oracle table
     reflection using synonyms would fail if the synonym and the table
     were in different remote schemas.  Patch to fix courtesy Kyle Derr.

     References: #2853(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2853

8.3.7.41 misc
.............

   * `[feature]' ¶. Added a new flag ‘system=True’ to
     Column, which marks the column as a “system” column which is
     automatically made present by the database (such as PostgreSQL
     ‘oid’ or ‘xmin’).  The column will be omitted from the ‘CREATE
     TABLE’ statement but will otherwise be available for querying.  In
     addition, the CreateColumn construct can be applied to
     a custom compilation rule which allows skipping of columns, by
     producing a rule that returns ‘None’.

   * `[feature] [examples]' ¶. Improved the examples in
     ‘examples/generic_associations’, including that
     ‘discriminator_on_association.py’ makes use of single table
     inheritance do the work with the “discriminator”.  Also added a
     true “generic foreign key” example, which works similarly to other
     popular frameworks in that it uses an open-ended integer to point
     to any other table, foregoing traditional referential integrity.
     While we don’t recommend this pattern, information wants to be
     free.

   * `[bug] [examples]' ¶. Added “autoincrement=False” to
     the history table created in the versioning example, as this table
     shouldn’t have autoinc on it in any case, courtesy Patrick Schmid.

8.3.7.42 0.8.2
..............

Released: July 3, 2013

8.3.7.43 orm
............

   * `[orm] [feature]' ¶. Added a new method
     Query.select_entity_from() which will in 0.9 replace part of
     the functionality of Query.select_from().  In 0.8, the
     two methods perform the same function, so that code can be migrated
     to use the Query.select_entity_from() method as
     appropriate.  See the 0.9 migration guide for details.

     References: #2736(1)

   * `[orm] [bug]' ¶. A warning is emitted when trying to
     flush an object of an inherited class where the polymorphic
     discriminator has been assigned to a value that is invalid for the
     class.

     References: #2750(2)

   * `[orm] [bug]' ¶. Fixed bug in polymorphic SQL
     generation where multiple joined-inheritance entities against the
     same base class joined to each other as well would not track
     columns on the base table independently of each other if the string
     of joins were more than two entities long.

     References: #2759(3)

   * `[orm] [bug]' ¶. Fixed bug where sending a composite
     attribute into Query.order_by() would produce a
     parenthesized expression not accepted by some databases.

     References: #2754(4)

   * `[orm] [bug]' ¶. Fixed the interaction between
     composite attributes and the aliased() function.
     Previously, composite attributes wouldn’t work correctly in
     comparison operations when aliasing was applied.

     References: #2755(5)

   * `[orm] [bug] [ext]' ¶. Fixed bug where
     MutableDict didn’t report a change event when ‘clear()’ was
     called.

     References: #2730(6)

   * `[orm] [bug]' ¶. Fixed a regression caused by #2682(7)
     whereby the evaluation invoked by Query.update() and
     Query.delete() would hit upon unsupported ‘True’ and
     ‘False’ symbols which now appear due to the usage of ‘IS’.

     References: #2737(8)

   * `[orm] [bug]' ¶. Fixed a regression from 0.7 caused by
     this ticket, which made the check for recursion overflow in
     self-referential eager joining too loose, missing a particular
     circumstance where a subclass had lazy=”joined” or “subquery”
     configured and the load was a “with_polymorphic” against the base.

     References: #2481(9)

   * `[orm] [bug]' ¶. Fixed a regression from 0.7 where the
     contextmanager feature of Session.begin_nested() would
     fail to correctly roll back the transaction when a flush error
     occurred, instead raising its own exception while leaving the
     session still pending a rollback.

     References: #2718(10)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2736

   (2) http://www.sqlalchemy.org/trac/ticket/2750

   (3) http://www.sqlalchemy.org/trac/ticket/2759

   (4) http://www.sqlalchemy.org/trac/ticket/2754

   (5) http://www.sqlalchemy.org/trac/ticket/2755

   (6) http://www.sqlalchemy.org/trac/ticket/2730

   (7) http://www.sqlalchemy.org/trac/ticket/2682

   (8) http://www.sqlalchemy.org/trac/ticket/2737

   (9) http://www.sqlalchemy.org/trac/ticket/2481

   (10) http://www.sqlalchemy.org/trac/ticket/2718

8.3.7.44 orm declarative
........................

   * `[orm] [declarative] [feature]' ¶. ORM descriptors such
     as hybrid properties can now be referenced by name in a string
     argument used with ‘order_by’, ‘primaryjoin’, or similar in
     relationship(), in addition to column-bound attributes.

     References: #2761(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2761

8.3.7.45 engine
...............

   * `[engine] [bug]' ¶. Fixed bug where the
     ‘reset_on_return’ argument to various Pool
     implementations would not be propagated when the pool was
     regenerated.  Courtesy Eevee.

   * `[engine] [bug] [sybase]' ¶. Fixed a bug where the
     routine to detect the correct kwargs being sent to
     create_engine() would fail in some cases, such as with the
     Sybase dialect.

     References: #2732(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2732

8.3.7.46 sql
............

   * `[sql] [feature]' ¶. Provided a new attribute for
     TypeDecorator called TypeDecorator.coerce_to_is_types,
     to make it easier to control how comparisons using ‘==’ or
     ‘!=’ to ‘None’ and boolean types goes about producing an ‘IS’
     expression, or a plain equality expression with a bound parameter.

     References: #2734(1), #2744(2)

   * `[sql] [bug]' ¶. Multiple fixes to the correlation
     behavior of Select constructs, first introduced in
     0.8.0:

        * To satisfy the use case where FROM entries should be
          correlated outwards to a SELECT that encloses another, which
          then encloses this one, correlation now works across multiple
          levels when explicit correlation is established via
          Select.correlate(), provided that the target select is
          somewhere along the chain contained by a WHERE/ORDER
          BY/columns clause, not just nested FROM clauses.  This makes
          Select.correlate() act more compatibly to that of
          0.7 again while still maintaining the new “smart” correlation.

        * When explicit correlation is not used, the usual “implicit”
          correlation limits its behavior to just the immediate
          enclosing SELECT, to maximize compatibility with 0.7
          applications, and also prevents correlation across nested
          FROMs in this case, maintaining compatibility with
          0.8.0/0.8.1.

        * The Select.correlate_except() method was not
          preventing the given FROM clauses from correlation in all
          cases, and also would cause FROM clauses to be incorrectly
          omitted entirely (more like what 0.7 would do), this has been
          fixed.

        * Calling ‘select.correlate_except(None)’ will enter all FROM
          clauses into correlation as would be expected.

     References: #2668(3), #2746(4)

   * `[sql] [bug]' ¶. Fixed bug whereby joining a select()
     of a table “A” with multiple foreign key paths to a table “B”, to
     that table “B”, would fail to produce the “ambiguous join
     condition” error that would be reported if you join table “A”
     directly to “B”; it would instead produce a join condition with
     multiple criteria.

     References: #2738(5)

   * `[sql] [bug] [reflection]' ¶. Fixed bug whereby using
     MetaData.reflect() across a remote schema as well as a
     local schema could produce wrong results in the case where both
     schemas had a table of the same name.

     References: #2728(6)

   * `[sql] [bug]' ¶. Removed the “not implemented”
     ‘__iter__()’ call from the base ColumnOperators class,
     while this was introduced in 0.8.0 to prevent an endless,
     memory-growing loop when one also implements a ‘__getitem__()’
     method on a custom operator and then calls erroneously ‘list()’ on
     that object, it had the effect of causing column elements to report
     that they were in fact iterable types which then throw an error
     when you try to iterate.  There’s no real way to have both sides
     here so we stick with Python best practices.  Careful with
     implementing ‘__getitem__()’ on your custom operators!

     References: #2726(7)

   * `[sql] [bug] [mssql]' ¶. Regression from this ticket
     caused the unsupported keyword “true” to render, added logic to
     convert this to 1/0 for SQL server.

     References: #2682(8)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2734

   (2) http://www.sqlalchemy.org/trac/ticket/2744

   (3) http://www.sqlalchemy.org/trac/ticket/2668

   (4) http://www.sqlalchemy.org/trac/ticket/2746

   (5) http://www.sqlalchemy.org/trac/ticket/2738

   (6) http://www.sqlalchemy.org/trac/ticket/2728

   (7) http://www.sqlalchemy.org/trac/ticket/2726

   (8) http://www.sqlalchemy.org/trac/ticket/2682

8.3.7.47 postgresql
...................

   * `[postgresql] [feature]' ¶. Support for PostgreSQL 9.2
     range types has been added.  Currently, no type translation is
     provided, so works directly with strings or psycopg2 2.5 range
     extension types at the moment.  Patch courtesy Chris Withers.

   * `[postgresql] [feature]' ¶. Added support for
     “AUTOCOMMIT” isolation when using the psycopg2 DBAPI. The keyword
     is available via the ‘isolation_level’ execution option.  Patch
     courtesy Roman Podolyaka.

     References: #2072(1)

   * `[postgresql] [bug]' ¶. The behavior of
     extract() has been simplified on the PostgreSQL dialect to no
     longer inject a hardcoded ‘::timestamp’ or similar cast into the
     given expression, as this interfered with types such as
     timezone-aware datetimes, but also does not appear to be at all
     necessary with modern versions of psycopg2.

     References: #2740(2)

   * `[postgresql] [bug]' ¶. Fixed bug in HSTORE type where
     keys/values that contained backslashed quotes would not be escaped
     correctly when using the “non native” (i.e.  non-psycopg2) means of
     translating HSTORE data.  Patch courtesy Ryan Kelly.

     References: #2766(3)

   * `[postgresql] [bug]' ¶. Fixed bug where the order of
     columns in a multi-column PostgreSQL index would be reflected in
     the wrong order.  Courtesy Roman Podolyaka.

     References: #2767(4)

   * `[postgresql] [bug]' ¶. Fixed the HSTORE type to
     correctly encode/decode for unicode.  This is always on, as the
     hstore is a textual type, and matches the behavior of psycopg2 when
     using Python 3.  Courtesy Dmitry Mugtasimov.

     References: #2735(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2072

   (2) http://www.sqlalchemy.org/trac/ticket/2740

   (3) http://www.sqlalchemy.org/trac/ticket/2766

   (4) http://www.sqlalchemy.org/trac/ticket/2767

   (5) http://www.sqlalchemy.org/trac/ticket/2735

8.3.7.48 mysql
..............

   * `[mysql] [feature]' ¶. The ‘mysql_length’ parameter
     used with Index can now be passed as a dictionary of
     column names/lengths, for use with composite indexes.  Big thanks
     to Roman Podolyaka for the patch.

     References: #2704(1)

   * `[mysql] [bug]' ¶. Fixed bug when using multi-table
     UPDATE where a supplemental table is a SELECT with its own bound
     parameters, where the positioning of the bound parameters would be
     reversed versus the statement itself when using MySQL’s special
     syntax.

     References: #2768(2)

   * `[mysql] [bug]' ¶. Added another conditional to the
     ‘mysql+gaerdbms’ dialect to detect so-called “development” mode,
     where we should use the ‘rdbms_mysqldb’ DBAPI. Patch courtesy Brett
     Slatkin.

     References: #2715(3)

   * `[mysql] [bug]' ¶. The ‘deferrable’ keyword argument on
     ForeignKey and ForeignKeyConstraint will not
     render the ‘DEFERRABLE’ keyword on the MySQL dialect.  For a long
     time we left this in place because a non-deferrable foreign key
     would act very differently than a deferrable one, but some
     environments just disable FKs on MySQL, so we’ll be less
     opinionated here.

     References: #2721(4)

   * `[mysql] [bug]' ¶. Updated mysqlconnector dialect to
     check for disconnect based on the apparent string message sent in
     the exception; tested against mysqlconnector 1.0.9.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2704

   (2) http://www.sqlalchemy.org/trac/ticket/2768

   (3) http://www.sqlalchemy.org/trac/ticket/2715

   (4) http://www.sqlalchemy.org/trac/ticket/2721

8.3.7.49 sqlite
...............

   * `[sqlite] [bug]' ¶. Added
     sqlalchemy.types.BIGINT to the list of type names that can
     be reflected by the SQLite dialect; courtesy Russell Stuart.

     References: #2764(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2764

8.3.7.50 mssql
..............

   * `[mssql] [bug]' ¶. When querying the information schema
     on SQL Server 2000, removed a CAST call that was added in 0.8.1 to
     help with driver issues, which apparently is not compatible on
     2000.  The CAST remains in place for SQL Server 2005 and greater.

     References: #2747(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2747

8.3.7.51 firebird
.................

   * `[firebird] [feature]' ¶. Added new flag
     ‘retaining=True’ to the kinterbasdb and fdb dialects.  This
     controls the value of the ‘retaining’ flag sent to the ‘commit()’
     and ‘rollback()’ methods of the DBAPI connection.  Due to
     historical concerns, this flag defaults to ‘True’ in 0.8.2, however
     in 0.9.0b1 this flag defaults to ‘False’.

     References: #2763(1)

   * `[firebird] [bug]' ¶. Type lookup when reflecting the
     Firebird types LONG and INT64 has been fixed so that LONG is
     treated as INTEGER, INT64 treated as BIGINT, unless the type has a
     “precision” in which case it’s treated as NUMERIC. Patch courtesy
     Russell Stuart.

     References: #2757(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2763

   (2) http://www.sqlalchemy.org/trac/ticket/2757

8.3.7.52 misc
.............

   * `[bug] [ext]' ¶. Fixed bug whereby if a composite type
     were set up with a function instead of a class, the mutable
     extension would trip up when it tried to check that column for
     being a MutableComposite. (which it isn’t).  Courtesy
     asldevi.

   * `[bug] [examples]' ¶. Fixed an issue with the
     “versioning” recipe whereby a many-to-one reference could produce a
     meaningless version for the target, even though it was not changed,
     when backrefs were present.  Patch courtesy Matt Chisholm.

   * `[bug] [examples]' ¶. Fixed a small bug in the dogpile
     example where the generation of SQL cache keys wasn’t applying
     deduping labels to the statement the same way Query
     normally does.

   * `[requirements]' ¶. The Python mock(1) library is now
     required in order to run the unit test suite.  While part of the
     standard library as of Python 3.3, previous Python installations
     will need to install this in order to run unit tests or to use the
     ‘sqlalchemy.testing’ package for external dialects.

   ---------- Footnotes ----------

   (1) https://pypi.python.org/pypi/mock

8.3.7.53 0.8.1
..............

Released: April 27, 2013

8.3.7.54 orm
............

   * `[orm] [feature]' ¶. Added a convenience method to
     Query that turns a query into an EXISTS subquery of the form
     ‘EXISTS (SELECT 1 FROM ... WHERE ...)’.

     References: #2673(1)

   * `[orm] [bug]' ¶. Fixes to the
     ‘sqlalchemy.ext.serializer’ extension, including that the “id”
     passed from the pickler is turned into a string to prevent against
     bytes being parsed on Py3K, as well as that ‘relationship()’ and
     ‘orm.join()’ constructs are now properly serialized.

     References: #2698(2)

   * `[orm] [bug]' ¶. A significant improvement to the inner
     workings of query.join(), such that the decisionmaking involved on
     how to join has been dramatically simplified.  New test cases now
     pass such as multiple joins extending from the middle of an already
     complex series of joins involving inheritance and such.  Joining
     from deeply nested subquery structures is still complicated and not
     without caveats, but with these improvements the edge cases are
     hopefully pushed even farther out to the edges.

     References: #2714(3)

   * `[orm] [bug]' ¶. Added a conditional to the unpickling
     process for ORM mapped objects, such that if the reference to the
     object were lost when the object was pickled, we don’t erroneously
     try to set up _sa_instance_state - fixes a NoneType error.

   * `[orm] [bug]' ¶. Fixed bug where many-to-many
     relationship with uselist=False would fail to delete the
     association row and raise an error if the scalar attribute were set
     to None.  This was a regression introduced by the changes for
     #2229(4).

     References: #2710(5)

   * `[orm] [bug]' ¶. Improved the behavior of instance
     management regarding the creation of strong references within the
     Session; an object will no longer have an internal reference cycle
     created if it’s in the transient state or moves into the detached
     state - the strong ref is created only when the object is attached
     to a Session and is removed when the object is detached.  This
     makes it somewhat safer for an object to have a ‘__del__()’ method,
     even though this is not recommended, as relationships with backrefs
     produce cycles too.  A warning has been added when a class with a
     ‘__del__()’ method is mapped.

     References: #2708(6)

   * `[orm] [bug]' ¶. Fixed bug whereby ORM would run the
     wrong kind of query when refreshing an inheritance-mapped class
     where the superclass was mapped to a non-Table object, like a
     custom join() or a select(), running a query that assumed a
     hierarchy that’s mapped to individual Table-per-class.

     References: #2697(7)

   * `[orm] [bug]' ¶. Fixed ‘__repr__()’ on mapper property
     constructs to work before the object is initialized, so that Sphinx
     builds with recent Sphinx versions can read them.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2673

   (2) http://www.sqlalchemy.org/trac/ticket/2698

   (3) http://www.sqlalchemy.org/trac/ticket/2714

   (4) http://www.sqlalchemy.org/trac/ticket/2229

   (5) http://www.sqlalchemy.org/trac/ticket/2710

   (6) http://www.sqlalchemy.org/trac/ticket/2708

   (7) http://www.sqlalchemy.org/trac/ticket/2697

8.3.7.55 orm declarative
........................

   * `[orm] [declarative] [bug]' ¶. Fixed indirect
     regression regarding has_inherited_table(), where since
     it considers the current class’ ‘__table__’, was sensitive to when
     it was called.  This is 0.7’s behavior also, but in 0.7 things
     tended to “work out” within events like ‘__mapper_args__()’.
     has_inherited_table() now only considers superclasses, so
     should return the same answer regarding the current class no matter
     when it’s called (obviously assuming the state of the superclass).

     References: #2656(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2656

8.3.7.56 sql
............

   * `[sql] [feature]' ¶. Loosened the check on
     dialect-specific argument names passed to Table(); since we want to
     support external dialects and also want to support args without a
     certain dialect being installed, it only checks the format of the
     arg now, rather than looking for that dialect in
     sqlalchemy.dialects.

   * `[sql] [bug] [mysql]' ¶. Fully implemented the IS and
     IS NOT operators with regards to the True/False constants.  An
     expression like ‘col.is_(True)’ will now render ‘col IS true’ on
     the target platform, rather than converting the True/ False
     constant to an integer bound parameter.  This allows the ‘is_()’
     operator to work on MySQL when given True/False constants.

     References: #2682(1)

   * `[sql] [bug]' ¶. A major fix to the way in which a
     select() object produces 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.

     References: #2702(2)

   * `[sql] [bug]' ¶. Fixed bug where disconnect detect on
     error would raise an attribute error if the error were being raised
     after the Connection object had already been closed.

     References: #2691(3)

   * `[sql] [bug]' ¶. Reworked internal exception raises
     that emit a rollback() before re-raising, so that the stack trace
     is preserved from sys.exc_info() before entering the rollback.
     This so that the traceback is preserved when using coroutine
     frameworks which may have switched contexts before the rollback
     function returns.

     References: #2703(4)

   * `[sql] [bug] [postgresql]' ¶. The _Binary base type now
     converts values through the bytes() callable when run on Python 3;
     in particular psycopg2 2.5 with Python 3.3 seems to now be
     returning the “memoryview” type, so this is converted to bytes
     before return.

   * `[sql] [bug]' ¶. Improvements to Connection
     auto-invalidation handling.  If a non-disconnect error occurs, but
     leads to a delayed disconnect error within error handling (happens
     with MySQL), the disconnect condition is detected.  The Connection
     can now also be closed when in an invalid state, meaning it will
     raise “closed” on next usage, and additionally the “close with
     result” feature will work even if the autorollback in an error
     handling routine fails and regardless of whether the condition is a
     disconnect or not.

     References: #2695(5)

   * `[sql] [bug]' ¶. Fixed bug whereby a DBAPI that can
     return “0” for cursor.lastrowid would not function correctly in
     conjunction with ‘ResultProxy.inserted_primary_key’.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2682

   (2) http://www.sqlalchemy.org/trac/ticket/2702

   (3) http://www.sqlalchemy.org/trac/ticket/2691

   (4) http://www.sqlalchemy.org/trac/ticket/2703

   (5) http://www.sqlalchemy.org/trac/ticket/2695

8.3.7.57 postgresql
...................

   * `[postgresql] [bug]' ¶. Opened up the checking for
     “disconnect” with psycopg2/libpq to check for all the various
     “disconnect” messages within the full exception hierarchy.
     Specifically the “closed the connection unexpectedly” message has
     now been seen in at least three different exception types.
     Courtesy Eli Collins.

     References: #2712(1)

   * `[postgresql] [bug]' ¶. The operators for the
     PostgreSQL ARRAY type supports input types of sets, generators,
     etc.  even when a dimension is not specified, by turning the given
     iterable into a collection unconditionally.

     References: #2681(2)

   * `[postgresql] [bug]' ¶. Added missing HSTORE type to
     postgresql type names so that the type can be reflected.

     References: #2680(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2712

   (2) http://www.sqlalchemy.org/trac/ticket/2681

   (3) http://www.sqlalchemy.org/trac/ticket/2680

8.3.7.58 mysql
..............

   * `[mysql] [bug]' ¶. Fixes to support the latest cymysql
     DBAPI, courtesy Hajime Nakagami.

   * `[mysql] [bug]' ¶. Improvements to the operation of the
     pymysql dialect on Python 3, including some important decode/bytes
     steps.  Issues remain with BLOB types due to driver issues.
     Courtesy Ben Trofatter.

     References: #2663(1)

   * `[mysql] [bug]' ¶. Updated a regexp to correctly
     extract error code on google app engine v1.7.5 and newer.  Courtesy
     Dan Ring.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2663

8.3.7.59 mssql
..............

   * `[mssql] [bug]' ¶. Part of a longer series of fixes
     needed for pyodbc+ mssql, a CAST to NVARCHAR(max) has been added to
     the bound parameter for the table name and schema name in all
     information schema queries to avoid the issue of comparing NVARCHAR
     to NTEXT, which seems to be rejected by the ODBC driver in some
     cases, such as FreeTDS (0.91 only?)  plus unicode bound parameters
     being passed.  The issue seems to be specific to the SQL Server
     information schema tables and the workaround is harmless for those
     cases where the problem doesn’t exist in the first place.

     References: #2355(1)

   * `[mssql] [bug]' ¶. Added support for additional
     “disconnect” messages to the pymssql dialect.  Courtesy John
     Anderson.

   * `[mssql] [bug]' ¶. Fixed Py3K bug regarding “binary”
     types and pymssql.  Courtesy Marc Abramowitz.

     References: #2683(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2355

   (2) http://www.sqlalchemy.org/trac/ticket/2683

8.3.7.60 misc
.............

   * `[bug] [examples]' ¶. Fixed a long-standing bug in the
     caching example, where the limit/offset parameter values wouldn’t
     be taken into account when computing the cache key.  The
     _key_from_query() function has been simplified to work directly
     from the final compiled statement in order to get at both the full
     statement as well as the fully processed parameter list.

8.3.7.61 0.8.0
..............

Released: March 9, 2013

     Note: There are some new behavioral changes as of 0.8.0 not present
     in 0.8.0b2.  They are present in the migration document as follows:

        * The consideration of a “pending” object as an “orphan” has been made more aggressive.

        * create_all() and drop_all() will now honor an empty list as such.

        * Correlation is now always context-specific.

8.3.7.62 orm
............

   * `[orm] [feature]' ¶. A meaningful
     QueryableAttribute.info attribute is added, which proxies
     down to the ‘.info’ attribute on either the Column
     object if directly present, or the MapperProperty
     otherwise.  The full behavior is documented and ensured by tests to
     remain stable.

     References: #2675(1)

   * `[orm] [feature]' ¶. Can set/change the “cascade”
     attribute on a relationship() construct after it’s been
     constructed already.  This is not a pattern for normal use but we
     like to change the setting for demonstration purposes in tutorials.

   * `[orm] [feature]' ¶. Added new helper function
     was_deleted(), returns True if the given object was the
     subject of a Session.delete() operation.

     References: #2658(2)

   * `[orm] [feature]' ¶. Extended the Runtime Inspection API
     system so that all Python descriptors
     associated with the ORM or its extensions can be retrieved.  This
     fulfills the common request of being able to inspect all
     QueryableAttribute descriptors in addition to extension types
     such as hybrid_property and AssociationProxy.
     See Mapper.all_orm_descriptors.

   * `[orm] [bug]' ¶. Improved checking for an existing
     backref name conflict during mapper configuration; will now test
     for name conflicts on superclasses and subclasses, in addition to
     the current mapper, as these conflicts break things just as much.
     This is new for 0.8, but see below for a warning that will also be
     triggered in 0.7.11.

     References: #2674(3)

   * `[orm] [bug]' ¶. Improved the error message emitted
     when a “backref loop” is detected, that is when an attribute event
     triggers a bidirectional assignment between two other attributes
     with no end.  This condition can occur not just when an object of
     the wrong type is assigned, but also when an attribute is
     mis-configured to backref into an existing backref pair.  Also in
     0.7.11.

     References: #2674(4)

   * `[orm] [bug]' ¶. A warning is emitted when a
     MapperProperty is assigned to a mapper that replaces an existing
     property, if the properties in question aren’t plain column-based
     properties.  Replacement of relationship properties is rarely
     (ever?)  what is intended and usually refers to a mapper
     mis-configuration.  Also in 0.7.11.

     References: #2674(5)

   * `[orm] [bug]' ¶. A clear error message is emitted if an
     event handler attempts to emit SQL on a Session within the
     after_commit() handler, where there is not a viable transaction in
     progress.

     References: #2662(6)

   * `[orm] [bug]' ¶. Detection of a primary key change
     within the process of cascading a natural primary key update will
     succeed even if the key is composite and only some of the
     attributes have changed.

     References: #2665(7)

   * `[orm] [bug]' ¶. An object that’s deleted from a
     session will be de-associated with that session fully after the
     transaction is committed, that is the object_session()
     function will return None.

     References: #2658(8)

   * `[orm] [bug]' ¶. Fixed bug whereby
     Query.yield_per() would set the execution options
     incorrectly, thereby breaking subsequent usage of the
     Query.execution_options() method.  Courtesy Ryan Kelly.

     References: #2661(9)

   * `[orm] [bug]' ¶. Fixed the consideration of the
     ‘between()’ operator so that it works correctly with the new
     relationship local/remote system.

     References: #1768(10)

   * `[orm] [bug]' ¶ the consideration of a pending object
     as an “orphan” has been modified to more closely match the behavior
     as that of persistent objects, which is that the object is expunged
     from the Session as soon as it is de-associated from any
     of its orphan-enabled parents.  Previously, the pending object
     would be expunged only if de-associated from all of its
     orphan-enabled parents.  The new flag ‘legacy_is_orphan’ is added
     to mapper() which re-establishes the legacy behavior.

     See the change note and example case at The consideration of a “pending” object as an “orphan” has been made more aggressive
     for a detailed discussion of this change.

     References: #2655(11)

   * `[orm] [bug]' ¶. Fixed the (most likely never used)
     “@collection.link” collection method, which fires off each time the
     collection is associated or de-associated with a mapped object -
     the decorator was not tested or functional.  The decorator method
     is now named ‘collection.linker()’ though the name “link” remains
     for backwards compatibility.  Courtesy Luca Wehrstedt.

     References: #2653(12)

   * `[orm] [bug]' ¶. Made some fixes to the system of
     producing custom instrumented collections, mainly that the usage of
     the @collection decorators will now honor the __mro__ of the given
     class, applying the logic of the sub-most classes’ version of a
     particular collection method.  Previously, it wasn’t predictable
     when subclassing an existing instrumented class such as
     MappedCollection whether or not custom methods would resolve
     correctly.

     References: #2654(13)

   * `[orm] [bug]' ¶. Fixed potential memory leak which
     could occur if an arbitrary number of sessionmaker
     objects were created.  The anonymous subclass created by the
     sessionmaker, when dereferenced, would not be garbage collected due
     to remaining class-level references from the event package.  This
     issue also applies to any custom system that made use of ad-hoc
     subclasses in conjunction with an event dispatcher.  Also in
     0.7.10.

     References: #2650(14)

   * `[orm] [bug]' ¶. Query.merge_result() can
     now load rows from an outer join where an entity may be ‘None’
     without throwing an error.  Also in 0.7.10.

     References: #2640(15)

   * `[orm] [bug]' ¶. Fixes to the “dynamic” loader on
     relationship(), includes that backrefs will work properly even
     when autoflush is disabled, history events are more accurate in
     scenarios where multiple add/remove of the same object occurs.

     References: #2637(16)

   * `[orm] [removed]' ¶. The undocumented (and hopefully
     unused) system of producing custom collections using an
     ‘__instrumentation__’ datastructure associated with the collection
     has been removed, as this was a complex and untested feature which
     was also essentially redundant versus the decorator approach.
     Other internal simplifications to the orm.collections module have
     been made as well.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2675

   (2) http://www.sqlalchemy.org/trac/ticket/2658

   (3) http://www.sqlalchemy.org/trac/ticket/2674

   (4) http://www.sqlalchemy.org/trac/ticket/2674

   (5) http://www.sqlalchemy.org/trac/ticket/2674

   (6) http://www.sqlalchemy.org/trac/ticket/2662

   (7) http://www.sqlalchemy.org/trac/ticket/2665

   (8) http://www.sqlalchemy.org/trac/ticket/2658

   (9) http://www.sqlalchemy.org/trac/ticket/2661

   (10) http://www.sqlalchemy.org/trac/ticket/1768

   (11) http://www.sqlalchemy.org/trac/ticket/2655

   (12) http://www.sqlalchemy.org/trac/ticket/2653

   (13) http://www.sqlalchemy.org/trac/ticket/2654

   (14) http://www.sqlalchemy.org/trac/ticket/2650

   (15) http://www.sqlalchemy.org/trac/ticket/2640

   (16) http://www.sqlalchemy.org/trac/ticket/2637

8.3.7.63 sql
............

   * `[sql] [feature]' ¶. Added a new argument to
     Enum and its base SchemaType. ‘inherit_schema’.
     When set to ‘True’, the type will set its ‘schema’ attribute of
     that of the Table to which it is associated.  This also
     occurs during a Table.tometadata() operation; the
     SchemaType is now copied in all cases when
     Table.tometadata() happens, and if ‘inherit_schema=True’,
     the type will take on the new schema name passed to the method.
     The ‘schema’ is important when used with the PostgreSQL backend, as
     the type results in a ‘CREATE TYPE’ statement.

     References: #2657(1)

   * `[sql] [feature]' ¶. Index now supports
     arbitrary SQL expressions and/or functions, in addition to straight
     columns.  Common modifiers include using ‘somecolumn.desc()’ for a
     descending index and ‘func.lower(somecolumn)’ for a
     case-insensitive index, depending on the capabilities of the target
     backend.

     References: #695(2)

   * `[sql] [bug]' ¶. The behavior of SELECT correlation has
     been improved such that the Select.correlate() and
     Select.correlate_except() methods, as well as their ORM
     analogues, will still retain “auto-correlation” behavior in that
     the FROM clause is modified only if the output would be legal SQL;
     that is, the FROM clause is left intact if the correlated SELECT is
     not used in the context of an enclosing SELECT inside of the WHERE,
     columns, or HAVING clause.  The two methods now only specify
     conditions to the default “auto correlation”, rather than absolute
     FROM lists.

     References: #2668(3)

   * `[sql] [bug]' ¶. Fixed a bug regarding column
     annotations which in particular could impact some usages of the new
     remote() and ‘local()’ annotation functions, where
     annotations could be lost when the column were used in a subsequent
     expression.

     References: #1768(4), #2660(5)

   * `[sql] [bug]' ¶. The ColumnOperators.in_().
     operator will now coerce values of ‘None’ to null().

     References: #2496(6)

   * `[sql] [bug]' ¶. Fixed bug where
     Table.tometadata() would fail if a Column had
     both a foreign key as well as an alternate “.key” name for the
     column.  Also in 0.7.10.

     References: #2643(7)

   * `[sql] [bug]' ¶ insert().returning() raises an
     informative CompileError if attempted to compile on a dialect that
     doesn’t support RETURNING.

     References: #2629(8)

   * `[sql] [bug]' ¶. Tweaked the “REQUIRED” symbol used by
     the compiler to identify INSERT/UPDATE bound parameters that need
     to be passed, so that it’s more easily identifiable when writing
     custom bind-handling code.

     References: #2648(9)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2657

   (2) http://www.sqlalchemy.org/trac/ticket/695

   (3) http://www.sqlalchemy.org/trac/ticket/2668

   (4) http://www.sqlalchemy.org/trac/ticket/1768

   (5) http://www.sqlalchemy.org/trac/ticket/2660

   (6) http://www.sqlalchemy.org/trac/ticket/2496

   (7) http://www.sqlalchemy.org/trac/ticket/2643

   (8) http://www.sqlalchemy.org/trac/ticket/2629

   (9) http://www.sqlalchemy.org/trac/ticket/2648

8.3.7.64 schema
...............

   * `[schema] [bug]' ¶. See MetaData.create_all().
     and MetaData.drop_all() will now accommodate an empty
     list as an instruction to not create/drop any items, rather than
     ignoring the collection.

     References: #2664(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2664

8.3.7.65 postgresql
...................

   * `[postgresql] [feature]' ¶. Added ‘Comparator.any()’
     and ‘Comparator.all()’ methods, as well as standalone expression
     constructs.  Big thanks to Audrius Kažukauskas for the terrific
     work here.

   * `[postgresql] [bug]' ¶. Fixed bug in array()
     construct whereby using it inside of an insert()
     construct would produce an error regarding a parameter issue in the
     ‘self_group()’ method.

8.3.7.66 mysql
..............

   * `[mysql] [feature]' ¶. New dialect for CyMySQL added,
     courtesy Hajime Nakagami.

   * `[mysql] [feature]' ¶. GAE dialect now accepts
     username/password arguments in the URL, courtesy Owen Nelson.

   * `[mysql] [bug] [gae]' ¶. Added a conditional import to
     the ‘gaerdbms’ dialect which attempts to import rdbms_apiproxy vs.
     rdbms_googleapi to work on both dev and production platforms.  Also
     now honors the ‘instance’ attribute.  Courtesy Sean Lynch.  Also in
     0.7.10.

     References: #2649(1)

   * `[mysql] [bug]' ¶. GAE dialect won’t fail on None match
     if the error code can’t be extracted from the exception throw;
     courtesy Owen Nelson.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2649

8.3.7.67 mssql
..............

   * `[mssql] [feature]' ¶. Added ‘mssql_include’ and
     ‘mssql_clustered’ options to Index, renders the
     ‘INCLUDE’ and ‘CLUSTERED’ keywords, respectively.  Courtesy Derek
     Harland.

   * `[mssql] [feature]' ¶. DDL for IDENTITY columns is now
     supported on non-primary key columns, by establishing a
     Sequence construct on any integer column.  Courtesy Derek
     Harland.

     References: #2644(1)

   * `[mssql] [bug]' ¶. Added a py3K conditional around
     unnecessary .decode() call in mssql information schema, fixes
     reflection in Py3K. Also in 0.7.10.

     References: #2638(2)

   * `[mssql] [bug]' ¶. Fixed a regression whereby the
     “collation” parameter of the character types CHAR, NCHAR, etc.
     stopped working, as “collation” is now supported by the base string
     types.  The TEXT, NCHAR, CHAR, VARCHAR types within the MSSQL
     dialect are now synonyms for the base types.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2644

   (2) http://www.sqlalchemy.org/trac/ticket/2638

8.3.7.68 oracle
...............

   * `[oracle] [bug]' ¶. The cx_oracle dialect will no
     longer run the bind parameter names through ‘encode()’, as this is
     not valid on Python 3, and prevented statements from functioning
     correctly on Python 3.  We now encode only if
     ‘supports_unicode_binds’ is False, which is not the case for
     cx_oracle when at least version 5 of cx_oracle is used.

8.3.7.69 misc
.............

   * `[bug] [tests]' ¶. Fixed an import of “logging” in
     test_execute which was not working on some linux platforms.  Also
     in 0.7.11.

     References: #2669(1)

   * `[bug] [examples]' ¶. Fixed a regression in the
     examples/dogpile_caching example which was due to the change in
     #2614(2).

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2669

   (2) http://www.sqlalchemy.org/trac/ticket/2614

8.3.7.70 0.8.0b2
................

Released: December 14, 2012

8.3.7.71 orm
............

   * `[orm] [feature]' ¶. Added ‘KeyedTuple._asdict()’ and
     ‘KeyedTuple._fields’ to the ‘KeyedTuple’ class to provide some
     degree of compatibility with the Python standard library
     ‘collections.namedtuple()’.

     References: #2601(1)

   * `[orm] [feature]' ¶. Allow synonyms to be used when
     defining primary and secondary joins for relationships.

   * `[orm] [feature] [extensions]' ¶. The
     sqlalchemy.ext.mutable extension now includes the example
     MutableDict class as part of the extension.

   * `[orm] [bug]' ¶. The Query.select_from().
     method can now be used with a aliased() construct
     without it interfering with the entities being selected.
     Basically, a statement like this:

          ua = aliased(User)
          session.query(User.name).select_from(ua).join(User, User.name > ua.name)

     Will maintain the columns clause of the SELECT as coming from the
     unaliased “user”, as specified; the select_from only takes place in
     the FROM clause:

          SELECT users.name AS users_name FROM users AS users_1
          JOIN users ON users.name < users_1.name

     Note that this behavior is in contrast to the original, older use
     case for Query.select_from(), which is that of restating
     the mapped entity in terms of a different selectable:

          session.query(User.name).\
            select_from(user_table.select().where(user_table.c.id > 5))

     Which produces:

          SELECT anon_1.name AS anon_1_name FROM (SELECT users.id AS id,
          users.name AS name FROM users WHERE users.id > :id_1) AS anon_1

     It was the “aliasing” behavior of the latter use case that was
     getting in the way of the former use case.  The method now
     specifically considers a SQL expression like select() or
     alias() separately from a mapped entity like a
     aliased() construct.

     References: #2635(2)

   * `[orm] [bug]' ¶. The MutableComposite type
     did not allow for the MutableBase.coerce() method to be
     used, even though the code seemed to indicate this intent, so this
     now works and a brief example is added.  As a side-effect, the
     mechanics of this event handler have been changed so that new
     MutableComposite types no longer add per-type global event
     handlers.  Also in 0.7.10.

     References: #2624(3)

   * `[orm] [bug]' ¶. A second overhaul of aliasing/internal
     pathing mechanics now allows two subclasses to have different
     relationships of the same name, supported with subquery or joined
     eager loading on both simultaneously when a full polymorphic load
     is used.

     References: #2614(4)

   * `[orm] [bug]' ¶. Fixed bug whereby a multi-hop
     subqueryload within a particular with_polymorphic load would
     produce a KeyError.  Takes advantage of the same internal pathing
     overhaul as #2614(5).

     References: #2617(6)

   * `[orm] [bug]' ¶. Fixed regression where query.update()
     would produce an error if an object matched by the “fetch”
     synchronization strategy wasn’t locally present.  Courtesy Scott
     Torborg.

     References: #2602(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2601

   (2) http://www.sqlalchemy.org/trac/ticket/2635

   (3) http://www.sqlalchemy.org/trac/ticket/2624

   (4) http://www.sqlalchemy.org/trac/ticket/2614

   (5) http://www.sqlalchemy.org/trac/ticket/2614

   (6) http://www.sqlalchemy.org/trac/ticket/2617

   (7) http://www.sqlalchemy.org/trac/ticket/2602

8.3.7.72 engine
...............

   * `[engine] [feature]' ¶. The Connection.connect()
     and ‘Connection.contextual_connect()’ methods now return a
     “branched” version so that the Connection.close()
     method can be called on the returned connection without affecting
     the original.  Allows symmetry when using Engine and
     Connection objects as context managers:

          with conn.connect() as c: # leaves the Connection open
            c.execute("...")

          with engine.connect() as c:  # closes the Connection
            c.execute("...")

   * `[engine] [bug]' ¶. Fixed MetaData.reflect()
     to correctly use the given Connection, if given,
     without opening a second connection from that connection’s
     Engine.

     This change is also `backported' to: 0.7.10

     References: #2604(1)

   * `[engine]' ¶. The “reflect=True” argument to
     MetaData is deprecated.  Please use the
     MetaData.reflect() method.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2604

8.3.7.73 sql
............

   * `[sql] [feature]' ¶. The Insert construct
     now supports multi-valued inserts, that is, an INSERT that renders
     like “INSERT INTO table VALUES (…), (…), …”.  Supported by
     PostgreSQL, SQLite, and MySQL. Big thanks to Idan Kamara for doing
     the legwork on this one.

     See also
     ........

     See Multiple-VALUES support for Insert.

     References: #2623(1)

   * `[sql] [bug]' ¶. Fixed bug where using
     server_onupdate=<FetchedValue|DefaultClause> without passing the
     “for_update=True” flag would apply the default object to the
     server_default, blowing away whatever was there.  The explicit
     for_update=True argument shouldn’t be needed with this usage
     (especially since the documentation shows an example without it
     being used) so it is now arranged internally using a copy of the
     given default object, if the flag isn’t set to what corresponds to
     that argument.

     This change is also `backported' to: 0.7.10

     References: #2631(2)

   * `[sql] [bug]' ¶. Fixed a regression caused by #2410(3)
     whereby a CheckConstraint would apply itself back to
     the original table during a Table.tometadata()
     operation, as it would parse the SQL expression for a parent table.
     The operation now copies the given expression to correspond to the
     new table.

     References: #2633(4)

   * `[sql] [bug]' ¶. Fixed bug whereby using a label_length
     on dialect that was smaller than the size of actual column
     identifiers would fail to render the columns correctly in a SELECT
     statement.

     References: #2610(5)

   * `[sql] [bug]' ¶. The DECIMAL type now
     honors the “precision” and “scale” arguments when rendering DDL.

     References: #2618(6)

   * `[sql] [bug]' ¶. Made an adjustment to the “boolean”,
     (i.e.  ‘__nonzero__’) evaluation of binary expressions, i.e.  ‘x1
     == x2’, such that the “auto-grouping” applied by
     BinaryExpression in some cases won’t get in the way of this
     comparison.  Previously, an expression like:

          expr1 = mycolumn > 2
          bool(expr1 == expr1)

     Would evaluate as ‘False’, even though this is an identity
     comparison, because ‘mycolumn > 2’ would be “grouped” before being
     placed into the BinaryExpression, thus changing its
     identity.  BinaryExpression now keeps track of the
     “original” objects passed in.  Additionally the ‘__nonzero__’
     method now only returns if the operator is ‘==’ or ‘!=’ - all
     others raise ‘TypeError’.

     References: #2621(7)

   * `[sql] [bug]' ¶. Fixed a gotcha where inadvertently
     calling list() on a ColumnElement would go into an
     endless loop, if ColumnOperators.__getitem__() were
     implemented.  A new NotImplementedError is emitted via
     ‘__iter__()’.

   * `[sql] [bug]' ¶. Fixed bug in type_coerce() whereby
     typing information could be lost if the statement were used as a
     subquery inside of another statement, as well as other similar
     situations.  Among other things, would cause typing information to
     be lost when the Oracle/mssql dialects would apply limit/offset
     wrappings.

     References: #2603(8)

   * `[sql] [bug]' ¶. Fixed bug whereby the “.key” of a
     Column wasn’t being used when producing a “proxy” of the column
     against a selectable.  This probably didn’t occur in 0.7 since 0.7
     doesn’t respect the “.key” in a wider range of scenarios.

     References: #2597(9)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2623

   (2) http://www.sqlalchemy.org/trac/ticket/2631

   (3) http://www.sqlalchemy.org/trac/ticket/2410

   (4) http://www.sqlalchemy.org/trac/ticket/2633

   (5) http://www.sqlalchemy.org/trac/ticket/2610

   (6) http://www.sqlalchemy.org/trac/ticket/2618

   (7) http://www.sqlalchemy.org/trac/ticket/2621

   (8) http://www.sqlalchemy.org/trac/ticket/2603

   (9) http://www.sqlalchemy.org/trac/ticket/2597

8.3.7.74 postgresql
...................

   * `[postgresql] [feature]' ¶. HSTORE is now
     available in the PostgreSQL dialect.  Will also use psycopg2’s
     extensions if available.  Courtesy Audrius Kažukauskas.

     References: #2606(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2606

8.3.7.75 sqlite
...............

   * `[sqlite] [bug]' ¶. More adjustment to this SQLite
     related issue which was released in 0.7.9, to intercept legacy
     SQLite quoting characters when reflecting foreign keys.  In
     addition to intercepting double quotes, other quoting characters
     such as brackets, backticks, and single quotes are now also
     intercepted.

     This change is also `backported' to: 0.7.10

     References: #2568(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2568

8.3.7.76 mssql
..............

   * `[mssql] [feature]' ¶. Support for reflection of the
     “name” of primary key constraints added, courtesy Dave Moore.

     References: #2600(1)

   * `[mssql] [bug]' ¶. Fixed bug whereby using “key” with
     Column in conjunction with “schema” for the owning Table would fail
     to locate result rows due to the MSSQL dialect’s “schema rendering”
     logic’s failure to take .key into account.

     This change is also `backported' to: 0.7.10

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2600

8.3.7.77 oracle
...............

   * `[oracle] [bug]' ¶. Fixed table reflection for Oracle
     when accessing a synonym that refers to a DBLINK remote database;
     while the syntax has been present in the Oracle dialect for some
     time, up until now it has never been tested.  The syntax has been
     tested against a sample database linking to itself, however there’s
     still some uncertainty as to what should be used for the “owner”
     when querying the remote database for table information.
     Currently, the value of “username” from user_db_links is used to
     match the “owner”.

     References: #2619(1)

   * `[oracle] [bug]' ¶. The Oracle LONG type, while an
     unbounded text type, does not appear to use the cx_Oracle.LOB type
     when result rows are returned, so the dialect has been repaired to
     exclude LONG from having cx_Oracle.LOB filtering applied.  Also in
     0.7.10.

     References: #2620(2)

   * `[oracle] [bug]' ¶. Repaired the usage of ‘.prepare()’
     in conjunction with cx_Oracle so that a return value of ‘False’
     will result in no call to ‘connection.commit()’, hence avoiding “no
     transaction” errors.  Two-phase transactions have now been shown to
     work in a rudimental fashion with SQLAlchemy and cx_oracle, however
     are subject to caveats observed with the driver; check the
     documentation for details.  Also in 0.7.10.

     References: #2611(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2619

   (2) http://www.sqlalchemy.org/trac/ticket/2620

   (3) http://www.sqlalchemy.org/trac/ticket/2611

8.3.7.78 firebird
.................

   * `[firebird] [bug]' ¶. Added missing import for “fdb” to
     the experimental “firebird+fdb” dialect.

     References: #2622(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2622

8.3.7.79 misc
.............

   * `[feature] [sybase]' ¶. Reflection support has been
     added to the Sybase dialect.  Big thanks to Ben Trofatter for all
     the work developing and testing this.

     References: #1753(1)

   * `[feature] [pool]' ¶. The Pool will now
     log all connection.close() operations equally, including closes
     which occur for invalidated connections, detached connections, and
     connections beyond the pool capacity.

   * `[feature] [pool]' ¶. The Pool now
     consults the Dialect for functionality regarding how
     the connection should be “auto rolled back”, as well as closed.
     This grants more control of transaction scope to the dialect, so
     that we will be better able to implement transactional workarounds
     like those potentially needed for pysqlite and cx_oracle.

     References: #2611(2)

   * `[feature] [pool]' ¶. Added new
     PoolEvents.reset() hook to capture the event before a
     connection is auto-rolled back, upon return to the pool.  Together
     with ConnectionEvents.rollback() this allows all
     rollback events to be intercepted.

   * `[informix]' ¶. Some cruft regarding informix
     transaction handling has been removed, including a feature that
     would skip calling commit()/rollback() as well as some hardcoded
     isolation level assumptions on begin()..  The status of this
     dialect is not well understood as we don’t have any users working
     with it, nor any access to an Informix database.  If someone with
     access to Informix wants to help test this dialect, please let us
     know.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1753

   (2) http://www.sqlalchemy.org/trac/ticket/2611

8.3.7.80 0.8.0b1
................

Released: October 30, 2012

8.3.7.81 general
................

   * `[general] [removed]' ¶. The “sqlalchemy.exceptions”
     synonym for “sqlalchemy.exc” is removed fully.

     References: #2433(1)

   * `[general]' ¶. SQLAlchemy 0.8 now targets Python 2.5
     and above.  Python 2.4 is no longer supported.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2433

8.3.7.82 orm
............

   * `[orm] [feature]' ¶. Major rewrite of relationship()
     internals now allow join conditions which include columns pointing
     to themselves within composite foreign keys.  A new API for very
     specialized primaryjoin conditions is added, allowing conditions
     based on SQL functions, CAST, etc.  to be handled by placing the
     annotation functions remote() and foreign() inline within the
     expression when necessary.  Previous recipes using the semi-private
     _local_remote_pairs approach can be upgraded to this new approach.

     See also
     ........

     See Rewritten _orm.relationship() mechanics.

     References: #1401(1)

   * `[orm] [feature]' ¶. New standalone function
     with_polymorphic() provides the functionality of
     query.with_polymorphic() in a standalone form.  It can be applied
     to any entity within a query, including as the target of a join in
     place of the “of_type()” modifier.

     References: #2333(2)

   * `[orm] [feature]' ¶. The of_type() construct on
     attributes now accepts aliased() class constructs as well as
     with_polymorphic constructs, and works with query.join(), any(),
     has(), and also eager loaders subqueryload(), joinedload(),
     contains_eager()

     References: #1106(3), #2438(4)

   * `[orm] [feature]' ¶. Improvements to event listening
     for mapped classes allows that unmapped classes can be specified
     for instance- and mapper-events.  The established events will be
     automatically set up on subclasses of that class when the
     propagate=True flag is passed, and the events will be set up for
     that class itself if and when it is ultimately mapped.

     References: #2585(5)

   * `[orm] [feature]' ¶. The “deferred declarative
     reflection” system has been moved into the declarative extension
     itself, using the new DeferredReflection class.  This class is now
     tested with both single and joined table inheritance use cases.

     References: #2485(6)

   * `[orm] [feature]' ¶. Added new core function
     “inspect()”, which serves as a generic gateway to introspection
     into mappers, objects, others.  The Mapper and InstanceState
     objects have been enhanced with a public API that allows inspection
     of mapped attributes, including filters for column-bound or
     relationship-bound properties, inspection of current object state,
     history of attributes, etc.

     References: #2208(7)

   * `[orm] [feature]' ¶. Calling rollback() within a
     session.begin_nested() will now only expire those objects that had
     net changes within the scope of that transaction, that is objects
     which were dirty or were modified on a flush.  This allows the
     typical use case for begin_nested(), that of altering a small
     subset of objects, to leave in place the data from the larger
     enclosing set of objects that weren’t modified in that
     sub-transaction.

     References: #2452(8)

   * `[orm] [feature]' ¶. Added utility feature
     Session.enable_relationship_loading(), supersedes
     relationship.load_on_pending.  Both features should be avoided,
     however.

     References: #2372(9)

   * `[orm] [feature]' ¶. Added support for .info dictionary
     argument to column_property(), relationship(), composite().  All
     MapperProperty classes have an auto-creating .info dict available
     overall.

   * `[orm] [feature]' ¶. Adding/removing None from a mapped
     collection now generates attribute events.  Previously, a None
     append would be ignored in some cases.  Related to.

     References: #2229(10)

   * `[orm] [feature]' ¶. The presence of None in a mapped
     collection now raises an error during flush.  Previously, None
     values in collections would be silently ignored.

     References: #2229(11)

   * `[orm] [feature]' ¶. The Query.update() method is now
     more lenient as to the table being updated.  Plain Table objects
     are better supported now, and additional a joined-inheritance
     subclass may be used with update(); the subclass table will be the
     target of the update, and if the parent table is referenced in the
     WHERE clause, the compiler will call upon UPDATE..FROM syntax as
     allowed by the dialect to satisfy the WHERE clause.  MySQL’s
     multi-table update feature is also supported if columns are
     specified by object in the “values” dictionary.  PG’s DELETE..USING
     is also not available in Core yet.

   * `[orm] [feature]' ¶. New session events
     after_transaction_create and after_transaction_end allows tracking
     of new SessionTransaction objects.  If the object is inspected, can
     be used to determine when a session first becomes active and when
     it deactivates.

   * `[orm] [feature]' ¶. The Query can now load
     entity/scalar-mixed “tuple” rows that contain types which aren’t
     hashable, by setting the flag “hashable=False” on the corresponding
     TypeEngine object in use.  Custom types that return unhashable
     types (typically lists) can set this flag to False.

     References: #2592(12)

   * `[orm] [feature]' ¶. Query now “auto correlates” by
     default in the same way as select() does.  Previously, a Query used
     as a subquery in another would require the correlate() method be
     called explicitly in order to correlate a table on the inside to
     the outside.  As always, correlate(None) disables correlation.

     References: #2179(13)

   * `[orm] [feature]' ¶. The after_attach event is now
     emitted after the object is established in Session.new or
     Session.identity_map upon Session.add(), Session.merge(), etc., so
     that the object is represented in these collections when the event
     is called.  Added before_attach event to accommodate use cases that
     need autoflush w pre-attached object.

     References: #2464(14)

   * `[orm] [feature]' ¶. The Session will produce warnings
     when unsupported methods are used inside the “execute” portion of
     the flush.  These are the familiar methods add(), delete(), etc.
     as well as collection and related-object manipulations, as called
     within mapper-level flush events like after_insert(),
     after_update(), etc.  It’s been prominently documented for a long
     time that SQLAlchemy cannot guarantee results when the Session is
     manipulated within the execution of the flush plan, however users
     are still doing it, so now there’s a warning.  Maybe someday the
     Session will be enhanced to support these operations inside of the
     flush, but for now, results can’t be guaranteed.

   * `[orm] [feature]' ¶. ORM entities can be passed to the
     core select() construct as well as to the select_from(),
     correlate(), and correlate_except() methods of select(), where they
     will be unwrapped into selectables.

     References: #2245(15)

   * `[orm] [feature]' ¶. Some support for auto-rendering of
     a relationship join condition based on the mapped attribute, with
     usage of core SQL constructs.  E.g.
     select([SomeClass]).where(SomeClass.somerelationship) would render
     SELECT from “someclass” and use the primaryjoin of
     “somerelationship” as the WHERE clause.  This changes the previous
     meaning of “SomeClass.somerelationship” when used in a core SQL
     context; previously, it would “resolve” to the parent selectable,
     which wasn’t generally useful.  Also works with query.filter().
     Related to.

     References: #2245(16)

   * `[orm] [feature]' ¶. The registry of classes in
     declarative_base() is now a WeakValueDictionary.  So subclasses of
     “Base” that are dereferenced will be garbage collected, `if they
     are not referred to by any other mappers/superclass mappers'.  See
     the next note for this ticket.

     References: #2526(17)

   * `[orm] [feature]' ¶. Conflicts between columns on
     single-inheritance declarative subclasses, with or without using a
     mixin, can be resolved using a new @declared_attr usage described
     in the documentation.

     References: #2472(18)

   * `[orm] [feature]' ¶ declared_attr can now be used on
     non-mixin classes, even though this is generally only useful for
     single-inheritance subclass column conflict resolution.

     References: #2472(19)

   * `[orm] [feature]' ¶ declared_attr can now be used with
     attributes that are not Column or MapperProperty; including any
     user-defined value as well as association proxy objects.

     References: #2517(20)

   * `[orm] [feature]' ¶. `Very limited' support for
     inheriting mappers to be GC’ed when the class itself is deferenced.
     The mapper must not have its own table (i.e.  single table inh
     only) without polymorphic attributes in place.  This allows for the
     use case of creating a temporary subclass of a declarative mapped
     class, with no table or mapping directives of its own, to be
     garbage collected when dereferenced by a unit test.

     References: #2526(21)

   * `[orm] [feature]' ¶. Declarative now maintains a
     registry of classes by string name as well as by full
     module-qualified name.  Multiple classes with the same name can now
     be looked up based on a module-qualified string within
     relationship().  Simple class name lookups where more than one
     class shares the same name now raises an informative error message.

     References: #2338(22)

   * `[orm] [feature]' ¶. Can now provide class-bound
     attributes that override columns which are of any non-ORM type, not
     just descriptors.

     References: #2535(23)

   * `[orm] [feature]' ¶. Added with_labels and
     reduce_columns keyword arguments to Query.subquery(), to provide
     two alternate strategies for producing queries with uniquely- named
     columns.  .

     References: #1729(24)

   * `[orm] [feature]' ¶. A warning is emitted when a
     reference to an instrumented collection is no longer associated
     with the parent class due to expiration/attribute
     refresh/collection replacement, but an append or remove operation
     is received on the now-detached collection.

     References: #2476(25)

   * `[orm] [bug]' ¶. ORM will perform extra effort to
     determine that an FK dependency between two tables is not
     significant during flush if the tables are related via joined
     inheritance and the FK dependency is not part of the
     inherit_condition, saves the user a use_alter directive.

     References: #2527(26)

   * `[orm] [bug]' ¶. The instrumentation events
     class_instrument(), class_uninstrument(), and
     attribute_instrument() will now fire off only for descendant
     classes of the class assigned to listen().  Previously, an event
     listener would be assigned to listen for all classes in all cases
     regardless of the “target” argument passed.

     References: #2590(27)

   * `[orm] [bug]' ¶ with_polymorphic() produces JOINs in
     the correct order and with correct inheriting tables in the case of
     sending multi-level subclasses in an arbitrary order or with
     intermediary classes missing.

     References: #1900(28)

   * `[orm] [bug]' ¶. Improvements to joined/subquery eager
     loading dealing with chains of subclass entities sharing a common
     base, with no specific “join depth” provided.  Will chain out to
     each subclass mapper individually before detecting a “cycle”,
     rather than considering the base class to be the source of the
     “cycle”.

     References: #2481(29)

   * `[orm] [bug]' ¶. The “passive” flag on
     Session.is_modified() no longer has any effect.  is_modified() in
     all cases looks only at local in-memory modified flags and will not
     emit any SQL or invoke loader callables/initializers.

     References: #2320(30)

   * `[orm] [bug]' ¶. The warning emitted when using
     delete-orphan cascade with one-to-many or many-to-many without
     single-parent=True is now an error.  The ORM would fail to function
     subsequent to this warning in any case.

     References: #2405(31)

   * `[orm] [bug]' ¶. Lazy loads emitted within flush events
     such as before_flush(), before_update(), etc.  will now function as
     they would within non-event code, regarding consideration of the
     PK/FK values used in the lazy-emitted query.  Previously, special
     flags would be established that would cause lazy loads to load
     related items based on the “previous” value of the parent PK/FK
     values specifically when called upon within a flush; the signal to
     load in this way is now localized to where the unit of work
     actually needs to load that way.  Note that the UOW does sometimes
     load these collections before the before_update() event is called,
     so the usage of “passive_updates” or not can affect whether or not
     a collection will represent the “old” or “new” data, when accessed
     within a flush event, based on when the lazy load was emitted.  The
     change is backwards incompatible in the exceedingly small chance
     that user event code depended on the old behavior.

     References: #2350(32)

   * `[orm] [bug]' ¶. Continuing regarding extra state
     post-flush due to event listeners; any states that are marked as
     “dirty” from an attribute perspective, usually via column-attribute
     set events within after_insert(), after_update(), etc., will get
     the “history” flag reset in all cases, instead of only those
     instances that were part of the flush.  This has the effect that
     this “dirty” state doesn’t carry over after the flush and won’t
     result in UPDATE statements.  A warning is emitted to this effect;
     the set_committed_state() method can be used to assign attributes
     on objects without producing history events.

     References: #2566(33), #2582(34)

   * `[orm] [bug]' ¶. Fixed a disconnect that slowly evolved
     between a @declared_attr Column and a directly-defined Column on a
     mixin.  In both cases, the Column will be applied to the declared
     class’ table, but not to that of a joined inheritance subclass.
     Previously, the directly-defined Column would be placed on both the
     base and the sub table, which isn’t typically what’s desired.

     References: #2565(35)

   * `[orm] [bug]' ¶. Declarative can now propagate a column
     declared on a single-table inheritance subclass up to the parent
     class’ table, when the parent class is itself mapped to a join() or
     select() statement, directly or via joined inheritance, and not
     just a Table.

     References: #2549(36)

   * `[orm] [bug]' ¶. An error is emitted when uselist=False
     is combined with a “dynamic” loader.  This is a warning in 0.7.9.

   * `[orm] [removed]' ¶. The legacy “mutable” system of the
     ORM, including the MutableType class as well as the mutable=True
     flag on PickleType and postgresql.ARRAY has been removed.  In-place
     mutations are detected by the ORM using the sqlalchemy.ext.mutable
     extension, introduced in 0.7.  The removal of MutableType and
     associated constructs removes a great deal of complexity from
     SQLAlchemy’s internals.  The approach performed poorly as it would
     incur a scan of the full contents of the Session when in use.

     References: #2442(37)

   * `[orm] [removed]' ¶. Deprecated identifiers removed:

        * allow_null_pks mapper() argument (use allow_partial_pks)

        * _get_col_to_prop() mapper method (use
          get_property_by_column())

        * dont_load argument to Session.merge() (use load=True)

        * sqlalchemy.orm.shard module (use
          sqlalchemy.ext.horizontal_shard)

   * `[orm] [moved]' ¶. The InstrumentationManager interface
     and the entire related system of alternate class implementation is
     now moved out to sqlalchemy.ext.instrumentation.  This is a seldom
     used system that adds significant complexity and overhead to the
     mechanics of class instrumentation.  The new architecture allows it
     to remain unused until InstrumentationManager is actually imported,
     at which point it is bootstrapped into the core.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1401

   (2) http://www.sqlalchemy.org/trac/ticket/2333

   (3) http://www.sqlalchemy.org/trac/ticket/1106

   (4) http://www.sqlalchemy.org/trac/ticket/2438

   (5) http://www.sqlalchemy.org/trac/ticket/2585

   (6) http://www.sqlalchemy.org/trac/ticket/2485

   (7) http://www.sqlalchemy.org/trac/ticket/2208

   (8) http://www.sqlalchemy.org/trac/ticket/2452

   (9) http://www.sqlalchemy.org/trac/ticket/2372

   (10) http://www.sqlalchemy.org/trac/ticket/2229

   (11) http://www.sqlalchemy.org/trac/ticket/2229

   (12) http://www.sqlalchemy.org/trac/ticket/2592

   (13) http://www.sqlalchemy.org/trac/ticket/2179

   (14) http://www.sqlalchemy.org/trac/ticket/2464

   (15) http://www.sqlalchemy.org/trac/ticket/2245

   (16) http://www.sqlalchemy.org/trac/ticket/2245

   (17) http://www.sqlalchemy.org/trac/ticket/2526

   (18) http://www.sqlalchemy.org/trac/ticket/2472

   (19) http://www.sqlalchemy.org/trac/ticket/2472

   (20) http://www.sqlalchemy.org/trac/ticket/2517

   (21) http://www.sqlalchemy.org/trac/ticket/2526

   (22) http://www.sqlalchemy.org/trac/ticket/2338

   (23) http://www.sqlalchemy.org/trac/ticket/2535

   (24) http://www.sqlalchemy.org/trac/ticket/1729

   (25) http://www.sqlalchemy.org/trac/ticket/2476

   (26) http://www.sqlalchemy.org/trac/ticket/2527

   (27) http://www.sqlalchemy.org/trac/ticket/2590

   (28) http://www.sqlalchemy.org/trac/ticket/1900

   (29) http://www.sqlalchemy.org/trac/ticket/2481

   (30) http://www.sqlalchemy.org/trac/ticket/2320

   (31) http://www.sqlalchemy.org/trac/ticket/2405

   (32) http://www.sqlalchemy.org/trac/ticket/2350

   (33) http://www.sqlalchemy.org/trac/ticket/2566

   (34) http://www.sqlalchemy.org/trac/ticket/2582

   (35) http://www.sqlalchemy.org/trac/ticket/2565

   (36) http://www.sqlalchemy.org/trac/ticket/2549

   (37) http://www.sqlalchemy.org/trac/ticket/2442

8.3.7.83 engine
...............

   * `[engine] [feature]' ¶. Connection event listeners can
     now be associated with individual Connection objects, not just
     Engine objects.

     References: #2511(1)

   * `[engine] [feature]' ¶. The before_cursor_execute event
     fires off for so-called “_cursor_execute” events, which are usually
     special-case executions of primary-key bound sequences and
     default-generation SQL phrases that invoke separately when
     RETURNING is not used with INSERT.

     References: #2459(2)

   * `[engine] [feature]' ¶. The libraries used by the test
     suite have been moved around a bit so that they are part of the
     SQLAlchemy install again.  In addition, a new suite of tests is
     present in the new sqlalchemy.testing.suite package.  This is an
     under-development system that hopes to provide a universal testing
     suite for external dialects.  Dialects which are maintained outside
     of SQLAlchemy can use the new test fixture as the framework for
     their own tests, and will get for free a “compliance” suite of
     dialect-focused tests, including an improved “requirements” system
     where specific capabilities and features can be enabled or disabled
     for testing.

   * `[engine] [feature]' ¶. Added a new system for
     registration of new dialects in-process without using an
     entrypoint.  See the docs for “Registering New Dialects”.

     References: #2462(3)

   * `[engine] [feature]' ¶. The “required” flag is set to
     True by default, if not passed explicitly, on bindparam() if the
     “value” or “callable” parameters are not passed.  This will cause
     statement execution to check for the parameter being present in the
     final collection of bound parameters, rather than implicitly
     assigning None.

     References: #2556(4)

   * `[engine] [feature]' ¶. Various API tweaks to the
     “dialect” API to better support highly specialized systems such as
     the Akiban database, including more hooks to allow an execution
     context to access type processors.

   * `[engine] [feature]' ¶. Inspector.get_primary_keys() is
     deprecated; use Inspector.get_pk_constraint().  Courtesy Diana
     Clarke.

     References: #2422(5)

   * `[engine] [feature]' ¶. New C extension module “utils”
     has been added for additional function speedups as we have time to
     implement.

   * `[engine] [bug]' ¶. The Inspector.get_table_names()
     order_by=”foreign_key” feature now sorts tables by dependee first,
     to be consistent with util.sort_tables and metadata.sorted_tables.

   * `[engine] [bug]' ¶. Fixed bug whereby if a database
     restart affected multiple connections, each connection would
     individually invoke a new disposal of the pool, even though only
     one disposal is needed.

     References: #2522(6)

   * `[engine] [bug]' ¶. The names of the columns on the .c.
     attribute of a select().apply_labels() is now based on
     <tablename>_<colkey> instead of <tablename>_<colname>, for those
     columns that have a distinctly named .key.

     References: #2397(7)

   * `[engine] [bug]' ¶. The autoload_replace flag on Table,
     when False, will cause any reflected foreign key constraints which
     refer to already-declared columns to be skipped, assuming that the
     in-Python declared column will take over the task of specifying
     in-Python ForeignKey or ForeignKeyConstraint declarations.

   * `[engine] [bug]' ¶. The ResultProxy methods
     inserted_primary_key, last_updated_params(),
     last_inserted_params(), postfetch_cols(), prefetch_cols() all
     assert that the given statement is a compiled construct, and is an
     insert() or update() statement as is appropriate, else raise
     InvalidRequestError.

     References: #2498(8)

   * `[engine]' ¶. ResultProxy.last_inserted_ids is removed,
     replaced by inserted_primary_key.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2511

   (2) http://www.sqlalchemy.org/trac/ticket/2459

   (3) http://www.sqlalchemy.org/trac/ticket/2462

   (4) http://www.sqlalchemy.org/trac/ticket/2556

   (5) http://www.sqlalchemy.org/trac/ticket/2422

   (6) http://www.sqlalchemy.org/trac/ticket/2522

   (7) http://www.sqlalchemy.org/trac/ticket/2397

   (8) http://www.sqlalchemy.org/trac/ticket/2498

8.3.7.84 sql
............

   * `[sql] [feature]' ¶. Added a new method
     Engine.execution_options() to Engine.  This method
     works similarly to Connection.execution_options() in
     that it creates a copy of the parent object which will refer to the
     new set of options.  The method can be used to build sharding
     schemes where each engine shares the same underlying pool of
     connections.  The method has been tested against the horizontal
     shard recipe in the ORM as well.

     See also
     ........

     See Engine.execution_options().

   * `[sql] [feature]' ¶. Major rework of operator system in
     Core, to allow redefinition of existing operators as well as
     addition of new operators at the type level.  New types can be
     created from existing ones which add or redefine operations that
     are exported out to column expressions, in a similar manner to how
     the ORM has allowed comparator_factory.  The new architecture moves
     this capability into the Core so that it is consistently usable in
     all cases, propagating cleanly using existing type propagation
     behavior.

     References: #2547(1)

   * `[sql] [feature]' ¶. To complement, types can now
     provide “bind expressions” and “column expressions” which allow
     compile-time injection of SQL expressions into statements on a
     per-column or per-bind level.  This is to suit the use case of a
     type which needs to augment bind- and result- behavior at the SQL
     level, as opposed to in the Python level.  Allows for schemes like
     transparent encryption/ decryption, usage of PostGIS functions,
     etc.

     References: #1534(2), #2547(3)

   * `[sql] [feature]' ¶. The Core operator system now
     includes the ‘getitem’ operator, i.e.  the bracket operator in
     Python.  This is used at first to provide index and slice behavior
     to the PostgreSQL ARRAY type, and also provides a hook for end-user
     definition of custom __getitem__ schemes which can be applied at
     the type level as well as within ORM-level custom operator schemes.
     ‘lshift’ (<<) and ‘rshift’ (>>) are also supported as optional
     operators.

     Note that this change has the effect that descriptor-based
     __getitem__ schemes used by the ORM in conjunction with synonym()
     or other “descriptor-wrapped” schemes will need to start using a
     custom comparator in order to maintain this behavior.

   * `[sql] [feature]' ¶. Revised the rules used to
     determine the operator precedence for the user-defined operator,
     i.e.  that granted using the ‘op()’ method.  Previously, the
     smallest precedence was applied in all cases, now the default
     precedence is zero, lower than all operators except “comma” (such
     as, used in the argument list of a ‘func’ call) and “AS”, and is
     also customizable via the “precedence” argument on the ‘op()’
     method.

     References: #2537(4)

   * `[sql] [feature]' ¶. Added “collation” parameter to all
     String types.  When present, renders as COLLATE <collation>.  This
     to support the COLLATE keyword now supported by several databases
     including MySQL, SQLite, and PostgreSQL.

     References: #2276(5)

   * `[sql] [feature]' ¶. Custom unary operators can now be
     used by combining operators.custom_op() with UnaryExpression().

   * `[sql] [feature]' ¶. Enhanced GenericFunction and
     func.* to allow for user-defined GenericFunction subclasses to be
     available via the func.* namespace automatically by classname,
     optionally using a package name, as well as with the ability to
     have the rendered name different from the identified name in
     func.*.

   * `[sql] [feature]' ¶. The cast() and extract()
     constructs will now be produced via the func.* accessor as well, as
     users naturally try to access these names from func.* they might as
     well do what’s expected, even though the returned object is not a
     FunctionElement.

     References: #2562(6)

   * `[sql] [feature]' ¶. The Inspector object can now be
     acquired using the new inspect() service, part of

     References: #2208(7)

   * `[sql] [feature]' ¶. The column_reflect event now
     accepts the Inspector object as the first argument, preceding
     “table”.  Code which uses the 0.7 version of this very new event
     will need modification to add the “inspector” object as the first
     argument.

     References: #2418(8)

   * `[sql] [feature]' ¶. The behavior of column targeting
     in result sets is now case sensitive by default.  SQLAlchemy for
     many years would run a case-insensitive conversion on these values,
     probably to alleviate early case sensitivity issues with dialects
     like Oracle and Firebird.  These issues have been more cleanly
     solved in more modern versions so the performance hit of calling
     lower() on identifiers is removed.  The case insensitive
     comparisons can be re-enabled by setting “case_insensitive=False”
     on create_engine().

     References: #2423(9)

   * `[sql] [feature]' ¶. The “unconsumed column names”
     warning emitted when keys are present in insert.values() or
     update.values() that aren’t in the target table is now an
     exception.

     References: #2415(10)

   * `[sql] [feature]' ¶. Added “MATCH” clause to
     ForeignKey, ForeignKeyConstraint, courtesy Ryan Kelly.

     References: #2502(11)

   * `[sql] [feature]' ¶. Added support for DELETE and
     UPDATE from an alias of a table, which would assumedly be related
     to itself elsewhere in the query, courtesy Ryan Kelly.

     References: #2507(12)

   * `[sql] [feature]' ¶ select() features a
     correlate_except() method, auto correlates all selectables except
     those passed.

   * `[sql] [feature]' ¶. The prefix_with() method is now
     available on each of select(), insert(), update(), delete(), all
     with the same API, accepting multiple prefix calls, as well as a
     “dialect name” so that the prefix can be limited to one kind of
     dialect.

     References: #2431(13)

   * `[sql] [feature]' ¶. Added reduce_columns() method to
     select() construct, replaces columns inline using the
     util.reduce_columns utility function to remove equivalent columns.
     reduce_columns() also adds “with_only_synonyms” to limit the
     reduction just to those columns which have the same name.  The
     deprecated fold_equivalents() feature is removed.

     References: #1729(14)

   * `[sql] [feature]' ¶. Reworked the startswith(),
     endswith(), contains() operators to do a better job with negation
     (NOT LIKE), and also to assemble them at compilation time so that
     their rendered SQL can be altered, such as in the case for Firebird
     STARTING WITH

     References: #2470(15)

   * `[sql] [feature]' ¶. Added a hook to the system of
     rendering CREATE TABLE that provides access to the render for each
     Column individually, by constructing a @compiles function against
     the new schema.CreateColumn construct.

     References: #2463(16)

   * `[sql] [feature]' ¶. ”scalar” selects now have a WHERE
     method to help with generative building.  Also slight adjustment
     regarding how SS “correlates” columns; the new methodology no
     longer applies meaning to the underlying Table column being
     selected.  This improves some fairly esoteric situations, and the
     logic that was there didn’t seem to have any purpose.

   * `[sql] [feature]' ¶. An explicit error is raised when a
     ForeignKeyConstraint() that was constructed to refer to multiple
     remote tables is first used.

     References: #2455(17)

   * `[sql] [feature]' ¶. Added
     ColumnOperators.notin_(), ColumnOperators.notlike(),
     see ColumnOperators.notilike() to
     ColumnOperators.

     References: #2580(18)

   * `[sql] [change]' ¶. The Text() type renders the length
     given to it, if a length was specified.

   * `[sql] [changed]' ¶. Most classes in expression.sql are
     no longer preceded with an underscore, i.e.  Label, SelectBase,
     Generative, CompareMixin.  _BindParamClause is also renamed to
     BindParameter.  The old underscore names for these classes will
     remain available as synonyms for the foreseeable future.

   * `[sql] [bug]' ¶. Fixed bug where keyword arguments
     passed to ‘Compiler.process()’ wouldn’t get propagated to the
     column expressions present in the columns clause of a SELECT
     statement.  In particular this would come up when used by custom
     compilation schemes that relied upon special flags.

     References: #2593(19)

   * `[sql] [bug] [orm]' ¶. The auto-correlation feature of
     select(), and by proxy that of Query, will not
     take effect for a SELECT statement that is being rendered directly
     in the FROM list of the enclosing SELECT. Correlation in SQL only
     applies to column expressions such as those in the WHERE, ORDER BY,
     columns clause.

     References: #2595(20)

   * `[sql] [bug]' ¶. A tweak to column precedence which
     moves the “concat” and “match” operators to be the same as that of
     “is”, “like”, and others; this helps with parenthesization
     rendering when used in conjunction with “IS”.

     References: #2564(21)

   * `[sql] [bug]' ¶. Applying a column expression to a
     select statement using a label with or without other modifying
     constructs will no longer “target” that expression to the
     underlying Column; this affects ORM operations that rely upon
     Column targeting in order to retrieve results.  That is, a query
     like query(User.id, User.id.label(‘foo’)) will now track the value
     of each “User.id” expression separately instead of munging them
     together.  It is not expected that any users will be impacted by
     this; however, a usage that uses select() in conjunction with
     query.from_statement() and attempts to load fully composed ORM
     entities may not function as expected if the select() named Column
     objects with arbitrary .label() names, as these will no longer
     target to the Column objects mapped by that entity.

     References: #2591(22)

   * `[sql] [bug]' ¶. Fixes to the interpretation of the
     Column “default” parameter as a callable to not pass
     ExecutionContext into a keyword argument parameter.

     References: #2520(23)

   * `[sql] [bug]' ¶. All of UniqueConstraint,
     ForeignKeyConstraint, CheckConstraint, and PrimaryKeyConstraint
     will attach themselves to their parent table automatically when
     they refer to a Table-bound Column object directly (i.e.  not just
     string column name), and refer to one and only one Table.  Prior to
     0.8 this behavior occurred for UniqueConstraint and
     PrimaryKeyConstraint, but not ForeignKeyConstraint or
     CheckConstraint.

     References: #2410(24)

   * `[sql] [bug]' ¶. TypeDecorator now includes a generic
     repr() that works in terms of the “impl” type by default.  This is
     a behavioral change for those TypeDecorator classes that specify a
     custom __init__ method; those types will need to re-define
     __repr__() if they need __repr__() to provide a faithful
     constructor representation.

     References: #2594(25)

   * `[sql] [bug]' ¶ column.label(None) now produces an
     anonymous label, instead of returning the column object itself,
     consistent with the behavior of label(column, None).

     References: #2168(26)

   * `[sql] [removed]' ¶. The long-deprecated and
     non-functional ‘assert_unicode’ flag on create_engine()
     as well as String is removed.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2547

   (2) http://www.sqlalchemy.org/trac/ticket/1534

   (3) http://www.sqlalchemy.org/trac/ticket/2547

   (4) http://www.sqlalchemy.org/trac/ticket/2537

   (5) http://www.sqlalchemy.org/trac/ticket/2276

   (6) http://www.sqlalchemy.org/trac/ticket/2562

   (7) http://www.sqlalchemy.org/trac/ticket/2208

   (8) http://www.sqlalchemy.org/trac/ticket/2418

   (9) http://www.sqlalchemy.org/trac/ticket/2423

   (10) http://www.sqlalchemy.org/trac/ticket/2415

   (11) http://www.sqlalchemy.org/trac/ticket/2502

   (12) http://www.sqlalchemy.org/trac/ticket/2507

   (13) http://www.sqlalchemy.org/trac/ticket/2431

   (14) http://www.sqlalchemy.org/trac/ticket/1729

   (15) http://www.sqlalchemy.org/trac/ticket/2470

   (16) http://www.sqlalchemy.org/trac/ticket/2463

   (17) http://www.sqlalchemy.org/trac/ticket/2455

   (18) http://www.sqlalchemy.org/trac/ticket/2580

   (19) http://www.sqlalchemy.org/trac/ticket/2593

   (20) http://www.sqlalchemy.org/trac/ticket/2595

   (21) http://www.sqlalchemy.org/trac/ticket/2564

   (22) http://www.sqlalchemy.org/trac/ticket/2591

   (23) http://www.sqlalchemy.org/trac/ticket/2520

   (24) http://www.sqlalchemy.org/trac/ticket/2410

   (25) http://www.sqlalchemy.org/trac/ticket/2594

   (26) http://www.sqlalchemy.org/trac/ticket/2168

8.3.7.85 postgresql
...................

   * `[postgresql] [feature]' ¶ postgresql.ARRAY features
     an optional “dimension” argument, will assign a specific number of
     dimensions to the array which will render in DDL as ARRAY[][]…,
     also improves performance of bind/result processing.

     References: #2441(1)

   * `[postgresql] [feature]' ¶ postgresql.ARRAY now
     supports indexing and slicing.  The Python [] operator is available
     on all SQL expressions that are of type ARRAY; integer or simple
     slices can be passed.  The slices can also be used on the
     assignment side in the SET clause of an UPDATE statement by passing
     them into Update.values(); see the docs for examples.

   * `[postgresql] [feature]' ¶. Added new “array literal”
     construct postgresql.array().  Basically a “tuple” that renders as
     ARRAY[1,2,3].

   * `[postgresql] [feature]' ¶. Added support for the
     PostgreSQL ONLY keyword, which can appear corresponding to a table
     in a SELECT, UPDATE, or DELETE statement.  The phrase is
     established using with_hint().  Courtesy Ryan Kelly

     References: #2506(2)

   * `[postgresql] [feature]' ¶. The “ischema_names”
     dictionary of the PostgreSQL dialect is “unofficially”
     customizable.  Meaning, new types such as PostGIS types can be
     added into this dictionary, and the PG type reflection code should
     be able to handle simple types with variable numbers of arguments.
     The functionality here is “unofficial” for three reasons:

       1. this is not an “official” API. Ideally an “official” API would
          allow custom type-handling callables at the dialect or global
          level in a generic way.

       2. This is only implemented for the PG dialect, in particular
          because PG has broad support for custom types vs.  other
          database backends.  A real API would be implemented at the
          default dialect level.

       3. The reflection code here is only tested against simple types
          and probably has issues with more compositional types.

     patch courtesy Éric Lemoine.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2441

   (2) http://www.sqlalchemy.org/trac/ticket/2506

8.3.7.86 mysql
..............

   * `[mysql] [feature]' ¶. Added TIME type to mysql
     dialect, accepts “fst” argument which is the new “fractional
     seconds” specifier for recent MySQL versions.  The datatype will
     interpret a microseconds portion received from the driver, however
     note that at this time most/all MySQL DBAPIs do not support
     returning this value.

     References: #2534(1)

   * `[mysql] [bug]' ¶. Dialect no longer emits expensive
     server collations query, as well as server casing, on first
     connect.  These functions are still available as semi-private.

     References: #2404(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2534

   (2) http://www.sqlalchemy.org/trac/ticket/2404

8.3.7.87 sqlite
...............

   * `[sqlite] [feature]' ¶ the SQLite date and time types
     have been overhauled to support a more open ended format for input
     and output, using name based format strings and regexps.  A new
     argument “microseconds” also provides the option to omit the
     “microseconds” portion of timestamps.  Thanks to Nathan Wright for
     the work and tests on this.

     References: #2363(1)

   * `[sqlite]' ¶. Added NCHAR, NVARCHAR
     to the SQLite dialect’s list of recognized type names for
     reflection.  SQLite returns the name given to a type as the name
     returned.

     References: rc3addcc9ffad(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2363

   (2) http://www.sqlalchemy.org/trac/changeset/c3addcc9ffad

8.3.7.88 mssql
..............

   * `[mssql] [feature]' ¶. SQL Server dialect can be given
     database-qualified schema names, i.e.  “schema=’mydatabase.dbo’”;
     reflection operations will detect this, split the schema among the
     “.” to get the owner separately, and emit a “USE mydatabase”
     statement before reflecting targets within the “dbo” owner; the
     existing database returned from DB_NAME() is then restored.

   * `[mssql] [feature]' ¶ updated support for the mxodbc
     driver; mxodbc 3.2.1 is recommended for full compatibility.

   * `[mssql] [bug]' ¶ removed legacy behavior whereby a
     column comparison to a scalar SELECT via == would coerce to an IN
     with the SQL server dialect.  This is implicit behavior which fails
     in other scenarios so is removed.  Code which relies on this needs
     to be modified to use column.in_(select) explicitly.

     References: #2277(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2277

8.3.7.89 oracle
...............

   * `[oracle] [feature]' ¶. The types of columns excluded
     from the setinputsizes() set can be customized by sending a list of
     string DBAPI type names to exclude, using the exclude_setinputsizes
     dialect parameter.  This list was previously fixed.  The list also
     now defaults to STRING, UNICODE, removing CLOB, NCLOB from the
     list.

     References: #2561(1)

   * `[oracle] [bug]' ¶. Quoting information is now passed
     along from a Column with quote=True when generating a same-named
     bound parameter to the bindparam() object, as is the case in
     generated INSERT and UPDATE statements, so that unknown reserved
     names can be fully supported.

     References: #2437(2)

   * `[oracle] [bug]' ¶. The CreateIndex construct in Oracle
     will now schema-qualify the name of the index to be that of the
     parent table.  Previously this name was omitted which apparently
     creates the index in the default schema, rather than that of the
     table.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2561

   (2) http://www.sqlalchemy.org/trac/ticket/2437

8.3.7.90 firebird
.................

   * `[firebird] [feature]' ¶. The “startswith()” operator
     renders as “STARTING WITH”, “~startswith()” renders as “NOT
     STARTING WITH”, using FB’s more efficient operator.

     References: #2470(1)

   * `[firebird] [feature]' ¶. An experimental dialect for
     the fdb driver is added, but is untested as I cannot get the fdb
     package to build.

     References: #2504(2)

   * `[firebird] [bug]' ¶. CompileError is raised when
     VARCHAR with no length is attempted to be emitted, same way as
     MySQL.

     References: #2505(3)

   * `[firebird] [bug]' ¶. Firebird now uses strict “ansi
     bind rules” so that bound parameters don’t render in the columns
     clause of a statement - they render literally instead.

   * `[firebird] [bug]' ¶. Support for passing datetime as
     date when using the DateTime type with Firebird; other dialects
     support this.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2470

   (2) http://www.sqlalchemy.org/trac/ticket/2504

   (3) http://www.sqlalchemy.org/trac/ticket/2505

8.3.7.91 misc
.............

   * `[feature] [access]' ¶ the MS Access dialect has been
     moved to its own project on Bitbucket, taking advantage of the new
     SQLAlchemy dialect compliance suite.  The dialect is still in very
     rough shape and probably not ready for general use yet, however it
     does have `extremely' rudimental functionality now.
     ‘https://bitbucket.org/zzzeek/sqlalchemy-access’

   * `[moved] [maxdb]' ¶. The MaxDB dialect, which hasn’t
     been functional for several years, is moved out to a pending
     bitbucket project, ‘https://bitbucket.org/zzzeek/sqlalchemy-maxdb’.

   * `[examples]' ¶. The Beaker caching example has been
     converted to use dogpile.cache(1).  This is a new caching library
     written by the same creator of Beaker’s caching internals, and
     represents a vastly improved, simplified, and modernized system of
     caching.

     See also
     ........

     See Dogpile Caching.

     References: #2589(2)

   ---------- Footnotes ----------

   (1) https://dogpilecache.readthedocs.io/

   (2) http://www.sqlalchemy.org/trac/ticket/2589

8.3.8 0.7 Changelog
-------------------

8.3.8.1 0.7.11
..............

no release date

8.3.8.2 orm
...........

   * `[orm] [bug]' ¶. Fixed bug where list instrumentation
     would fail to represent a setslice of ‘[0:0]’ correctly, which in
     particular could occur when using ‘insert(0, item)’ with the
     association proxy.  Due to some quirk in Python collections, the
     issue was much more likely with Python 3 rather than 2.

     References: #2807(1)

   * `[orm] [bug]' ¶. Fixed bug when a query of the form:
     ‘query(SubClass).options(subqueryload(Baseclass.attrname))’, where
     ‘SubClass’ is a joined inh of ‘BaseClass’, would fail to apply the
     ‘JOIN’ inside the subquery on the attribute load, producing a
     cartesian product.  The populated results still tended to be
     correct as additional rows are just ignored, so this issue may be
     present as a performance degradation in applications that are
     otherwise working correctly.

     References: #2699(2)

   * `[orm] [bug]' ¶. Fixed bug in unit of work whereby a
     joined-inheritance subclass could insert the row for the “sub”
     table before the parent table, if the two tables had no ForeignKey
     constraints set up between them.

     References: #2689(3)

   * `[orm] [bug]' ¶. Improved the error message emitted
     when a “backref loop” is detected, that is when an attribute event
     triggers a bidirectional assignment between two other attributes
     with no end.  This condition can occur not just when an object of
     the wrong type is assigned, but also when an attribute is
     mis-configured to backref into an existing backref pair.

     References: #2674(4)

   * `[orm] [bug]' ¶. A warning is emitted when a
     MapperProperty is assigned to a mapper that replaces an existing
     property, if the properties in question aren’t plain column-based
     properties.  Replacement of relationship properties is rarely
     (ever?)  what is intended and usually refers to a mapper
     mis-configuration.  This will also warn if a backref configures
     itself on top of an existing one in an inheritance relationship
     (which is an error in 0.8).

     References: #2674(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2807

   (2) http://www.sqlalchemy.org/trac/ticket/2699

   (3) http://www.sqlalchemy.org/trac/ticket/2689

   (4) http://www.sqlalchemy.org/trac/ticket/2674

   (5) http://www.sqlalchemy.org/trac/ticket/2674

8.3.8.3 engine
..............

   * `[engine] [bug]' ¶. The regexp used by the ‘make_url()’
     function now parses ipv6 addresses, e.g.  surrounded by brackets.

     References: #2851(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2851

8.3.8.4 sql
...........

   * `[sql] [bug]' ¶. Fixed regression dating back to 0.7.9
     whereby the name of a CTE might not be properly quoted if it was
     referred to in multiple FROM clauses.

     References: #2801(1)

   * `[sql] [bug] [cte]' ¶. Fixed bug in common table
     expression system where if the CTE were used only as an ‘alias()’
     construct, it would not render using the WITH keyword.

     References: #2783(2)

   * `[sql] [bug]' ¶. Fixed bug in CheckConstraint.
     DDL where the “quote” flag from a Column object
     would not be propagated.

     References: #2784(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2801

   (2) http://www.sqlalchemy.org/trac/ticket/2783

   (3) http://www.sqlalchemy.org/trac/ticket/2784

8.3.8.5 postgresql
..................

   * `[postgresql] [feature]' ¶. Added support for
     PostgreSQL’s traditional SUBSTRING function syntax, renders as
     “SUBSTRING(x FROM y FOR z)” when regular ‘func.substring()’ is
     used.  Courtesy Gunnlaugur Þór Briem.

     References: #2676(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2676

8.3.8.6 mysql
.............

   * `[mysql] [bug]' ¶. Updates to MySQL reserved words for
     versions 5.5, 5.6, courtesy Hanno Schlichting.

     References: #2791(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2791

8.3.8.7 misc
............

   * `[bug] [tests]' ¶. Fixed an import of “logging” in
     test_execute which was not working on some linux platforms.

     References: #2669(1), pull request 41(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2669

   (2) https://github.com/sqlalchemy/sqlalchemy/pull/41

8.3.8.8 0.7.10
..............

Released: Thu Feb 7 2013

8.3.8.9 orm
...........

   * `[orm] [bug]' ¶. Fixed potential memory leak which
     could occur if an arbitrary number of sessionmaker
     objects were created.  The anonymous subclass created by the
     sessionmaker, when dereferenced, would not be garbage collected due
     to remaining class-level references from the event package.  This
     issue also applies to any custom system that made use of ad-hoc
     subclasses in conjunction with an event dispatcher.

     References: #2650(1)

   * `[orm] [bug]' ¶. Query.merge_result() can
     now load rows from an outer join where an entity may be ‘None’
     without throwing an error.

     References: #2640(2)

   * `[orm] [bug]' ¶. The MutableComposite type
     did not allow for the MutableBase.coerce() method to be
     used, even though the code seemed to indicate this intent, so this
     now works and a brief example is added.  As a side-effect, the
     mechanics of this event handler have been changed so that new
     MutableComposite types no longer add per-type global event
     handlers.  Also in 0.8.0b2.

     References: #2624(3)

   * `[orm] [bug]' ¶. Fixed Session accounting bug whereby
     replacing a deleted object in the identity map with another object
     of the same primary key would raise a “conflicting state” error on
     rollback(), if the replaced primary key were established either via
     non-unitofwork-established INSERT statement or by primary key
     switch of another instance.

     References: #2583(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2650

   (2) http://www.sqlalchemy.org/trac/ticket/2640

   (3) http://www.sqlalchemy.org/trac/ticket/2624

   (4) http://www.sqlalchemy.org/trac/ticket/2583

8.3.8.10 engine
...............

   * `[engine] [bug]' ¶. Fixed MetaData.reflect()
     to correctly use the given Connection, if given,
     without opening a second connection from that connection’s
     Engine.

     References: #2604(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2604

8.3.8.11 sql
............

   * `[sql] [bug]' ¶. Backported adjustment to ‘__repr__’
     for TypeDecorator to 0.7, allows PickleType
     to produce a clean ‘repr()’ to help with Alembic.

     References: #2584(1), #2594(2)

   * `[sql] [bug]' ¶. Fixed bug where
     Table.tometadata() would fail if a Column had
     both a foreign key as well as an alternate “.key” name for the
     column.

     References: #2643(3)

   * `[sql] [bug]' ¶. Fixed bug where using
     server_onupdate=<FetchedValue|DefaultClause> without passing the
     “for_update=True” flag would apply the default object to the
     server_default, blowing away whatever was there.  The explicit
     for_update=True argument shouldn’t be needed with this usage
     (especially since the documentation shows an example without it
     being used) so it is now arranged internally using a copy of the
     given default object, if the flag isn’t set to what corresponds to
     that argument.

     References: #2631(4)

   * `[sql] [gae] [mysql]' ¶. Added a conditional import to
     the ‘gaerdbms’ dialect which attempts to import rdbms_apiproxy vs.
     rdbms_googleapi to work on both dev and production platforms.  Also
     now honors the ‘instance’ attribute.  Courtesy Sean Lynch.  Also
     backported enhancements to allow username/password as well as
     fixing error code interpretation from 0.8.

     References: #2649(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2584

   (2) http://www.sqlalchemy.org/trac/ticket/2594

   (3) http://www.sqlalchemy.org/trac/ticket/2643

   (4) http://www.sqlalchemy.org/trac/ticket/2631

   (5) http://www.sqlalchemy.org/trac/ticket/2649

8.3.8.12 mysql
..............

   * `[mysql] [feature]' ¶. Added “raise_on_warnings” flag
     to OurSQL dialect.

     References: #2523(1)

   * `[mysql] [feature]' ¶. Added “read_timeout” flag to
     MySQLdb dialect.

     References: #2554(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2523

   (2) http://www.sqlalchemy.org/trac/ticket/2554

8.3.8.13 sqlite
...............

   * `[sqlite] [bug]' ¶. More adjustment to this SQLite
     related issue which was released in 0.7.9, to intercept legacy
     SQLite quoting characters when reflecting foreign keys.  In
     addition to intercepting double quotes, other quoting characters
     such as brackets, backticks, and single quotes are now also
     intercepted.

     References: #2568(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2568

8.3.8.14 mssql
..............

   * `[mssql] [bug]' ¶. Fixed bug whereby using “key” with
     Column in conjunction with “schema” for the owning Table would fail
     to locate result rows due to the MSSQL dialect’s “schema rendering”
     logic’s failure to take .key into account.

   * `[mssql] [bug]' ¶. Added a Py3K conditional around
     unnecessary .decode() call in mssql information schema, fixes
     reflection in Py3k.

     References: #2638(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2638

8.3.8.15 oracle
...............

   * `[oracle] [bug]' ¶. The Oracle LONG type, while an
     unbounded text type, does not appear to use the cx_Oracle.LOB type
     when result rows are returned, so the dialect has been repaired to
     exclude LONG from having cx_Oracle.LOB filtering applied.

     References: #2620(1)

   * `[oracle] [bug]' ¶. Repaired the usage of ‘.prepare()’
     in conjunction with cx_Oracle so that a return value of ‘False’
     will result in no call to ‘connection.commit()’, hence avoiding “no
     transaction” errors.  Two-phase transactions have now been shown to
     work in a rudimental fashion with SQLAlchemy and cx_oracle, however
     are subject to caveats observed with the driver; check the
     documentation for details.

     References: #2611(2)

   * `[oracle] [bug]' ¶ changed the list of cx_oracle types
     that are excluded from the setinputsizes() step to only include
     STRING and UNICODE; CLOB and NCLOB are removed.  This is to work
     around cx_oracle behavior which is broken for the executemany()
     call.  In 0.8, this same change is applied however it is also
     configurable via the exclude_setinputsizes argument.

     References: #2561(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2620

   (2) http://www.sqlalchemy.org/trac/ticket/2611

   (3) http://www.sqlalchemy.org/trac/ticket/2561

8.3.8.16 0.7.9
..............

Released: Mon Oct 01 2012

8.3.8.17 orm
............

   * `[orm] [bug]' ¶. Fixed bug mostly local to new
     AbstractConcreteBase helper where the “type” attribute from the
     superclass would not be overridden on the subclass to produce the
     “reserved for base” error message, instead placing a do-nothing
     attribute there.  This was inconsistent vs.  using ConcreteBase as
     well as all the behavior of classical concrete mappings, where the
     “type” column from the polymorphic base would be explicitly
     disabled on subclasses, unless overridden explicitly.

   * `[orm] [bug]' ¶. A warning is emitted when
     lazy=’dynamic’ is combined with uselist=False.  This is an
     exception raise in 0.8.

   * `[orm] [bug]' ¶. Fixed bug whereby user error in
     related-object assignment could cause recursion overflow if the
     assignment triggered a backref of the same name as a bi-directional
     attribute on the incorrect class to the same target.  An
     informative error is raised now.

   * `[orm] [bug]' ¶. Fixed bug where incorrect type
     information would be passed when the ORM would bind the “version”
     column, when using the “version” feature.  Tests courtesy Daniel
     Miller.

     References: #2539(1)

   * `[orm] [bug]' ¶. Extra logic has been added to the
     “flush” that occurs within Session.commit(), such that the extra
     state added by an after_flush() or after_flush_postexec() hook is
     also flushed in a subsequent flush, before the “commit” completes.
     Subsequent calls to flush() will continue until the after_flush
     hooks stop adding new state.  An “overflow” counter of 100 is also
     in place, in the event of a broken after_flush() hook adding new
     content each time.

     References: #2566(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2539

   (2) http://www.sqlalchemy.org/trac/ticket/2566

8.3.8.18 engine
...............

   * `[engine] [feature]' ¶. Dramatic improvement in memory
     usage of the event system; instance-level collections are no longer
     created for a particular type of event until instance-level
     listeners are established for that event.

     References: #2516(1)

   * `[engine] [bug]' ¶. Fixed bug whereby a disconnect
     detect + dispose that occurs when the QueuePool has threads waiting
     for connections would leave those threads waiting for the duration
     of the timeout on the old pool (or indefinitely if timeout was
     disabled).  The fix now notifies those waiters with a special
     exception case and has them move onto the new pool.

     References: #2522(2)

   * `[engine] [bug]' ¶. Added gaerdbms import to
     mysql/__init__.py, the absence of which was preventing the new GAE
     dialect from being loaded.

     References: #2529(3)

   * `[engine] [bug]' ¶. Fixed cextension bug whereby the
     “ambiguous column error” would fail to function properly if the
     given index were a Column object and not a string.  Note there are
     still some column-targeting issues here which are fixed in 0.8.

     References: #2553(4)

   * `[engine] [bug]' ¶. Fixed the repr() of Enum to include
     the “name” and “native_enum” flags.  Helps Alembic autogenerate.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2516

   (2) http://www.sqlalchemy.org/trac/ticket/2522

   (3) http://www.sqlalchemy.org/trac/ticket/2529

   (4) http://www.sqlalchemy.org/trac/ticket/2553

8.3.8.19 sql
............

   * `[sql] [bug]' ¶. Fixed the DropIndex construct to
     support an Index associated with a Table in a remote schema.

     References: #2571(1)

   * `[sql] [bug]' ¶. Fixed bug in over() construct whereby
     passing an empty list for either partition_by or order_by, as
     opposed to None, would fail to generate correctly.  Courtesy
     Gunnlaugur Þór Briem.

     References: #2574(2)

   * `[sql] [bug]' ¶. Fixed CTE bug whereby positional bound
     parameters present in the CTEs themselves would corrupt the overall
     ordering of bound parameters.  This primarily affected SQL Server
     as the platform with positional binds + CTE support.

     References: #2521(3)

   * `[sql] [bug]' ¶. Fixed more un-intuitivenesses in CTEs
     which prevented referring to a CTE in a union of itself without it
     being aliased.  CTEs now render uniquely on name, rendering the
     outermost CTE of a given name only - all other references are
     rendered just as the name.  This even includes other CTE/SELECTs
     that refer to different versions of the same CTE object, such as a
     SELECT or a UNION ALL of that SELECT. We are somewhat loosening the
     usual link between object identity and lexical identity in this
     case.  A true name conflict between two unrelated CTEs now raises
     an error.

   * `[sql] [bug]' ¶ quoting is applied to the column names
     inside the WITH RECURSIVE clause of a common table expression
     according to the quoting rules for the originating Column.

     References: #2512(4)

   * `[sql] [bug]' ¶. Fixed regression introduced in 0.7.6
     whereby the FROM list of a SELECT statement could be incorrect in
     certain “clone+replace” scenarios.

     References: #2518(5)

   * `[sql] [bug]' ¶. Fixed bug whereby usage of a UNION or
     similar inside of an embedded subquery would interfere with
     result-column targeting, in the case that a result-column had the
     same ultimate name as a name inside the embedded UNION.

     References: #2552(6)

   * `[sql] [bug]' ¶. Fixed a regression since 0.6 regarding
     result-row targeting.  It should be possible to use a select()
     statement with string based columns in it, that is select([‘id’,
     ‘name’]).select_from(‘mytable’), and have this statement be
     targetable by Column objects with those names; this is the
     mechanism by which query(MyClass).from_statement(some_statement)
     works.  At some point the specific case of using select([‘id’]),
     which is equivalent to select([literal_column(‘id’)]), stopped
     working here, so this has been re-instated and of course tested.

     References: #2558(7)

   * `[sql] [bug]' ¶. Added missing operators is_(), isnot()
     to the ColumnOperators base, so that these long-available operators
     are present as methods like all the other operators.

     References: #2544(8)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2571

   (2) http://www.sqlalchemy.org/trac/ticket/2574

   (3) http://www.sqlalchemy.org/trac/ticket/2521

   (4) http://www.sqlalchemy.org/trac/ticket/2512

   (5) http://www.sqlalchemy.org/trac/ticket/2518

   (6) http://www.sqlalchemy.org/trac/ticket/2552

   (7) http://www.sqlalchemy.org/trac/ticket/2558

   (8) http://www.sqlalchemy.org/trac/ticket/2544

8.3.8.20 postgresql
...................

   * `[postgresql] [bug]' ¶. Columns in reflected primary
     key constraint are now returned in the order in which the
     constraint itself defines them, rather than how the table orders
     them.  Courtesy Gunnlaugur Þór Briem..

     References: #2531(1)

   * `[postgresql] [bug]' ¶. Added ‘terminating connection’
     to the list of messages we use to detect a disconnect with PG,
     which appears to be present in some versions when the server is
     restarted.

     References: #2570(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2531

   (2) http://www.sqlalchemy.org/trac/ticket/2570

8.3.8.21 mysql
..............

   * `[mysql] [bug]' ¶. Updated mysqlconnector interface to
     use updated “client flag” and “charset” APIs, courtesy David
     McNelis.

8.3.8.22 sqlite
...............

   * `[sqlite] [feature]' ¶. Added support for the
     localtimestamp() SQL function implemented in SQLite, courtesy
     Richard Mitchell.

   * `[sqlite] [bug]' ¶. Adjusted a very old bugfix which
     attempted to work around a SQLite issue that itself was “fixed” as
     of sqlite 3.6.14, regarding quotes surrounding a table name when
     using the “foreign_key_list” pragma.  The fix has been adjusted to
     not interfere with quotes that are `actually in the name' of a
     column or table, to as much a degree as possible; sqlite still
     doesn’t return the correct result for foreign_key_list() if the
     target table actually has quotes surrounding its name, as `part' of
     its name (i.e.  “””mytable”””).

     References: #2568(1)

   * `[sqlite] [bug]' ¶. Adjusted column default reflection
     code to convert non-string values to string, to accommodate old
     SQLite versions that don’t deliver default info as a string.

     References: #2265(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2568

   (2) http://www.sqlalchemy.org/trac/ticket/2265

8.3.8.23 mssql
..............

   * `[mssql] [bug]' ¶. Fixed compiler bug whereby using a
     correlated subquery within an ORDER BY would fail to render
     correctly if the statement also used LIMIT/OFFSET, due to
     mis-rendering within the ROW_NUMBER() OVER clause.  Fix courtesy
     sayap

     References: #2538(1)

   * `[mssql] [bug]' ¶. Fixed compiler bug whereby a given
     select() would be modified if it had an “offset” attribute, causing
     the construct to not compile correctly a second time.

     References: #2545(2)

   * `[mssql] [bug]' ¶. Fixed bug where reflection of
     primary key constraint would double up columns if the same
     constraint/table existed in multiple schemas.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2538

   (2) http://www.sqlalchemy.org/trac/ticket/2545

8.3.8.24 0.7.8
..............

Released: Sat Jun 16 2012

8.3.8.25 orm
............

   * `[orm] [feature]' ¶. The ‘objects’ argument to flush()
     is no longer deprecated, as some valid use cases have been
     identified.

   * `[orm] [bug]' ¶. Fixed bug whereby subqueryload() from
     a polymorphic mapping to a target would incur a new invocation of
     the query for each distinct class encountered in the polymorphic
     result.

     References: #2480(1)

   * `[orm] [bug]' ¶. Fixed bug in declarative whereby the
     precedence of columns in a joined-table, composite column
     (typically for id) would fail to be correct if the columns
     contained names distinct from their attribute names.  This would
     cause things like primaryjoin conditions made against the entity
     attributes to be incorrect.  Related to as this was supposed to be
     part of that, this is.

     References: #1892(2), #2491(3)

   * `[orm] [bug]' ¶. Fixed identity_key() function which
     was not accepting a scalar argument for the identity.  .

     References: #2508(4)

   * `[orm] [bug]' ¶. Fixed bug whereby populate_existing
     option would not propagate to subquery eager loaders.  .

     References: #2497(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2480

   (2) http://www.sqlalchemy.org/trac/ticket/1892

   (3) http://www.sqlalchemy.org/trac/ticket/2491

   (4) http://www.sqlalchemy.org/trac/ticket/2508

   (5) http://www.sqlalchemy.org/trac/ticket/2497

8.3.8.26 engine
...............

   * `[engine] [bug]' ¶. Fixed memory leak in C version of
     result proxy whereby DBAPIs which don’t deliver pure Python tuples
     for result rows would fail to decrement refcounts correctly.  The
     most prominently affected DBAPI is pyodbc.

     References: #2489(1)

   * `[engine] [bug]' ¶. Fixed bug affecting Py3K whereby
     string positional parameters passed to engine/connection execute()
     would fail to be interpreted correctly, due to __iter__ being
     present on Py3K string..

     References: #2503(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2489

   (2) http://www.sqlalchemy.org/trac/ticket/2503

8.3.8.27 sql
............

   * `[sql] [bug]' ¶ added BIGINT to types.__all__, BIGINT,
     BINARY, VARBINARY to sqlalchemy module namespace, plus test to
     ensure this breakage doesn’t occur again.

     References: #2499(1)

   * `[sql] [bug]' ¶. Repaired common table expression
     rendering to function correctly when the SELECT statement contains
     UNION or other compound expressions, courtesy btbuilder.

     References: #2490(2)

   * `[sql] [bug]' ¶. Fixed bug whereby append_column()
     wouldn’t function correctly on a cloned select() construct,
     courtesy Gunnlaugur Þór Briem.

     References: #2482(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2499

   (2) http://www.sqlalchemy.org/trac/ticket/2490

   (3) http://www.sqlalchemy.org/trac/ticket/2482

8.3.8.28 postgresql
...................

   * `[postgresql] [bug]' ¶ removed unnecessary table
     clause when reflecting enums,.  Courtesy Gunnlaugur Þór Briem.

     References: #2510(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2510

8.3.8.29 mysql
..............

   * `[mysql] [feature]' ¶. Added a new dialect for Google
     App Engine.  Courtesy Richie Foreman.

     References: #2484(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2484

8.3.8.30 oracle
...............

   * `[oracle] [bug]' ¶. Added ROWID to oracle.*.

     References: #2483(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2483

8.3.8.31 0.7.7
..............

Released: Sat May 05 2012

8.3.8.32 orm
............

   * `[orm] [feature]' ¶. Added prefix_with() method to
     Query, calls upon select().prefix_with() to allow placement of
     MySQL SELECT directives in statements.  Courtesy Diana Clarke

     References: #2443(1)

   * `[orm] [feature]' ¶. Added new flag to @validates
     include_removes.  When True, collection remove and attribute del
     events will also be sent to the validation function, which accepts
     an additional argument “is_remove” when this flag is used.

   * `[orm] [bug]' ¶. Fixed issue in unit of work whereby
     setting a non-None self-referential many-to-one relationship to
     None would fail to persist the change if the former value was not
     already loaded..

     References: #2477(2)

   * `[orm] [bug]' ¶. Fixed bug in 0.7.6 introduced by
     whereby column_mapped_collection used against columns that were
     mapped as joins or other indirect selectables would fail to
     function.

     References: #2409(3)

   * `[orm] [bug]' ¶. Fixed bug whereby polymorphic_on
     column that’s not otherwise mapped on the class would be
     incorrectly included in a merge() operation, raising an error.

     References: #2449(4)

   * `[orm] [bug]' ¶. Fixed bug in expression annotation
     mechanics which could lead to incorrect rendering of SELECT
     statements with aliases and joins, particularly when using
     column_property().

     References: #2453(5)

   * `[orm] [bug]' ¶. Fixed bug which would prevent
     OrderingList from being pickleable.  Courtesy Jeff Dairiki

     References: #2454(6)

   * `[orm] [bug]' ¶. Fixed bug in relationship comparisons
     whereby calling unimplemented methods like
     SomeClass.somerelationship.like() would produce a recursion
     overflow, instead of NotImplementedError.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2443

   (2) http://www.sqlalchemy.org/trac/ticket/2477

   (3) http://www.sqlalchemy.org/trac/ticket/2409

   (4) http://www.sqlalchemy.org/trac/ticket/2449

   (5) http://www.sqlalchemy.org/trac/ticket/2453

   (6) http://www.sqlalchemy.org/trac/ticket/2454

8.3.8.33 sql
............

   * `[sql] [feature]' ¶. Added new connection event
     dbapi_error().  Is called for all DBAPI-level errors passing the
     original DBAPI exception before SQLAlchemy modifies the state of
     the cursor.

   * `[sql] [bug]' ¶. Removed warning when Index is created
     with no columns; while this might not be what the user intended, it
     is a valid use case as an Index could be a placeholder for just an
     index of a certain name.

   * `[sql] [bug]' ¶. If conn.begin() fails when calling
     “with engine.begin()”, the newly acquired Connection is closed
     explicitly before propagating the exception onward normally.

   * `[sql] [bug]' ¶. Add BINARY, VARBINARY to
     types.__all__.

     References: #2474(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2474

8.3.8.34 postgresql
...................

   * `[postgresql] [feature]' ¶. Added new
     for_update/with_lockmode() options for PostgreSQL:
     for_update=”read”/ with_lockmode(“read”), for_update=”read_nowait”/
     with_lockmode(“read_nowait”).  These emit “FOR SHARE” and “FOR
     SHARE NOWAIT”, respectively.  Courtesy Diana Clarke

     References: #2445(1)

   * `[postgresql] [bug]' ¶ removed unnecessary table
     clause when reflecting domains.

     References: #2473(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2445

   (2) http://www.sqlalchemy.org/trac/ticket/2473

8.3.8.35 mysql
..............

   * `[mysql] [bug]' ¶. Fixed bug whereby column name inside
     of “KEY” clause for autoincrement composite column with InnoDB
     would double quote a name that’s a reserved word.  Courtesy Jeff
     Dairiki.

     References: #2460(1)

   * `[mysql] [bug]' ¶. Fixed bug whereby get_view_names()
     for “information_schema” schema would fail to retrieve views marked
     as “SYSTEM VIEW”.  courtesy Matthew Turland.

   * `[mysql] [bug]' ¶. Fixed bug whereby if cast() is used
     on a SQL expression whose type is not supported by cast() and
     therefore CAST isn’t rendered by the dialect, the order of
     evaluation could change if the casted expression required that it
     be grouped; grouping is now applied to those expressions.

     References: #2467(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2460

   (2) http://www.sqlalchemy.org/trac/ticket/2467

8.3.8.36 sqlite
...............

   * `[sqlite] [feature]' ¶. Added SQLite execution option
     “sqlite_raw_colnames=True”, will bypass attempts to remove “.” from
     column names returned by SQLite cursor.description.

     References: #2475(1)

   * `[sqlite] [bug]' ¶. When the primary key column of a
     Table is replaced, such as via extend_existing, the “auto
     increment” column used by insert() constructs is reset.  Previously
     it would remain referring to the previous primary key column.

     References: #2525(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2475

   (2) http://www.sqlalchemy.org/trac/ticket/2525

8.3.8.37 mssql
..............

   * `[mssql] [feature]' ¶. Added interim create_engine flag
     supports_unicode_binds to PyODBC dialect, to force whether or not
     the dialect passes Python unicode literals to PyODBC or not.

   * `[mssql] [bug]' ¶. Repaired the use_scope_identity
     create_engine() flag when using the pyodbc dialect.  Previously
     this flag would be ignored if set to False.  When set to False,
     you’ll get “SELECT @@identity” after each INSERT to get at the last
     inserted ID, for those tables which have “implicit_returning” set
     to False.

   * `[mssql] [bug]' ¶. UPDATE..FROM syntax with SQL Server
     requires that the updated table be present in the FROM clause when
     an alias of that table is also present in the FROM clause.  The
     updated table is now always present in the FROM, when FROM is
     present in the first place.  Courtesy sayap.

     References: #2468(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2468

8.3.8.38 0.7.6
..............

Released: Wed Mar 14 2012

8.3.8.39 orm
............

   * `[orm] [feature]' ¶. Added “no_autoflush” context
     manager to Session, used with with: will temporarily disable
     autoflush.

   * `[orm] [feature]' ¶. Added cte() method to Query,
     invokes common table expression support from the Core (see below).

     References: #1859(1)

   * `[orm] [feature]' ¶. Added the ability to query for
     Table-bound column names when using
     query(sometable).filter_by(colname=value).

     References: #2400(2)

   * `[orm] [bug]' ¶. Fixed event registration bug which
     would primarily show up as events not being registered with
     sessionmaker() instances created after the event was associated
     with the Session class.

     References: #2424(3)

   * `[orm] [bug]' ¶. Fixed bug whereby a primaryjoin
     condition with a “literal” in it would raise an error on compile
     with certain kinds of deeply nested expressions which also needed
     to render the same bound parameter name more than once.

     References: #2425(4)

   * `[orm] [bug]' ¶. Removed the check for number of rows
     affected when doing a multi-delete against mapped objects.  If an
     ON DELETE CASCADE exists between two rows, we can’t get an accurate
     rowcount from the DBAPI; this particular count is not supported on
     most DBAPIs in any case, MySQLdb is the notable case where it is.

     References: #2403(5)

   * `[orm] [bug]' ¶. Fixed bug whereby objects using
     attribute_mapped_collection or column_mapped_collection could not
     be pickled.

     References: #2409(6)

   * `[orm] [bug]' ¶. Fixed bug whereby MappedCollection
     would not get the appropriate collection instrumentation if it were
     only used in a custom subclass that used
     @collection.internally_instrumented.

     References: #2406(7)

   * `[orm] [bug]' ¶. Fixed bug whereby SQL adaption
     mechanics would fail in a very nested scenario involving
     joined-inheritance, joinedload(), limit(), and a derived function
     in the columns clause.

     References: #2419(8)

   * `[orm] [bug]' ¶. Fixed the repr() for CascadeOptions to
     include refresh-expire.  Also reworked CascadeOptions to be a
     <frozenset>.

     References: #2417(9)

   * `[orm] [bug]' ¶. Improved the “declarative reflection”
     example to support single-table inheritance, multiple calls to
     prepare(), tables that are present in alternate schemas,
     establishing only a subset of classes as reflected.

   * `[orm] [bug]' ¶. Scaled back the test applied within
     flush() to check for UPDATE against partially NULL PK within one
     table to only actually happen if there’s really an UPDATE to occur.

     References: #2390(10)

   * `[orm] [bug]' ¶. Fixed bug whereby if a method name
     conflicted with a column name, a TypeError would be raised when the
     mapper tried to inspect the __get__() method on the method object.

     References: #2352(11)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1859

   (2) http://www.sqlalchemy.org/trac/ticket/2400

   (3) http://www.sqlalchemy.org/trac/ticket/2424

   (4) http://www.sqlalchemy.org/trac/ticket/2425

   (5) http://www.sqlalchemy.org/trac/ticket/2403

   (6) http://www.sqlalchemy.org/trac/ticket/2409

   (7) http://www.sqlalchemy.org/trac/ticket/2406

   (8) http://www.sqlalchemy.org/trac/ticket/2419

   (9) http://www.sqlalchemy.org/trac/ticket/2417

   (10) http://www.sqlalchemy.org/trac/ticket/2390

   (11) http://www.sqlalchemy.org/trac/ticket/2352

8.3.8.40 engine
...............

   * `[engine] [feature]' ¶. Added “no_parameters=True”
     execution option for connections.  If no parameters are present,
     will pass the statement as cursor.execute(statement), thereby
     invoking the DBAPIs behavior when no parameter collection is
     present; for psycopg2 and mysql-python, this means not interpreting
     % signs in the string.  This only occurs with this option, and not
     just if the param list is blank, as otherwise this would produce
     inconsistent behavior of SQL expressions that normally escape
     percent signs (and while compiling, can’t know ahead of time if
     parameters will be present in some cases).

     References: #2407(1)

   * `[engine] [feature]' ¶. Added pool_reset_on_return
     argument to create_engine, allows control over “connection return”
     behavior.  Also added new arguments ‘rollback’, ‘commit’, None to
     pool.reset_on_return to allow more control over connection return
     activity.

     References: #2378(2)

   * `[engine] [feature]' ¶. Added some decent context
     managers to Engine, Connection:

          with engine.begin() as conn:
              <work with conn in a transaction>

     and:

          with engine.connect() as conn:
              <work with conn>

     Both close out the connection when done, commit or rollback
     transaction with errors on engine.begin().

   * `[engine] [bug]' ¶. Added execution_options() call to
     MockConnection (i.e., that used with strategy=”mock”) which acts as
     a pass through for arguments.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2407

   (2) http://www.sqlalchemy.org/trac/ticket/2378

8.3.8.41 sql
............

   * `[sql] [feature]' ¶. Added support for SQL standard
     common table expressions (CTE), allowing SELECT objects as the CTE
     source (DML not yet supported).  This is invoked via the cte()
     method on any select() construct.

     References: #1859(1)

   * `[sql] [bug]' ¶. Fixed memory leak in core which would
     occur when C extensions were used with particular types of result
     fetches, in particular when orm query.count() were called.

     References: #2427(2)

   * `[sql] [bug]' ¶. Fixed issue whereby attribute-based
     column access on a row would raise AttributeError with non-C
     version, NoSuchColumnError with C version.  Now raises
     AttributeError in both cases.

     References: #2398(3)

   * `[sql] [bug]' ¶. Added support for using the .key of a
     Column as a string identifier in a result set row.  The .key is
     currently listed as an “alternate” name for a column, and is
     superseded by the name of a column which has that key value as its
     regular name.  For the next major release of SQLAlchemy we may
     reverse this precedence so that .key takes precedence, but this is
     not decided on yet.

     References: #2392(4)

   * `[sql] [bug]' ¶. A warning is emitted when a
     not-present column is stated in the values() clause of an insert()
     or update() construct.  Will move to an exception in 0.8.

     References: #2413(5)

   * `[sql] [bug]' ¶. A significant change to how labeling
     is applied to columns in SELECT statements allows “truncated”
     labels, that is label names that are generated in Python which
     exceed the maximum identifier length (note this is configurable via
     label_length on create_engine()), to be properly referenced when
     rendered inside of a subquery, as well as to be present in a result
     set row using their original in-Python names.

     References: #2396(6)

   * `[sql] [bug]' ¶. Fixed bug in new “autoload_replace”
     flag which would fail to preserve the primary key constraint of the
     reflected table.

     References: #2402(7)

   * `[sql] [bug]' ¶. Index will raise when arguments passed
     cannot be interpreted as columns or expressions.  Will warn when
     Index is created with no columns at all.

     References: #2380(8)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1859

   (2) http://www.sqlalchemy.org/trac/ticket/2427

   (3) http://www.sqlalchemy.org/trac/ticket/2398

   (4) http://www.sqlalchemy.org/trac/ticket/2392

   (5) http://www.sqlalchemy.org/trac/ticket/2413

   (6) http://www.sqlalchemy.org/trac/ticket/2396

   (7) http://www.sqlalchemy.org/trac/ticket/2402

   (8) http://www.sqlalchemy.org/trac/ticket/2380

8.3.8.42 mysql
..............

   * `[mysql] [feature]' ¶. Added support for MySQL index
     and primary key constraint types (i.e.  USING) via new mysql_using
     parameter to Index and PrimaryKeyConstraint, courtesy Diana Clarke.

     References: #2386(1)

   * `[mysql] [feature]' ¶. Added support for the
     “isolation_level” parameter to all MySQL dialects.  Thanks to
     mu_mind for the patch here.

     References: #2394(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2386

   (2) http://www.sqlalchemy.org/trac/ticket/2394

8.3.8.43 sqlite
...............

   * `[sqlite] [bug]' ¶. Fixed bug in C extensions whereby
     string format would not be applied to a Numeric value returned as
     integer; this affected primarily SQLite which does not maintain
     numeric scale settings.

     References: #2432(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2432

8.3.8.44 mssql
..............

   * `[mssql] [feature]' ¶. Added support for MSSQL INSERT,
     UPDATE, and DELETE table hints, using new with_hint() method on
     UpdateBase.

     References: #2430(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2430

8.3.8.45 oracle
...............

   * `[oracle] [feature]' ¶. Added a new create_engine()
     flag coerce_to_decimal=False, disables the precision numeric
     handling which can add lots of overhead by converting all numeric
     values to Decimal.

     References: #2399(1)

   * `[oracle] [bug]' ¶. Added missing compilation support
     for LONG

     References: #2401(2)

   * `[oracle] [bug]' ¶. Added ‘LEVEL’ to the list of
     reserved words for Oracle.

     References: #2435(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2399

   (2) http://www.sqlalchemy.org/trac/ticket/2401

   (3) http://www.sqlalchemy.org/trac/ticket/2435

8.3.8.46 misc
.............

   * `[bug] [examples]' ¶. Altered _params_from_query()
     function in Beaker example to pull bindparams from the fully
     compiled statement, as a quick means to get everything including
     subqueries in the columns clause, etc.

8.3.8.47 0.7.5
..............

Released: Sat Jan 28 2012

8.3.8.48 orm
............

   * `[orm] [feature]' ¶. Added “class_registry” argument to
     declarative_base().  Allows two or more declarative bases to share
     the same registry of class names.

   * `[orm] [feature]' ¶ query.filter() accepts multiple
     criteria which will join via AND, i.e.  query.filter(x==y, z>q, …)

   * `[orm] [feature]' ¶. Added new capability to
     relationship loader options to allow “default” loader strategies.
     Pass ‘*’ to any of joinedload(), lazyload(), subqueryload(), or
     noload() and that becomes the loader strategy used for all
     relationships, except for those explicitly stated in the Query.
     Thanks to up-and-coming contributor Kent Bower for an exhaustive
     and well written test suite !

     References: #2351(1)

   * `[orm] [feature]' ¶. New declarative reflection example
     added, illustrates how best to mix table reflection with
     declarative as well as uses some new features from.

     References: #2356(2)

   * `[orm] [bug]' ¶. Fixed issue where modified session
     state established after a failed flush would be committed as part
     of the subsequent transaction that begins automatically after
     manual call to rollback().  The state of the session is checked
     within rollback(), and if new state is present, a warning is
     emitted and restore_snapshot() is called a second time, discarding
     those changes.

     References: #2389(3)

   * `[orm] [bug]' ¶. Fixed regression from 0.7.4 whereby
     using an already instrumented column from a superclass as
     “polymorphic_on” failed to resolve the underlying Column.

     References: #2345(4)

   * `[orm] [bug]' ¶. Raise an exception if xyzload_all() is
     used inappropriately with two non-connected relationships.

     References: #2370(5)

   * `[orm] [bug]' ¶. Fixed bug whereby
     event.listen(SomeClass) forced an entirely unnecessary compile of
     the mapper, making events very hard to set up at module import time
     (nobody noticed this ??)

     References: #2367(6)

   * `[orm] [bug]' ¶. Fixed bug whereby hybrid_property
     didn’t work as a kw arg in any(), has().

   * `[orm] [bug]' ¶ ensure pickleability of all ORM
     exceptions for multiprocessing compatibility.

     References: #2371(7)

   * `[orm] [bug]' ¶ implemented standard “can’t set
     attribute” / “can’t delete attribute” AttributeError when
     setattr/delattr used on a hybrid that doesn’t define fset or fdel.

     References: #2353(8)

   * `[orm] [bug]' ¶. Fixed bug where unpickled object
     didn’t have enough of its state set up to work correctly within the
     unpickle() event established by the mutable object extension, if
     the object needed ORM attribute access within __eq__() or similar.

     References: #2362(9)

   * `[orm] [bug]' ¶. Fixed bug where “merge” cascade could
     mis-interpret an unloaded attribute, if the load_on_pending flag
     were used with relationship().  Thanks to Kent Bower for tests.

     References: #2374(10)

   * `[orm]' ¶. Fixed regression from 0.6 whereby if
     “load_on_pending” relationship() flag were used where a non-“get()”
     lazy clause needed to be emitted on a pending object, it would fail
     to load.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2351

   (2) http://www.sqlalchemy.org/trac/ticket/2356

   (3) http://www.sqlalchemy.org/trac/ticket/2389

   (4) http://www.sqlalchemy.org/trac/ticket/2345

   (5) http://www.sqlalchemy.org/trac/ticket/2370

   (6) http://www.sqlalchemy.org/trac/ticket/2367

   (7) http://www.sqlalchemy.org/trac/ticket/2371

   (8) http://www.sqlalchemy.org/trac/ticket/2353

   (9) http://www.sqlalchemy.org/trac/ticket/2362

   (10) http://www.sqlalchemy.org/trac/ticket/2374

8.3.8.49 engine
...............

   * `[engine] [bug]' ¶. Added __reduce__ to StatementError,
     DBAPIError, column errors so that exceptions are pickleable, as
     when using multiprocessing.  However, not all DBAPIs support this
     yet, such as psycopg2.

     References: #2371(1)

   * `[engine] [bug]' ¶. Improved error messages when a
     non-string or invalid string is passed to any of the date/time
     processors used by SQLite, including C and Python versions.

     References: #2382(2)

   * `[engine] [bug]' ¶. Fixed bug whereby a table-bound
     Column object named “<a>_<b>” which matched a column labeled as
     “<tablename>_<colname>” could match inappropriately when targeting
     in a result set row.

     References: #2377(3)

   * `[engine] [bug]' ¶. Fixed bug in “mock” strategy
     whereby correct DDL visit method wasn’t called, resulting in
     “CREATE/DROP SEQUENCE” statements being duplicated

     References: #2384(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2371

   (2) http://www.sqlalchemy.org/trac/ticket/2382

   (3) http://www.sqlalchemy.org/trac/ticket/2377

   (4) http://www.sqlalchemy.org/trac/ticket/2384

8.3.8.50 sql
............

   * `[sql] [feature]' ¶. New reflection feature
     “autoload_replace”; when set to False on Table, the Table can be
     autoloaded without existing columns being replaced.  Allows more
     flexible chains of Table construction/reflection to be constructed,
     including that it helps with combining Declarative with table
     reflection.  See the new example on the wiki.

     References: #2356(1)

   * `[sql] [feature]' ¶. Added “false()” and “true()”
     expression constructs to sqlalchemy.sql namespace, though not part
     of __all__ as of yet.

   * `[sql] [feature]' ¶. Dialect-specific compilers now
     raise CompileError for all type/statement compilation issues,
     instead of InvalidRequestError or ArgumentError.  The DDL for
     CREATE TABLE will re-raise CompileError to include table/column
     information for the problematic column.

     References: #2361(2)

   * `[sql] [bug]' ¶. Improved the API for add_column() such
     that if the same column is added to its own table, an error is not
     raised and the constraints don’t get doubled up.  Also helps with
     some reflection/declarative patterns.

     References: #2356(3)

   * `[sql] [bug]' ¶. Fixed issue where the “required”
     exception would not be raised for bindparam() with required=True,
     if the statement were given no parameters at all.

     References: #2381(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2356

   (2) http://www.sqlalchemy.org/trac/ticket/2361

   (3) http://www.sqlalchemy.org/trac/ticket/2356

   (4) http://www.sqlalchemy.org/trac/ticket/2381

8.3.8.51 mysql
..............

   * `[mysql] [bug]' ¶ fixed regexp that filters out
     warnings for non-reflected “PARTITION” directives, thanks to George
     Reilly

     References: #2376(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2376

8.3.8.52 sqlite
...............

   * `[sqlite] [bug]' ¶ the “name” of an FK constraint in
     SQLite is reflected as “None”, not “0” or other integer value.
     SQLite does not appear to support constraint naming in any case.

     References: #2364(1)

   * `[sqlite] [bug]' ¶ sql.false() and sql.true() compile
     to 0 and 1, respectively in sqlite

     References: #2368(2)

   * `[sqlite] [bug]' ¶ removed an erroneous “raise” in the
     SQLite dialect when getting table names and view names, where logic
     is in place to fall back to an older version of SQLite that doesn’t
     have the “sqlite_temp_master” table.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2364

   (2) http://www.sqlalchemy.org/trac/ticket/2368

8.3.8.53 mssql
..............

   * `[mssql] [bug]' ¶. Adjusted the regexp used in the
     mssql.TIME type to ensure only six digits are received for the
     “microseconds” portion of the value, which is expected by Python’s
     datetime.time().  Note that support for sending microseconds
     doesn’t seem to be possible yet with pyodbc at least.

     References: #2340(1)

   * `[mssql] [bug]' ¶. Dropped the “30 char” limit on
     pymssql, based on reports that it’s doing things better these days.
     pymssql hasn’t been well tested and as the DBAPI is in flux it’s
     still not clear what the status is on this driver and how
     SQLAlchemy’s implementation should adapt.

     References: #2347(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2340

   (2) http://www.sqlalchemy.org/trac/ticket/2347

8.3.8.54 oracle
...............

   * `[oracle] [bug]' ¶. Added ORA-03135 to the never ending
     list of oracle “connection lost” errors

     References: #2388(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2388

8.3.8.55 misc
.............

   * `[feature] [examples]' ¶. Simplified the versioning
     example a bit to use a declarative mixin as well as an event
     listener, instead of a metaclass + SessionExtension.

     References: #2313(1)

   * `[bug] [core]' ¶. Changed LRUCache, used by the mapper
     to cache INSERT/UPDATE/DELETE statements, to use an incrementing
     counter instead of a timestamp to track entries, for greater
     reliability versus using time.time(), which can cause test failures
     on some platforms.

     References: #2379(2)

   * `[bug] [core]' ¶. Added a boolean check for the
     “finalize” function within the pool connection proxy’s weakref
     callback before calling it, so that a warning isn’t emitted that
     this function is None when the application is exiting and gc has
     removed the function from the module before the weakref callback
     was invoked.

     References: #2383(3)

   * `[bug] [py3k]' ¶. Fixed inappropriate usage of
     util.py3k flag and renamed it to util.py3k_warning, since this flag
     is intended to detect the -3 flag series of import restrictions
     only.

     References: #2348(4)

   * `[bug] [examples]' ¶. Fixed large_collection.py to
     close the session before dropping tables.

     References: #2346(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2313

   (2) http://www.sqlalchemy.org/trac/ticket/2379

   (3) http://www.sqlalchemy.org/trac/ticket/2383

   (4) http://www.sqlalchemy.org/trac/ticket/2348

   (5) http://www.sqlalchemy.org/trac/ticket/2346

8.3.8.56 0.7.4
..............

Released: Fri Dec 09 2011

8.3.8.57 orm
............

   * `[orm] [feature]' ¶ polymorphic_on now accepts many
     new kinds of values:

             * standalone expressions that aren’t otherwise mapped

             * column_property() objects

             * string names of any column_property() or attribute name
               of a mapped Column

     The docs include an example using the case() construct, which is
     likely to be a common constructed used here.  and part of

     Standalone expressions in polymorphic_on propagate to single-table
     inheritance subclasses so that they are used in the WHERE /JOIN
     clause to limit rows to that subclass as is the usual behavior.

     References: #2238(1), #2345(2)

   * `[orm] [feature]' ¶. IdentitySet supports the -
     operator as the same as difference(), handy when dealing with
     Session.dirty etc.

     References: #2301(3)

   * `[orm] [feature]' ¶. Added new value for Column
     autoincrement called “ignore_fk”, can be used to force
     autoincrement on a column that’s still part of a
     ForeignKeyConstraint.  New example in the relationship docs
     illustrates its use.

   * `[orm] [bug]' ¶. Fixed backref behavior when “popping”
     the value off of a many-to-one in response to a removal from a
     stale one-to-many - the operation is skipped, since the many-to-one
     has since been updated.

     References: #2315(4)

   * `[orm] [bug]' ¶. After some years of not doing this,
     added more granularity to the “is X a parent of Y” functionality,
     which is used when determining if the FK on “Y” needs to be “nulled
     out” as well as if “Y” should be deleted with delete-orphan
     cascade.  The test now takes into account the Python identity of
     the parent as well its identity key, to see if the last known
     parent of Y is definitely X. If a decision can’t be made, a
     StaleDataError is raised.  The conditions where this error is
     raised are fairly rare, requiring that the previous parent was
     garbage collected, and previously could very well inappropriately
     update/delete a record that’s since moved onto a new parent, though
     there may be some cases where “silent success” occurred previously
     that will now raise in the face of ambiguity.  Expiring “Y” resets
     the “parent” tracker, meaning X.remove(Y) could then end up
     deleting Y even if X is stale, but this is the same behavior as
     before; it’s advised to expire X also in that case.

     References: #2264(5)

   * `[orm] [bug]' ¶ fixed inappropriate evaluation of
     user-mapped object in a boolean context within query.get().  Also
     in 0.6.9.

     References: #2310(6)

   * `[orm] [bug]' ¶. Added missing comma to
     PASSIVE_RETURN_NEVER_SET symbol

     References: #2304(7)

   * `[orm] [bug]' ¶. Cls.column.collate(“some collation”)
     now works.  Also in 0.6.9

     References: #1776(8)

   * `[orm] [bug]' ¶ the value of a composite attribute is
     now expired after an insert or update operation, instead of
     regenerated in place.  This ensures that a column value which is
     expired within a flush will be loaded first, before the composite
     is regenerated using that value.

     References: #2309(9)

   * `[orm] [bug]' ¶. The fix in also emits the “refresh”
     event when the composite value is loaded on access, even if all
     column values were already present, as is appropriate.  This fixes
     the “mutable” extension which relies upon the “load” event to
     ensure the _parents dictionary is up to date, fixes.  Thanks to
     Scott Torborg for the test case here.

     References: #2308(10), #2309(11)

   * `[orm] [bug]' ¶. Fixed bug whereby a subclass of a
     subclass using concrete inheritance in conjunction with the new
     ConcreteBase or AbstractConcreteBase would fail to apply the
     subclasses deeper than one level to the “polymorphic loader” of
     each base

     References: #2312(12)

   * `[orm] [bug]' ¶. Fixed bug whereby a subclass of a
     subclass using the new AbstractConcreteBase would fail to acquire
     the correct “base_mapper” attribute when the “base” mapper was
     generated, thereby causing failures later on.

     References: #2312(13)

   * `[orm] [bug]' ¶. Fixed bug whereby column_property()
     created against ORM-level column could be treated as a distinct
     entity when producing certain kinds of joined-inh joins.

     References: #2316(14)

   * `[orm] [bug]' ¶. Fixed the error formatting raised when
     a tuple is inadvertently passed to session.query().  Also in 0.6.9.

     References: #2297(15)

   * `[orm] [bug]' ¶. Calls to query.join() to a
     single-table inheritance subclass are now tracked, and are used to
     eliminate the additional WHERE.. IN criterion normally tacked on
     with single table inheritance, since the join should accommodate
     it.  This allows OUTER JOIN to a single table subclass to produce
     the correct results, and overall will produce fewer WHERE criterion
     when dealing with single table inheritance joins.

     References: #2328(16)

   * `[orm] [bug]' ¶. __table_args__ can now be passed as an
     empty tuple as well as an empty dict..  Thanks to Fayaz Yusuf Khan
     for the patch.

     References: #2339(17)

   * `[orm] [bug]' ¶. Updated warning message when setting
     delete-orphan without delete to no longer refer to 0.6, as we never
     got around to upgrading this to an exception.  Ideally this might
     be better as an exception but it’s not critical either way.

     References: #2325(18)

   * `[orm] [bug]' ¶. Fixed bug in get_history() when
     referring to a composite attribute that has no value; added
     coverage for get_history() regarding composites which is otherwise
     just a userland function.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2238

   (2) http://www.sqlalchemy.org/trac/ticket/2345

   (3) http://www.sqlalchemy.org/trac/ticket/2301

   (4) http://www.sqlalchemy.org/trac/ticket/2315

   (5) http://www.sqlalchemy.org/trac/ticket/2264

   (6) http://www.sqlalchemy.org/trac/ticket/2310

   (7) http://www.sqlalchemy.org/trac/ticket/2304

   (8) http://www.sqlalchemy.org/trac/ticket/1776

   (9) http://www.sqlalchemy.org/trac/ticket/2309

   (10) http://www.sqlalchemy.org/trac/ticket/2308

   (11) http://www.sqlalchemy.org/trac/ticket/2309

   (12) http://www.sqlalchemy.org/trac/ticket/2312

   (13) http://www.sqlalchemy.org/trac/ticket/2312

   (14) http://www.sqlalchemy.org/trac/ticket/2316

   (15) http://www.sqlalchemy.org/trac/ticket/2297

   (16) http://www.sqlalchemy.org/trac/ticket/2328

   (17) http://www.sqlalchemy.org/trac/ticket/2339

   (18) http://www.sqlalchemy.org/trac/ticket/2325

8.3.8.58 engine
...............

   * `[engine] [bug]' ¶. Fixed bug whereby
     transaction.rollback() would throw an error on an invalidated
     connection if the transaction were a two-phase or savepoint
     transaction.  For plain transactions, rollback() is a no-op if the
     connection is invalidated, so while it wasn’t 100% clear if it
     should be a no-op, at least now the interface is consistent.

     References: #2317(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2317

8.3.8.59 sql
............

   * `[sql] [feature]' ¶. The update() construct can now
     accommodate multiple tables in the WHERE clause, which will render
     an “UPDATE..FROM” construct, recognized by PostgreSQL and MSSQL.
     When compiled on MySQL, will instead generate “UPDATE t1, t2, ..”.
     MySQL additionally can render against multiple tables in the SET
     clause, if Column objects are used as keys in the “values”
     parameter or generative method.

     References: #1944(1), #2166(2)

   * `[sql] [feature]' ¶. Added accessor to types called
     “python_type”, returns the rudimentary Python type object for a
     particular TypeEngine instance, if known, else raises
     NotImplementedError.

     References: #77(3)

   * `[sql] [bug]' ¶ related to, made some adjustments to
     the change from regarding the “from” list on a select().  The
     _froms collection is no longer memoized, as this simplifies various
     use cases and removes the need for a “warning” if a column is
     attached to a table after it was already used in an expression -
     the select() construct will now always produce the correct
     expression.  There’s probably no real-world performance hit here;
     select() objects are almost always made ad-hoc, and systems that
     wish to optimize the re-use of a select() would be using the
     “compiled_cache” feature.  A hit which would occur when calling
     select.bind has been reduced, but the vast majority of users
     shouldn’t be using “bound metadata” anyway :).

     References: #2261(4), #2316(5)

   * `[sql] [bug]' ¶ further tweak to the fix from, so that
     generative methods work a bit better off of cloned (this is almost
     a non-use case though).  In particular this allows
     with_only_columns() to behave more consistently.  Added additional
     documentation to with_only_columns() to clarify expected behavior,
     which changed as a result of.

     References: #2261(6), #2319(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1944

   (2) http://www.sqlalchemy.org/trac/ticket/2166

   (3) http://www.sqlalchemy.org/trac/ticket/77

   (4) http://www.sqlalchemy.org/trac/ticket/2261

   (5) http://www.sqlalchemy.org/trac/ticket/2316

   (6) http://www.sqlalchemy.org/trac/ticket/2261

   (7) http://www.sqlalchemy.org/trac/ticket/2319

8.3.8.60 schema
...............

   * `[schema] [feature]' ¶. Added new support for remote
     “schemas”:

   * `[schema] [feature]' ¶. The “extend_existing” flag on
     Table now allows for the reflection process to take effect for a
     Table object that’s already been defined; when autoload=True and
     extend_existing=True are both set, the full set of columns will be
     reflected from the Table which will then `overwrite' those columns
     already present, rather than no activity occurring.  Columns that
     are present directly in the autoload run will be used as always,
     however.

     References: #1410(1)

   * `[schema] [bug]' ¶. Fixed bug whereby TypeDecorator
     would return a stale value for _type_affinity, when using a
     TypeDecorator that “switches” types, like the CHAR/UUID type.

   * `[schema] [bug]' ¶. Fixed bug whereby
     “order_by=’foreign_key’” option to Inspector.get_table_names wasn’t
     implementing the sort properly, replaced with the existing sort
     algorithm

   * `[schema] [bug]' ¶ the “name” of a column-level CHECK
     constraint, if present, is now rendered in the CREATE TABLE
     statement using “CONSTRAINT <name> CHECK <expression>”.

     References: #2305(2)

   * `[schema]' ¶. MetaData() accepts “schema” and
     “quote_schema” arguments, which will be applied to the same-named
     arguments of a Table or Sequence which leaves these at their
     default of ‘None’.

   * `[schema]' ¶. Sequence accepts “quote_schema” argument

   * `[schema]' ¶ tometadata() for Table will use the
     “schema” of the incoming MetaData for the new Table if the schema
     argument is explicitly “None”

   * `[schema]' ¶. Added CreateSchema and DropSchema DDL
     constructs - these accept just the string name of a schema and a
     “quote” flag.

   * `[schema]' ¶. When using default “schema” with
     MetaData, ForeignKey will also assume the “default” schema when
     locating remote table.  This allows the “schema” argument on
     MetaData to be applied to any set of Table objects that otherwise
     don’t have a “schema”.

   * `[schema]' ¶ a “has_schema” method has been
     implemented on dialect, but only works on PostgreSQL so far.
     Courtesy Manlio Perillo.

     References: #1679(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1410

   (2) http://www.sqlalchemy.org/trac/ticket/2305

   (3) http://www.sqlalchemy.org/trac/ticket/1679

8.3.8.61 postgresql
...................

   * `[postgresql] [feature]' ¶. Added create_type
     constructor argument to pg.ENUM. When False, no CREATE/DROP or
     checking for the type will be performed as part of a table
     create/drop event; only the create()/drop)() methods called
     directly will do this.  Helps with Alembic “offline” scripts.

   * `[postgresql] [bug]' ¶. PostgreSQL dialect memoizes
     that an ENUM of a particular name was processed during a
     create/drop sequence.  This allows a create/drop sequence to work
     without any calls to “checkfirst”, and also means with “checkfirst”
     turned on it only needs to check for the ENUM once.

     References: #2311(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2311

8.3.8.62 mysql
..............

   * `[mysql] [bug]' ¶. Unicode adjustments allow latest
     pymysql (post 0.4) to pass 100% on Python 2.

8.3.8.63 mssql
..............

   * `[mssql] [feature]' ¶ lifted the restriction on
     SAVEPOINT for SQL Server.  All tests pass using it, it’s not known
     if there are deeper issues however.

     References: #822(1)

   * `[mssql] [bug]' ¶ repaired the with_hint() feature
     which wasn’t implemented correctly on MSSQL - usually used for the
     “WITH (NOLOCK)” hint (which you shouldn’t be using anyway !  use
     snapshot isolation instead :) )

     References: #2336(2)

   * `[mssql] [bug]' ¶ use new pyodbc version detection for
     _need_decimal_fix option.

     References: #2318(3)

   * `[mssql] [bug]' ¶ don’t cast “table name” as NVARCHAR
     on SQL Server 2000.  Still mostly in the dark what incantations are
     needed to make PyODBC work fully with FreeTDS 0.91 here, however.

     References: #2343(4)

   * `[mssql] [bug]' ¶. Decode incoming values when
     retrieving list of index names and the names of columns within
     those indexes.

     References: #2269(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/822

   (2) http://www.sqlalchemy.org/trac/ticket/2336

   (3) http://www.sqlalchemy.org/trac/ticket/2318

   (4) http://www.sqlalchemy.org/trac/ticket/2343

   (5) http://www.sqlalchemy.org/trac/ticket/2269

8.3.8.64 misc
.............

   * `[feature] [ext]' ¶. Added an example to the hybrid
     docs of a “transformer” - a hybrid that returns a
     query-transforming callable in combination with a custom
     comparator.  Uses a new method on Query called
     with_transformation().  The use case here is fairly experimental,
     but only adds one line of code to Query.

   * `[bug] [pyodbc]' ¶ pyodbc-based dialects now parse the
     pyodbc accurately as far as observed pyodbc strings, including such
     gems as “py3-3.0.1-beta4”

     References: #2318(1)

   * `[bug] [ext]' ¶ the @compiles decorator raises an
     informative error message when no “default” compilation handler is
     present, rather than KeyError.

   * `[bug] [examples]' ¶. Fixed bug in history_meta.py
     example where the “unique” flag was not removed from a
     single-table-inheritance subclass which generates columns to put up
     onto the base.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2318

8.3.8.65 0.7.3
..............

Released: Sun Oct 16 2011

8.3.8.66 general
................

   * `[general]' ¶. Adjusted the “importlater” mechanism,
     which is used internally to resolve import cycles, such that the
     usage of __import__ is completed when the import of sqlalchemy or
     sqlalchemy.orm is done, thereby avoiding any usage of __import__
     after the application starts new threads, fixes.  Also in 0.6.9.

     References: #2279(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2279

8.3.8.67 orm
............

   * `[orm]' ¶. Improved query.join() such that the “left”
     side can more flexibly be a non-ORM selectable, such as a subquery.
     A selectable placed in select_from() will now be used as the left
     side, favored over implicit usage of a mapped entity.  If the join
     still fails based on lack of foreign keys, the error message
     includes this detail.  Thanks to brianrhude on IRC for the test
     case.

     References: #2298(1)

   * `[orm]' ¶. Added after_soft_rollback() Session event.
     This event fires unconditionally whenever rollback() is called,
     regardless of if an actual DBAPI level rollback occurred.  This
     event is specifically designed to allow operations with the Session
     to proceed after a rollback when the Session.is_active is True.

     References: #2241(2)

   * `[orm]' ¶ added “adapt_on_names” boolean flag to
     orm.aliased() construct.  Allows an aliased() construct to link the
     ORM entity to a selectable that contains aggregates or other
     derived forms of a particular attribute, provided the name is the
     same as that of the entity mapped column.

   * `[orm]' ¶. Added new flag expire_on_flush=False to
     column_property(), marks those properties that would otherwise be
     considered to be “readonly”, i.e.  derived from SQL expressions, to
     retain their value after a flush has occurred, including if the
     parent object itself was involved in an update.

   * `[orm]' ¶. Enhanced the instrumentation in the ORM to
     support Py3K’s new argument style of “required kw arguments”, i.e.
     fn(a, b, *, c, d), fn(a, b, *args, c, d).  Argument signatures of
     mapped object’s __init__ method will be preserved, including
     required kw rules.

     References: #2237(3)

   * `[orm]' ¶. Fixed bug in unit of work whereby detection
     of “cycles” among classes in highly interlinked patterns would not
     produce a deterministic result; thereby sometimes missing some
     nodes that should be considered cycles and causing further issues
     down the road.  Note this bug is in 0.6 also; not backported at the
     moment.

     References: #2282(4)

   * `[orm]' ¶. Fixed a variety of synonym()-related
     regressions from 0.6:

             * making a synonym against a synonym now works.

             * synonyms made against a relationship() can be passed to
               query.join(), options sent to query.options(), passed by
               name to query.with_parent().

   * `[orm]' ¶. Fixed bug whereby mapper.order_by attribute
     would be ignored in the “inner” query within a subquery eager load.
     .  Also in 0.6.9.

     References: #2287(5)

   * `[orm]' ¶. Identity map .discard() uses dict.pop(,None)
     internally instead of “del” to avoid KeyError/warning during a
     non-determinate gc teardown

     References: #2267(6)

   * `[orm]' ¶. Fixed regression in new composite rewrite
     where deferred=True option failed due to missing import

     References: #2253(7)

   * `[orm]' ¶. Reinstated “comparator_factory” argument to
     composite(), removed when 0.7 was released.

     References: #2248(8)

   * `[orm]' ¶. Fixed bug in query.join() which would occur
     in a complex multiple-overlapping path scenario, where the same
     table could be joined to twice.  Thanks `much' to Dave Vitek for
     the excellent fix here.

     References: #2247(9)

   * `[orm]' ¶. Query will convert an OFFSET of zero when
     slicing into None, so that needless OFFSET clauses are not invoked.

   * `[orm]' ¶. Repaired edge case where mapper would fail
     to fully update internal state when a relationship on a new mapper
     would establish a backref on the first mapper.

   * `[orm]' ¶. Fixed bug whereby if __eq__() was redefined,
     a relationship many-to-one lazyload would hit the __eq__() and
     fail.  Does not apply to 0.6.9.

     References: #2260(10)

   * `[orm]' ¶. Calling class_mapper() and passing in an
     object that is not a “type” (i.e.  a class that could potentially
     be mapped) now raises an informative ArgumentError, rather than
     UnmappedClassError.

     References: #2196(11)

   * `[orm]' ¶. New event hook,
     MapperEvents.after_configured().  Called after a configure() step
     has completed and mappers were in fact affected.  Theoretically
     this event is called once per application, unless new mappings are
     constructed after existing ones have been used already.

   * `[orm]' ¶. When an open Session is garbage collected,
     the objects within it which remain are considered detached again
     when they are add()-ed to a new Session.  This is accomplished by
     an extra check that the previous “session_key” doesn’t actually
     exist among the pool of Sessions.

     References: #2281(12)

   * `[orm]' ¶. New declarative features:

             * __declare_last__() method, establishes an event listener
               for the class method that will be called when mappers are
               completed with the final “configure” step.

             * __abstract__ flag.  The class will not be mapped at all
               when this flag is present on the class.

             * New helper classes ConcreteBase, AbstractConcreteBase.
               Allow concrete mappings using declarative which
               automatically set up the “polymorphic_union” when the
               “configure” mapper step is invoked.

             * The mapper itself has semi-private methods that allow the
               “with_polymorphic” selectable to be assigned to the
               mapper after it has already been configured.

     References: #2239(13)

   * `[orm]' ¶. Declarative will warn when a subclass’ base
     uses @declared_attr for a regular column - this attribute does not
     propagate to subclasses.

     References: #2283(14)

   * `[orm]' ¶. The integer “id” used to link a mapped
     instance with its owning Session is now generated by a sequence
     generation function rather than id(Session), to eliminate the
     possibility of recycled id() values causing an incorrect result, no
     need to check that object actually in the session.

     References: #2280(15)

   * `[orm]' ¶. Behavioral improvement: empty conjunctions
     such as and_() and or_() will be flattened in the context of an
     enclosing conjunction, i.e.  and_(x, or_()) will produce ‘X’ and
     not ‘X AND ()’..

     References: #2257(16)

   * `[orm]' ¶. Fixed bug regarding calculation of “from”
     list for a select() element.  The “from” calc is now delayed, so
     that if the construct uses a Column object that is not yet attached
     to a Table, but is later associated with a Table, it generates SQL
     using the table as a FROM. This change impacted fairly deeply the
     mechanics of how the FROM list as well as the “correlates”
     collection is calculated, as some “clause adaption” schemes (these
     are used very heavily in the ORM) were relying upon the fact that
     the “froms” collection would typically be cached before the
     adaption completed.  The rework allows it such that the “froms”
     collection can be cleared and re-generated at any time.

     References: #2261(17)

   * `[orm]' ¶. Fixed bug whereby with_only_columns() method
     of Select would fail if a selectable were passed..  Also in 0.6.9.

     References: #2270(18)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2298

   (2) http://www.sqlalchemy.org/trac/ticket/2241

   (3) http://www.sqlalchemy.org/trac/ticket/2237

   (4) http://www.sqlalchemy.org/trac/ticket/2282

   (5) http://www.sqlalchemy.org/trac/ticket/2287

   (6) http://www.sqlalchemy.org/trac/ticket/2267

   (7) http://www.sqlalchemy.org/trac/ticket/2253

   (8) http://www.sqlalchemy.org/trac/ticket/2248

   (9) http://www.sqlalchemy.org/trac/ticket/2247

   (10) http://www.sqlalchemy.org/trac/ticket/2260

   (11) http://www.sqlalchemy.org/trac/ticket/2196

   (12) http://www.sqlalchemy.org/trac/ticket/2281

   (13) http://www.sqlalchemy.org/trac/ticket/2239

   (14) http://www.sqlalchemy.org/trac/ticket/2283

   (15) http://www.sqlalchemy.org/trac/ticket/2280

   (16) http://www.sqlalchemy.org/trac/ticket/2257

   (17) http://www.sqlalchemy.org/trac/ticket/2261

   (18) http://www.sqlalchemy.org/trac/ticket/2270

8.3.8.68 engine
...............

   * `[engine]' ¶. The recreate() method in all pool classes
     uses self.__class__ to get at the type of pool to produce, in the
     case of subclassing.  Note there’s no usual need to subclass pools.

     References: #2254(1)

   * `[engine]' ¶. Improvement to multi-param statement
     logging, long lists of bound parameter sets will be compressed with
     an informative indicator of the compression taking place.
     Exception messages use the same improved formatting.

     References: #2243(2)

   * `[engine]' ¶. Added optional “sa_pool_key” argument to
     pool.manage(dbapi).connect() so that serialization of args is not
     necessary.

   * `[engine]' ¶. The entry point resolution supported by
     create_engine() now supports resolution of individual DBAPI drivers
     on top of a built-in or entry point-resolved dialect, using the
     standard ‘+’ notation - it’s converted to a ‘.’ before being
     resolved as an entry point.

     References: #2286(3)

   * `[engine]' ¶. Added an exception catch + warning for
     the “return unicode detection” step within connect, allows
     databases that crash on NVARCHAR to continue initializing, assuming
     no NVARCHAR type implemented.

     References: #2299(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2254

   (2) http://www.sqlalchemy.org/trac/ticket/2243

   (3) http://www.sqlalchemy.org/trac/ticket/2286

   (4) http://www.sqlalchemy.org/trac/ticket/2299

8.3.8.69 schema
...............

   * `[schema]' ¶. Modified Column.copy() to use
     _constructor(), which defaults to self.__class__, in order to
     create the new object.  This allows easier support of subclassing
     Column.

     References: #2284(1)

   * `[schema]' ¶. Added a slightly nicer __repr__() to
     SchemaItem classes.  Note the repr here can’t fully support the
     “repr is the constructor” idea since schema items can be very
     deeply nested/cyclical, have late initialization of some things,
     etc.

     References: #2223(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2284

   (2) http://www.sqlalchemy.org/trac/ticket/2223

8.3.8.70 postgresql
...................

   * `[postgresql]' ¶. Added “postgresql_using” argument to
     Index(), produces USING clause to specify index implementation for
     PG. .  Thanks to Ryan P. Kelly for the patch.

     References: #2290(1)

   * `[postgresql]' ¶. Added client_encoding parameter to
     create_engine() when the postgresql+psycopg2 dialect is used; calls
     the psycopg2 set_client_encoding() method with the value upon
     connect.

     References: #1839(2)

   * `[postgresql]' ¶. Fixed bug related to whereby the same
     modified index behavior in PG 9 affected primary key reflection on
     a renamed column..  Also in 0.6.9.

     References: #2141(3), #2291(4)

   * `[postgresql]' ¶. Reflection functions for Table,
     Sequence no longer case insensitive.  Names can be differ only in
     case and will be correctly distinguished.

     References: #2256(5)

   * `[postgresql]' ¶. Use an atomic counter as the “random
     number” source for server side cursor names; conflicts have been
     reported in rare cases.

   * `[postgresql]' ¶. Narrowed the assumption made when
     reflecting a foreign-key referenced table with schema in the
     current search path; an explicit schema will be applied to the
     referenced table only if it actually matches that of the
     referencing table, which also has an explicit schema.  Previously
     it was assumed that “current” schema was synonymous with the full
     search_path.

     References: #2249(6)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2290

   (2) http://www.sqlalchemy.org/trac/ticket/1839

   (3) http://www.sqlalchemy.org/trac/ticket/2141

   (4) http://www.sqlalchemy.org/trac/ticket/2291

   (5) http://www.sqlalchemy.org/trac/ticket/2256

   (6) http://www.sqlalchemy.org/trac/ticket/2249

8.3.8.71 mysql
..............

   * `[mysql]' ¶ a CREATE TABLE will put the COLLATE option
     after CHARSET, which appears to be part of MySQL’s arbitrary rules
     regarding if it will actually work or not.  Also in 0.6.9.

     References: #2225(1)

   * `[mysql]' ¶. Added mysql_length parameter to Index
     construct, specifies “length” for indexes.

     References: #2293(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2225

   (2) http://www.sqlalchemy.org/trac/ticket/2293

8.3.8.72 sqlite
...............

   * `[sqlite]' ¶. Ensured that the same ValueError is
     raised for illegal date/time/datetime string parsed from the
     database regardless of whether C extensions are in use or not.

8.3.8.73 mssql
..............

   * `[mssql]' ¶. Changes to attempt support of FreeTDS 0.91
     with Pyodbc.  This includes that string binds are sent as Python
     unicode objects when FreeTDS 0.91 is detected, and a CAST(?  AS
     NVARCHAR) is used when we detect for a table.  However, I’d
     continue to characterize Pyodbc + FreeTDS 0.91 behavior as pretty
     crappy, there are still many queries such as used in reflection
     which cause a core dump on Linux, and it is not really usable at
     all on OSX, MemoryErrors abound and just plain broken unicode
     support.

     References: #2273(1)

   * `[mssql]' ¶. The behavior of =/!= when comparing a
     scalar select to a value will no longer produce IN/NOT IN as of
     0.8; this behavior is a little too heavy handed (use ‘in_()’ if you
     want to emit IN) and now emits a deprecation warning.  To get the
     0.8 behavior immediately and remove the warning, a compiler recipe
     is given at
     ‘http://www.sqlalchemy.org/docs/07/dialects/mssql.html#scalar-select-comparisons’
     to override the behavior of visit_binary().

     References: #2277(2)

   * `[mssql]' ¶. ”0” is accepted as an argument for limit()
     which will produce “TOP 0”.

     References: #2222(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2273

   (2) http://www.sqlalchemy.org/trac/ticket/2277

   (3) http://www.sqlalchemy.org/trac/ticket/2222

8.3.8.74 oracle
...............

   * `[oracle]' ¶. Fixed ReturningResultProxy for zxjdbc
     dialect..  Regression from 0.6.

     References: #2272(1)

   * `[oracle]' ¶. The String type now generates VARCHAR2 on
     Oracle which is recommended as the default VARCHAR. Added an
     explicit VARCHAR2 and NVARCHAR2 to the Oracle dialect as well.
     Using NVARCHAR still generates “NVARCHAR2” - there is no “NVARCHAR”
     on Oracle - this remains a slight breakage of the “uppercase types
     always give exactly that” policy.  VARCHAR still generates
     “VARCHAR”, keeping with the policy.  If Oracle were to ever define
     “VARCHAR” as something different as they claim (IMHO this will
     never happen), the type would be available.

     References: #2252(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2272

   (2) http://www.sqlalchemy.org/trac/ticket/2252

8.3.8.75 misc
.............

   * `[types]' ¶. Extra keyword arguments to the base Float
     type beyond “precision” and “asdecimal” are ignored; added a
     deprecation warning here and additional docs, related to

     References: #2258(1)

   * `[ext]' ¶. SQLSoup will not be included in version 0.8
     of SQLAlchemy; while useful, we would like to keep SQLAlchemy
     itself focused on one ORM usage paradigm.  SQLSoup will hopefully
     soon be superseded by a third party project.

     References: #2262(2)

   * `[ext]' ¶. Added local_attr, remote_attr, attr
     accessors to AssociationProxy, providing quick access to the
     proxied attributes at the class level.

     References: #2236(3)

   * `[ext]' ¶. Changed the update() method on association
     proxy dictionary to use a duck typing approach, i.e.  checks for
     “keys”, to discern between update({}) and update((a, b)).
     Previously, passing a dictionary that had tuples as keys would be
     misinterpreted as a sequence.

     References: #2275(4)

   * `[examples]' ¶. Adjusted dictlike-polymorphic.py
     example to apply the CAST such that it works on PG, other
     databases.  Also in 0.6.9.

     References: #2266(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2258

   (2) http://www.sqlalchemy.org/trac/ticket/2262

   (3) http://www.sqlalchemy.org/trac/ticket/2236

   (4) http://www.sqlalchemy.org/trac/ticket/2275

   (5) http://www.sqlalchemy.org/trac/ticket/2266

8.3.8.76 0.7.2
..............

Released: Sun Jul 31 2011

8.3.8.77 orm
............

   * `[orm]' ¶. Feature enhancement: joined and subquery
     loading will now traverse already-present related objects and
     collections in search of unpopulated attributes throughout the
     scope of the eager load being defined, so that the eager loading
     that is specified via mappings or query options unconditionally
     takes place for the full depth, populating whatever is not already
     populated.  Previously, this traversal would stop if a related
     object or collection were already present leading to inconsistent
     behavior (though would save on loads/cycles for an already-loaded
     graph).  For a subqueryload, this means that the additional SELECT
     statements emitted by subqueryload will invoke unconditionally, no
     matter how much of the existing graph is already present (hence the
     controversy).  The previous behavior of “stopping” is still in
     effect when a query is the result of an attribute-initiated
     lazyload, as otherwise an “N+1” style of collection iteration can
     become needlessly expensive when the same related object is
     encountered repeatedly.  There’s also an as-yet-not-public
     generative Query method _with_invoke_all_eagers() which selects
     old/new behavior

     References: #2213(1)

   * `[orm]' ¶. A rework of “replacement traversal” within
     the ORM as it alters selectables to be against aliases of things
     (i.e.  clause adaption) includes a fix for multiply-nested
     any()/has() constructs against a joined table structure.

     References: #2195(2)

   * `[orm]' ¶. Fixed bug where query.join() + aliased=True
     from a joined-inh structure to itself on relationship() with join
     condition on the child table would convert the lead entity into the
     joined one inappropriately.  Also in 0.6.9.

     References: #2234(3)

   * `[orm]' ¶. Fixed regression from 0.6 where
     Session.add() against an object which contained None in a
     collection would raise an internal exception.  Reverted this to
     0.6’s behavior which is to accept the None but obviously nothing is
     persisted.  Ideally, collections with None present or on append()
     should at least emit a warning, which is being considered for 0.8.

     References: #2205(4)

   * `[orm]' ¶. Load of a deferred() attribute on an object
     where row can’t be located raises ObjectDeletedError instead of
     failing later on; improved the message in ObjectDeletedError to
     include other conditions besides a simple “delete”.

     References: #2191(5)

   * `[orm]' ¶. Fixed regression from 0.6 where a get
     history operation on some relationship() based attributes would
     fail when a lazyload would emit; this could trigger within a
     flush() under certain conditions.  Thanks to the user who submitted
     the great test for this.

     References: #2224(6)

   * `[orm]' ¶. Fixed bug apparent only in Python 3 whereby
     sorting of persistent + pending objects during flush would produce
     an illegal comparison, if the persistent object primary key is not
     a single integer.  Also in 0.6.9

     References: #2228(7)

   * `[orm]' ¶. Fixed bug whereby the source clause used by
     query.join() would be inconsistent if against a column expression
     that combined multiple entities together.  Also in 0.6.9

     References: #2197(8)

   * `[orm]' ¶. Fixed bug whereby if a mapped class
     redefined __hash__() or __eq__() to something non-standard, which
     is a supported use case as SQLA should never consult these, the
     methods would be consulted if the class was part of a “composite”
     (i.e.  non-single-entity) result set.  Also in 0.6.9.

     References: #2215(9)

   * `[orm]' ¶. Added public attribute “.validators” to
     Mapper, an immutable dictionary view of all attributes that have
     been decorated with the @validates decorator.  courtesy Stefano
     Fontanelli

     References: #2240(10)

   * `[orm]' ¶. Fixed subtle bug that caused SQL to blow up
     if: column_property() against subquery + joinedload + LIMIT + order
     by the column property() occurred.  .  Also in 0.6.9

     References: #2188(11)

   * `[orm]' ¶. The join condition produced by with_parent
     as well as when using a “dynamic” relationship against a parent
     will generate unique bindparams, rather than incorrectly repeating
     the same bindparam.  .  Also in 0.6.9.

     References: #2207(12)

   * `[orm]' ¶. Added the same “columns-only” check to
     mapper.polymorphic_on as used when receiving user arguments to
     relationship.order_by, foreign_keys, remote_side, etc.

   * `[orm]' ¶. Fixed bug whereby comparison of column
     expression to a Query() would not call as_scalar() on the
     underlying SELECT statement to produce a scalar subquery, in the
     way that occurs if you called it on Query().subquery().

     References: #2190(13)

   * `[orm]' ¶. Fixed declarative bug where a class
     inheriting from a superclass of the same name would fail due to an
     unnecessary lookup of the name in the _decl_class_registry.

     References: #2194(14)

   * `[orm]' ¶. Repaired the “no statement condition”
     assertion in Query which would attempt to raise if a generative
     method were called after from_statement() were called..  Also in
     0.6.9.

     References: #2199(15)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2213

   (2) http://www.sqlalchemy.org/trac/ticket/2195

   (3) http://www.sqlalchemy.org/trac/ticket/2234

   (4) http://www.sqlalchemy.org/trac/ticket/2205

   (5) http://www.sqlalchemy.org/trac/ticket/2191

   (6) http://www.sqlalchemy.org/trac/ticket/2224

   (7) http://www.sqlalchemy.org/trac/ticket/2228

   (8) http://www.sqlalchemy.org/trac/ticket/2197

   (9) http://www.sqlalchemy.org/trac/ticket/2215

   (10) http://www.sqlalchemy.org/trac/ticket/2240

   (11) http://www.sqlalchemy.org/trac/ticket/2188

   (12) http://www.sqlalchemy.org/trac/ticket/2207

   (13) http://www.sqlalchemy.org/trac/ticket/2190

   (14) http://www.sqlalchemy.org/trac/ticket/2194

   (15) http://www.sqlalchemy.org/trac/ticket/2199

8.3.8.78 engine
...............

   * `[engine]' ¶. Context manager provided by
     Connection.begin() will issue rollback() if the commit() fails, not
     just if an exception occurs.

   * `[engine]' ¶. Use urllib.parse_qsl() in Python 2.6 and
     above, no deprecation warning about cgi.parse_qsl()

     References: #1682(1)

   * `[engine]' ¶. Added mixin class
     sqlalchemy.ext.DontWrapMixin.  User-defined exceptions of this type
     are never wrapped in StatementException when they occur in the
     context of a statement execution.

   * `[engine]' ¶. StatementException wrapping will display
     the original exception class in the message.

   * `[engine]' ¶. Failures on connect which raise
     dbapi.Error will forward the error to dialect.is_disconnect() and
     set the “connection_invalidated” flag if the dialect knows this to
     be a potentially “retryable” condition.  Only Oracle ORA-01033
     implemented for now.

     References: #2201(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1682

   (2) http://www.sqlalchemy.org/trac/ticket/2201

8.3.8.79 sql
............

   * `[sql]' ¶. Fixed two subtle bugs involving column
     correspondence in a selectable, one with the same labeled subquery
     repeated, the other when the label has been “grouped” and loses
     itself.  Affects.

     References: #2188(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2188

8.3.8.80 schema
...............

   * `[schema]' ¶. New feature: with_variant() method on all
     types.  Produces an instance of Variant(), a special TypeDecorator
     which will select the usage of a different type based on the
     dialect in use.

     References: #2187(1)

   * `[schema]' ¶. Added an informative error message when
     ForeignKeyConstraint refers to a column name in the parent that is
     not found.  Also in 0.6.9.

   * `[schema]' ¶. Fixed bug whereby adaptation of old
     append_ddl_listener() function was passing unexpected **kw through
     to the Table event.  Table gets no kws, the MetaData event in 0.6
     would get “tables=somecollection”, this behavior is preserved.

     References: #2206(2)

   * `[schema]' ¶. Fixed bug where “autoincrement” detection
     on Table would fail if the type had no “affinity” value, in
     particular this would occur when using the UUID example on the site
     that uses TypeEngine as the “impl”.

   * `[schema]' ¶. Added an improved repr() to TypeEngine
     objects that will only display constructor args which are
     positional or kwargs that deviate from the default.

     References: #2209(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2187

   (2) http://www.sqlalchemy.org/trac/ticket/2206

   (3) http://www.sqlalchemy.org/trac/ticket/2209

8.3.8.81 postgresql
...................

   * `[postgresql]' ¶. Added new “postgresql_ops” argument
     to Index, allows specification of PostgreSQL operator classes for
     indexed columns.  Courtesy Filip Zyzniewski.

     References: #2198(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2198

8.3.8.82 mysql
..............

   * `[mysql]' ¶. Fixed OurSQL dialect to use ansi-neutral
     quote symbol “’” for XA commands instead of ‘”’.  .  Also in 0.6.9.

     References: #2186(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2186

8.3.8.83 sqlite
...............

   * `[sqlite]' ¶. SQLite dialect no longer strips quotes
     off of reflected default value, allowing a round trip CREATE TABLE
     to work.  This is consistent with other dialects that also maintain
     the exact form of the default.

     References: #2189(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2189

8.3.8.84 mssql
..............

   * `[mssql]' ¶. Adjusted the pyodbc dialect such that
     bound values are passed as bytes and not unicode if the “Easysoft”
     unix drivers are detected.  This is the same behavior as occurs
     with FreeTDS. Easysoft appears to segfault if Python unicodes are
     passed under certain circumstances.

8.3.8.85 oracle
...............

   * `[oracle]' ¶. Added ORA-00028 to disconnect codes, use
     cx_oracle _Error.code to get at the code,.  Also in 0.6.9.

     References: #2200(1)

   * `[oracle]' ¶. Added ORA-01033 to disconnect codes,
     which can be caught during a connection event.

     References: #2201(2)

   * `[oracle]' ¶ repaired the oracle.RAW type which did
     not generate the correct DDL. Also in 0.6.9.

     References: #2220(3)

   * `[oracle]' ¶ added CURRENT to reserved word list.
     Also in 0.6.9.

     References: #2212(4)

   * `[oracle]' ¶. Fixed bug in the mutable extension
     whereby if the same type were used twice in one mapping, the
     attributes beyond the first would not get instrumented.

   * `[oracle]' ¶. Fixed bug in the mutable extension
     whereby if None or a non-corresponding type were set, an error
     would be raised.  None is now accepted which assigns None to all
     attributes, illegal values raise ValueError.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2200

   (2) http://www.sqlalchemy.org/trac/ticket/2201

   (3) http://www.sqlalchemy.org/trac/ticket/2220

   (4) http://www.sqlalchemy.org/trac/ticket/2212

8.3.8.86 misc
.............

   * `[examples]' ¶. Repaired the examples/versioning test
     runner to not rely upon SQLAlchemy test libs, nosetests must be run
     from within examples/versioning to get around setup.cfg breaking
     it.

   * `[examples]' ¶. Tweak to examples/versioning to pick
     the correct foreign key in a multi-level inheritance situation.

   * `[examples]' ¶. Fixed the attribute shard example to
     check for bind param callable correctly in 0.7 style.

8.3.8.87 0.7.1
..............

Released: Sun Jun 05 2011

8.3.8.88 general
................

   * `[general]' ¶. Added a workaround for Python bug 7511
     where failure of C extension build does not raise an appropriate
     exception on Windows 64 bit + VC express

     References: #2184(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2184

8.3.8.89 orm
............

   * `[orm]' ¶. ”delete-orphan” cascade is now allowed on
     self-referential relationships - this since SQLA 0.7 no longer
     enforces “parent with no child” at the ORM level; this check is
     left up to foreign key nullability.  Related to

     References: #1912(1)

   * `[orm]' ¶. Repaired new “mutable” extension to
     propagate events to subclasses correctly; don’t create multiple
     event listeners for subclasses either.

     References: #2180(2)

   * `[orm]' ¶. Modify the text of the message which occurs
     when the “identity” key isn’t detected on flush, to include the
     common cause that the Column isn’t set up to detect auto-increment
     correctly;.  Also in 0.6.8.

     References: #2170(3)

   * `[orm]' ¶. Fixed bug where transaction-level “deleted”
     collection wouldn’t be cleared of expunged states, raising an error
     if they later became transient.  Also in 0.6.8.

     References: #2182(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1912

   (2) http://www.sqlalchemy.org/trac/ticket/2180

   (3) http://www.sqlalchemy.org/trac/ticket/2170

   (4) http://www.sqlalchemy.org/trac/ticket/2182

8.3.8.90 engine
...............

   * `[engine]' ¶. Deprecate schema/SQL-oriented methods on
     Connection/Engine that were never well known and are redundant:
     reflecttable(), create(), drop(), text(), engine.func

   * `[engine]' ¶. Adjusted the __contains__() method of a
     RowProxy result row such that no exception throw is generated
     internally; NoSuchColumnError() also will generate its message
     regardless of whether or not the column construct can be coerced to
     a string..  Also in 0.6.8.

     References: #2178(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2178

8.3.8.91 sql
............

   * `[sql]' ¶. Fixed bug whereby metadata.reflect(bind)
     would close a Connection passed as a bind argument.  Regression
     from 0.6.

   * `[sql]' ¶. Streamlined the process by which a Select
     determines what’s in its ‘.c’ collection.  Behaves identically,
     except that a raw ClauseList() passed to select([]) (which is not a
     documented case anyway) will now be expanded into its individual
     column elements instead of being ignored.

8.3.8.92 postgresql
...................

   * `[postgresql]' ¶. Some unit test fixes regarding
     numeric arrays, MATCH operator.  A potential floating-point
     inaccuracy issue was fixed, and certain tests of the MATCH operator
     only execute within an EN-oriented locale for now.  .  Also in
     0.6.8.

     References: #2175(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2175

8.3.8.93 mysql
..............

   * `[mysql]' ¶. Unit tests pass 100% on MySQL installed on
     windows.

   * `[mysql]' ¶. Removed the “adjust casing” step that
     would fail when reflecting a table on MySQL on windows with a mixed
     case name.  After some experimenting with a windows MySQL server,
     it’s been determined that this step wasn’t really helping the
     situation much; MySQL does not return FK names with proper casing
     on non-windows platforms either, and removing the step at least
     allows the reflection to act more like it does on other OSes.  A
     warning here has been considered but its difficult to determine
     under what conditions such a warning can be raised, so punted on
     that for now - added some docs instead.

     References: #2181(1)

   * `[mysql]' ¶ supports_sane_rowcount will be set to
     False if using MySQLdb and the DBAPI doesn’t provide the
     constants.CLIENT module.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2181

8.3.8.94 sqlite
...............

   * `[sqlite]' ¶. Accept None from cursor.fetchone() when
     “PRAGMA read_uncommitted” is called to determine current isolation
     mode at connect time and default to SERIALIZABLE; this to support
     SQLite versions pre-3.3.0 that did not have this feature.

     References: #2173(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2173

8.3.8.95 0.7.0
..............

Released: Fri May 20 2011

8.3.8.96 orm
............

   * `[orm]' ¶. Fixed regression introduced in 0.7b4 (!)
     whereby query.options(someoption(“nonexistent name”)) would fail to
     raise an error.  Also added additional error catching for cases
     where the option would try to build off a column-based element,
     further fixed up some of the error messages tailored in

     References: #2069(1)

   * `[orm]' ¶ query.count() emits “count(*)” instead of
     “count(1)”.

     References: #2162(2)

   * `[orm]' ¶. Fine tuning of Query clause adaptation when
     from_self(), union(), or other “select from myself” operation, such
     that plain SQL expression elements added to filter(), order_by()
     etc.  which are present in the nested “from myself” query `will' be
     adapted in the same way an ORM expression element will, since these
     elements are otherwise not easily accessible.

     References: #2155(3)

   * `[orm]' ¶. Fixed bug where determination of “self
     referential” relationship would fail with no workaround for
     joined-inh subclass related to itself, or joined-inh subclass
     related to a subclass of that with no cols in the sub-sub class in
     the join condition.  Also in 0.6.8.

     References: #2149(4)

   * `[orm]' ¶ mapper() will ignore non-configured foreign
     keys to unrelated tables when determining inherit condition between
     parent and child class, but will raise as usual for unresolved
     columns and table names regarding the inherited table.  This is an
     enhanced generalization of behavior that was already applied to
     declarative previously.  0.6.8 has a more conservative version of
     this which doesn’t fundamentally alter how join conditions are
     determined.

     References: #2153(5)

   * `[orm]' ¶. It is an error to call query.get() when the
     given entity is not a single, full class entity or mapper (i.e.  a
     column).  This is a deprecation warning in 0.6.8.

     References: #2144(6)

   * `[orm]' ¶. Fixed a potential KeyError which under some
     circumstances could occur with the identity map, part of

     References: #2148(7)

   * `[orm]' ¶ added Query.with_session() method, switches
     Query to use a different session.

   * `[orm]' ¶ horizontal shard query should use execution
     options per connection as per

     References: #2131(8)

   * `[orm]' ¶ a non_primary mapper will inherit the
     _identity_class of the primary mapper.  This so that a non_primary
     established against a class that’s normally in an inheritance
     mapping will produce results that are identity-map compatible with
     that of the primary mapper (also in 0.6.8)

     References: #2151(9)

   * `[orm]' ¶. Fixed the error message emitted for “can’t
     execute syncrule for destination column ‘q’; mapper ‘X’ does not
     map this column” to reference the correct mapper.  .  Also in
     0.6.8.

     References: #2163(10)

   * `[orm]' ¶ polymorphic_union() gets a “cast_nulls”
     option, disables the usage of CAST when it renders the labeled NULL
     columns.

     References: #1502(11)

   * `[orm]' ¶ polymorphic_union() renders the columns in
     their original table order, as according to the first
     table/selectable in the list of polymorphic unions in which they
     appear.  (which is itself an unordered mapping unless you pass an
     OrderedDict).

   * `[orm]' ¶. Fixed bug whereby mapper mapped to an
     anonymous alias would fail if logging were used, due to unescaped %
     sign in the alias name.  Also in 0.6.8.

     References: #2171(12)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2069

   (2) http://www.sqlalchemy.org/trac/ticket/2162

   (3) http://www.sqlalchemy.org/trac/ticket/2155

   (4) http://www.sqlalchemy.org/trac/ticket/2149

   (5) http://www.sqlalchemy.org/trac/ticket/2153

   (6) http://www.sqlalchemy.org/trac/ticket/2144

   (7) http://www.sqlalchemy.org/trac/ticket/2148

   (8) http://www.sqlalchemy.org/trac/ticket/2131

   (9) http://www.sqlalchemy.org/trac/ticket/2151

   (10) http://www.sqlalchemy.org/trac/ticket/2163

   (11) http://www.sqlalchemy.org/trac/ticket/1502

   (12) http://www.sqlalchemy.org/trac/ticket/2171

8.3.8.97 sql
............

   * `[sql]' ¶. Fixed bug whereby nesting a label of a
     select() with another label in it would produce incorrect exported
     columns.  Among other things this would break an ORM
     column_property() mapping against another column_property().  .
     Also in 0.6.8

     References: #2167(1)

   * `[sql]' ¶. Changed the handling in determination of
     join conditions such that foreign key errors are only considered
     between the two given tables.  That is, t1.join(t2) will report FK
     errors that involve ‘t1’ or ‘t2’, but anything involving ‘t3’ will
     be skipped.  This affects join(), as well as ORM relationship and
     inherit condition logic.

   * `[sql]' ¶. Some improvements to error handling inside
     of the execute procedure to ensure auto-close connections are
     really closed when very unusual DBAPI errors occur.

   * `[sql]' ¶ metadata.reflect() and
     reflection.Inspector() had some reliance on GC to close connections
     which were internally procured, fixed this.

   * `[sql]' ¶. Added explicit check for when Column .name
     is assigned as blank string

     References: #2140(2)

   * `[sql]' ¶. Fixed bug whereby if FetchedValue was passed
     to column server_onupdate, it would not have its parent “column”
     assigned, added test coverage for all column default assignment
     patterns.  also in 0.6.8

     References: #2147(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2167

   (2) http://www.sqlalchemy.org/trac/ticket/2140

   (3) http://www.sqlalchemy.org/trac/ticket/2147

8.3.8.98 postgresql
...................

   * `[postgresql]' ¶. Fixed the psycopg2_version parsing in
     the psycopg2 dialect.

   * `[postgresql]' ¶. Fixed bug affecting PG 9 whereby
     index reflection would fail if against a column whose name had
     changed.  .  Also in 0.6.8.

     References: #2141(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2141

8.3.8.99 mssql
..............

   * `[mssql]' ¶. Fixed bug in MSSQL dialect whereby the
     aliasing applied to a schema-qualified table would leak into
     enclosing select statements.  Also in 0.6.8.

     References: #2169(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2169

8.3.8.100 misc
..............

   * `[no_tags]' ¶. This section documents those changes
     from 0.7b4 to 0.7.0.  For an overview of what’s new in SQLAlchemy
     0.7, see
     ‘http://docs.sqlalchemy.org/en/latest/changelog/migration_07.html’

   * `[documentation]' ¶. Removed the usage of the
     “collections.MutableMapping” abc from the ext.mutable docs as it
     was being used incorrectly and makes the example more difficult to
     understand in any case.

     References: #2152(1)

   * `[examples]' ¶ removed the ancient “polymorphic
     association” examples and replaced with an updated set of examples
     that use declarative mixins, “generic_associations”.  Each presents
     an alternative table layout.

   * `[ext]' ¶. Fixed bugs in sqlalchemy.ext.mutable
     extension where ‘None’ was not appropriately handled, replacement
     events were not appropriately handled.

     References: #2143(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2152

   (2) http://www.sqlalchemy.org/trac/ticket/2143

8.3.8.101 0.7.0b4
.................

Released: Sun Apr 17 2011

8.3.8.102 general
.................

   * `[general]' ¶. Changes to the format of CHANGES, this
     file.  The format changes have been applied to the 0.7 releases.

   * `[general]' ¶. The “-declarative” changes will now be
     listed directly under the “-orm” section, as these are closely
     related.

   * `[general]' ¶. The 0.5 series changes have been moved
     to the file CHANGES_PRE_06 which replaces CHANGES_PRE_05.

   * `[general]' ¶. The changelog for 0.6.7 and subsequent
     within the 0.6 series is now listed only in the CHANGES file within
     the 0.6 branch.  In the 0.7 CHANGES file (i.e.  this file), all the
     0.6 changes are listed inline within the 0.7 section in which they
     were also applied (since all 0.6 changes are in 0.7 as well).
     Changes that apply to an 0.6 version here are noted as are if any
     differences in implementation/behavior are present.

8.3.8.103 orm
.............

   * `[orm]' ¶. Some fixes to “evaluate” and “fetch”
     evaluation when query.update(), query.delete() are called.  The
     retrieval of records is done after autoflush in all cases, and
     before update/delete is emitted, guarding against unflushed data
     present as well as expired objects failing during the evaluation.

     References: #2122(1)

   * `[orm]' ¶. Reworded the exception raised when a flush
     is attempted of a subclass that is not polymorphic against the
     supertype.

     References: #2063(2)

   * `[orm]' ¶. Still more wording adjustments when a query
     option can’t find the target entity.  Explain that the path must be
     from one of the root entities.

   * `[orm]' ¶. Some fixes to the state handling regarding
     backrefs, typically when autoflush=False, where the back-referenced
     collection wouldn’t properly handle add/removes with no net change.
     Thanks to Richard Murri for the test case + patch.  (also in
     0.6.7).

     References: #2123(3)

   * `[orm]' ¶. Added checks inside the UOW to detect the
     unusual condition of being asked to UPDATE or DELETE on a primary
     key value that contains NULL in it.

     References: #2127(4)

   * `[orm]' ¶. Some refinements to attribute history.  More
     changes are pending possibly in 0.8, but for now history has been
     modified such that scalar history doesn’t have a “side effect” of
     populating None for a non-present value.  This allows a slightly
     better ability to distinguish between a None set and no actual
     change, affects as well.

     References: #2127(5)

   * `[orm]' ¶ a “having” clause would be copied from the
     inside to the outside query if from_self() were used; in particular
     this would break an 0.7 style count() query.  (also in 0.6.7)

     References: #2130(6)

   * `[orm]' ¶ the Query.execution_options() method now
     passes those options to the Connection rather than the SELECT
     statement, so that all available options including isolation level
     and compiled cache may be used.

     References: #2131(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2122

   (2) http://www.sqlalchemy.org/trac/ticket/2063

   (3) http://www.sqlalchemy.org/trac/ticket/2123

   (4) http://www.sqlalchemy.org/trac/ticket/2127

   (5) http://www.sqlalchemy.org/trac/ticket/2127

   (6) http://www.sqlalchemy.org/trac/ticket/2130

   (7) http://www.sqlalchemy.org/trac/ticket/2131

8.3.8.104 engine
................

   * `[engine]' ¶. The C extension is now enabled by default
     on CPython 2.x with a fallback to pure python if it fails to
     compile.

     References: #2129(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2129

8.3.8.105 sql
.............

   * `[sql]' ¶. The “compiled_cache” execution option now
     raises an error when passed to a SELECT statement rather than a
     Connection.  Previously it was being ignored entirely.  We may look
     into having this option work on a per-statement level at some
     point.

     References: #2131(1)

   * `[sql]' ¶. Restored the “catchall” constructor on the
     base TypeEngine class, with a deprecation warning.  This so that
     code which does something like Integer(11) still succeeds.

   * `[sql]' ¶. Fixed regression whereby MetaData() coming
     back from unpickling did not keep track of new things it keeps
     track of now, i.e.  collection of Sequence objects, list of schema
     names.

     References: #2104(2)

   * `[sql]' ¶. The limit/offset keywords to select() as
     well as the value passed to select.limit()/offset() will be coerced
     to integer.  (also in 0.6.7)

     References: #2116(3)

   * `[sql]' ¶ fixed bug where “from” clause gathering from
     an over() clause would be an itertools.chain() and not a list,
     causing “can only concatenate list” TypeError when combined with
     other clauses.

   * `[sql]' ¶. Fixed incorrect usage of “,” in over()
     clause being placed between the “partition” and “order by” clauses.

     References: #2134(4)

   * `[sql]' ¶. Before/after attach events for
     PrimaryKeyConstraint now function, tests added for before/after
     events on all constraint types.

     References: #2105(5)

   * `[sql]' ¶. Added explicit true()/false() constructs to
     expression lib - coercion rules will intercept “False”/”True” into
     these constructs.  In 0.6, the constructs were typically converted
     straight to string, which was no longer accepted in 0.7.

     References: #2117(6)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2131

   (2) http://www.sqlalchemy.org/trac/ticket/2104

   (3) http://www.sqlalchemy.org/trac/ticket/2116

   (4) http://www.sqlalchemy.org/trac/ticket/2134

   (5) http://www.sqlalchemy.org/trac/ticket/2105

   (6) http://www.sqlalchemy.org/trac/ticket/2117

8.3.8.106 schema
................

   * `[schema]' ¶. The ‘useexisting’ flag on Table has been
     superseded by a new pair of flags ‘keep_existing’ and
     ‘extend_existing’.  ‘extend_existing’ is equivalent to
     ‘useexisting’ - the existing Table is returned, and additional
     constructor elements are added.  With ‘keep_existing’, the existing
     Table is returned, but additional constructor elements are not
     added - these elements are only applied when the Table is newly
     created.

     References: #2109(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2109

8.3.8.107 postgresql
....................

   * `[postgresql]' ¶. Psycopg2 for Python 3 is now
     supported.

   * `[postgresql]' ¶. Fixed support for precision numerics
     when using pg8000.

     References: #2132(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2132

8.3.8.108 sqlite
................

   * `[sqlite]' ¶. Fixed bug where reflection of foreign key
     created as “REFERENCES <tablename>” without col name would fail.
     (also in 0.6.7)

     References: #2115(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2115

8.3.8.109 oracle
................

   * `[oracle]' ¶. Using column names that would require
     quotes for the column itself or for a name-generated bind
     parameter, such as names with special characters, underscores,
     non-ascii characters, now properly translate bind parameter keys
     when talking to cx_oracle.  (Also in 0.6.7)

     References: #2100(1)

   * `[oracle]' ¶. Oracle dialect adds
     use_binds_for_limits=False create_engine() flag, will render the
     LIMIT/OFFSET values inline instead of as binds, reported to modify
     the execution plan used by Oracle.  (Also in 0.6.7)

     References: #2116(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2100

   (2) http://www.sqlalchemy.org/trac/ticket/2116

8.3.8.110 misc
..............

   * `[types]' ¶. REAL has been added to the core types.
     Supported by PostgreSQL, SQL Server, MySQL, SQLite.  Note that the
     SQL Server and MySQL versions, which add extra arguments, are also
     still available from those dialects.

     References: #2081(1)

   * `[types]' ¶. Added @event.listens_for() decorator,
     given target + event name, applies the decorated function as a
     listener.

     References: #2106(2)

   * `[pool]' ¶. AssertionPool now stores the traceback
     indicating where the currently checked out connection was acquired;
     this traceback is reported within the assertion raised upon a
     second concurrent checkout; courtesy Gunnlaugur Briem

     References: #2103(3)

   * `[pool]' ¶. The “pool.manage” feature doesn’t use
     pickle anymore to hash the arguments for each pool.

   * `[documentation]' ¶. Documented SQLite
     DATE/TIME/DATETIME types.  (also in 0.6.7)

     References: #2029(4)

   * `[documentation]' ¶. Fixed mutable extension docs to
     show the correct type-association methods.

     References: #2118(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2081

   (2) http://www.sqlalchemy.org/trac/ticket/2106

   (3) http://www.sqlalchemy.org/trac/ticket/2103

   (4) http://www.sqlalchemy.org/trac/ticket/2029

   (5) http://www.sqlalchemy.org/trac/ticket/2118

8.3.8.111 0.7.0b3
.................

Released: Sun Mar 20 2011

8.3.8.112 general
.................

   * `[general]' ¶. Lots of fixes to unit tests when run
     under PyPy (courtesy Alex Gaynor).

8.3.8.113 orm
.............

   * `[orm]' ¶. Changed the underlying approach to
     query.count().  query.count() is now in all cases exactly:

          query.

               from_self(func.count(literal_column(‘1’))).  scalar()

     That is, “select count(1) from (<full query>)”.  This produces a
     subquery in all cases, but vastly simplifies all the guessing
     count() tried to do previously, which would still fail in many
     scenarios particularly when joined table inheritance and other
     joins were involved.  If the subquery produced for an otherwise
     very simple count is really an issue, use query(func.count()) as an
     optimization.

     References: #2093(1)

   * `[orm]' ¶ some changes to the identity map regarding
     rare weakref callbacks during iterations.  The mutex has been
     removed as it apparently can cause a reentrant (i.e.  in one
     thread) deadlock, perhaps when gc collects objects at the point of
     iteration in order to gain more memory.  It is hoped that
     “dictionary changed during iteration” will be exceedingly rare as
     iteration methods internally acquire the full list of objects in a
     single values() call.  Note 0.6.7 has a more conservative fix here
     which still keeps the mutex in place.

     References: #2087(2)

   * `[orm]' ¶. A tweak to the unit of work causes it to
     order the flush along relationship() dependencies even if the given
     objects don’t have any inter-attribute references in memory, which
     was the behavior in 0.5 and earlier, so a flush of Parent/Child
     with only foreign key/primary key set will succeed.  This while
     still maintaining 0.6 and above’s not generating a ton of useless
     internal dependency structures within the flush that don’t
     correspond to state actually within the current flush.

     References: #2082(3)

   * `[orm]' ¶. Improvements to the error messages emitted
     when querying against column-only entities in conjunction with
     (typically incorrectly) using loader options, where the parent
     entity is not fully present.

     References: #2069(4)

   * `[orm]' ¶. Fixed bug in query.options() whereby a path
     applied to a lazyload using string keys could overlap a same named
     attribute on the wrong entity.  Note 0.6.7 has a more conservative
     fix to this.

     References: #2098(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2093

   (2) http://www.sqlalchemy.org/trac/ticket/2087

   (3) http://www.sqlalchemy.org/trac/ticket/2082

   (4) http://www.sqlalchemy.org/trac/ticket/2069

   (5) http://www.sqlalchemy.org/trac/ticket/2098

8.3.8.114 engine
................

   * `[engine]' ¶. Fixed AssertionPool regression bug.

     References: #2097(1)

   * `[engine]' ¶. Changed exception raised to ArgumentError
     when an invalid dialect is specified.

     References: #2060(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2097

   (2) http://www.sqlalchemy.org/trac/ticket/2060

8.3.8.115 sql
.............

   * `[sql]' ¶. Added a fully descriptive error message for
     the case where Column is subclassed and _make_proxy() fails to make
     a copy due to TypeError on the constructor.  The method
     _constructor should be implemented in this case.

   * `[sql]' ¶. Added new event “column_reflect” for Table
     objects.  Receives the info dictionary about a Column before the
     object is generated within reflection, and allows modification to
     the dictionary for control over most aspects of the resulting
     Column including key, name, type, info dictionary.

     References: #2095(1)

   * `[sql]' ¶. To help with the “column_reflect” event
     being used with specific Table objects instead of all instances of
     Table, listeners can be added to a Table object inline with its
     construction using a new argument “listeners”, a list of tuples of
     the form (<eventname>, <fn>), which are applied to the Table before
     the reflection process begins.

   * `[sql]' ¶. Added new generic function “next_value()”,
     accepts a Sequence object as its argument and renders the
     appropriate “next value” generation string on the target platform,
     if supported.  Also provides “.next_value()” method on Sequence
     itself.

     References: #2085(2)

   * `[sql]' ¶ func.next_value() or other SQL expression
     can be embedded directly into an insert() construct, and if
     implicit or explicit “returning” is used in conjunction with a
     primary key column, the newly generated value will be present in
     result.inserted_primary_key.

     References: #2084(3)

   * `[sql]' ¶. Added accessors to ResultProxy
     “returns_rows”, “is_insert” (also in 0.6.7)

     References: #2089(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2095

   (2) http://www.sqlalchemy.org/trac/ticket/2085

   (3) http://www.sqlalchemy.org/trac/ticket/2084

   (4) http://www.sqlalchemy.org/trac/ticket/2089

8.3.8.116 postgresql
....................

   * `[postgresql]' ¶. Added RESERVED_WORDS for postgresql
     dialect.  (also in 0.6.7)

     References: #2092(1)

   * `[postgresql]' ¶. Fixed the BIT type to allow a
     “length” parameter, “varying” parameter.  Reflection also fixed.
     (also in 0.6.7)

     References: #2073(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2092

   (2) http://www.sqlalchemy.org/trac/ticket/2073

8.3.8.117 mssql
...............

   * `[mssql]' ¶. Rewrote the query used to get the
     definition of a view, typically when using the Inspector interface,
     to use sys.sql_modules instead of the information schema, thereby
     allowing views definitions longer than 4000 characters to be fully
     returned.  (also in 0.6.7)

     References: #2071(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2071

8.3.8.118 firebird
..................

   * `[firebird]' ¶. The “implicit_returning” flag on
     create_engine() is honored if set to False.  (also in 0.6.7)

     References: #2083(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2083

8.3.8.119 misc
..............

   * `[declarative]' ¶. Arguments in __mapper_args__ that
     aren’t “hashable” aren’t mistaken for always-hashable,
     possibly-column arguments.  (also in 0.6.7)

     References: #2091(1)

   * `[informix]' ¶. Added RESERVED_WORDS informix dialect.
     (also in 0.6.7)

     References: #2092(2)

   * `[ext]' ¶. The horizontal_shard ShardedSession class
     accepts the common Session argument “query_cls” as a constructor
     argument, to enable further subclassing of ShardedQuery.  (also in
     0.6.7)

     References: #2090(3)

   * `[examples]' ¶. Updated the association, association
     proxy examples to use declarative, added a new example
     dict_of_sets_with_default.py, a “pushing the envelope” example of
     association proxy.

   * `[examples]' ¶. The Beaker caching example allows a
     “query_cls” argument to the query_callable() function.  (also in
     0.6.7)

     References: #2090(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2091

   (2) http://www.sqlalchemy.org/trac/ticket/2092

   (3) http://www.sqlalchemy.org/trac/ticket/2090

   (4) http://www.sqlalchemy.org/trac/ticket/2090

8.3.8.120 0.7.0b2
.................

Released: Sat Feb 19 2011

8.3.8.121 orm
.............

   * `[orm]' ¶. Fixed bug whereby Session.merge() would call
     the load() event with one too few arguments.

     References: #2053(1)

   * `[orm]' ¶. Added logic which prevents the generation of
     events from a MapperExtension or SessionExtension from generating
     do-nothing events for all the methods not overridden.

     References: #2052(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2053

   (2) http://www.sqlalchemy.org/trac/ticket/2052

8.3.8.122 sql
.............

   * `[sql]' ¶. Renamed the EngineEvents event class to
     ConnectionEvents.  As these classes are never accessed directly by
     end-user code, this strictly is a documentation change for end
     users.  Also simplified how events get linked to engines and
     connections internally.

     References: #2059(1)

   * `[sql]' ¶. The Sequence() construct, when passed a
     MetaData() object via its ‘metadata’ argument, will be included in
     CREATE/DROP statements within metadata.create_all() and
     metadata.drop_all(), including “checkfirst” logic.

     References: #2055(2)

   * `[sql]' ¶. The Column.references() method now returns
     True if it has a foreign key referencing the given column exactly,
     not just its parent table.

     References: #2064(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2059

   (2) http://www.sqlalchemy.org/trac/ticket/2055

   (3) http://www.sqlalchemy.org/trac/ticket/2064

8.3.8.123 postgresql
....................

   * `[postgresql]' ¶. Fixed regression from 0.6 where
     SMALLINT and BIGINT types would both generate SERIAL on an integer
     PK column, instead of SMALLINT and BIGSERIAL

     References: #2065(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2065

8.3.8.124 misc
..............

   * `[declarative]' ¶. Fixed regression whereby composite()
     with Column objects placed inline would fail to initialize.  The
     Column objects can now be inline with the composite() or external
     and pulled in via name or object ref.

     References: #2058(1)

   * `[declarative]' ¶. Fix error message referencing old
     @classproperty name to reference @declared_attr (also in 0.6.7)

     References: #2061(2)

   * `[declarative]' ¶ the dictionary at the end of the
     __table_args__ tuple is now optional.

     References: #1468(3)

   * `[ext]' ¶. Association proxy now has correct behavior
     for any(), has(), and contains() when proxying a many-to-one scalar
     attribute to a one-to-many collection (i.e.  the reverse of the
     ‘typical’ association proxy use case)

     References: #2054(4)

   * `[examples]' ¶. Beaker example now takes into account
     ‘limit’ and ‘offset’, bind params within embedded FROM clauses
     (like when you use union() or from_self()) when generating a cache
     key.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2058

   (2) http://www.sqlalchemy.org/trac/ticket/2061

   (3) http://www.sqlalchemy.org/trac/ticket/1468

   (4) http://www.sqlalchemy.org/trac/ticket/2054

8.3.8.125 0.7.0b1
.................

Released: Sat Feb 12 2011

8.3.8.126 general
.................

   * `[general]' ¶. New event system, supersedes all
     extensions, listeners, etc.

     References: #1902(1)

   * `[general]' ¶. Logging enhancements

     References: #1926(2)

   * `[general]' ¶. Setup no longer installs a Nose plugin

     References: #1949(3)

   * `[general]' ¶. The “sqlalchemy.exceptions” alias in
     sys.modules has been removed.  Base SQLA exceptions are available
     via “from sqlalchemy import exc”.  The “exceptions” alias for “exc”
     remains in “sqlalchemy” for now, it’s just not patched into
     sys.modules.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1902

   (2) http://www.sqlalchemy.org/trac/ticket/1926

   (3) http://www.sqlalchemy.org/trac/ticket/1949

8.3.8.127 orm
.............

   * `[orm]' ¶. More succinct form of query.join(target,
     onclause)

     References: #1923(1)

   * `[orm]' ¶. Hybrid Attributes, implements/supersedes
     synonym()

     References: #1903(2)

   * `[orm]' ¶. Rewrite of composites

     References: #2008(3)

   * `[orm]' ¶. Mutation Event Extension, supersedes
     “mutable=True”

     See also
     ........

     See Mutation event extension, supersedes “mutable=True”.

   * `[orm]' ¶. PickleType and ARRAY mutability turned off
     by default

     References: #1980(4)

   * `[orm]' ¶. Simplified polymorphic_on assignment

     References: #1895(5)

   * `[orm]' ¶. Flushing of Orphans that have no parent is
     allowed

     References: #1912(6)

   * `[orm]' ¶. Adjusted flush accounting step to occur
     before the commit in the case of autocommit=True.  This allows
     autocommit=True to work appropriately with expire_on_commit=True,
     and also allows post-flush session hooks to operate in the same
     transactional context as when autocommit=False.

     References: #2041(7)

   * `[orm]' ¶. Warnings generated when collection members,
     scalar referents not part of the flush

     References: #1973(8)

   * `[orm]' ¶. Non-‘Table’-derived constructs can be mapped

     References: #1876(9)

   * `[orm]' ¶. Tuple label names in Query Improved

     References: #1942(10)

   * `[orm]' ¶. Mapped column attributes reference the most
     specific column first

     References: #1892(11)

   * `[orm]' ¶. Mapping to joins with two or more same-named
     columns requires explicit declaration

     References: #1896(12)

   * `[orm]' ¶. Mapper requires that polymorphic_on column
     be present in the mapped selectable

     References: #1875(13)

   * `[orm]' ¶ compile_mappers() renamed
     configure_mappers(), simplified configuration internals

     References: #1966(14)

   * `[orm]' ¶ the aliased() function, if passed a SQL
     FromClause element (i.e.  not a mapped class), will return
     element.alias() instead of raising an error on AliasedClass.

     References: #2018(15)

   * `[orm]' ¶. Session.merge() will check the version id of
     the incoming state against that of the database, assuming the
     mapping uses version ids and incoming state has a version_id
     assigned, and raise StaleDataError if they don’t match.

     References: #2027(16)

   * `[orm]' ¶. Session.connection(), Session.execute()
     accept ‘bind’, to allow execute/connection operations to
     participate in the open transaction of an engine explicitly.

     References: #1996(17)

   * `[orm]' ¶. Query.join(), Query.outerjoin(),
     eagerload(), eagerload_all(), others no longer allow lists of
     attributes as arguments (i.e.  option([x, y, z]) form, deprecated
     since 0.5)

   * `[orm]' ¶. ScopedSession.mapper is removed (deprecated
     since 0.5).

   * `[orm]' ¶. Horizontal shard query places ‘shard_id’ in
     context.attributes where it’s accessible by the “load()” event.

     References: #2031(18)

   * `[orm]' ¶. A single contains_eager() call across
     multiple entities will indicate all collections along that path
     should load, instead of requiring distinct contains_eager() calls
     for each endpoint (which was never correctly documented).

     References: #2032(19)

   * `[orm]' ¶. The “name” field used in orm.aliased() now
     renders in the resulting SQL statement.

   * `[orm]' ¶. Session weak_instance_dict=False is
     deprecated.

     References: #1473(20)

   * `[orm]' ¶. An exception is raised in the unusual case
     that an append or similar event on a collection occurs after the
     parent object has been dereferenced, which prevents the parent from
     being marked as “dirty” in the session.  Was a warning in 0.6.6.

     References: #2046(21)

   * `[orm]' ¶. Query.distinct() now accepts column
     expressions as *args, interpreted by the PostgreSQL dialect as
     DISTINCT ON (<expr>).

     References: #1069(22)

   * `[orm]' ¶. Additional tuning to “many-to-one”
     relationship loads during a flush().  A change in version 0.6.6
     ([ticket:2002]) required that more “unnecessary” m2o loads during a
     flush could occur.  Extra loading modes have been added so that the
     SQL emitted in this specific use case is trimmed back, while still
     retrieving the information the flush needs in order to not miss
     anything.

     References: #2049(23)

   * `[orm]' ¶ the value of “passive” as passed to
     attributes.get_history() should be one of the constants defined in
     the attributes package.  Sending True or False is deprecated.

   * `[orm]' ¶. Added a ‘name’ argument to
     ‘Query.subquery()’, to allow a fixed name to be assigned to the
     alias object.  (also in 0.6.7)

     References: #2030(24)

   * `[orm]' ¶. A warning is emitted when a joined-table
     inheriting mapper has no primary keys on the locally mapped table
     (but has pks on the superclass table).  (also in 0.6.7)

     References: #2019(25)

   * `[orm]' ¶. Fixed bug where “middle” class in a
     polymorphic hierarchy would have no ‘polymorphic_on’ column if it
     didn’t also specify a ‘polymorphic_identity’, leading to strange
     errors upon refresh, wrong class loaded when querying from that
     target.  Also emits the correct WHERE criterion when using single
     table inheritance.  (also in 0.6.7)

     References: #2038(26)

   * `[orm]' ¶. Fixed bug where a column with a SQL or
     server side default that was excluded from a mapping with
     include_properties or exclude_properties would result in
     UnmappedColumnError.  (also in 0.6.7)

     References: #1995(27)

   * `[orm]' ¶. A warning is emitted in the unusual case
     that an append or similar event on a collection occurs after the
     parent object has been dereferenced, which prevents the parent from
     being marked as “dirty” in the session.  This will be an exception
     in 0.7.  (also in 0.6.7)

     References: #2046(28)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1923

   (2) http://www.sqlalchemy.org/trac/ticket/1903

   (3) http://www.sqlalchemy.org/trac/ticket/2008

   (4) http://www.sqlalchemy.org/trac/ticket/1980

   (5) http://www.sqlalchemy.org/trac/ticket/1895

   (6) http://www.sqlalchemy.org/trac/ticket/1912

   (7) http://www.sqlalchemy.org/trac/ticket/2041

   (8) http://www.sqlalchemy.org/trac/ticket/1973

   (9) http://www.sqlalchemy.org/trac/ticket/1876

   (10) http://www.sqlalchemy.org/trac/ticket/1942

   (11) http://www.sqlalchemy.org/trac/ticket/1892

   (12) http://www.sqlalchemy.org/trac/ticket/1896

   (13) http://www.sqlalchemy.org/trac/ticket/1875

   (14) http://www.sqlalchemy.org/trac/ticket/1966

   (15) http://www.sqlalchemy.org/trac/ticket/2018

   (16) http://www.sqlalchemy.org/trac/ticket/2027

   (17) http://www.sqlalchemy.org/trac/ticket/1996

   (18) http://www.sqlalchemy.org/trac/ticket/2031

   (19) http://www.sqlalchemy.org/trac/ticket/2032

   (20) http://www.sqlalchemy.org/trac/ticket/1473

   (21) http://www.sqlalchemy.org/trac/ticket/2046

   (22) http://www.sqlalchemy.org/trac/ticket/1069

   (23) http://www.sqlalchemy.org/trac/ticket/2049

   (24) http://www.sqlalchemy.org/trac/ticket/2030

   (25) http://www.sqlalchemy.org/trac/ticket/2019

   (26) http://www.sqlalchemy.org/trac/ticket/2038

   (27) http://www.sqlalchemy.org/trac/ticket/1995

   (28) http://www.sqlalchemy.org/trac/ticket/2046

8.3.8.128 sql
.............

   * `[sql]' ¶. Added over() function, method to
     FunctionElement classes, produces the _Over() construct which in
     turn generates “window functions”, i.e.  “<window function> OVER
     (PARTITION BY <partition by>, ORDER BY <order by>)”.

     References: #1844(1)

   * `[sql]' ¶. LIMIT/OFFSET clauses now use bind parameters

     References: #805(2)

   * `[sql]' ¶ select.distinct() now accepts column
     expressions as *args, interpreted by the PostgreSQL dialect as
     DISTINCT ON (<expr>).  Note this was already available via passing
     a list to the ‘distinct’ keyword argument to select().

     References: #1069(3)

   * `[sql]' ¶ select.prefix_with() accepts multiple
     expressions (i.e.  *expr), ‘prefix’ keyword argument to select()
     accepts a list or tuple.

   * `[sql]' ¶. Passing a string to the ‘distinct’ keyword
     argument of ‘select()’ for the purpose of emitting special MySQL
     keywords (DISTINCTROW etc.)  is deprecated - use ‘prefix_with()’
     for this.

   * `[sql]' ¶. TypeDecorator works with primary key columns

     References: #2005(4), #2006(5)

   * `[sql]' ¶. DDL() constructs now escape percent signs

     References: #1897(6)

   * `[sql]' ¶. Table.c / MetaData.tables refined a bit,
     don’t allow direct mutation

     References: #1893(7), #1917(8)

   * `[sql]' ¶. Callables passed to ‘bindparam()’ don’t get
     evaluated

     References: #1950(9)

   * `[sql]' ¶ types.type_map is now private,
     types._type_map

     References: #1870(10)

   * `[sql]' ¶. Non-public Pool methods underscored

     References: #1982(11)

   * `[sql]' ¶. Added NULLS FIRST and NULLS LAST support.
     It’s implemented as an extension to the asc() and desc() operators,
     called nullsfirst() and nullslast().

     References: #723(12)

   * `[sql]' ¶. The Index() construct can be created inline
     with a Table definition, using strings as column names, as an
     alternative to the creation of the index outside of the Table.

   * `[sql]' ¶ execution_options() on Connection accepts
     “isolation_level” argument, sets transaction isolation level for
     that connection only until returned to the connection pool, for
     those backends which support it (SQLite, PostgreSQL)

     References: #2001(13)

   * `[sql]' ¶. A TypeDecorator of Integer can be used with
     a primary key column, and the “autoincrement” feature of various
     dialects as well as the “sqlite_autoincrement” flag will honor the
     underlying database type as being Integer-based.

     References: #2005(14)

   * `[sql]' ¶. Established consistency when server_default
     is present on an Integer PK column.  SQLA doesn’t pre-fetch these,
     nor do they come back in cursor.lastrowid (DBAPI). Ensured all
     backends consistently return None in result.inserted_primary_key
     for these.  Regarding reflection for this case, reflection of an
     int PK col with a server_default sets the “autoincrement” flag to
     False, except in the case of a PG SERIAL col where we detected a
     sequence default.

     References: #2020(15), #2021(16)

   * `[sql]' ¶. Result-row processors are applied to
     pre-executed SQL defaults, as well as cursor.lastrowid, when
     determining the contents of result.inserted_primary_key.

     References: #2006(17)

   * `[sql]' ¶. Bind parameters present in the “columns
     clause” of a select are now auto-labeled like other “anonymous”
     clauses, which among other things allows their “type” to be
     meaningful when the row is fetched, as in result row processors.

   * `[sql]' ¶. TypeDecorator is present in the “sqlalchemy”
     import space.

   * `[sql]' ¶. Non-DBAPI errors which occur in the scope of
     an ‘execute()’ call are now wrapped in
     sqlalchemy.exc.StatementError, and the text of the SQL statement
     and repr() of params is included.  This makes it easier to identify
     statement executions which fail before the DBAPI becomes involved.

     References: #2015(18)

   * `[sql]' ¶. The concept of associating a “.bind”
     directly with a ClauseElement has been explicitly moved to
     Executable, i.e.  the mixin that describes ClauseElements which
     represent engine-executable constructs.  This change is an
     improvement to internal organization and is unlikely to affect any
     real-world usage.

     References: #2048(19)

   * `[sql]' ¶. Column.copy(), as used in
     table.tometadata(), copies the ‘doc’ attribute.  (also in 0.6.7)

     References: #2028(20)

   * `[sql]' ¶. Added some defs to the resultproxy.c
     extension so that the extension compiles and runs on Python 2.4.
     (also in 0.6.7)

     References: #2023(21)

   * `[sql]' ¶. The compiler extension now supports
     overriding the default compilation of expression._BindParamClause
     including that the auto-generated binds within the VALUES/SET
     clause of an insert()/update() statement will also use the new
     compilation rules.  (also in 0.6.7)

     References: #2042(22)

   * `[sql]' ¶. SQLite dialect now uses ‘NullPool’ for
     file-based databases

     References: #1921(23)

   * `[sql]' ¶. The path given as the location of a sqlite
     database is now normalized via os.path.abspath(), so that directory
     changes within the process don’t affect the ultimate location of a
     relative file path.

     References: #2036(24)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1844

   (2) http://www.sqlalchemy.org/trac/ticket/805

   (3) http://www.sqlalchemy.org/trac/ticket/1069

   (4) http://www.sqlalchemy.org/trac/ticket/2005

   (5) http://www.sqlalchemy.org/trac/ticket/2006

   (6) http://www.sqlalchemy.org/trac/ticket/1897

   (7) http://www.sqlalchemy.org/trac/ticket/1893

   (8) http://www.sqlalchemy.org/trac/ticket/1917

   (9) http://www.sqlalchemy.org/trac/ticket/1950

   (10) http://www.sqlalchemy.org/trac/ticket/1870

   (11) http://www.sqlalchemy.org/trac/ticket/1982

   (12) http://www.sqlalchemy.org/trac/ticket/723

   (13) http://www.sqlalchemy.org/trac/ticket/2001

   (14) http://www.sqlalchemy.org/trac/ticket/2005

   (15) http://www.sqlalchemy.org/trac/ticket/2020

   (16) http://www.sqlalchemy.org/trac/ticket/2021

   (17) http://www.sqlalchemy.org/trac/ticket/2006

   (18) http://www.sqlalchemy.org/trac/ticket/2015

   (19) http://www.sqlalchemy.org/trac/ticket/2048

   (20) http://www.sqlalchemy.org/trac/ticket/2028

   (21) http://www.sqlalchemy.org/trac/ticket/2023

   (22) http://www.sqlalchemy.org/trac/ticket/2042

   (23) http://www.sqlalchemy.org/trac/ticket/1921

   (24) http://www.sqlalchemy.org/trac/ticket/2036

8.3.8.129 postgresql
....................

   * `[postgresql]' ¶. When explicit sequence execution
     derives the name of the auto-generated sequence of a SERIAL column,
     which currently only occurs if implicit_returning=False, now
     accommodates if the table + column name is greater than 63
     characters using the same logic PostgreSQL uses.  (also in 0.6.7)

     References: #1083(1)

   * `[postgresql]' ¶. Added an additional libpq message to
     the list of “disconnect” exceptions, “could not receive data from
     server” (also in 0.6.7)

     References: #2044(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1083

   (2) http://www.sqlalchemy.org/trac/ticket/2044

8.3.8.130 mysql
...............

   * `[mysql]' ¶. New DBAPI support for pymysql, a pure
     Python port of MySQL-python.

     References: #1991(1)

   * `[mysql]' ¶ oursql dialect accepts the same “ssl”
     arguments in create_engine() as that of MySQLdb.  (also in 0.6.7)

     References: #2047(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1991

   (2) http://www.sqlalchemy.org/trac/ticket/2047

8.3.8.131 mssql
...............

   * `[mssql]' ¶ the String/Unicode types, and their
     counterparts VARCHAR/ NVARCHAR, emit “max” as the length when no
     length is specified, so that the default length, normally ‘1’ as
     per SQL server documentation, is instead ‘unbounded’.  This also
     occurs for the VARBINARY type..

     This behavior makes these types more closely compatible with
     PostgreSQL’s VARCHAR type which is similarly unbounded when no
     length is specified.

     References: #1833(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1833

8.3.8.132 firebird
..................

   * `[firebird]' ¶. Some adjustments so that Interbase is
     supported as well.  FB/Interbase version idents are parsed into a
     structure such as (8, 1, 1, ‘interbase’) or (2, 1, 588, ‘firebird’)
     so they can be distinguished.

     References: #1885(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1885

8.3.8.133 misc
..............

   * `[no_tags]' ¶. Detailed descriptions of each change
     below are described at:
     ‘http://docs.sqlalchemy.org/en/latest/changelog/migration_07.html’

   * `[declarative]' ¶. Added an explicit check for the case
     that the name ‘metadata’ is used for a column attribute on a
     declarative class.  (also in 0.6.7)

     References: #2050(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2050

8.3.9 0.6 Changelog
-------------------

8.3.9.1 0.6.9
.............

Released: Sat May 05 2012

8.3.9.2 general
...............

   * `[general]' ¶. Adjusted the “importlater” mechanism,
     which is used internally to resolve import cycles, such that the
     usage of __import__ is completed when the import of sqlalchemy or
     sqlalchemy.orm is done, thereby avoiding any usage of __import__
     after the application starts new threads, fixes.

     References: #2279(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2279

8.3.9.3 orm
...........

   * `[orm] [bug]' ¶ fixed inappropriate evaluation of
     user-mapped object in a boolean context within query.get().

     References: #2310(1)

   * `[orm] [bug]' ¶. Fixed the error formatting raised when
     a tuple is inadvertently passed to session.query().

     References: #2297(2)

   * `[orm]' ¶. Fixed bug whereby the source clause used by
     query.join() would be inconsistent if against a column expression
     that combined multiple entities together.

     References: #2197(3)

   * `[orm]' ¶. Fixed bug apparent only in Python 3 whereby
     sorting of persistent + pending objects during flush would produce
     an illegal comparison, if the persistent object primary key is not
     a single integer.

     References: #2228(4)

   * `[orm]' ¶. Fixed bug where query.join() + aliased=True
     from a joined-inh structure to itself on relationship() with join
     condition on the child table would convert the lead entity into the
     joined one inappropriately.

     References: #2234(5)

   * `[orm]' ¶. Fixed bug whereby mapper.order_by attribute
     would be ignored in the “inner” query within a subquery eager load.
     .

     References: #2287(6)

   * `[orm]' ¶. Fixed bug whereby if a mapped class
     redefined __hash__() or __eq__() to something non-standard, which
     is a supported use case as SQLA should never consult these, the
     methods would be consulted if the class was part of a “composite”
     (i.e.  non-single-entity) result set.

     References: #2215(7)

   * `[orm]' ¶. Fixed subtle bug that caused SQL to blow up
     if: column_property() against subquery + joinedload + LIMIT + order
     by the column property() occurred.  .

     References: #2188(8)

   * `[orm]' ¶. The join condition produced by with_parent
     as well as when using a “dynamic” relationship against a parent
     will generate unique bindparams, rather than incorrectly repeating
     the same bindparam.  .

     References: #2207(9)

   * `[orm]' ¶. Repaired the “no statement condition”
     assertion in Query which would attempt to raise if a generative
     method were called after from_statement() were called..

     References: #2199(10)

   * `[orm]' ¶. Cls.column.collate(“some collation”) now
     works.

     References: #1776(11)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2310

   (2) http://www.sqlalchemy.org/trac/ticket/2297

   (3) http://www.sqlalchemy.org/trac/ticket/2197

   (4) http://www.sqlalchemy.org/trac/ticket/2228

   (5) http://www.sqlalchemy.org/trac/ticket/2234

   (6) http://www.sqlalchemy.org/trac/ticket/2287

   (7) http://www.sqlalchemy.org/trac/ticket/2215

   (8) http://www.sqlalchemy.org/trac/ticket/2188

   (9) http://www.sqlalchemy.org/trac/ticket/2207

   (10) http://www.sqlalchemy.org/trac/ticket/2199

   (11) http://www.sqlalchemy.org/trac/ticket/1776

8.3.9.4 engine
..............

   * `[engine]' ¶. Backported the fix for introduced in
     0.7.4, which ensures that the connection is in a valid state before
     attempting to call rollback()/prepare()/release() on savepoint and
     two-phase transactions.

     References: #2317(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2317

8.3.9.5 sql
...........

   * `[sql]' ¶. Fixed two subtle bugs involving column
     correspondence in a selectable, one with the same labeled subquery
     repeated, the other when the label has been “grouped” and loses
     itself.  Affects.

     References: #2188(1)

   * `[sql]' ¶. Fixed bug whereby “warn on unicode” flag
     would get set for the String type when used with certain dialects.
     This bug is not in 0.7.

   * `[sql]' ¶. Fixed bug whereby with_only_columns() method
     of Select would fail if a selectable were passed..  However, the
     FROM behavior is still incorrect here, so you need 0.7 in any case
     for this use case to be usable.

     References: #2270(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2188

   (2) http://www.sqlalchemy.org/trac/ticket/2270

8.3.9.6 schema
..............

   * `[schema]' ¶. Added an informative error message when
     ForeignKeyConstraint refers to a column name in the parent that is
     not found.

8.3.9.7 postgresql
..................

   * `[postgresql]' ¶. Fixed bug related to whereby the same
     modified index behavior in PG 9 affected primary key reflection on
     a renamed column..

     References: #2141(1), #2291(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2141

   (2) http://www.sqlalchemy.org/trac/ticket/2291

8.3.9.8 mysql
.............

   * `[mysql]' ¶. Fixed OurSQL dialect to use ansi-neutral
     quote symbol “’” for XA commands instead of ‘”’.  .

     References: #2186(1)

   * `[mysql]' ¶ a CREATE TABLE will put the COLLATE option
     after CHARSET, which appears to be part of MySQL’s arbitrary rules
     regarding if it will actually work or not.

     References: #2225(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2186

   (2) http://www.sqlalchemy.org/trac/ticket/2225

8.3.9.9 mssql
.............

   * `[mssql] [bug]' ¶. Decode incoming values when
     retrieving list of index names and the names of columns within
     those indexes.

     References: #2269(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2269

8.3.9.10 oracle
...............

   * `[oracle]' ¶. Added ORA-00028 to disconnect codes, use
     cx_oracle _Error.code to get at the code,.

     References: #2200(1)

   * `[oracle]' ¶ repaired the oracle.RAW type which did
     not generate the correct DDL.

     References: #2220(2)

   * `[oracle]' ¶ added CURRENT to reserved word list.

     References: #2212(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2200

   (2) http://www.sqlalchemy.org/trac/ticket/2220

   (3) http://www.sqlalchemy.org/trac/ticket/2212

8.3.9.11 misc
.............

   * `[examples]' ¶. Adjusted dictlike-polymorphic.py
     example to apply the CAST such that it works on PG, other
     databases.

     References: #2266(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2266

8.3.9.12 0.6.8
..............

Released: Sun Jun 05 2011

8.3.9.13 orm
............

   * `[orm]' ¶. Calling query.get() against a column-based
     entity is invalid, this condition now raises a deprecation warning.

     References: #2144(1)

   * `[orm]' ¶ a non_primary mapper will inherit the
     _identity_class of the primary mapper.  This so that a non_primary
     established against a class that’s normally in an inheritance
     mapping will produce results that are identity-map compatible with
     that of the primary mapper

     References: #2151(2)

   * `[orm]' ¶. Backported 0.7’s identity map
     implementation, which does not use a mutex around removal.  This as
     some users were still getting deadlocks despite the adjustments in
     0.6.7; the 0.7 approach that doesn’t use a mutex does not appear to
     produce “dictionary changed size” issues, the original rationale
     for the mutex.

     References: #2148(3)

   * `[orm]' ¶. Fixed the error message emitted for “can’t
     execute syncrule for destination column ‘q’; mapper ‘X’ does not
     map this column” to reference the correct mapper.  .

     References: #2163(4)

   * `[orm]' ¶. Fixed bug where determination of “self
     referential” relationship would fail with no workaround for
     joined-inh subclass related to itself, or joined-inh subclass
     related to a subclass of that with no cols in the sub-sub class in
     the join condition.

     References: #2149(5)

   * `[orm]' ¶ mapper() will ignore non-configured foreign
     keys to unrelated tables when determining inherit condition between
     parent and child class.  This is equivalent to behavior already
     applied to declarative.  Note that 0.7 has a more comprehensive
     solution to this, altering how join() itself determines an FK
     error.

     References: #2153(6)

   * `[orm]' ¶. Fixed bug whereby mapper mapped to an
     anonymous alias would fail if logging were used, due to unescaped %
     sign in the alias name.

     References: #2171(7)

   * `[orm]' ¶. Modify the text of the message which occurs
     when the “identity” key isn’t detected on flush, to include the
     common cause that the Column isn’t set up to detect auto-increment
     correctly;.

     References: #2170(8)

   * `[orm]' ¶. Fixed bug where transaction-level “deleted”
     collection wouldn’t be cleared of expunged states, raising an error
     if they later became transient.

     References: #2182(9)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2144

   (2) http://www.sqlalchemy.org/trac/ticket/2151

   (3) http://www.sqlalchemy.org/trac/ticket/2148

   (4) http://www.sqlalchemy.org/trac/ticket/2163

   (5) http://www.sqlalchemy.org/trac/ticket/2149

   (6) http://www.sqlalchemy.org/trac/ticket/2153

   (7) http://www.sqlalchemy.org/trac/ticket/2171

   (8) http://www.sqlalchemy.org/trac/ticket/2170

   (9) http://www.sqlalchemy.org/trac/ticket/2182

8.3.9.14 engine
...............

   * `[engine]' ¶. Adjusted the __contains__() method of a
     RowProxy result row such that no exception throw is generated
     internally; NoSuchColumnError() also will generate its message
     regardless of whether or not the column construct can be coerced to
     a string..

     References: #2178(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2178

8.3.9.15 sql
............

   * `[sql]' ¶. Fixed bug whereby if FetchedValue was passed
     to column server_onupdate, it would not have its parent “column”
     assigned, added test coverage for all column default assignment
     patterns.

     References: #2147(1)

   * `[sql]' ¶. Fixed bug whereby nesting a label of a
     select() with another label in it would produce incorrect exported
     columns.  Among other things this would break an ORM
     column_property() mapping against another column_property().  .

     References: #2167(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2147

   (2) http://www.sqlalchemy.org/trac/ticket/2167

8.3.9.16 postgresql
...................

   * `[postgresql]' ¶. Fixed bug affecting PG 9 whereby
     index reflection would fail if against a column whose name had
     changed.  .

     References: #2141(1)

   * `[postgresql]' ¶. Some unit test fixes regarding
     numeric arrays, MATCH operator.  A potential floating-point
     inaccuracy issue was fixed, and certain tests of the MATCH operator
     only execute within an EN-oriented locale for now.  .

     References: #2175(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2141

   (2) http://www.sqlalchemy.org/trac/ticket/2175

8.3.9.17 mssql
..............

   * `[mssql]' ¶. Fixed bug in MSSQL dialect whereby the
     aliasing applied to a schema-qualified table would leak into
     enclosing select statements.

     References: #2169(1)

   * `[mssql]' ¶. Fixed bug whereby DATETIME2 type would
     fail on the “adapt” step when used in result sets or bound
     parameters.  This issue is not in 0.7.

     References: #2159(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2169

   (2) http://www.sqlalchemy.org/trac/ticket/2159

8.3.9.18 0.6.7
..............

Released: Wed Apr 13 2011

8.3.9.19 orm
............

   * `[orm]' ¶. Tightened the iterate vs.  remove mutex
     around the identity map iteration, attempting to reduce the chance
     of an (extremely rare) reentrant gc operation causing a deadlock.
     Might remove the mutex in 0.7.

     References: #2087(1)

   * `[orm]' ¶. Added a ‘name’ argument to
     ‘Query.subquery()’, to allow a fixed name to be assigned to the
     alias object.

     References: #2030(2)

   * `[orm]' ¶. A warning is emitted when a joined-table
     inheriting mapper has no primary keys on the locally mapped table
     (but has pks on the superclass table).

     References: #2019(3)

   * `[orm]' ¶. Fixed bug where “middle” class in a
     polymorphic hierarchy would have no ‘polymorphic_on’ column if it
     didn’t also specify a ‘polymorphic_identity’, leading to strange
     errors upon refresh, wrong class loaded when querying from that
     target.  Also emits the correct WHERE criterion when using single
     table inheritance.

     References: #2038(4)

   * `[orm]' ¶. Fixed bug where a column with a SQL or
     server side default that was excluded from a mapping with
     include_properties or exclude_properties would result in
     UnmappedColumnError.

     References: #1995(5)

   * `[orm]' ¶. A warning is emitted in the unusual case
     that an append or similar event on a collection occurs after the
     parent object has been dereferenced, which prevents the parent from
     being marked as “dirty” in the session.  This will be an exception
     in 0.7.

     References: #2046(6)

   * `[orm]' ¶. Fixed bug in query.options() whereby a path
     applied to a lazyload using string keys could overlap a same named
     attribute on the wrong entity.  Note 0.7 has an updated version of
     this fix.

     References: #2098(7)

   * `[orm]' ¶. Reworded the exception raised when a flush
     is attempted of a subclass that is not polymorphic against the
     supertype.

     References: #2063(8)

   * `[orm]' ¶. Some fixes to the state handling regarding
     backrefs, typically when autoflush=False, where the back-referenced
     collection wouldn’t properly handle add/removes with no net change.
     Thanks to Richard Murri for the test case + patch.

     References: #2123(9)

   * `[orm]' ¶ a “having” clause would be copied from the
     inside to the outside query if from_self() were used..

     References: #2130(10)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2087

   (2) http://www.sqlalchemy.org/trac/ticket/2030

   (3) http://www.sqlalchemy.org/trac/ticket/2019

   (4) http://www.sqlalchemy.org/trac/ticket/2038

   (5) http://www.sqlalchemy.org/trac/ticket/1995

   (6) http://www.sqlalchemy.org/trac/ticket/2046

   (7) http://www.sqlalchemy.org/trac/ticket/2098

   (8) http://www.sqlalchemy.org/trac/ticket/2063

   (9) http://www.sqlalchemy.org/trac/ticket/2123

   (10) http://www.sqlalchemy.org/trac/ticket/2130

8.3.9.20 engine
...............

   * `[engine]' ¶. Fixed bug in QueuePool,
     SingletonThreadPool whereby connections that were discarded via
     overflow or periodic cleanup() were not explicitly closed, leaving
     garbage collection to the task instead.  This generally only
     affects non-reference-counting backends like Jython and PyPy.
     Thanks to Jaimy Azle for spotting this.

     References: #2102(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2102

8.3.9.21 sql
............

   * `[sql]' ¶. Column.copy(), as used in
     table.tometadata(), copies the ‘doc’ attribute.

     References: #2028(1)

   * `[sql]' ¶. Added some defs to the resultproxy.c
     extension so that the extension compiles and runs on Python 2.4.

     References: #2023(2)

   * `[sql]' ¶. The compiler extension now supports
     overriding the default compilation of expression._BindParamClause
     including that the auto-generated binds within the VALUES/SET
     clause of an insert()/update() statement will also use the new
     compilation rules.

     References: #2042(3)

   * `[sql]' ¶. Added accessors to ResultProxy
     “returns_rows”, “is_insert”

     References: #2089(4)

   * `[sql]' ¶. The limit/offset keywords to select() as
     well as the value passed to select.limit()/offset() will be coerced
     to integer.

     References: #2116(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2028

   (2) http://www.sqlalchemy.org/trac/ticket/2023

   (3) http://www.sqlalchemy.org/trac/ticket/2042

   (4) http://www.sqlalchemy.org/trac/ticket/2089

   (5) http://www.sqlalchemy.org/trac/ticket/2116

8.3.9.22 postgresql
...................

   * `[postgresql]' ¶. When explicit sequence execution
     derives the name of the auto-generated sequence of a SERIAL column,
     which currently only occurs if implicit_returning=False, now
     accommodates if the table + column name is greater than 63
     characters using the same logic PostgreSQL uses.

     References: #1083(1)

   * `[postgresql]' ¶. Added an additional libpq message to
     the list of “disconnect” exceptions, “could not receive data from
     server”

     References: #2044(2)

   * `[postgresql]' ¶. Added RESERVED_WORDS for postgresql
     dialect.

     References: #2092(3)

   * `[postgresql]' ¶. Fixed the BIT type to allow a
     “length” parameter, “varying” parameter.  Reflection also fixed.

     References: #2073(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1083

   (2) http://www.sqlalchemy.org/trac/ticket/2044

   (3) http://www.sqlalchemy.org/trac/ticket/2092

   (4) http://www.sqlalchemy.org/trac/ticket/2073

8.3.9.23 mysql
..............

   * `[mysql]' ¶ oursql dialect accepts the same “ssl”
     arguments in create_engine() as that of MySQLdb.

     References: #2047(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2047

8.3.9.24 sqlite
...............

   * `[sqlite]' ¶. Fixed bug where reflection of foreign key
     created as “REFERENCES <tablename>” without col name would fail.

     References: #2115(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2115

8.3.9.25 mssql
..............

   * `[mssql]' ¶. Rewrote the query used to get the
     definition of a view, typically when using the Inspector interface,
     to use sys.sql_modules instead of the information schema, thereby
     allowing views definitions longer than 4000 characters to be fully
     returned.

     References: #2071(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2071

8.3.9.26 oracle
...............

   * `[oracle]' ¶. Using column names that would require
     quotes for the column itself or for a name-generated bind
     parameter, such as names with special characters, underscores,
     non-ascii characters, now properly translate bind parameter keys
     when talking to cx_oracle.

     References: #2100(1)

   * `[oracle]' ¶. Oracle dialect adds
     use_binds_for_limits=False create_engine() flag, will render the
     LIMIT/OFFSET values inline instead of as binds, reported to modify
     the execution plan used by Oracle.

     References: #2116(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2100

   (2) http://www.sqlalchemy.org/trac/ticket/2116

8.3.9.27 firebird
.................

   * `[firebird]' ¶. The “implicit_returning” flag on
     create_engine() is honored if set to False.

     References: #2083(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2083

8.3.9.28 misc
.............

   * `[informix]' ¶. Added RESERVED_WORDS informix dialect.

     References: #2092(1)

   * `[ext]' ¶. The horizontal_shard ShardedSession class
     accepts the common Session argument “query_cls” as a constructor
     argument, to enable further subclassing of ShardedQuery.

     References: #2090(2)

   * `[declarative]' ¶. Added an explicit check for the case
     that the name ‘metadata’ is used for a column attribute on a
     declarative class.

     References: #2050(3)

   * `[declarative]' ¶. Fix error message referencing old
     @classproperty name to reference @declared_attr

     References: #2061(4)

   * `[declarative]' ¶. Arguments in __mapper_args__ that
     aren’t “hashable” aren’t mistaken for always-hashable,
     possibly-column arguments.

     References: #2091(5)

   * `[documentation]' ¶. Documented SQLite
     DATE/TIME/DATETIME types.

     References: #2029(6)

   * `[examples]' ¶. The Beaker caching example allows a
     “query_cls” argument to the query_callable() function.

     References: #2090(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2092

   (2) http://www.sqlalchemy.org/trac/ticket/2090

   (3) http://www.sqlalchemy.org/trac/ticket/2050

   (4) http://www.sqlalchemy.org/trac/ticket/2061

   (5) http://www.sqlalchemy.org/trac/ticket/2091

   (6) http://www.sqlalchemy.org/trac/ticket/2029

   (7) http://www.sqlalchemy.org/trac/ticket/2090

8.3.9.29 0.6.6
..............

Released: Sat Jan 08 2011

8.3.9.30 orm
............

   * `[orm]' ¶. Fixed bug whereby a non-“mutable” attribute
     modified event which occurred on an object that was clean except
     for preceding mutable attribute changes would fail to strongly
     reference itself in the identity map.  This would cause the object
     to be garbage collected, losing track of any changes that weren’t
     previously saved in the “mutable changes” dictionary.

   * `[orm]' ¶. Fixed bug whereby “passive_deletes=’all’”
     wasn’t passing the correct symbols to lazy loaders during flush,
     thereby causing an unwarranted load.

     References: #2013(1)

   * `[orm]' ¶. Fixed bug which prevented composite mapped
     attributes from being used on a mapped select statement..  Note the
     workings of composite are slated to change significantly in 0.7.

     References: #1997(2)

   * `[orm]' ¶ active_history flag also added to
     composite().  The flag has no effect in 0.6, but is instead a
     placeholder flag for forwards compatibility, as it applies in 0.7
     for composites.

     References: #1976(3)

   * `[orm]' ¶. Fixed uow bug whereby expired objects passed
     to Session.delete() would not have unloaded references or
     collections taken into account when deleting objects, despite
     passive_deletes remaining at its default of False.

     References: #2002(4)

   * `[orm]' ¶. A warning is emitted when version_id_col is
     specified on an inheriting mapper when the inherited mapper already
     has one, if those column expressions are not the same.

     References: #1987(5)

   * `[orm]' ¶. ”innerjoin” flag doesn’t take effect along
     the chain of joinedload() joins if a previous join in that chain is
     an outer join, thus allowing primary rows without a referenced
     child row to be correctly returned in results.

     References: #1954(6)

   * `[orm]' ¶. Fixed bug regarding “subqueryload” strategy
     whereby strategy would fail if the entity was an aliased()
     construct.

     References: #1964(7)

   * `[orm]' ¶. Fixed bug regarding “subqueryload” strategy
     whereby the join would fail if using a multi-level load of the form
     from A->joined-subclass->C

     References: #2014(8)

   * `[orm]' ¶. Fixed indexing of Query objects by -1.  It
     was erroneously transformed to the empty slice -1:0 that resulted
     in IndexError.

     References: #1968(9)

   * `[orm]' ¶. The mapper argument “primary_key” can be
     passed as a single column as well as a list or tuple.  The
     documentation examples that illustrated it as a scalar value have
     been changed to lists.

     References: #1971(10)

   * `[orm]' ¶. Added active_history flag to relationship()
     and column_property(), forces attribute events to always load the
     “old” value, so that it’s available to attributes.get_history().

     References: #1961(11)

   * `[orm]' ¶. Query.get() will raise if the number of
     params in a composite key is too large, as well as too small.

     References: #1977(12)

   * `[orm]' ¶. Backport of “optimized get” fix from 0.7,
     improves the generation of joined-inheritance “load expired row”
     behavior.

     References: #1992(13)

   * `[orm]' ¶. A little more verbiage to the “primaryjoin”
     error, in an unusual condition that the join condition “works” for
     viewonly but doesn’t work for non-viewonly, and foreign_keys wasn’t
     used - adds “foreign_keys” to the suggestion.  Also add
     “foreign_keys” to the suggestion for the generic “direction” error.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2013

   (2) http://www.sqlalchemy.org/trac/ticket/1997

   (3) http://www.sqlalchemy.org/trac/ticket/1976

   (4) http://www.sqlalchemy.org/trac/ticket/2002

   (5) http://www.sqlalchemy.org/trac/ticket/1987

   (6) http://www.sqlalchemy.org/trac/ticket/1954

   (7) http://www.sqlalchemy.org/trac/ticket/1964

   (8) http://www.sqlalchemy.org/trac/ticket/2014

   (9) http://www.sqlalchemy.org/trac/ticket/1968

   (10) http://www.sqlalchemy.org/trac/ticket/1971

   (11) http://www.sqlalchemy.org/trac/ticket/1961

   (12) http://www.sqlalchemy.org/trac/ticket/1977

   (13) http://www.sqlalchemy.org/trac/ticket/1992

8.3.9.31 engine
...............

   * `[engine]' ¶. The “unicode warning” against non-unicode
     bind data is now raised only when the Unicode type is used
     explicitly; not when convert_unicode=True is used on the engine or
     String type.

   * `[engine]' ¶. Fixed memory leak in C version of Decimal
     result processor.

     References: #1978(1)

   * `[engine]' ¶. Implemented sequence check capability for
     the C version of RowProxy, as well as 2.7 style
     “collections.Sequence” registration for RowProxy.

     References: #1871(2)

   * `[engine]' ¶. Threadlocal engine methods rollback(),
     commit(), prepare() won’t raise if no transaction is in progress;
     this was a regression introduced in 0.6.

     References: #1998(3)

   * `[engine]' ¶. Threadlocal engine returns itself upon
     begin(), begin_nested(); engine then implements contextmanager
     methods to allow the “with” statement.

     References: #2004(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1978

   (2) http://www.sqlalchemy.org/trac/ticket/1871

   (3) http://www.sqlalchemy.org/trac/ticket/1998

   (4) http://www.sqlalchemy.org/trac/ticket/2004

8.3.9.32 sql
............

   * `[sql]' ¶. Fixed operator precedence rules for multiple
     chains of a single non-associative operator.  I.e.  “x - (y - z)”
     will compile as “x - (y - z)” and not “x - y - z”.  Also works with
     labels, i.e.  “x - (y - z).label(‘foo’)”

     References: #1984(1)

   * `[sql]' ¶. The ‘info’ attribute of Column is copied
     during Column.copy(), i.e.  as occurs when using columns in
     declarative mixins.

     References: #1967(2)

   * `[sql]' ¶. Added a bind processor for booleans which
     coerces to int, for DBAPIs such as pymssql that naively call str()
     on values.

   * `[sql]' ¶. CheckConstraint will copy its ‘initially’,
     ‘deferrable’, and ‘_create_rule’ attributes within a
     copy()/tometadata()

     References: #2000(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1984

   (2) http://www.sqlalchemy.org/trac/ticket/1967

   (3) http://www.sqlalchemy.org/trac/ticket/2000

8.3.9.33 postgresql
...................

   * `[postgresql]' ¶. Single element tuple expressions
     inside an IN clause parenthesize correctly, also from

     References: #1984(1)

   * `[postgresql]' ¶. Ensured every numeric, float, int
     code, scalar + array, are recognized by psycopg2 and pg8000’s
     “numeric” base type.

     References: #1955(2)

   * `[postgresql]' ¶. Added as_uuid=True flag to the UUID
     type, will receive and return values as Python UUID() objects
     rather than strings.  Currently, the UUID type is only known to
     work with psycopg2.

     References: #1956(3)

   * `[postgresql]' ¶. Fixed bug whereby KeyError would
     occur with non-ENUM supported PG versions after a pool
     dispose+recreate would occur.

     References: #1989(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1984

   (2) http://www.sqlalchemy.org/trac/ticket/1955

   (3) http://www.sqlalchemy.org/trac/ticket/1956

   (4) http://www.sqlalchemy.org/trac/ticket/1989

8.3.9.34 mysql
..............

   * `[mysql]' ¶. Fixed error handling for Jython + zxjdbc,
     such that has_table() property works again.  Regression from 0.6.3
     (we don’t have a Jython buildbot, sorry)

     References: #1960(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1960

8.3.9.35 sqlite
...............

   * `[sqlite]' ¶. The REFERENCES clause in a CREATE TABLE
     that includes a remote schema to another table with the same schema
     name now renders the remote name without the schema clause, as
     required by SQLite.

     References: #1851(1)

   * `[sqlite]' ¶. On the same theme, the REFERENCES clause
     in a CREATE TABLE that includes a remote schema to a `different'
     schema than that of the parent table doesn’t render at all, as
     cross-schema references do not appear to be supported.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1851

8.3.9.36 mssql
..............

   * `[mssql]' ¶. The rewrite of index reflection in was
     unfortunately not tested correctly, and returned incorrect results.
     This regression is now fixed.

     References: #1770(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1770

8.3.9.37 oracle
...............

   * `[oracle]' ¶. The cx_oracle “decimal detection” logic,
     which takes place for result set columns with ambiguous numeric
     characteristics, now uses the decimal point character determined by
     the locale/ NLS_LANG setting, using an on-first-connect detection
     of this character.  cx_oracle 5.0.3 or greater is also required
     when using a non-period-decimal-point NLS_LANG setting..

     References: #1953(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1953

8.3.9.38 firebird
.................

   * `[firebird]' ¶. Firebird numeric type now checks for
     Decimal explicitly, lets float() pass right through, thereby
     allowing special values such as float(‘inf’).

     References: #2012(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2012

8.3.9.39 misc
.............

   * `[declarative]' ¶. An error is raised if __table_args__
     is not in tuple or dict format, and is not None.

     References: #1972(1)

   * `[sqlsoup]' ¶. Added “map_to()” method to SqlSoup,
     which is a “master” method which accepts explicit arguments for
     each aspect of the selectable and mapping, including a base class
     per mapping.

     References: #1975(2)

   * `[sqlsoup]' ¶. Mapped selectables used with the map(),
     with_labels(), join() methods no longer put the given argument into
     the internal “cache” dictionary.  Particularly since the join() and
     select() objects are created in the method itself this was pretty
     much a pure memory leaking behavior.

   * `[examples]' ¶. The versioning example now supports
     detection of changes in an associated relationship().

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1972

   (2) http://www.sqlalchemy.org/trac/ticket/1975

8.3.9.40 0.6.5
..............

Released: Sun Oct 24 2010

8.3.9.41 orm
............

   * `[orm]' ¶. Added a new “lazyload” option
     “immediateload”.  Issues the usual “lazy” load operation
     automatically as the object is populated.  The use case here is
     when loading objects to be placed in an offline cache, or otherwise
     used after the session isn’t available, and straight ‘select’
     loading, not ‘joined’ or ‘subquery’, is desired.

     References: #1914(1)

   * `[orm]' ¶. New Query methods: query.label(name),
     query.as_scalar(), return the query’s statement as a scalar
     subquery with /without label; query.with_entities(*ent), replaces
     the SELECT list of the query with new entities.  Roughly equivalent
     to a generative form of query.values() which accepts mapped
     entities as well as column expressions.

     References: #1920(2)

   * `[orm]' ¶. Fixed recursion bug which could occur when
     moving an object from one reference to another, with backrefs
     involved, where the initiating parent was a subclass (with its own
     mapper) of the previous parent.

   * `[orm]' ¶. Fixed a regression in 0.6.4 which occurred
     if you passed an empty list to “include_properties” on mapper()

     References: #1918(3)

   * `[orm]' ¶. Fixed labeling bug in Query whereby the
     NamedTuple would mis-apply labels if any of the column expressions
     were un-labeled.

   * `[orm]' ¶. Patched a case where query.join() would
     adapt the right side to the right side of the left’s join
     inappropriately

     References: #1925(4)

   * `[orm]' ¶. Query.select_from() has been beefed up to
     help ensure that a subsequent call to query.join() will use the
     select_from() entity, assuming it’s a mapped entity and not a plain
     selectable, as the default “left” side, not the first entity in the
     Query object’s list of entities.

   * `[orm]' ¶. The exception raised by Session when it is
     used subsequent to a subtransaction rollback (which is what happens
     when a flush fails in autocommit=False mode) has now been reworded
     (this is the “inactive due to a rollback in a subtransaction”
     message).  In particular, if the rollback was due to an exception
     during flush(), the message states this is the case, and reiterates
     the string form of the original exception that occurred during
     flush.  If the session is closed due to explicit usage of
     subtransactions (not very common), the message just states this is
     the case.

   * `[orm]' ¶. The exception raised by Mapper when repeated
     requests to its initialization are made after initialization
     already failed no longer assumes the “hasattr” case, since there’s
     other scenarios in which this message gets emitted, and the message
     also does not compound onto itself multiple times - you get the
     same message for each attempt at usage.  The misnomer “compiles” is
     being traded out for “initialize”.

   * `[orm]' ¶. Fixed bug in query.update() where ‘evaluate’
     or ‘fetch’ expiration would fail if the column expression key was a
     class attribute with a different keyname as the actual column name.

     References: #1935(5)

   * `[orm]' ¶. Added an assertion during flush which
     ensures that no NULL-holding identity keys were generated on “newly
     persistent” objects.  This can occur when user defined code
     inadvertently triggers flushes on not-fully-loaded objects.

   * `[orm]' ¶ lazy loads for relationship attributes now
     use the current state, not the “committed” state, of foreign and
     primary key attributes when issuing SQL, if a flush is not in
     process.  Previously, only the database-committed state would be
     used.  In particular, this would cause a many-to-one
     get()-on-lazyload operation to fail, as autoflush is not triggered
     on these loads when the attributes are determined and the
     “committed” state may not be available.

     References: #1910(6)

   * `[orm]' ¶. A new flag on relationship(),
     load_on_pending, allows the lazy loader to fire off on pending
     objects without a flush taking place, as well as a transient object
     that’s been manually “attached” to the session.  Note that this
     flag blocks attribute events from taking place when an object is
     loaded, so backrefs aren’t available until after a flush.  The flag
     is only intended for very specific use cases.

   * `[orm]' ¶. Another new flag on relationship(),
     cascade_backrefs, disables the “save-update” cascade when the event
     was initiated on the “reverse” side of a bidirectional
     relationship.  This is a cleaner behavior so that many-to-ones can
     be set on a transient object without it getting sucked into the
     child object’s session, while still allowing the forward collection
     to cascade.  We `might' default this to False in 0.7.

   * `[orm]' ¶. Slight improvement to the behavior of
     “passive_updates=False” when placed only on the many-to-one side of
     a relationship; documentation has been clarified that
     passive_updates=False should really be on the one-to-many side.

   * `[orm]' ¶. Placing passive_deletes=True on a
     many-to-one emits a warning, since you probably intended to put it
     on the one-to-many side.

   * `[orm]' ¶. Fixed bug that would prevent “subqueryload”
     from working correctly with single table inheritance for a
     relationship from a subclass - the “where type in (x, y, z)” only
     gets placed on the inside, instead of repeatedly.

   * `[orm]' ¶. When using from_self() with single table
     inheritance, the “where type in (x, y, z)” is placed on the outside
     of the query only, instead of repeatedly.  May make some more
     adjustments to this.

   * `[orm]' ¶ scoped_session emits a warning when
     configure() is called if a Session is already present (checks only
     the current thread)

     References: #1924(7)

   * `[orm]' ¶ reworked the internals of
     mapper.cascade_iterator() to cut down method calls by about 9% in
     some circumstances.

     References: #1932(8)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1914

   (2) http://www.sqlalchemy.org/trac/ticket/1920

   (3) http://www.sqlalchemy.org/trac/ticket/1918

   (4) http://www.sqlalchemy.org/trac/ticket/1925

   (5) http://www.sqlalchemy.org/trac/ticket/1935

   (6) http://www.sqlalchemy.org/trac/ticket/1910

   (7) http://www.sqlalchemy.org/trac/ticket/1924

   (8) http://www.sqlalchemy.org/trac/ticket/1932

8.3.9.42 engine
...............

   * `[engine]' ¶. Fixed a regression in 0.6.4 whereby the
     change that allowed cursor errors to be raised consistently broke
     the result.lastrowid accessor.  Test coverage has been added for
     result.lastrowid.  Note that lastrowid is only supported by
     Pysqlite and some MySQL drivers, so isn’t super-useful in the
     general case.

   * `[engine]' ¶ the logging message emitted by the engine
     when a connection is first used is now “BEGIN (implicit)” to
     emphasize that DBAPI has no explicit begin().

   * `[engine]' ¶ added “views=True” option to
     metadata.reflect(), will add the list of available views to those
     being reflected.

     References: #1936(1)

   * `[engine]' ¶ engine_from_config() now accepts ‘debug’
     for ‘echo’, ‘echo_pool’, ‘force’ for ‘convert_unicode’, boolean
     values for ‘use_native_unicode’.

     References: #1899(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1936

   (2) http://www.sqlalchemy.org/trac/ticket/1899

8.3.9.43 sql
............

   * `[sql]' ¶. Fixed bug in TypeDecorator whereby the
     dialect-specific type was getting pulled in to generate the DDL for
     a given type, which didn’t always return the correct result.

   * `[sql]' ¶. TypeDecorator can now have a fully
     constructed type specified as its “impl”, in addition to a type
     class.

   * `[sql]' ¶. TypeDecorator will now place itself as the
     resulting type for a binary expression where the type coercion
     rules would normally return its impl type - previously, a copy of
     the impl type would be returned which would have the TypeDecorator
     embedded into it as the “dialect” impl, this was probably an
     unintentional way of achieving the desired effect.

   * `[sql]' ¶. TypeDecorator.load_dialect_impl() returns
     “self.impl” by default, i.e.  not the dialect implementation type
     of “self.impl”.  This to support compilation correctly.  Behavior
     can be user-overridden in exactly the same way as before to the
     same effect.

   * `[sql]' ¶. Added type_coerce(expr, type_) expression
     element.  Treats the given expression as the given type when
     evaluating expressions and processing result rows, but does not
     affect the generation of SQL, other than an anonymous label.

   * `[sql]' ¶. Table.tometadata() now copies Index objects
     associated with the Table as well.

   * `[sql]' ¶. Table.tometadata() issues a warning if the
     given Table is already present in the target MetaData - the
     existing Table object is returned.

   * `[sql]' ¶. An informative error message is raised if a
     Column which has not yet been assigned a name, i.e.  as in
     declarative, is used in a context where it is exported to the
     columns collection of an enclosing select() construct, or if any
     construct involving that column is compiled before its name is
     assigned.

   * `[sql]' ¶ as_scalar(), label() can be called on a
     selectable which contains a Column that is not yet named.

     References: #1862(1)

   * `[sql]' ¶. Fixed recursion overflow which could occur
     when operating with two expressions both of type “NullType”, but
     not the singleton NULLTYPE instance.

     References: #1907(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1862

   (2) http://www.sqlalchemy.org/trac/ticket/1907

8.3.9.44 postgresql
...................

   * `[postgresql]' ¶. Added “as_tuple” flag to ARRAY type,
     returns results as tuples instead of lists to allow hashing.

   * `[postgresql]' ¶. Fixed bug which prevented “domain”
     built from a custom type such as “enum” from being reflected.

     References: #1933(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1933

8.3.9.45 mysql
..............

   * `[mysql]' ¶. Fixed bug involving reflection of
     CURRENT_TIMESTAMP default used with ON UPDATE clause, thanks to
     Taavi Burns

     References: #1940(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1940

8.3.9.46 mssql
..............

   * `[mssql]' ¶. Fixed reflection bug which did not
     properly handle reflection of unknown types.

     References: #1946(1)

   * `[mssql]' ¶. Fixed bug where aliasing of tables with
     “schema” would fail to compile properly.

     References: #1943(2)

   * `[mssql]' ¶. Rewrote the reflection of indexes to use
     sys.  catalogs, so that column names of any configuration (spaces,
     embedded commas, etc.)  can be reflected.  Note that reflection of
     indexes requires SQL Server 2005 or greater.

     References: #1770(3)

   * `[mssql]' ¶ mssql+pymssql dialect now honors the
     “port” portion of the URL instead of discarding it.

     References: #1952(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1946

   (2) http://www.sqlalchemy.org/trac/ticket/1943

   (3) http://www.sqlalchemy.org/trac/ticket/1770

   (4) http://www.sqlalchemy.org/trac/ticket/1952

8.3.9.47 oracle
...............

   * `[oracle]' ¶. The implicit_returning argument to
     create_engine() is now honored regardless of detected version of
     Oracle.  Previously, the flag would be forced to False if server
     version info was < 10.

     References: #1878(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1878

8.3.9.48 misc
.............

   * `[declarative]' ¶. @classproperty (soon/now
     @declared_attr) takes effect for __mapper_args__, __table_args__,
     __tablename__ on a base class that is not a mixin, as well as
     mixins.

     References: #1922(1)

   * `[declarative]' ¶. @classproperty ‘s official
     name/location for usage with declarative is
     sqlalchemy.ext.declarative.declared_attr.  Same thing, but moving
     there since it is more of a “marker” that’s specific to
     declarative, not just an attribute technique.

     References: #1915(2)

   * `[declarative]' ¶. Fixed bug whereby columns on a mixin
     wouldn’t propagate correctly to a single-table, or joined-table,
     inheritance scheme where the attribute name is different than that
     of the column.,.

     References: #1930(3), #1931(4)

   * `[declarative]' ¶. A mixin can now specify a column
     that overrides a column of the same name associated with a
     superclass.  Thanks to Oystein Haaland.

   * `[informix]' ¶. `Major' cleanup / modernization of the
     Informix dialect for 0.6, courtesy Florian Apolloner.

     References: #1906(5)

   * `[tests]' ¶ the NoseSQLAlchemyPlugin has been moved to
     a new package “sqlalchemy_nose” which installs along with
     “sqlalchemy”.  This so that the “nosetests” script works as always
     but also allows the –with-coverage option to turn on coverage
     before SQLAlchemy modules are imported, allowing coverage to work
     correctly.

   * `[misc]' ¶. CircularDependencyError now has .cycles and
     .edges members, which are the set of elements involved in one or
     more cycles, and the set of edges as 2-tuples.

     References: #1890(6)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1922

   (2) http://www.sqlalchemy.org/trac/ticket/1915

   (3) http://www.sqlalchemy.org/trac/ticket/1930

   (4) http://www.sqlalchemy.org/trac/ticket/1931

   (5) http://www.sqlalchemy.org/trac/ticket/1906

   (6) http://www.sqlalchemy.org/trac/ticket/1890

8.3.9.49 0.6.4
..............

Released: Tue Sep 07 2010

8.3.9.50 orm
............

   * `[orm]' ¶. The name ConcurrentModificationError has
     been changed to StaleDataError, and descriptive error messages have
     been revised to reflect exactly what the issue is.  Both names will
     remain available for the foreseeable future for schemes that may be
     specifying ConcurrentModificationError in an “except:” clause.

   * `[orm]' ¶. Added a mutex to the identity map which
     mutexes remove operations against iteration methods, which now
     pre-buffer before returning an iterable.  This because asynchronous
     gc can remove items via the gc thread at any time.

     References: #1891(1)

   * `[orm]' ¶. The Session class is now present in
     sqlalchemy.orm.*.  We’re moving away from the usage of
     create_session(), which has non-standard defaults, for those
     situations where a one-step Session constructor is desired.  Most
     users should stick with sessionmaker() for general use, however.

   * `[orm]' ¶ query.with_parent() now accepts transient
     objects and will use the non-persistent values of their pk/fk
     attributes in order to formulate the criterion.  Docs are also
     clarified as to the purpose of with_parent().

   * `[orm]' ¶. The include_properties and
     exclude_properties arguments to mapper() now accept Column objects
     as members in addition to strings.  This so that same-named Column
     objects, such as those within a join(), can be disambiguated.

   * `[orm]' ¶. A warning is now emitted if a mapper is
     created against a join or other single selectable that includes
     multiple columns with the same name in its .c.  collection, and
     those columns aren’t explicitly named as part of the same or
     separate attributes (or excluded).  In 0.7 this warning will be an
     exception.  Note that this warning is not emitted when the
     combination occurs as a result of inheritance, so that attributes
     still allow being overridden naturally..  In 0.7 this will be
     improved further.

     References: #1896(2)

   * `[orm]' ¶. The primary_key argument to mapper() can now
     specify a series of columns that are only a subset of the
     calculated “primary key” columns of the mapped selectable, without
     an error being raised.  This helps for situations where a
     selectable’s effective primary key is simpler than the number of
     columns in the selectable that are actually marked as
     “primary_key”, such as a join against two tables on their primary
     key columns.

     References: #1896(3)

   * `[orm]' ¶. An object that’s been deleted now gets a
     flag ‘deleted’, which prohibits the object from being re-add()ed to
     the session, as previously the object would live in the identity
     map silently until its attributes were accessed.  The
     make_transient() function now resets this flag along with the “key”
     flag.

   * `[orm]' ¶ make_transient() can be safely called on an
     already transient instance.

   * `[orm]' ¶ a warning is emitted in mapper() if the
     polymorphic_on column is not present either in direct or derived
     form in the mapped selectable or in the with_polymorphic
     selectable, instead of silently ignoring it.  Look for this to
     become an exception in 0.7.

   * `[orm]' ¶. Another pass through the series of error
     messages emitted when relationship() is configured with ambiguous
     arguments.  The “foreign_keys” setting is no longer mentioned, as
     it is almost never needed and it is preferable users set up correct
     ForeignKey metadata, which is now the recommendation.  If
     ‘foreign_keys’ is used and is incorrect, the message suggests the
     attribute is probably unnecessary.  Docs for the attribute are
     beefed up.  This because all confused relationship() users on the
     ML appear to be attempting to use foreign_keys due to the message,
     which only confuses them further since Table metadata is much
     clearer.

   * `[orm]' ¶. If the “secondary” table has no ForeignKey
     metadata and no foreign_keys is set, even though the user is
     passing screwed up information, it is assumed that
     primary/secondaryjoin expressions should consider only and all cols
     in “secondary” to be foreign.  It’s not possible with “secondary”
     for the foreign keys to be elsewhere in any case.  A warning is now
     emitted instead of an error, and the mapping succeeds.

     References: #1877(4)

   * `[orm]' ¶. Moving an o2m object from one collection to
     another, or vice versa changing the referenced object by an m2o,
     where the foreign key is also a member of the primary key, will now
     be more carefully checked during flush if the change in value of
     the foreign key on the “many” side is the result of a change in the
     primary key of the “one” side, or if the “one” is just a different
     object.  In one case, a cascade-capable DB would have cascaded the
     value already and we need to look at the “new” PK value to do an
     UPDATE, in the other we need to continue looking at the “old”.  We
     now look at the “old”, assuming passive_updates=True, unless we
     know it was a PK switch that triggered the change.

     References: #1856(5)

   * `[orm]' ¶. The value of version_id_col can be changed
     manually, and this will result in an UPDATE of the row.  Versioned
     UPDATEs and DELETEs now use the “committed” value of the
     version_id_col in the WHERE clause and not the pending changed
     value.  The version generator is also bypassed if manual changes
     are present on the attribute.

     References: #1857(6)

   * `[orm]' ¶. Repaired the usage of merge() when used with
     concrete inheriting mappers.  Such mappers frequently have
     so-called “concrete” attributes, which are subclass attributes that
     “disable” propagation from the parent - these needed to allow a
     merge() operation to pass through without effect.

   * `[orm]' ¶. Specifying a non-column based argument for
     column_mapped_collection, including string, text() etc., will raise
     an error message that specifically asks for a column element, no
     longer misleads with incorrect information about text() or
     literal().

     References: #1863(7)

   * `[orm]' ¶. Similarly, for relationship(), foreign_keys,
     remote_side, order_by - all column-based expressions are enforced -
     lists of strings are explicitly disallowed since this is a very
     common error

   * `[orm]' ¶. Dynamic attributes don’t support collection
     population - added an assertion for when set_committed_value() is
     called, as well as when joinedload() or subqueryload() options are
     applied to a dynamic attribute, instead of failure / silent
     failure.

     References: #1864(8)

   * `[orm]' ¶. Fixed bug whereby generating a Query derived
     from one which had the same column repeated with different label
     names, typically in some UNION situations, would fail to propagate
     the inner columns completely to the outer query.

     References: #1852(9)

   * `[orm]' ¶ object_session() raises the proper
     UnmappedInstanceError when presented with an unmapped instance.

     References: #1881(10)

   * `[orm]' ¶. Applied further memoizations to calculated
     Mapper properties, with significant (~90%) runtime mapper.py call
     count reduction in heavily polymorphic mapping configurations.

   * `[orm]' ¶ mapper _get_col_to_prop private method used
     by the versioning example is deprecated; now use
     mapper.get_property_by_column() which will remain the public method
     for this.

   * `[orm]' ¶ the versioning example works correctly now
     if versioning on a col that was formerly NULL.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1891

   (2) http://www.sqlalchemy.org/trac/ticket/1896

   (3) http://www.sqlalchemy.org/trac/ticket/1896

   (4) http://www.sqlalchemy.org/trac/ticket/1877

   (5) http://www.sqlalchemy.org/trac/ticket/1856

   (6) http://www.sqlalchemy.org/trac/ticket/1857

   (7) http://www.sqlalchemy.org/trac/ticket/1863

   (8) http://www.sqlalchemy.org/trac/ticket/1864

   (9) http://www.sqlalchemy.org/trac/ticket/1852

   (10) http://www.sqlalchemy.org/trac/ticket/1881

8.3.9.51 engine
...............

   * `[engine]' ¶. Calling fetchone() or similar on a result
     that has already been exhausted, has been closed, or is not a
     result-returning result now raises ResourceClosedError, a subclass
     of InvalidRequestError, in all cases, regardless of backend.
     Previously, some DBAPIs would raise ProgrammingError (i.e.
     pysqlite), others would return None leading to downstream breakages
     (i.e.  MySQL-python).

   * `[engine]' ¶. Fixed bug in Connection whereby if a
     “disconnect” event occurred in the “initialize” phase of the first
     connection pool connect, an AttributeError would be raised when the
     Connection would attempt to invalidate the DBAPI connection.

     References: #1894(1)

   * `[engine]' ¶. Connection, ResultProxy, as well as
     Session use ResourceClosedError for all “this
     connection/transaction/result is closed” types of errors.

   * `[engine]' ¶. Connection.invalidate() can be called
     more than once and subsequent calls do nothing.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1894

8.3.9.52 sql
............

   * `[sql]' ¶. Calling execute() on an alias() construct is
     pending deprecation for 0.7, as it is not itself an “executable”
     construct.  It currently “proxies” its inner element and is
     conditionally “executable” but this is not the kind of ambiguity we
     like these days.

   * `[sql]' ¶. The execute() and scalar() methods of
     ClauseElement are now moved appropriately to the Executable
     subclass.  ClauseElement.execute()/ scalar() are still present and
     are pending deprecation in 0.7, but note these would always raise
     an error anyway if you were not an Executable (unless you were an
     alias(), see previous note).

   * `[sql]' ¶. Added basic math expression coercion for
     Numeric->Integer, so that resulting type is Numeric regardless of
     the direction of the expression.

   * `[sql]' ¶. Changed the scheme used to generate
     truncated “auto” index names when using the “index=True” flag on
     Column.  The truncation only takes place with the auto-generated
     name, not one that is user-defined (an error would be raised
     instead), and the truncation scheme itself is now based on a
     fragment of an md5 hash of the identifier name, so that multiple
     indexes on columns with similar names still have unique names.

     References: #1855(1)

   * `[sql]' ¶. The generated index name also is based on a
     “max index name length” attribute which is separate from the “max
     identifier length” - this to appease MySQL who has a max length of
     64 for index names, separate from their overall max length of 255.

     References: #1412(2)

   * `[sql]' ¶ the text() construct, if placed in a column
     oriented situation, will at least return NULLTYPE for its type
     instead of None, allowing it to be used a little more freely for
     ad-hoc column expressions than before.  literal_column() is still
     the better choice, however.

   * `[sql]' ¶. Added full description of parent
     table/column, target table/column in error message raised when
     ForeignKey can’t resolve target.

   * `[sql]' ¶. Fixed bug whereby replacing composite
     foreign key columns in a reflected table would cause an attempt to
     remove the reflected constraint from the table a second time,
     raising a KeyError.

     References: #1865(3)

   * `[sql]' ¶ the _Label construct, i.e.  the one that is
     produced whenever you say somecol.label(), now counts itself in its
     “proxy_set” unioned with that of its contained column’s proxy set,
     instead of directly returning that of the contained column.  This
     allows column correspondence operations which depend on the
     identity of the _Labels themselves to return the correct result

   * `[sql]' ¶ fixes ORM bug.

     References: #1852(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1855

   (2) http://www.sqlalchemy.org/trac/ticket/1412

   (3) http://www.sqlalchemy.org/trac/ticket/1865

   (4) http://www.sqlalchemy.org/trac/ticket/1852

8.3.9.53 postgresql
...................

   * `[postgresql]' ¶. Fixed the psycopg2 dialect to use its
     set_isolation_level() method instead of relying upon the base “SET
     SESSION ISOLATION” command, as psycopg2 resets the isolation level
     on each new transaction otherwise.

8.3.9.54 mssql
..............

   * `[mssql]' ¶. Fixed “default schema” query to work with
     pymssql backend.

8.3.9.55 oracle
...............

   * `[oracle]' ¶. Added ROWID type to the Oracle dialect,
     for those cases where an explicit CAST might be needed.

     References: #1879(1)

   * `[oracle]' ¶. Oracle reflection of indexes has been
     tuned so that indexes which include some or all primary key
     columns, but not the same set of columns as that of the primary
     key, are reflected.  Indexes which contain the identical columns as
     that of the primary key are skipped within reflection, as the index
     in that case is assumed to be the auto-generated primary key index.
     Previously, any index with PK columns present would be skipped.
     Thanks to Kent Bower for the patch.

     References: #1867(2)

   * `[oracle]' ¶. Oracle now reflects the names of primary
     key constraints - also thanks to Kent Bower.

     References: #1868(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1879

   (2) http://www.sqlalchemy.org/trac/ticket/1867

   (3) http://www.sqlalchemy.org/trac/ticket/1868

8.3.9.56 firebird
.................

   * `[firebird]' ¶. Fixed bug whereby a column default
     would fail to reflect if the “default” keyword were lower case.

8.3.9.57 misc
.............

   * `[declarative]' ¶ if @classproperty is used with a
     regular class-bound mapper property attribute, it will be called to
     get the actual attribute value during initialization.  Currently,
     there’s no advantage to using @classproperty on a column or
     relationship attribute of a declarative class that isn’t a mixin -
     evaluation is at the same time as if @classproperty weren’t used.
     But here we at least allow it to function as expected.

   * `[declarative]' ¶. Fixed bug where “Can’t add
     additional column” message would display the wrong name.

   * `[informix]' ¶. Applied patches from to get basic
     Informix functionality up again.  We rely upon end-user testing to
     ensure that Informix is working to some degree.

     References: #1904(1)

   * `[documentation]' ¶. The docs have been reorganized
     such that the “API Reference” section is gone - all the docstrings
     from there which were public API are moved into the context of the
     main doc section that talks about it.  Main docs divided into
     “SQLAlchemy Core” and “SQLAlchemy ORM” sections,
     mapper/relationship docs have been broken out.  Lots of sections
     rewritten and/or reorganized.

   * `[examples]' ¶. The beaker_caching example has been
     reorganized such that the Session, cache manager, declarative_base
     are part of environment, and custom cache code is portable and now
     within “caching_query.py”.  This allows the example to be easier to
     “drop in” to existing projects.

   * `[examples]' ¶ the history_meta versioning recipe sets
     “unique=False” when copying columns, so that the versioning table
     handles multiple rows with repeating values.

     References: #1887(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1904

   (2) http://www.sqlalchemy.org/trac/ticket/1887

8.3.9.58 0.6.3
..............

Released: Thu Jul 15 2010

8.3.9.59 orm
............

   * `[orm]' ¶. Removed errant many-to-many load in
     unitofwork which triggered unnecessarily on expired/unloaded
     collections.  This load now takes place only if passive_updates is
     False and the parent primary key has changed, or if passive_deletes
     is False and a delete of the parent has occurred.

     References: #1845(1)

   * `[orm]' ¶. Column-entities (i.e.  query(Foo.id)) copy
     their state more fully when queries are derived from themselves + a
     selectable (i.e.  from_self(), union(), etc.), so that join() and
     such have the correct state to work from.

     References: #1853(2)

   * `[orm]' ¶. Fixed bug where Query.join() would fail if
     querying a non-ORM column then joining without an on clause when a
     FROM clause is already present, now raises a checked exception the
     same way it does when the clause is not present.

     References: #1853(3)

   * `[orm]' ¶. Improved the check for an “unmapped class”,
     including the case where the superclass is mapped but the subclass
     is not.  Any attempts to access cls._sa_class_manager.mapper now
     raise UnmappedClassError().

     References: #1142(4)

   * `[orm]' ¶. Added “column_descriptions” accessor to
     Query, returns a list of dictionaries containing naming/typing
     information about the entities the Query will return.  Can be
     helpful for building GUIs on top of ORM queries.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1845

   (2) http://www.sqlalchemy.org/trac/ticket/1853

   (3) http://www.sqlalchemy.org/trac/ticket/1853

   (4) http://www.sqlalchemy.org/trac/ticket/1142

8.3.9.60 mysql
..............

   * `[mysql]' ¶. The _extract_error_code() method now works
     correctly with each MySQL dialect ( MySQL-python, OurSQL,
     MySQL-Connector-Python, PyODBC). Previously, the reconnect logic
     would fail for OperationalError conditions, however since MySQLdb
     and OurSQL have their own reconnect feature, there was no symptom
     for these drivers here unless one watched the logs.

     References: #1848(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1848

8.3.9.61 oracle
...............

   * `[oracle]' ¶. More tweaks to cx_oracle Decimal
     handling.  “Ambiguous” numerics with no decimal place are coerced
     to int at the connection handler level.  The advantage here is that
     ints come back as ints without SQLA type objects being involved and
     without needless conversion to Decimal first.

     Unfortunately, some exotic subquery cases can even see different
     types between individual result rows, so the Numeric handler, when
     instructed to return Decimal, can’t take full advantage of “native
     decimal” mode and must run isinstance() on every value to check if
     its Decimal already.  Reopen of

     References: #1840(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1840

8.3.9.62 0.6.2
..............

Released: Tue Jul 06 2010

8.3.9.63 orm
............

   * `[orm]' ¶. Query.join() will check for a call of the
     form query.join(target, clause_expression), i.e.  missing the
     tuple, and raise an informative error message that this is the
     wrong calling form.

   * `[orm]' ¶. Fixed bug regarding flushes on
     self-referential bi-directional many-to-many relationships, where
     two objects made to mutually reference each other in one flush
     would fail to insert a row for both sides.  Regression from 0.5.

     References: #1824(1)

   * `[orm]' ¶ the post_update feature of relationship()
     has been reworked architecturally to integrate more closely with
     the new 0.6 unit of work.  The motivation for the change is so that
     multiple “post update” calls, each affecting different foreign key
     columns of the same row, are executed in a single UPDATE statement,
     rather than one UPDATE statement per column per row.  Multiple row
     updates are also batched into executemany()s as possible, while
     maintaining consistent row ordering.

   * `[orm]' ¶. Query.statement, Query.subquery(), etc.  now
     transfer the values of bind parameters, i.e.  those specified by
     query.params(), into the resulting SQL expression.  Previously the
     values would not be transferred and bind parameters would come out
     as None.

   * `[orm]' ¶. Subquery-eager-loading now works with Query
     objects which include params(), as well as get() Queries.

   * `[orm]' ¶. Can now call make_transient() on an instance
     that is referenced by parent objects via many-to-one, without the
     parent’s foreign key value getting temporarily set to None - this
     was a function of the “detect primary key switch” flush handler.
     It now ignores objects that are no longer in the “persistent”
     state, and the parent’s foreign key identifier is left unaffected.

   * `[orm]' ¶ query.order_by() now accepts False, which
     cancels any existing order_by() state on the Query, allowing
     subsequent generative methods to be called which do not support
     ORDER BY. This is not the same as the already existing feature of
     passing None, which suppresses any existing order_by() settings,
     including those configured on the mapper.  False will make it as
     though order_by() was never called, while None is an active
     setting.

   * `[orm]' ¶. An instance which is moved to “transient”,
     has an incomplete or missing set of primary key attributes, and
     contains expired attributes, will raise an InvalidRequestError if
     an expired attribute is accessed, instead of getting a recursion
     overflow.

   * `[orm]' ¶. The make_transient() function is now in the
     generated documentation.

   * `[orm]' ¶ make_transient() removes all “loader”
     callables from the state being made transient, removing any
     “expired” state - all unloaded attributes reset back to undefined,
     None/empty on access.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1824

8.3.9.64 sql
............

   * `[sql]' ¶. The warning emitted by the Unicode and
     String types with convert_unicode=True no longer embeds the actual
     value passed.  This so that the Python warning registry does not
     continue to grow in size, the warning is emitted once as per the
     warning filter settings, and large string values don’t pollute the
     output.

     References: #1822(1)

   * `[sql]' ¶. Fixed bug that would prevent overridden
     clause compilation from working for “annotated” expression
     elements, which are often generated by the ORM.

   * `[sql]' ¶. The argument to “ESCAPE” of a LIKE operator
     or similar is passed through render_literal_value(), which may
     implement escaping of backslashes.

     References: #1400(2)

   * `[sql]' ¶. Fixed bug in Enum type which blew away
     native_enum flag when used with TypeDecorators or other adaption
     scenarios.

   * `[sql]' ¶. Inspector hits bind.connect() when invoked
     to ensure initialize has been called.  the internal name “.conn” is
     changed to “.bind”, since that’s what it is.

   * `[sql]' ¶. Modified the internals of “column
     annotation” such that a custom Column subclass can safely override
     _constructor to return Column, for the purposes of making
     “configurational” column classes that aren’t involved in proxying,
     etc.

   * `[sql]' ¶. Column.copy() takes along the “unique”
     attribute among others, fixes regarding declarative mixins

     References: #1829(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1822

   (2) http://www.sqlalchemy.org/trac/ticket/1400

   (3) http://www.sqlalchemy.org/trac/ticket/1829

8.3.9.65 postgresql
...................

   * `[postgresql]' ¶ render_literal_value() is overridden
     which escapes backslashes, currently applies to the ESCAPE clause
     of LIKE and similar expressions.  Ultimately this will have to
     detect the value of “standard_conforming_strings” for full
     behavior.

     References: #1400(1)

   * `[postgresql]' ¶. Won’t generate “CREATE TYPE” / “DROP
     TYPE” if using types.Enum on a PG version prior to 8.3 - the
     supports_native_enum flag is fully honored.

     References: #1836(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1400

   (2) http://www.sqlalchemy.org/trac/ticket/1836

8.3.9.66 mysql
..............

   * `[mysql]' ¶. MySQL dialect doesn’t emit CAST() for
     MySQL version detected < 4.0.2.  This allows the unicode check on
     connect to proceed.

     References: #1826(1)

   * `[mysql]' ¶. MySQL dialect now detects
     NO_BACKSLASH_ESCAPES sql mode, in addition to ANSI_QUOTES.

   * `[mysql]' ¶ render_literal_value() is overridden which
     escapes backslashes, currently applies to the ESCAPE clause of LIKE
     and similar expressions.  This behavior is derived from detecting
     the value of NO_BACKSLASH_ESCAPES.

     References: #1400(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1826

   (2) http://www.sqlalchemy.org/trac/ticket/1400

8.3.9.67 mssql
..............

   * `[mssql]' ¶. If server_version_info is outside the
     usual range of (8, ), (9, ), (10, ), a warning is emitted which
     suggests checking that the FreeTDS version configuration is using
     7.0 or 8.0, not 4.2.

     References: #1825(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1825

8.3.9.68 oracle
...............

   * `[oracle]' ¶. Fixed ora-8 compatibility flags such that
     they don’t cache a stale value from before the first database
     connection actually occurs.

     References: #1819(1)

   * `[oracle]' ¶. Oracle’s “native decimal” metadata begins
     to return ambiguous typing information about numerics when columns
     are embedded in subqueries as well as when ROWNUM is consulted with
     subqueries, as we do for limit/offset.  We’ve added these ambiguous
     conditions to the cx_oracle “convert to Decimal()” handler, so that
     we receive numerics as Decimal in more cases instead of as floats.
     These are then converted, if requested, into Integer or Float, or
     otherwise kept as the lossless Decimal.

     References: #1840(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1819

   (2) http://www.sqlalchemy.org/trac/ticket/1840

8.3.9.69 firebird
.................

   * `[firebird]' ¶. Fixed incorrect signature in
     do_execute(), error introduced in 0.6.1.

     References: #1823(1)

   * `[firebird]' ¶. Firebird dialect adds CHAR, VARCHAR
     types which accept a “charset” flag, to support Firebird “CHARACTER
     SET” clause.

     References: #1813(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1823

   (2) http://www.sqlalchemy.org/trac/ticket/1813

8.3.9.70 misc
.............

   * `[declarative]' ¶. Added support for @classproperty to
     provide any kind of schema/mapping construct from a declarative
     mixin, including columns with foreign keys, relationships,
     column_property, deferred.  This solves all such issues on
     declarative mixins.  An error is raised if any MapperProperty
     subclass is specified on a mixin without using @classproperty.

     References: #1751(1), #1796(2), #1805(3)

   * `[declarative]' ¶ a mixin class can now define a
     column that matches one which is present on a __table__ defined on
     a subclass.  It cannot, however, define one that is not present in
     the __table__, and the error message here now works.

     References: #1821(4)

   * `[compiler] [extension]' ¶. The ‘default’ compiler is
     automatically copied over when overriding the compilation of a
     built in clause construct, so no KeyError is raised if the
     user-defined compiler is specific to certain backends and
     compilation for a different backend is invoked.

     References: #1838(5)

   * `[documentation]' ¶. Added documentation for the
     Inspector.

     References: #1820(6)

   * `[documentation]' ¶. Fixed @memoized_property and
     @memoized_instancemethod decorators so that Sphinx documentation
     picks up these attributes and methods, such as
     ResultProxy.inserted_primary_key.

     References: #1830(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1751

   (2) http://www.sqlalchemy.org/trac/ticket/1796

   (3) http://www.sqlalchemy.org/trac/ticket/1805

   (4) http://www.sqlalchemy.org/trac/ticket/1821

   (5) http://www.sqlalchemy.org/trac/ticket/1838

   (6) http://www.sqlalchemy.org/trac/ticket/1820

   (7) http://www.sqlalchemy.org/trac/ticket/1830

8.3.9.71 0.6.1
..............

Released: Mon May 31 2010

8.3.9.72 orm
............

   * `[orm]' ¶. Fixed regression introduced in 0.6.0
     involving improper history accounting on mutable attributes.

     References: #1782(1)

   * `[orm]' ¶. Fixed regression introduced in 0.6.0 unit of
     work refactor that broke updates for bi-directional relationship()
     with post_update=True.

     References: #1807(2)

   * `[orm]' ¶ session.merge() will not expire attributes
     on the returned instance if that instance is “pending”.

     References: #1789(3)

   * `[orm]' ¶ fixed __setstate__ method of
     CollectionAdapter to not fail during deserialize where parent
     InstanceState not yet unserialized.

     References: #1802(4)

   * `[orm]' ¶. Added internal warning in case an instance
     without a full PK happened to be expired and then was asked to
     refresh.

     References: #1797(5)

   * `[orm]' ¶. Added more aggressive caching to the
     mapper’s usage of UPDATE, INSERT, and DELETE expressions.  Assuming
     the statement has no per-object SQL expressions attached, the
     expression objects are cached by the mapper after the first create,
     and their compiled form is stored persistently in a cache
     dictionary for the duration of the related Engine.  The cache is an
     LRUCache for the rare case that a mapper receives an extremely high
     number of different column patterns as UPDATEs.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1782

   (2) http://www.sqlalchemy.org/trac/ticket/1807

   (3) http://www.sqlalchemy.org/trac/ticket/1789

   (4) http://www.sqlalchemy.org/trac/ticket/1802

   (5) http://www.sqlalchemy.org/trac/ticket/1797

8.3.9.73 sql
............

   * `[sql]' ¶ expr.in_() now accepts a text() construct as
     the argument.  Grouping parenthesis are added automatically, i.e.
     usage is like ‘col.in_(text(“select id from table”))’.

     References: #1793(1)

   * `[sql]' ¶. Columns of _Binary type (i.e.  LargeBinary,
     BLOB, etc.)  will coerce a “basestring” on the right side into a
     _Binary as well so that required DBAPI processing takes place.

   * `[sql]' ¶. Added table.add_is_dependent_on(othertable),
     allows manual placement of dependency rules between two Table
     objects for use within create_all(), drop_all(), sorted_tables.

     References: #1801(2)

   * `[sql]' ¶. Fixed bug that prevented implicit RETURNING
     from functioning properly with composite primary key that contained
     zeroes.

     References: #1778(3)

   * `[sql]' ¶. Fixed errant space character when generating
     ADD CONSTRAINT for a named UNIQUE constraint.

   * `[sql]' ¶. Fixed “table” argument on constructor of
     ForeignKeyConstraint

     References: #1571(4)

   * `[sql]' ¶. Fixed bug in connection pool cursor wrapper
     whereby if a cursor threw an exception on close(), the logging of
     the message would fail.

     References: #1786(5)

   * `[sql]' ¶ the _make_proxy() method of ColumnClause and
     Column now use self.__class__ to determine the class of object to
     be returned instead of hardcoding to ColumnClause/Column, making it
     slightly easier to produce specific subclasses of these which work
     in alias/subquery situations.

   * `[sql]' ¶ func.XXX() doesn’t inadvertently resolve to
     non-Function classes (e.g.  fixes func.text()).

     References: #1798(6)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1793

   (2) http://www.sqlalchemy.org/trac/ticket/1801

   (3) http://www.sqlalchemy.org/trac/ticket/1778

   (4) http://www.sqlalchemy.org/trac/ticket/1571

   (5) http://www.sqlalchemy.org/trac/ticket/1786

   (6) http://www.sqlalchemy.org/trac/ticket/1798

8.3.9.74 mysql
..............

   * `[mysql]' ¶ func.sysdate() emits “SYSDATE()”, i.e.
     with the ending parenthesis, on MySQL.

     References: #1794(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1794

8.3.9.75 sqlite
...............

   * `[sqlite]' ¶. Fixed concatenation of constraints when
     “PRIMARY KEY” constraint gets moved to column level due to SQLite
     AUTOINCREMENT keyword being rendered.

     References: #1812(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1812

8.3.9.76 oracle
...............

   * `[oracle]' ¶. Added a check for cx_oracle versions
     lower than version 5, in which case the incompatible “output type
     handler” won’t be used.  This will impact decimal accuracy and some
     unicode handling issues.

     References: #1775(1)

   * `[oracle]' ¶. Fixed use_ansi=False mode, which was
     producing broken WHERE clauses in pretty much all cases.

     References: #1790(2)

   * `[oracle]' ¶. Re-established support for Oracle 8 with
     cx_oracle, including that use_ansi is set to False automatically,
     NVARCHAR2 and NCLOB are not rendered for Unicode, “native unicode”
     check doesn’t fail, cx_oracle “native unicode” mode is disabled,
     VARCHAR() is emitted with bytes count instead of char count.

     References: #1808(3)

   * `[oracle]' ¶ oracle_xe 5 doesn’t accept a Python
     unicode object in its connect string in normal Python 2.x mode - so
     we coerce to str() directly.  non-ascii characters aren’t supported
     in connect strings here since we don’t know what encoding we could
     use.

     References: #1670(4)

   * `[oracle]' ¶. FOR UPDATE is emitted in the
     syntactically correct position when limit/offset is used, i.e.  the
     ROWNUM subquery.  However, Oracle can’t really handle FOR UPDATE
     with ORDER BY or with subqueries, so its still not very usable, but
     at least SQLA gets the SQL past the Oracle parser.

     References: #1815(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1775

   (2) http://www.sqlalchemy.org/trac/ticket/1790

   (3) http://www.sqlalchemy.org/trac/ticket/1808

   (4) http://www.sqlalchemy.org/trac/ticket/1670

   (5) http://www.sqlalchemy.org/trac/ticket/1815

8.3.9.77 firebird
.................

   * `[firebird]' ¶. Added a label to the query used within
     has_table() and has_sequence() to work with older versions of
     Firebird that don’t provide labels for result columns.

     References: #1521(1)

   * `[firebird]' ¶. Added integer coercion to the
     “type_conv” attribute when passed via query string, so that it is
     properly interpreted by Kinterbasdb.

     References: #1779(2)

   * `[firebird]' ¶. Added ‘connection shutdown’ to the list
     of exception strings which indicate a dropped connection.

     References: #1646(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1521

   (2) http://www.sqlalchemy.org/trac/ticket/1779

   (3) http://www.sqlalchemy.org/trac/ticket/1646

8.3.9.78 misc
.............

   * `[engines]' ¶. Fixed building the C extensions on
     Python 2.4.

     References: #1781(1)

   * `[engines]' ¶. Pool classes will reuse the same
     “pool_logging_name” setting after a dispose() occurs.

   * `[engines]' ¶. Engine gains an “execution_options”
     argument and update_execution_options() method, which will apply to
     all connections generated by this engine.

   * `[sqlsoup]' ¶ the SqlSoup constructor accepts a ‘base’
     argument which specifies the base class to use for mapped classes,
     the default being ‘object’.

     References: #1783(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1781

   (2) http://www.sqlalchemy.org/trac/ticket/1783

8.3.9.79 0.6.0
..............

Released: Sun Apr 18 2010

8.3.9.80 orm
............

   * `[orm]' ¶. Unit of work internals have been rewritten.
     Units of work with large numbers of objects interdependent objects
     can now be flushed without recursion overflows as there is no
     longer reliance upon recursive calls.  The number of internal
     structures now stays constant for a particular session state,
     regardless of how many relationships are present on mappings.  The
     flow of events now corresponds to a linear list of steps, generated
     by the mappers and relationships based on actual work to be done,
     filtered through a single topological sort for correct ordering.
     Flush actions are assembled using far fewer steps and less memory.

     References: #1081(1), #1742(2)

   * `[orm]' ¶. Along with the UOW rewrite, this also
     removes an issue introduced in 0.6beta3 regarding topological cycle
     detection for units of work with long dependency cycles.  We now
     use an algorithm written by Guido (thanks Guido!).

   * `[orm]' ¶ one-to-many relationships now maintain a
     list of positive parent-child associations within the flush,
     preventing previous parents marked as deleted from cascading a
     delete or NULL foreign key set on those child objects, despite the
     end-user not removing the child from the old association.

     References: #1764(3)

   * `[orm]' ¶. A collection lazy load will switch off
     default eagerloading on the reverse many-to-one side, since that
     loading is by definition unnecessary.

     References: #1495(4)

   * `[orm]' ¶. Session.refresh() now does an equivalent
     expire() on the given instance first, so that the “refresh-expire”
     cascade is propagated.  Previously, refresh() was not affected in
     any way by the presence of “refresh-expire” cascade.  This is a
     change in behavior versus that of 0.6beta2, where the “lockmode”
     flag passed to refresh() would cause a version check to occur.
     Since the instance is first expired, refresh() always upgrades the
     object to the most recent version.

   * `[orm]' ¶. The ‘refresh-expire’ cascade, when reaching
     a pending object, will expunge the object if the cascade also
     includes “delete-orphan”, or will simply detach it otherwise.

     References: #1754(5)

   * `[orm]' ¶ id(obj) is no longer used internally within
     topological.py, as the sorting functions now require hashable
     objects only.

     References: #1756(6)

   * `[orm]' ¶. The ORM will set the docstring of all
     generated descriptors to None by default.  This can be overridden
     using ‘doc’ (or if using Sphinx, attribute docstrings work too).

   * `[orm]' ¶. Added kw argument ‘doc’ to all mapper
     property callables as well as Column().  Will assemble the string
     ‘doc’ as the ‘__doc__’ attribute on the descriptor.

   * `[orm]' ¶. Usage of version_id_col on a backend that
     supports cursor.rowcount for execute() but not executemany() now
     works when a delete is issued (already worked for saves, since
     those don’t use executemany()).  For a backend that doesn’t support
     cursor.rowcount at all, a warning is emitted the same as with
     saves.

     References: #1761(7)

   * `[orm]' ¶. The ORM now short-term caches the “compiled”
     form of insert() and update() constructs when flushing lists of
     objects of all the same class, thereby avoiding redundant
     compilation per individual INSERT/UPDATE within an individual
     flush() call.

   * `[orm]' ¶ internal getattr(), setattr(),
     getcommitted() methods on ColumnProperty, CompositeProperty,
     RelationshipProperty have been underscored (i.e.  are private),
     signature has changed.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1081

   (2) http://www.sqlalchemy.org/trac/ticket/1742

   (3) http://www.sqlalchemy.org/trac/ticket/1764

   (4) http://www.sqlalchemy.org/trac/ticket/1495

   (5) http://www.sqlalchemy.org/trac/ticket/1754

   (6) http://www.sqlalchemy.org/trac/ticket/1756

   (7) http://www.sqlalchemy.org/trac/ticket/1761

8.3.9.81 sql
............

   * `[sql]' ¶. Restored some bind-labeling logic from 0.5
     which ensures that tables with column names that overlap another
     column of the form “<tablename>_<columnname>” won’t produce errors
     if column._label is used as a bind name during an UPDATE. Test
     coverage which wasn’t present in 0.5 has been added.

     References: #1755(1)

   * `[sql]' ¶ somejoin.select(fold_equivalents=True) is no
     longer deprecated, and will eventually be rolled into a more
     comprehensive version of the feature for.

     References: #1729(2)

   * `[sql]' ¶ the Numeric type raises an `enormous'
     warning when expected to convert floats to Decimal from a DBAPI
     that returns floats.  This includes SQLite, Sybase, MS-SQL.

     References: #1759(3)

   * `[sql]' ¶. Fixed an error in expression typing which
     caused an endless loop for expressions with two NULL types.

   * `[sql]' ¶. Fixed bug in execution_options() feature
     whereby the existing Transaction and other state information from
     the parent connection would not be propagated to the
     sub-connection.

   * `[sql]' ¶. Added new ‘compiled_cache’ execution option.
     A dictionary where Compiled objects will be cached when the
     Connection compiles a clause expression into a dialect- and
     parameter- specific Compiled object.  It is the user’s
     responsibility to manage the size of this dictionary, which will
     have keys corresponding to the dialect, clause element, the column
     names within the VALUES or SET clause of an INSERT or UPDATE, as
     well as the “batch” mode for an INSERT or UPDATE statement.

   * `[sql]' ¶. Added get_pk_constraint() to
     reflection.Inspector, similar to get_primary_keys() except returns
     a dict that includes the name of the constraint, for supported
     backends (PG so far).

     References: #1769(4)

   * `[sql]' ¶. Table.create() and Table.drop() no longer
     apply metadata- level create/drop events.

     References: #1771(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1755

   (2) http://www.sqlalchemy.org/trac/ticket/1729

   (3) http://www.sqlalchemy.org/trac/ticket/1759

   (4) http://www.sqlalchemy.org/trac/ticket/1769

   (5) http://www.sqlalchemy.org/trac/ticket/1771

8.3.9.82 postgresql
...................

   * `[postgresql]' ¶. PostgreSQL now reflects sequence
     names associated with SERIAL columns correctly, after the name of
     the sequence has been changed.  Thanks to Kumar McMillan for the
     patch.

     References: #1071(1)

   * `[postgresql]' ¶. Repaired missing import in
     psycopg2._PGNumeric type when unknown numeric is received.

   * `[postgresql]' ¶ psycopg2/pg8000 dialects now aware of
     REAL[], FLOAT[], DOUBLE_PRECISION[], NUMERIC[] return types without
     raising an exception.

   * `[postgresql]' ¶. PostgreSQL reflects the name of
     primary key constraints, if one exists.

     References: #1769(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1071

   (2) http://www.sqlalchemy.org/trac/ticket/1769

8.3.9.83 oracle
...............

   * `[oracle]' ¶. Now using cx_oracle output converters so
     that the DBAPI returns natively the kinds of values we prefer:

   * `[oracle]' ¶. NUMBER values with positive precision +
     scale convert to cx_oracle.STRING and then to Decimal.  This allows
     perfect precision for the Numeric type when using cx_oracle.

     References: #1759(1)

   * `[oracle]' ¶. STRING/FIXED_CHAR now convert to unicode
     natively.  SQLAlchemy’s String types then don’t need to apply any
     kind of conversions.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1759

8.3.9.84 firebird
.................

   * `[firebird]' ¶. The functionality of result.rowcount
     can be disabled on a per-engine basis by setting
     ‘enable_rowcount=False’ on create_engine().  Normally,
     cursor.rowcount is called after any UPDATE or DELETE statement
     unconditionally, because the cursor is then closed and Firebird
     requires an open cursor in order to get a rowcount.  This call is
     slightly expensive however so it can be disabled.  To re-enable on
     a per-execution basis, the ‘enable_rowcount=True’ execution option
     may be used.

8.3.9.85 misc
.............

   * `[engines]' ¶. The C extension now also works with
     DBAPIs which use custom sequences as row (and not only tuples).

     References: #1757(1)

   * `[ext]' ¶ the compiler extension now allows @compiles
     decorators on base classes that extend to child classes, @compiles
     decorators on child classes that aren’t broken by a @compiles
     decorator on the base class.

   * `[ext]' ¶. Declarative will raise an informative error
     message if a non-mapped class attribute is referenced in the
     string-based relationship() arguments.

   * `[ext]' ¶. Further reworked the “mixin” logic in
     declarative to additionally allow __mapper_args__ as a
     @classproperty on a mixin, such as to dynamically assign
     polymorphic_identity.

   * `[examples]' ¶. Updated attribute_shard.py example to
     use a more robust method of searching a Query for binary
     expressions which compare columns against literal values.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1757

8.3.9.86 0.6beta3
.................

Released: Sun Mar 28 2010

8.3.9.87 orm
............

   * `[orm]' ¶. Major feature: Added new “subquery” loading
     capability to relationship().  This is an eager loading option
     which generates a second SELECT for each collection represented in
     a query, across all parents at once.  The query re-issues the
     original end-user query wrapped in a subquery, applies joins out to
     the target collection, and loads all those collections fully in one
     result, similar to “joined” eager loading but using all inner joins
     and not re-fetching full parent rows repeatedly (as most DBAPIs
     seem to do, even if columns are skipped).  Subquery loading is
     available at mapper config level using “lazy=’subquery’” and at the
     query options level using “subqueryload(props..)”,
     “subqueryload_all(props…)”.

     References: #1675(1)

   * `[orm]' ¶. To accommodate the fact that there are now
     two kinds of eager loading available, the new names for eagerload()
     and eagerload_all() are joinedload() and joinedload_all().  The old
     names will remain as synonyms for the foreseeable future.

   * `[orm]' ¶. The “lazy” flag on the relationship()
     function now accepts a string argument for all kinds of loading:
     “select”, “joined”, “subquery”, “noload” and “dynamic”, where the
     default is now “select”.  The old values of True/ False/None still
     retain their usual meanings and will remain as synonyms for the
     foreseeable future.

   * `[orm]' ¶. Added with_hint() method to Query()
     construct.  This calls directly down to select().with_hint() and
     also accepts entities as well as tables and aliases.  See
     with_hint() in the SQL section below.

     References: #921(2)

   * `[orm]' ¶. Fixed bug in Query whereby calling
     q.join(prop).from_self(…).  join(prop) would fail to render the
     second join outside the subquery, when joining on the same
     criterion as was on the inside.

   * `[orm]' ¶. Fixed bug in Query whereby the usage of
     aliased() constructs would fail if the underlying table (but not
     the actual alias) were referenced inside the subquery generated by
     q.from_self() or q.select_from().

   * `[orm]' ¶. Fixed bug which affected all eagerload() and
     similar options such that “remote” eager loads, i.e.  eagerloads
     off of a lazy load such as query(A).options(eagerload(A.b, B.c))
     wouldn’t eagerload anything, but using eagerload(“b.c”) would work
     fine.

   * `[orm]' ¶. Query gains an add_columns(*columns) method
     which is a multi- version of add_column(col).  add_column(col) is
     future deprecated.

   * `[orm]' ¶. Query.join() will detect if the end result
     will be “FROM A JOIN A”, and will raise an error if so.

   * `[orm]' ¶. Query.join(Cls.propname,
     from_joinpoint=True) will check more carefully that “Cls” is
     compatible with the current joinpoint, and act the same way as
     Query.join(“propname”, from_joinpoint=True) in that regard.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1675

   (2) http://www.sqlalchemy.org/trac/ticket/921

8.3.9.88 sql
............

   * `[sql]' ¶. Added with_hint() method to select()
     construct.  Specify a table/alias, hint text, and optional dialect
     name, and “hints” will be rendered in the appropriate place in the
     statement.  Works for Oracle, Sybase, MySQL.

     References: #921(1)

   * `[sql]' ¶. Fixed bug introduced in 0.6beta2 where
     column labels would render inside of column expressions already
     assigned a label.

     References: #1747(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/921

   (2) http://www.sqlalchemy.org/trac/ticket/1747

8.3.9.89 postgresql
...................

   * `[postgresql]' ¶. The psycopg2 dialect will log NOTICE
     messages via the “sqlalchemy.dialects.postgresql” logger name.

     References: #877(1)

   * `[postgresql]' ¶ the TIME and TIMESTAMP types are now
     available from the postgresql dialect directly, which add the
     PG-specific argument ‘precision’ to both.  ‘precision’ and
     ‘timezone’ are correctly reflected for both TIME and TIMEZONE
     types.

     References: #997(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/877

   (2) http://www.sqlalchemy.org/trac/ticket/997

8.3.9.90 mysql
..............

   * `[mysql]' ¶. No longer guessing that TINYINT(1) should
     be BOOLEAN when reflecting - TINYINT(1) is returned.  Use Boolean/
     BOOLEAN in table definition to get boolean conversion behavior.

     References: #1752(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1752

8.3.9.91 oracle
...............

   * `[oracle]' ¶. The Oracle dialect will issue VARCHAR
     type definitions using character counts, i.e.  VARCHAR2(50 CHAR),
     so that the column is sized in terms of characters and not bytes.
     Column reflection of character types will also use
     ALL_TAB_COLUMNS.CHAR_LENGTH instead of ALL_TAB_COLUMNS.DATA_LENGTH.
     Both of these behaviors take effect when the server version is 9 or
     higher - for version 8, the old behaviors are used.

     References: #1744(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1744

8.3.9.92 misc
.............

   * `[declarative]' ¶. Using a mixin won’t break if the
     mixin implements an unpredictable __getattribute__(), i.e.  Zope
     interfaces.

     References: #1746(1)

   * `[declarative]' ¶. Using @classdecorator and similar on
     mixins to define __tablename__, __table_args__, etc.  now works if
     the method references attributes on the ultimate subclass.

     References: #1749(2)

   * `[declarative]' ¶ relationships and columns with
     foreign keys aren’t allowed on declarative mixins, sorry.

     References: #1751(3)

   * `[ext]' ¶. The sqlalchemy.orm.shard module now becomes
     an extension, sqlalchemy.ext.horizontal_shard.  The old import
     works with a deprecation warning.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1746

   (2) http://www.sqlalchemy.org/trac/ticket/1749

   (3) http://www.sqlalchemy.org/trac/ticket/1751

8.3.9.93 0.6beta2
.................

Released: Sat Mar 20 2010

8.3.9.94 orm
............

   * `[orm]' ¶. The official name for the relation()
     function is now relationship(), to eliminate confusion over the
     relational algebra term.  relation() however will remain available
     in equal capacity for the foreseeable future.

     References: #1740(1)

   * `[orm]' ¶. Added “version_id_generator” argument to
     Mapper, this is a callable that, given the current value of the
     “version_id_col”, returns the next version number.  Can be used for
     alternate versioning schemes such as uuid, timestamps.

     References: #1692(2)

   * `[orm]' ¶ added “lockmode” kw argument to
     Session.refresh(), will pass through the string value to Query the
     same as in with_lockmode(), will also do version check for a
     version_id_col-enabled mapping.

   * `[orm]' ¶. Fixed bug whereby calling
     query(A).join(A.bs).add_entity(B) in a joined inheritance scenario
     would double-add B as a target and produce an invalid query.

     References: #1188(3)

   * `[orm]' ¶. Fixed bug in session.rollback() which
     involved not removing formerly “pending” objects from the session
     before re-integrating “deleted” objects, typically occurred with
     natural primary keys.  If there was a primary key conflict between
     them, the attach of the deleted would fail internally.  The
     formerly “pending” objects are now expunged first.

     References: #1674(4)

   * `[orm]' ¶. Removed a lot of logging that nobody really
     cares about, logging that remains will respond to live changes in
     the log level.  No significant overhead is added.

     References: #1719(5)

   * `[orm]' ¶. Fixed bug in session.merge() which prevented
     dict-like collections from merging.

   * `[orm]' ¶ session.merge() works with relations that
     specifically don’t include “merge” in their cascade options - the
     target is ignored completely.

   * `[orm]' ¶ session.merge() will not expire existing
     scalar attributes on an existing target if the target has a value
     for that attribute, even if the incoming merged doesn’t have a
     value for the attribute.  This prevents unnecessary loads on
     existing items.  Will still mark the attr as expired if the
     destination doesn’t have the attr, though, which fulfills some
     contracts of deferred cols.

     References: #1681(6)

   * `[orm]' ¶. The “allow_null_pks” flag is now called
     “allow_partial_pks”, defaults to True, acts like it did in 0.5
     again.  Except, it also is implemented within merge() such that a
     SELECT won’t be issued for an incoming instance with partially NULL
     primary key if the flag is False.

     References: #1680(7)

   * `[orm]' ¶. Fixed bug in 0.6-reworked “many-to-one”
     optimizations such that a many-to-one that is against a non-primary
     key column on the remote table (i.e.  foreign key against a UNIQUE
     column) will pull the “old” value in from the database during a
     change, since if it’s in the session we will need it for proper
     history/backref accounting, and we can’t pull from the local
     identity map on a non-primary key column.

     References: #1737(8)

   * `[orm]' ¶ fixed internal error which would occur if
     calling has() or similar complex expression on a single-table
     inheritance relation().

     References: #1731(9)

   * `[orm]' ¶ query.one() no longer applies LIMIT to the
     query, this to ensure that it fully counts all object identities
     present in the result, even in the case where joins may conceal
     multiple identities for two or more rows.  As a bonus, one() can
     now also be called with a query that issued from_statement() to
     start with since it no longer modifies the query.

     References: #1688(10)

   * `[orm]' ¶ query.get() now returns None if queried for
     an identifier that is present in the identity map with a different
     class than the one requested, i.e.  when using polymorphic loading.

     References: #1727(11)

   * `[orm]' ¶. A major fix in query.join(), when the “on”
     clause is an attribute of an aliased() construct, but there is
     already an existing join made out to a compatible target, query
     properly joins to the right aliased() construct instead of sticking
     onto the right side of the existing join.

     References: #1706(12)

   * `[orm]' ¶. Slight improvement to the fix for to not
     issue needless updates of the primary key column during a so-called
     “row switch” operation, i.e.  add + delete of two objects with the
     same PK.

     References: #1362(13)

   * `[orm]' ¶. Now uses
     sqlalchemy.orm.exc.DetachedInstanceError when an attribute load or
     refresh action fails due to object being detached from any Session.
     UnboundExecutionError is specific to engines bound to sessions and
     statements.

   * `[orm]' ¶. Query called in the context of an expression
     will render disambiguating labels in all cases.  Note that this
     does not apply to the existing .statement and .subquery()
     accessor/method, which still honors the .with_labels() setting that
     defaults to False.

   * `[orm]' ¶. Query.union() retains disambiguating labels
     within the returned statement, thus avoiding various SQL
     composition errors which can result from column name conflicts.

     References: #1676(14)

   * `[orm]' ¶. Fixed bug in attribute history that
     inadvertently invoked __eq__ on mapped instances.

   * `[orm]' ¶. Some internal streamlining of object loading
     grants a small speedup for large results, estimates are around
     10-15%.  Gave the “state” internals a good solid cleanup with less
     complexity, datamembers, method calls, blank dictionary creates.

   * `[orm]' ¶. Documentation clarification for
     query.delete()

     References: #1689(15)

   * `[orm]' ¶. Fixed cascade bug in many-to-one relation()
     when attribute was set to None, introduced in r6711 (cascade
     deleted items into session during add()).

   * `[orm]' ¶. Calling query.order_by() or query.distinct()
     before calling query.select_from(), query.with_polymorphic(), or
     query.from_statement() raises an exception now instead of silently
     dropping those criterion.

     References: #1736(16)

   * `[orm]' ¶ query.scalar() now raises an exception if
     more than one row is returned.  All other behavior remains the
     same.

     References: #1735(17)

   * `[orm]' ¶. Fixed bug which caused “row switch” logic,
     that is an INSERT and DELETE replaced by an UPDATE, to fail when
     version_id_col was in use.

     References: #1692(18)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1740

   (2) http://www.sqlalchemy.org/trac/ticket/1692

   (3) http://www.sqlalchemy.org/trac/ticket/1188

   (4) http://www.sqlalchemy.org/trac/ticket/1674

   (5) http://www.sqlalchemy.org/trac/ticket/1719

   (6) http://www.sqlalchemy.org/trac/ticket/1681

   (7) http://www.sqlalchemy.org/trac/ticket/1680

   (8) http://www.sqlalchemy.org/trac/ticket/1737

   (9) http://www.sqlalchemy.org/trac/ticket/1731

   (10) http://www.sqlalchemy.org/trac/ticket/1688

   (11) http://www.sqlalchemy.org/trac/ticket/1727

   (12) http://www.sqlalchemy.org/trac/ticket/1706

   (13) http://www.sqlalchemy.org/trac/ticket/1362

   (14) http://www.sqlalchemy.org/trac/ticket/1676

   (15) http://www.sqlalchemy.org/trac/ticket/1689

   (16) http://www.sqlalchemy.org/trac/ticket/1736

   (17) http://www.sqlalchemy.org/trac/ticket/1735

   (18) http://www.sqlalchemy.org/trac/ticket/1692

8.3.9.95 sql
............

   * `[sql]' ¶ join() will now simulate a NATURAL JOIN by
     default.  Meaning, if the left side is a join, it will attempt to
     join the right side to the rightmost side of the left first, and
     not raise any exceptions about ambiguous join conditions if
     successful even if there are further join targets across the rest
     of the left.

     References: #1714(1)

   * `[sql]' ¶. The most common result processors conversion
     function were moved to the new “processors” module.  Dialect
     authors are encouraged to use those functions whenever they
     correspond to their needs instead of implementing custom ones.

   * `[sql]' ¶. SchemaType and subclasses Boolean, Enum are
     now serializable, including their ddl listener and other event
     callables.

     References: #1694(2), #1698(3)

   * `[sql]' ¶. Some platforms will now interpret certain
     literal values as non-bind parameters, rendered literally into the
     SQL statement.  This to support strict SQL-92 rules that are
     enforced by some platforms including MS-SQL and Sybase.  In this
     model, bind parameters aren’t allowed in the columns clause of a
     SELECT, nor are certain ambiguous expressions like “?=?”.  When
     this mode is enabled, the base compiler will render the binds as
     inline literals, but only across strings and numeric values.  Other
     types such as dates will raise an error, unless the dialect
     subclass defines a literal rendering function for those.  The bind
     parameter must have an embedded literal value already or an error
     is raised (i.e.  won’t work with straight bindparam(‘x’)).
     Dialects can also expand upon the areas where binds are not
     accepted, such as within argument lists of functions (which don’t
     work on MS-SQL when native SQL binding is used).

   * `[sql]' ¶. Added “unicode_errors” parameter to String,
     Unicode, etc.  Behaves like the ‘errors’ keyword argument to the
     standard library’s string.decode() functions.  This flag requires
     that ‘convert_unicode’ is set to ‘“force”’ - otherwise, SQLAlchemy
     is not guaranteed to handle the task of unicode conversion.  Note
     that this flag adds significant performance overhead to
     row-fetching operations for backends that already return unicode
     objects natively (which most DBAPIs do).  This flag should only be
     used as an absolute last resort for reading strings from a column
     with varied or corrupted encodings, which only applies to databases
     that accept invalid encodings in the first place (i.e.  MySQL.
     `not' PG, Sqlite, etc.)

   * `[sql]' ¶. Added math negation operator support, -x.

   * `[sql]' ¶. FunctionElement subclasses are now directly
     executable the same way any func.foo() construct is, with automatic
     SELECT being applied when passed to execute().

   * `[sql]' ¶. The “type” and “bind” keyword arguments of a
     func.foo() construct are now local to “func.” constructs and are
     not part of the FunctionElement base class, allowing a “type” to be
     handled in a custom constructor or class-level variable.

   * `[sql]' ¶. Restored the keys() method to ResultProxy.

   * `[sql]' ¶. The type/expression system now does a more
     complete job of determining the return type from an expression as
     well as the adaptation of the Python operator into a SQL operator,
     based on the full left/right/operator of the given expression.  In
     particular the date/time/interval system created for PostgreSQL
     EXTRACT in has now been generalized into the type system.  The
     previous behavior which often occurred of an expression “column +
     literal” forcing the type of “literal” to be the same as that of
     “column” will now usually not occur - the type of “literal” is
     first derived from the Python type of the literal, assuming
     standard native Python types + date types, before falling back to
     that of the known type on the other side of the expression.  If the
     “fallback” type is compatible (i.e.  CHAR from String), the literal
     side will use that.  TypeDecorator types override this by default
     to coerce the “literal” side unconditionally, which can be changed
     by implementing the coerce_compared_value() method.  Also part of.

     References: #1647(4), #1683(5)

   * `[sql]' ¶. Made sqlalchemy.sql.expressions.Executable
     part of public API, used for any expression construct that can be
     sent to execute().  FunctionElement now inherits Executable so that
     it gains execution_options(), which are also propagated to the
     select() that’s generated within execute().  Executable in turn
     subclasses _Generative which marks any ClauseElement that supports
     the @_generative decorator - these may also become “public” for the
     benefit of the compiler extension at some point.

   * `[sql]' ¶. A change to the solution for - an end-user
     defined bind parameter name that directly conflicts with a
     column-named bind generated directly from the SET or VALUES clause
     of an update/insert generates a compile error.  This reduces call
     counts and eliminates some cases where undesirable name conflicts
     could still occur.

     References: #1579(6)

   * `[sql]' ¶. Column() requires a type if it has no
     foreign keys (this is not new).  An error is now raised if a
     Column() has no type and no foreign keys.

     References: #1705(7)

   * `[sql]' ¶ the “scale” argument of the Numeric() type
     is honored when coercing a returned floating point value into a
     string on its way to Decimal - this allows accuracy to function on
     SQLite, MySQL.

     References: #1717(8)

   * `[sql]' ¶ the copy() method of Column now copies over
     uninitialized “on table attach” events.  Helps with the new
     declarative “mixin” capability.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1714

   (2) http://www.sqlalchemy.org/trac/ticket/1694

   (3) http://www.sqlalchemy.org/trac/ticket/1698

   (4) http://www.sqlalchemy.org/trac/ticket/1647

   (5) http://www.sqlalchemy.org/trac/ticket/1683

   (6) http://www.sqlalchemy.org/trac/ticket/1579

   (7) http://www.sqlalchemy.org/trac/ticket/1705

   (8) http://www.sqlalchemy.org/trac/ticket/1717

8.3.9.96 mysql
..............

   * `[mysql]' ¶. Fixed reflection bug whereby when COLLATE
     was present, nullable flag and server defaults would not be
     reflected.

     References: #1655(1)

   * `[mysql]' ¶. Fixed reflection of TINYINT(1) “boolean”
     columns defined with integer flags like UNSIGNED.

   * `[mysql]' ¶. Further fixes for the mysql-connector
     dialect.

     References: #1668(2)

   * `[mysql]' ¶. Composite PK table on InnoDB where the
     “autoincrement” column isn’t first will emit an explicit “KEY”
     phrase within CREATE TABLE thereby avoiding errors.

     References: #1496(3)

   * `[mysql]' ¶. Added reflection/create table support for
     a wide range of MySQL keywords.

     References: #1634(4)

   * `[mysql]' ¶. Fixed import error which could occur
     reflecting tables on a Windows host

     References: #1580(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1655

   (2) http://www.sqlalchemy.org/trac/ticket/1668

   (3) http://www.sqlalchemy.org/trac/ticket/1496

   (4) http://www.sqlalchemy.org/trac/ticket/1634

   (5) http://www.sqlalchemy.org/trac/ticket/1580

8.3.9.97 sqlite
...............

   * `[sqlite]' ¶. Added “native_datetime=True” flag to
     create_engine().  This will cause the DATE and TIMESTAMP types to
     skip all bind parameter and result row processing, under the
     assumption that PARSE_DECLTYPES has been enabled on the connection.
     Note that this is not entirely compatible with the
     “func.current_date()”, which will be returned as a string.

     References: #1685(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1685

8.3.9.98 mssql
..............

   * `[mssql]' ¶. Re-established support for the pymssql
     dialect.

   * `[mssql]' ¶. Various fixes for implicit returning,
     reflection, etc.  - the MS-SQL dialects aren’t quite complete in
     0.6 yet (but are close)

   * `[mssql]' ¶. Added basic support for mxODBC.

     References: #1710(1)

   * `[mssql]' ¶. Removed the text_as_varchar option.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1710

8.3.9.99 oracle
...............

   * `[oracle]' ¶. ”out” parameters require a type that is
     supported by cx_oracle.  An error will be raised if no cx_oracle
     type can be found.

   * `[oracle]' ¶. Oracle ‘DATE’ now does not perform any
     result processing, as the DATE type in Oracle stores full date+time
     objects, that’s what you’ll get.  Note that the generic types.Date
     type `will' still call value.date() on incoming values, however.
     When reflecting a table, the reflected type will be ‘DATE’.

   * `[oracle]' ¶. Added preliminary support for Oracle’s
     WITH_UNICODE mode.  At the very least this establishes initial
     support for cx_Oracle with Python 3.  When WITH_UNICODE mode is
     used in Python 2.xx, a large and scary warning is emitted asking
     that the user seriously consider the usage of this difficult mode
     of operation.

     References: #1670(1)

   * `[oracle]' ¶. The except_() method now renders as MINUS
     on Oracle, which is more or less equivalent on that platform.

     References: #1712(2)

   * `[oracle]' ¶. Added support for rendering and
     reflecting TIMESTAMP WITH TIME ZONE, i.e.
     TIMESTAMP(timezone=True).

     References: #651(3)

   * `[oracle]' ¶. Oracle INTERVAL type can now be
     reflected.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1670

   (2) http://www.sqlalchemy.org/trac/ticket/1712

   (3) http://www.sqlalchemy.org/trac/ticket/651

8.3.9.100 misc
..............

   * `[py3k]' ¶. Improved the installation/test setup
     regarding Python 3, now that Distribute runs on Py3k.
     distribute_setup.py is now included.  See README.py3k for Python 3
     installation/ testing instructions.

   * `[engines]' ¶. Added an optional C extension to speed
     up the sql layer by reimplementing RowProxy and the most common
     result processors.  The actual speedups will depend heavily on your
     DBAPI and the mix of datatypes used in your tables, and can vary
     from a 30% improvement to more than 200%.  It also provides a
     modest (~15-20%) indirect improvement to ORM speed for large
     queries.  Note that it is `not' built/installed by default.  See
     README for installation instructions.

   * `[engines]' ¶ the execution sequence pulls all
     rowcount/last inserted ID info from the cursor before commit() is
     called on the DBAPI connection in an “autocommit” scenario.  This
     helps mxodbc with rowcount and is probably a good idea overall.

   * `[engines]' ¶. Opened up logging a bit such that
     isEnabledFor() is called more often, so that changes to the log
     level for engine/pool will be reflected on next connect.  This adds
     a small amount of method call overhead.  It’s negligible and will
     make life a lot easier for all those situations when logging just
     happens to be configured after create_engine() is called.

     References: #1719(1)

   * `[engines]' ¶. The assert_unicode flag is deprecated.
     SQLAlchemy will raise a warning in all cases where it is asked to
     encode a non-unicode Python string, as well as when a Unicode or
     UnicodeType type is explicitly passed a bytestring.  The String
     type will do nothing for DBAPIs that already accept Python unicode
     objects.

   * `[engines]' ¶. Bind parameters are sent as a tuple
     instead of a list.  Some backend drivers will not accept bind
     parameters as a list.

   * `[engines]' ¶ threadlocal engine wasn’t properly
     closing the connection upon close() - fixed that.

   * `[engines]' ¶. Transaction object doesn’t rollback or
     commit if it isn’t “active”, allows more accurate nesting of
     begin/rollback/commit.

   * `[engines]' ¶. Python unicode objects as binds result
     in the Unicode type, not string, thus eliminating a certain class
     of unicode errors on drivers that don’t support unicode binds.

   * `[engines]' ¶. Added “logging_name” argument to
     create_engine(), Pool() constructor as well as “pool_logging_name”
     argument to create_engine() which filters down to that of Pool.
     Issues the given string name within the “name” field of logging
     messages instead of the default hex identifier string.

     References: #1555(2)

   * `[engines]' ¶. The visit_pool() method of Dialect is
     removed, and replaced with on_connect().  This method returns a
     callable which receives the raw DBAPI connection after each one is
     created.  The callable is assembled into a first_connect/connect
     pool listener by the connection strategy if non-None.  Provides a
     simpler interface for dialects.

   * `[engines]' ¶. StaticPool now initializes, disposes and
     recreates without opening a new connection - the connection is only
     opened when first requested.  dispose() also works on AssertionPool
     now.

     References: #1728(3)

   * `[metadata] [ticket: 1673]' ¶. Added the ability to
     strip schema information when using “tometadata” by passing
     “schema=None” as an argument.  If schema is not specified then the
     table’s schema is retained.

   * `[declarative]' ¶. DeclarativeMeta exclusively uses
     cls.__dict__ (not dict_) as the source of class information;
     _as_declarative exclusively uses the dict_ passed to it as the
     source of class information (which when using DeclarativeMeta is
     cls.__dict__).  This should in theory make it easier for custom
     metaclasses to modify the state passed into _as_declarative.

   * `[declarative]' ¶ declarative now accepts mixin
     classes directly, as a means to provide common functional and
     column-based elements on all subclasses, as well as a means to
     propagate a fixed set of __table_args__ or __mapper_args__ to
     subclasses.  For custom combinations of
     __table_args__/__mapper_args__ from an inherited mixin to local,
     descriptors can now be used.  New details are all up in the
     Declarative documentation.  Thanks to Chris Withers for putting up
     with my strife on this.

     References: #1707(4)

   * `[declarative]' ¶ the __mapper_args__ dict is copied
     when propagating to a subclass, and is taken straight off the class
     __dict__ to avoid any propagation from the parent.  mapper
     inheritance already propagates the things you want from the parent
     mapper.

     References: #1393(5)

   * `[declarative]' ¶. An exception is raised when a
     single-table subclass specifies a column that is already present on
     the base class.

     References: #1732(6)

   * `[sybase]' ¶. Implemented a preliminary working dialect
     for Sybase, with sub-implementations for Python-Sybase as well as
     Pyodbc.  Handles table creates/drops and basic round trip
     functionality.  Does not yet include reflection or comprehensive
     support of unicode/special expressions/etc.

   * `[examples]' ¶. Changed the beaker cache example a bit
     to have a separate RelationCache option for lazyload caching.  This
     object does a lookup among any number of potential attributes more
     efficiently by grouping several into a common structure.  Both
     FromCache and RelationCache are simpler individually.

   * `[documentation]' ¶. Major cleanup work in the docs to
     link class, function, and method names into the API docs.

     References: #1700(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1719

   (2) http://www.sqlalchemy.org/trac/ticket/1555

   (3) http://www.sqlalchemy.org/trac/ticket/1728

   (4) http://www.sqlalchemy.org/trac/ticket/1707

   (5) http://www.sqlalchemy.org/trac/ticket/1393

   (6) http://www.sqlalchemy.org/trac/ticket/1732

   (7) http://www.sqlalchemy.org/trac/ticket/1700

8.3.9.101 0.6beta1
..................

Released: Wed Feb 03 2010

8.3.9.102 orm
.............

   * `[orm]' ¶.

     Changes to query.update() and query.delete():

             - the ‘expire’ option on query.update() has been renamed to
               ‘fetch’, thus matching that of query.delete().  ‘expire’
               is deprecated and issues a warning.

             - query.update() and query.delete() both default to
               ‘evaluate’ for the synchronize strategy.

             - the ‘synchronize’ strategy for update() and delete()
               raises an error on failure.  There is no implicit
               fallback onto “fetch”.  Failure of evaluation is based on
               the structure of criteria, so success/failure is
               deterministic based on code structure.

   * `[orm]' ¶.

     Enhancements on many-to-one relations:

             - many-to-one relations now fire off a lazyload in fewer
               cases, including in most cases will not fetch the “old”
               value when a new one is replaced.

             - many-to-one relation to a joined-table subclass now uses
               get() for a simple load (known as the “use_get”
               condition), i.e.  Related->Sub(Base), without the need to
               redefine the primaryjoin condition in terms of the base
               table.

             - specifying a foreign key with a declarative column, i.e.
               ForeignKey(MyRelatedClass.id) doesn’t break the “use_get”
               condition from taking place

             - relation(), eagerload(), and eagerload_all() now feature
               an option called “innerjoin”.  Specify ‘True’ or ‘False’
               to control whether an eager join is constructed as an
               INNER or OUTER join.  Default is ‘False’ as always.  The
               mapper options will override whichever setting is
               specified on relation().  Should generally be set for
               many-to-one, not nullable foreign key relations to allow
               improved join performance.

             - the behavior of eagerloading such that the main query is
               wrapped in a subquery when LIMIT/OFFSET are present now
               makes an exception for the case when all eager loads are
               many-to-one joins.  In those cases, the eager joins are
               against the parent table directly along with the
               limit/offset without the extra overhead of a subquery,
               since a many-to-one join does not add rows to the result.

     References: #1186(1), #1492(2), #1544(3)

   * `[orm]' ¶. Enhancements / Changes on Session.merge():

   * `[orm]' ¶ the “dont_load=True” flag on Session.merge()
     is deprecated and is now “load=False”.

   * `[orm]' ¶. Session.merge() is performance optimized,
     using half the call counts for “load=False” mode compared to 0.5
     and significantly fewer SQL queries in the case of collections for
     “load=True” mode.

   * `[orm]' ¶ merge() will not issue a needless merge of
     attributes if the given instance is the same instance which is
     already present.

   * `[orm]' ¶ merge() now also merges the “options”
     associated with a given state, i.e.  those passed through
     query.options() which follow along with an instance, such as
     options to eagerly- or lazyily- load various attributes.  This is
     essential for the construction of highly integrated caching
     schemes.  This is a subtle behavioral change vs.  0.5.

   * `[orm]' ¶. A bug was fixed regarding the serialization
     of the “loader path” present on an instance’s state, which is also
     necessary when combining the usage of merge() with serialized state
     and associated options that should be preserved.

   * `[orm]' ¶. The all new merge() is showcased in a new
     comprehensive example of how to integrate Beaker with SQLAlchemy.
     See the notes in the “examples” note below.

   * `[orm]' ¶. Primary key values can now be changed on a
     joined-table inheritance object, and ON UPDATE CASCADE will be
     taken into account when the flush happens.  Set the new
     “passive_updates” flag to False on mapper() when using SQLite or
     MySQL/MyISAM.

     References: #1362(4)

   * `[orm]' ¶ flush() now detects when a primary key
     column was updated by an ON UPDATE CASCADE operation from another
     primary key, and can then locate the row for a subsequent UPDATE on
     the new PK value.  This occurs when a relation() is there to
     establish the relationship as well as passive_updates=True.

     References: #1671(5)

   * `[orm]' ¶ the “save-update” cascade will now cascade
     the pending `removed' values from a scalar or collection attribute
     into the new session during an add() operation.  This so that the
     flush() operation will also delete or modify rows of those
     disconnected items.

   * `[orm]' ¶. Using a “dynamic” loader with a “secondary”
     table now produces a query where the “secondary” table is `not'
     aliased.  This allows the secondary Table object to be used in the
     “order_by” attribute of the relation(), and also allows it to be
     used in filter criterion against the dynamic relation.

     References: #1531(6)

   * `[orm]' ¶ relation() with uselist=False will emit a
     warning when an eager or lazy load locates more than one valid
     value for the row.  This may be due to primaryjoin/secondaryjoin
     conditions which aren’t appropriate for an eager LEFT OUTER JOIN or
     for other conditions.

     References: #1643(7)

   * `[orm]' ¶ an explicit check occurs when a synonym() is
     used with map_column=True, when a ColumnProperty (deferred or
     otherwise) exists separately in the properties dictionary sent to
     mapper with the same keyname.  Instead of silently replacing the
     existing property (and possible options on that property), an error
     is raised.

     References: #1633(8)

   * `[orm]' ¶ a “dynamic” loader sets up its query
     criterion at construction time so that the actual query is returned
     from non-cloning accessors like “statement”.

   * `[orm]' ¶ the “named tuple” objects returned when
     iterating a Query() are now pickleable.

   * `[orm]' ¶ mapping to a select() construct now requires
     that you make an alias() out of it distinctly.  This to eliminate
     confusion over such issues as

     References: #1542(9)

   * `[orm]' ¶ query.join() has been reworked to provide
     more consistent behavior and more flexibility (includes)

     References: #1537(10)

   * `[orm]' ¶ query.select_from() accepts multiple clauses
     to produce multiple comma separated entries within the FROM clause.
     Useful when selecting from multiple-homed join() clauses.

   * `[orm]' ¶ query.select_from() also accepts mapped
     classes, aliased() constructs, and mappers as arguments.  In
     particular this helps when querying from multiple joined-table
     classes to ensure the full join gets rendered.

   * `[orm]' ¶ query.get() can be used with a mapping to an
     outer join where one or more of the primary key values are None.

     References: #1135(11)

   * `[orm]' ¶ query.from_self(), query.union(), others
     which do a “SELECT * from (SELECT…)” type of nesting will do a
     better job translating column expressions within the subquery to
     the columns clause of the outer query.  This is potentially
     backwards incompatible with 0.5, in that this may break queries
     with literal expressions that do not have labels applied (i.e.
     literal(‘foo’), etc.)

     References: #1568(12)

   * `[orm]' ¶ relation primaryjoin and secondaryjoin now
     check that they are column-expressions, not just clause elements.
     this prohibits things like FROM expressions being placed there
     directly.

     References: #1622(13)

   * `[orm]' ¶. ‘expression.null()’ is fully understood the
     same way None is when comparing an object/collection-referencing
     attribute within query.filter(), filter_by(), etc.

     References: #1415(14)

   * `[orm]' ¶ added “make_transient()” helper function
     which transforms a persistent/ detached instance into a transient
     one (i.e.  deletes the instance_key and removes from any session.)

     References: #1052(15)

   * `[orm]' ¶ the allow_null_pks flag on mapper() is
     deprecated, and the feature is turned “on” by default.  This means
     that a row which has a non-null value for any of its primary key
     columns will be considered an identity.  The need for this scenario
     typically only occurs when mapping to an outer join.

     References: #1339(16)

   * `[orm]' ¶ the mechanics of “backref” have been fully
     merged into the finer grained “back_populates” system, and take
     place entirely within the _generate_backref() method of
     RelationProperty.  This makes the initialization procedure of
     RelationProperty simpler and allows easier propagation of settings
     (such as from subclasses of RelationProperty) into the reverse
     reference.  The internal BackRef() is gone and backref() returns a
     plain tuple that is understood by RelationProperty.

   * `[orm]' ¶. The version_id_col feature on mapper() will
     raise a warning when used with dialects that don’t support
     “rowcount” adequately.

     References: #1569(17)

   * `[orm]' ¶ added “execution_options()” to Query, to so
     options can be passed to the resulting statement.  Currently only
     Select-statements have these options, and the only option used is
     “stream_results”, and the only dialect which knows “stream_results”
     is psycopg2.

   * `[orm]' ¶. Query.yield_per() will set the
     “stream_results” statement option automatically.

   * `[orm]' ¶.

     Deprecated or removed:

             * ’allow_null_pks’ flag on mapper() is deprecated.  It does
               nothing now and the setting is “on” in all cases.

             * ’transactional’ flag on sessionmaker() and others is
               removed.  Use ‘autocommit=True’ to indicate
               ‘transactional=False’.

             * ’polymorphic_fetch’ argument on mapper() is removed.
               Loading can be controlled using the ‘with_polymorphic’
               option.

             * ’select_table’ argument on mapper() is removed.  Use
               ‘with_polymorphic=(“*”, <some selectable>)’ for this
               functionality.

             * ’proxy’ argument on synonym() is removed.  This flag did
               nothing throughout 0.5, as the “proxy generation”
               behavior is now automatic.

             * Passing a single list of elements to eagerload(),
               eagerload_all(), contains_eager(), lazyload(), defer(),
               and undefer() instead of multiple positional *args is
               deprecated.

             * Passing a single list of elements to query.order_by(),
               query.group_by(), query.join(), or query.outerjoin()
               instead of multiple positional *args is deprecated.

             * query.iterate_instances() is removed.  Use
               query.instances().

             * Query.query_from_parent() is removed.  Use the
               sqlalchemy.orm.with_parent() function to produce a
               “parent” clause, or alternatively query.with_parent().

             * query._from_self() is removed, use query.from_self()
               instead.

             * the “comparator” argument to composite() is removed.  Use
               “comparator_factory”.

             * RelationProperty._get_join() is removed.

             * the ‘echo_uow’ flag on Session is removed.  Use logging
               on the “sqlalchemy.orm.unitofwork” name.

             * session.clear() is removed.  use session.expunge_all().

             * session.save(), session.update(),
               session.save_or_update() are removed.  Use session.add()
               and session.add_all().

             * the “objects” flag on session.flush() remains deprecated.

             * the “dont_load=True” flag on session.merge() is
               deprecated in favor of “load=False”.

             * ScopedSession.mapper remains deprecated.  See the usage
               recipe at
               ‘http://www.sqlalchemy.org/trac/wiki/UsageRecipes/SessionAwareMapper’

             * passing an InstanceState (internal SQLAlchemy state
               object) to attributes.init_collection() or
               attributes.get_history() is deprecated.  These functions
               are public API and normally expect a regular mapped
               object instance.

             * the ‘engine’ parameter to declarative_base() is removed.
               Use the ‘bind’ keyword argument.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1186

   (2) http://www.sqlalchemy.org/trac/ticket/1492

   (3) http://www.sqlalchemy.org/trac/ticket/1544

   (4) http://www.sqlalchemy.org/trac/ticket/1362

   (5) http://www.sqlalchemy.org/trac/ticket/1671

   (6) http://www.sqlalchemy.org/trac/ticket/1531

   (7) http://www.sqlalchemy.org/trac/ticket/1643

   (8) http://www.sqlalchemy.org/trac/ticket/1633

   (9) http://www.sqlalchemy.org/trac/ticket/1542

   (10) http://www.sqlalchemy.org/trac/ticket/1537

   (11) http://www.sqlalchemy.org/trac/ticket/1135

   (12) http://www.sqlalchemy.org/trac/ticket/1568

   (13) http://www.sqlalchemy.org/trac/ticket/1622

   (14) http://www.sqlalchemy.org/trac/ticket/1415

   (15) http://www.sqlalchemy.org/trac/ticket/1052

   (16) http://www.sqlalchemy.org/trac/ticket/1339

   (17) http://www.sqlalchemy.org/trac/ticket/1569

8.3.9.103 sql
.............

   * `[sql]' ¶ the “autocommit” flag on select() and text()
     as well as select().autocommit() are deprecated - now call
     .execution_options(autocommit=True) on either of those constructs,
     also available directly on Connection and orm.Query.

   * `[sql]' ¶ the autoincrement flag on column now
     indicates the column which should be linked to cursor.lastrowid, if
     that method is used.  See the API docs for details.

   * `[sql]' ¶ an executemany() now requires that all bound
     parameter sets require that all keys are present which are present
     in the first bound parameter set.  The structure and behavior of an
     insert/update statement is very much determined by the first
     parameter set, including which defaults are going to fire off, and
     a minimum of guesswork is performed with all the rest so that
     performance is not impacted.  For this reason defaults would
     otherwise silently “fail” for missing parameters, so this is now
     guarded against.

     References: #1566(1)

   * `[sql]' ¶ returning() support is native to insert(),
     update(), delete().  Implementations of varying levels of
     functionality exist for PostgreSQL, Firebird, MSSQL and Oracle.
     returning() can be called explicitly with column expressions which
     are then returned in the resultset, usually via fetchone() or
     first().

     insert() constructs will also use RETURNING implicitly to get newly
     generated primary key values, if the database version in use
     supports it (a version number check is performed).  This occurs if
     no end-user returning() was specified.

   * `[sql]' ¶ union(), intersect(), except() and other
     “compound” types of statements have more consistent behavior w.r.t.
     parenthesizing.  Each compound element embedded within another will
     now be grouped with parenthesis - previously, the first compound
     element in the list would not be grouped, as SQLite doesn’t like a
     statement to start with parenthesis.  However, PostgreSQL in
     particular has precedence rules regarding INTERSECT, and it is more
     consistent for parenthesis to be applied equally to all
     sub-elements.  So now, the workaround for SQLite is also what the
     workaround for PG was previously - when nesting compound elements,
     the first one usually needs “.alias().select()” called on it to
     wrap it inside of a subquery.

     References: #1665(2)

   * `[sql]' ¶ insert() and update() constructs can now
     embed bindparam() objects using names that match the keys of
     columns.  These bind parameters will circumvent the usual route to
     those keys showing up in the VALUES or SET clause of the generated
     SQL.

     References: #1579(3)

   * `[sql]' ¶ the Binary type now returns data as a Python
     string (or a “bytes” type in Python 3), instead of the built- in
     “buffer” type.  This allows symmetric round trips of binary data.

     References: #1524(4)

   * `[sql]' ¶. Added a tuple_() construct, allows sets of
     expressions to be compared to another set, typically with IN
     against composite primary keys or similar.  Also accepts an IN with
     multiple columns.  The “scalar select can have only one column”
     error message is removed - will rely upon the database to report
     problems with col mismatch.

   * `[sql]' ¶. User-defined “default” and “onupdate”
     callables which accept a context should now call upon
     “context.current_parameters” to get at the dictionary of bind
     parameters currently being processed.  This dict is available in
     the same way regardless of single-execute or executemany-style
     statement execution.

   * `[sql]' ¶ multi-part schema names, i.e.  with dots
     such as “dbo.master”, are now rendered in select() labels with
     underscores for dots, i.e.  “dbo_master_table_column”.  This is a
     “friendly” label that behaves better in result sets.

     References: #1428(5)

   * `[sql]' ¶ removed needless “counter” behavior with
     select() labelnames that match a column name in the table, i.e.
     generates “tablename_id” for “id”, instead of “tablename_id_1” in
     an attempt to avoid naming conflicts, when the table has a column
     actually named “tablename_id” - this is because the labeling logic
     is always applied to all columns so a naming conflict will never
     occur.

   * `[sql]' ¶ calling expr.in_([]), i.e.  with an empty
     list, emits a warning before issuing the usual “expr != expr”
     clause.  The “expr != expr” can be very expensive, and it’s
     preferred that the user not issue in_() if the list is empty,
     instead simply not querying, or modifying the criterion as
     appropriate for more complex situations.

     References: #1628(6)

   * `[sql]' ¶. Added “execution_options()” to
     select()/text(), which set the default options for the Connection.
     See the note in “engines”.

   * `[sql]' ¶.

     Deprecated or removed:

             * ”scalar” flag on select() is removed, use
               select.as_scalar().

             * ”shortname” attribute on bindparam() is removed.

             * postgres_returning, firebird_returning flags on insert(),
               update(), delete() are deprecated, use the new
               returning() method.

             * fold_equivalents flag on join is deprecated (will remain
               until is implemented)

     References: #1131(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1566

   (2) http://www.sqlalchemy.org/trac/ticket/1665

   (3) http://www.sqlalchemy.org/trac/ticket/1579

   (4) http://www.sqlalchemy.org/trac/ticket/1524

   (5) http://www.sqlalchemy.org/trac/ticket/1428

   (6) http://www.sqlalchemy.org/trac/ticket/1628

   (7) http://www.sqlalchemy.org/trac/ticket/1131

8.3.9.104 schema
................

   * `[schema]' ¶ the ‘__contains__()’ method of ‘MetaData’
     now accepts strings or ‘Table’ objects as arguments.  If given a
     ‘Table’, the argument is converted to ‘table.key’ first, i.e.
     “[schemaname.]<tablename>”

     References: #1541(1)

   * `[schema]' ¶ deprecated MetaData.connect() and
     ThreadLocalMetaData.connect() have been removed - send the “bind”
     attribute to bind a metadata.

   * `[schema]' ¶ deprecated metadata.table_iterator()
     method removed (use sorted_tables)

   * `[schema]' ¶ deprecated PassiveDefault - use
     DefaultClause.

   * `[schema]' ¶ the “metadata” argument is removed from
     DefaultGenerator and subclasses, but remains locally present on
     Sequence, which is a standalone construct in DDL.

   * `[schema]' ¶. Removed public mutability from Index and
     Constraint objects:

             * ForeignKeyConstraint.append_element()

             * Index.append_column()

             * UniqueConstraint.append_column()

             * PrimaryKeyConstraint.add()

             * PrimaryKeyConstraint.remove()

     These should be constructed declaratively (i.e.  in one
     construction).

   * `[schema]' ¶. The “start” and “increment” attributes on
     Sequence now generate “START WITH” and “INCREMENT BY” by default,
     on Oracle and PostgreSQL. Firebird doesn’t support these keywords
     right now.

     References: #1545(2)

   * `[schema]' ¶. UniqueConstraint, Index,
     PrimaryKeyConstraint all accept lists of column names or column
     objects as arguments.

   * `[schema]' ¶.

     Other removed things:

             - Table.key (no idea what this was for)

             - Table.primary_key is not assignable - use
               table.append_constraint(PrimaryKeyConstraint(…))

             - Column.bind (get via column.table.bind)

             - Column.metadata (get via column.table.metadata)

             - Column.sequence (use column.default)

             - ForeignKey(constraint=some_parent) (is now private
               _constraint)

   * `[schema]' ¶. The use_alter flag on ForeignKey is now a
     shortcut option for operations that can be hand-constructed using
     the DDL() event system.  A side effect of this refactor is that
     ForeignKeyConstraint objects with use_alter=True will `not' be
     emitted on SQLite, which does not support ALTER for foreign keys.

   * `[schema]' ¶. ForeignKey and ForeignKeyConstraint
     objects now correctly copy() all their public keyword arguments.

     References: #1605(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1541

   (2) http://www.sqlalchemy.org/trac/ticket/1545

   (3) http://www.sqlalchemy.org/trac/ticket/1605

8.3.9.105 postgresql
....................

   * `[postgresql]' ¶. New dialects: pg8000, zxjdbc, and
     pypostgresql on py3k.

   * `[postgresql]' ¶. The “postgres” dialect is now named
     “postgresql” !  Connection strings look like:

               postgresql://scott:tiger@localhost/test
               postgresql+pg8000://scott:tiger@localhost/test

          The “postgres” name remains for backwards compatibility in the
          following ways:

                  - There is a “postgres.py” dummy dialect which allows
                    old URLs to work, i.e.
                    postgres://scott:tiger@localhost/test

                  - The “postgres” name can be imported from the old
                    “databases” module, i.e.  “from sqlalchemy.databases
                    import postgres” as well as “dialects”, “from
                    sqlalchemy.dialects.postgres import base as pg”,
                    will send a deprecation warning.

                  - Special expression arguments are now named
                    “postgresql_returning” and “postgresql_where”, but
                    the older “postgres_returning” and “postgres_where”
                    names still work with a deprecation warning.

   * `[postgresql]' ¶. ”postgresql_where” now accepts SQL
     expressions which can also include literals, which will be quoted
     as needed.

   * `[postgresql]' ¶. The psycopg2 dialect now uses
     psycopg2’s “unicode extension” on all new connections, which allows
     all String/Text/etc.  types to skip the need to post-process
     bytestrings into unicode (an expensive step due to its volume).
     Other dialects which return unicode natively (pg8000, zxjdbc) also
     skip unicode post-processing.

   * `[postgresql]' ¶. Added new ENUM type, which exists as
     a schema-level construct and extends the generic Enum type.
     Automatically associates itself with tables and their parent
     metadata to issue the appropriate CREATE TYPE/DROP TYPE commands as
     needed, supports unicode labels, supports reflection.

     References: #1511(1)

   * `[postgresql]' ¶. INTERVAL supports an optional
     “precision” argument corresponding to the argument that PG accepts.

   * `[postgresql]' ¶ using new dialect.initialize()
     feature to set up version-dependent behavior.

   * `[postgresql]' ¶ somewhat better support for % signs
     in table/column names; psycopg2 can’t handle a bind parameter name
     of %(foobar)s however and SQLA doesn’t want to add overhead just to
     treat that one non-existent use case.

     References: #1279(2)

   * `[postgresql]' ¶. Inserting NULL into a primary key +
     foreign key column will allow the “not null constraint” error to
     raise, not an attempt to execute a nonexistent “col_id_seq”
     sequence.

     References: #1516(3)

   * `[postgresql]' ¶ autoincrement SELECT statements, i.e.
     those which select from a procedure that modifies rows, now work
     with server-side cursor mode (the named cursor isn’t used for such
     statements.)

   * `[postgresql]' ¶ postgresql dialect can properly
     detect pg “devel” version strings, i.e.  “8.5devel”

     References: #1636(4)

   * `[postgresql]' ¶. The psycopg2 now respects the
     statement option “stream_results”.  This option overrides the
     connection setting “server_side_cursors”.  If true, server side
     cursors will be used for the statement.  If false, they will not be
     used, even if “server_side_cursors” is true on the connection.

     References: #1619(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1511

   (2) http://www.sqlalchemy.org/trac/ticket/1279

   (3) http://www.sqlalchemy.org/trac/ticket/1516

   (4) http://www.sqlalchemy.org/trac/ticket/1636

   (5) http://www.sqlalchemy.org/trac/ticket/1619

8.3.9.106 mysql
...............

   * `[mysql]' ¶. New dialects: oursql, a new native
     dialect, MySQL Connector/Python, a native Python port of MySQLdb,
     and of course zxjdbc on Jython.

   * `[mysql]' ¶. VARCHAR/NVARCHAR will not render without a
     length, raises an error before passing to MySQL. Doesn’t impact
     CAST since VARCHAR is not allowed in MySQL CAST anyway, the dialect
     renders CHAR/NCHAR in those cases.

   * `[mysql]' ¶ all the _detect_XXX() functions now run
     once underneath dialect.initialize()

   * `[mysql]' ¶ somewhat better support for % signs in
     table/column names; MySQLdb can’t handle % signs in SQL when
     executemany() is used, and SQLA doesn’t want to add overhead just
     to treat that one non-existent use case.

     References: #1279(1)

   * `[mysql]' ¶ the BINARY and MSBinary types now generate
     “BINARY” in all cases.  Omitting the “length” parameter will
     generate “BINARY” with no length.  Use BLOB to generate an
     unlengthed binary column.

   * `[mysql]' ¶ the “quoting=’quoted’” argument to
     MSEnum/ENUM is deprecated.  It’s best to rely upon the automatic
     quoting.

   * `[mysql]' ¶. ENUM now subclasses the new generic Enum
     type, and also handles unicode values implicitly, if the given
     labelnames are unicode objects.

   * `[mysql]' ¶ a column of type TIMESTAMP now defaults to
     NULL if “nullable=False” is not passed to Column(), and no default
     is present.  This is now consistent with all other types, and in
     the case of TIMESTAMP explicitly renders “NULL” due to MySQL’s
     “switching” of default nullability for TIMESTAMP columns.

     References: #1539(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1279

   (2) http://www.sqlalchemy.org/trac/ticket/1539

8.3.9.107 sqlite
................

   * `[sqlite]' ¶. DATE, TIME and DATETIME types can now
     take optional storage_format and regexp argument.  storage_format
     can be used to store those types using a custom string format.
     regexp allows to use a custom regular expression to match string
     values from the database.

   * `[sqlite]' ¶. Time and DateTime types now use by a
     default a stricter regular expression to match strings from the
     database.  Use the regexp argument if you are using data stored in
     a legacy format.

   * `[sqlite]' ¶. __legacy_microseconds__ on SQLite Time
     and DateTime types is not supported anymore.  You should use the
     storage_format argument instead.

   * `[sqlite]' ¶. Date, Time and DateTime types are now
     stricter in what they accept as bind parameters: Date type only
     accepts date objects (and datetime ones, because they inherit from
     date), Time only accepts time objects, and DateTime only accepts
     date and datetime objects.

   * `[sqlite]' ¶. Table() supports a keyword argument
     “sqlite_autoincrement”, which applies the SQLite keyword
     “AUTOINCREMENT” to the single integer primary key column when
     generating DDL. Will prevent generation of a separate PRIMARY KEY
     constraint.

     References: #1016(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1016

8.3.9.108 mssql
...............

   * `[mssql]' ¶. MSSQL + Pyodbc + FreeTDS now works for the
     most part, with possible exceptions regarding binary data as well
     as unicode schema identifiers.

   * `[mssql]' ¶ the “has_window_funcs” flag is removed.
     LIMIT/OFFSET usage will use ROW NUMBER as always, and if on an
     older version of SQL Server, the operation fails.  The behavior is
     exactly the same except the error is raised by SQL server instead
     of the dialect, and no flag setting is required to enable it.

   * `[mssql]' ¶ the “auto_identity_insert” flag is
     removed.  This feature always takes effect when an INSERT statement
     overrides a column that is known to have a sequence on it.  As with
     “has_window_funcs”, if the underlying driver doesn’t support this,
     then you can’t do this operation in any case, so there’s no point
     in having a flag.

   * `[mssql]' ¶ using new dialect.initialize() feature to
     set up version-dependent behavior.

   * `[mssql]' ¶ removed references to sequence which is no
     longer used.  implicit identities in mssql work the same as
     implicit sequences on any other dialects.  Explicit sequences are
     enabled through the use of “default=Sequence()”.  See the MSSQL
     dialect documentation for more information.

8.3.9.109 oracle
................

   * `[oracle]' ¶ unit tests pass 100% with cx_oracle !

   * `[oracle]' ¶ support for cx_Oracle’s “native unicode”
     mode which does not require NLS_LANG to be set.  Use the latest
     5.0.2 or later of cx_oracle.

   * `[oracle]' ¶ an NCLOB type is added to the base types.

   * `[oracle]' ¶ use_ansi=False won’t leak into the
     FROM/WHERE clause of a statement that’s selecting from a subquery
     that also uses JOIN/OUTERJOIN.

   * `[oracle]' ¶ added native INTERVAL type to the
     dialect.  This supports only the DAY TO SECOND interval type so far
     due to lack of support in cx_oracle for YEAR TO MONTH.

     References: #1467(1)

   * `[oracle]' ¶ usage of the CHAR type results in
     cx_oracle’s FIXED_CHAR dbapi type being bound to statements.

   * `[oracle]' ¶ the Oracle dialect now features NUMBER
     which intends to act justlike Oracle’s NUMBER type.  It is the
     primary numeric type returned by table reflection and attempts to
     return Decimal()/float/int based on the precision/scale parameters.

     References: #885(2)

   * `[oracle]' ¶ func.char_length is a generic function
     for LENGTH

   * `[oracle]' ¶. ForeignKey() which includes
     onupdate=<value> will emit a warning, not emit ON UPDATE CASCADE
     which is unsupported by oracle

   * `[oracle]' ¶ the keys() method of RowProxy() now
     returns the result column names `normalized' to be SQLAlchemy case
     insensitive names.  This means they will be lower case for case
     insensitive names, whereas the DBAPI would normally return them as
     UPPERCASE names.  This allows row keys() to be compatible with
     further SQLAlchemy operations.

   * `[oracle]' ¶ using new dialect.initialize() feature to
     set up version-dependent behavior.

   * `[oracle]' ¶ using types.BigInteger with Oracle will
     generate NUMBER(19)

     References: #1125(3)

   * `[oracle]' ¶. ”case sensitivity” feature will detect an
     all-lowercase case-sensitive column name during reflect and add
     “quote=True” to the generated Column, so that proper quoting is
     maintained.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1467

   (2) http://www.sqlalchemy.org/trac/ticket/885

   (3) http://www.sqlalchemy.org/trac/ticket/1125

8.3.9.110 firebird
..................

   * `[firebird]' ¶ the keys() method of RowProxy() now
     returns the result column names `normalized' to be SQLAlchemy case
     insensitive names.  This means they will be lower case for case
     insensitive names, whereas the DBAPI would normally return them as
     UPPERCASE names.  This allows row keys() to be compatible with
     further SQLAlchemy operations.

   * `[firebird]' ¶ using new dialect.initialize() feature
     to set up version-dependent behavior.

   * `[firebird]' ¶. ”case sensitivity” feature will detect
     an all-lowercase case-sensitive column name during reflect and add
     “quote=True” to the generated Column, so that proper quoting is
     maintained.

8.3.9.111 misc
..............

   * `[major] [release]' ¶. For the full set of feature
     descriptions, see
     ‘http://docs.sqlalchemy.org/en/latest/changelog/migration_06.html’
     .  This document is a work in progress.

   * `[major] [release]' ¶. All bug fixes and feature
     enhancements from the most recent 0.5 version and below are also
     included within 0.6.

   * `[major] [release]' ¶. Platforms targeted now include
     Python 2.4/2.5/2.6, Python 3.1, Jython2.5.

   * `[engines]' ¶ transaction isolation level may be
     specified with create_engine(… isolation_level=”…”); available on
     postgresql and sqlite.

     References: #443(1)

   * `[engines]' ¶. Connection has execution_options(),
     generative method which accepts keywords that affect how the
     statement is executed w.r.t.  the DBAPI. Currently supports
     “stream_results”, causes psycopg2 to use a server side cursor for
     that statement, as well as “autocommit”, which is the new location
     for the “autocommit” option from select() and text().  select() and
     text() also have .execution_options() as well as ORM Query().

   * `[engines]' ¶ fixed the import for entrypoint-driven
     dialects to not rely upon silly tb_info trick to determine import
     error status.

     References: #1630(2)

   * `[engines]' ¶ added first() method to ResultProxy,
     returns first row and closes result set immediately.

   * `[engines]' ¶. RowProxy objects are now pickleable,
     i.e.  the object returned by result.fetchone(), result.fetchall()
     etc.

   * `[engines]' ¶. RowProxy no longer has a close() method,
     as the row no longer maintains a reference to the parent.  Call
     close() on the parent ResultProxy instead, or use autoclose.

   * `[engines]' ¶. ResultProxy internals have been
     overhauled to greatly reduce method call counts when fetching
     columns.  Can provide a large speed improvement (up to more than
     100%) when fetching large result sets.  The improvement is larger
     when fetching columns that have no type-level processing applied
     and when using results as tuples (instead of as dictionaries).
     Many thanks to Elixir’s Gaëtan de Menten for this dramatic
     improvement !

     References: #1586(3)

   * `[engines]' ¶. Databases which rely upon postfetch of
     “last inserted id” to get at a generated sequence value (i.e.
     MySQL, MS-SQL) now work correctly when there is a composite primary
     key where the “autoincrement” column is not the first primary key
     column in the table.

   * `[engines]' ¶ the last_inserted_ids() method has been
     renamed to the descriptor “inserted_primary_key”.

   * `[engines]' ¶ setting echo=False on create_engine()
     now sets the loglevel to WARN instead of NOTSET. This so that
     logging can be disabled for a particular engine even if logging for
     “sqlalchemy.engine” is enabled overall.  Note that the default
     setting of “echo” is ‘None’.

     References: #1554(4)

   * `[engines]' ¶. ConnectionProxy now has wrapper methods
     for all transaction lifecycle events, including begin(),
     rollback(), commit() begin_nested(), begin_prepared(), prepare(),
     release_savepoint(), etc.

   * `[engines]' ¶. Connection pool logging now uses both
     INFO and DEBUG log levels for logging.  INFO is for major events
     such as invalidated connections, DEBUG for all the acquire/return
     logging.  ‘echo_pool’ can be False, None, True or “debug” the same
     way as ‘echo’ works.

   * `[engines]' ¶. All pyodbc-dialects now support extra
     pyodbc-specific kw arguments ‘ansi’, ‘unicode_results’,
     ‘autocommit’.

     References: #1621(5)

   * `[engines]' ¶ the “threadlocal” engine has been
     rewritten and simplified and now supports SAVEPOINT operations.

   * `[engines]' ¶.

     deprecated or removed

             * result.last_inserted_ids() is deprecated.  Use
               result.inserted_primary_key

             * dialect.get_default_schema_name(connection) is now public
               via dialect.default_schema_name.

             * the “connection” argument from engine.transaction() and
               engine.run_callable() is removed - Connection itself now
               has those methods.  All four methods accept *args and
               **kwargs which are passed to the given callable, as well
               as the operating connection.

   * `[reflection/inspection]' ¶. Table reflection has been
     expanded and generalized into a new API called
     “sqlalchemy.engine.reflection.Inspector”.  The Inspector object
     provides fine-grained information about a wide variety of schema
     information, with room for expansion, including table names, column
     names, view definitions, sequences, indexes, etc.

   * `[reflection/inspection]' ¶. Views are now reflectable
     as ordinary Table objects.  The same Table constructor is used,
     with the caveat that “effective” primary and foreign key
     constraints aren’t part of the reflection results; these have to be
     specified explicitly if desired.

   * `[reflection/inspection]' ¶. The existing autoload=True
     system now uses Inspector underneath so that each dialect need only
     return “raw” data about tables and other objects - Inspector is the
     single place that information is compiled into Table objects so
     that consistency is at a maximum.

   * `[ddl]' ¶ the DDL system has been greatly expanded.
     the DDL() class now extends the more generic DDLElement(), which
     forms the basis of many new constructs:

                  - CreateTable()

                  - DropTable()

                  - AddConstraint()

                  - DropConstraint()

                  - CreateIndex()

                  - DropIndex()

                  - CreateSequence()

                  - DropSequence()

          These support “on” and “execute-at()” just like plain DDL()
          does.  User-defined DDLElement subclasses can be created and
          linked to a compiler using the sqlalchemy.ext.compiler
          extension.

   * `[ddl]' ¶. The signature of the “on” callable passed to
     DDL() and DDLElement() is revised as follows:

          ddl

               the DDLElement object itself

          event

               the string event name.

          target

               previously “schema_item”, the Table or MetaData object
               triggering the event.

          connection

               the Connection object in use for the operation.

          **kw

               keyword arguments.  In the case of MetaData before/after
               create/drop, the list of Table objects for which
               CREATE/DROP DDL is to be issued is passed as the kw
               argument “tables”.  This is necessary for metadata-level
               DDL that is dependent on the presence of specific tables.

     The “schema_item” attribute of DDL has been renamed to

          ”target”.

   * `[dialect] [refactor]' ¶. Dialect modules are now
     broken into database dialects plus DBAPI implementations.  Connect
     URLs are now preferred to be specified using dialect+driver://…,
     i.e.  “mysql+mysqldb://scott:tiger@localhost/test”.  See the 0.6
     documentation for examples.

   * `[dialect] [refactor]' ¶ the setuptools entrypoint for
     external dialects is now called “sqlalchemy.dialects”.

   * `[dialect] [refactor]' ¶ the “owner” keyword argument
     is removed from Table.  Use “schema” to represent any namespaces to
     be prepended to the table name.

   * `[dialect] [refactor]' ¶ server_version_info becomes a
     static attribute.

   * `[dialect] [refactor]' ¶ dialects receive an
     initialize() event on initial connection to determine connection
     properties.

   * `[dialect] [refactor]' ¶ dialects receive a visit_pool
     event have an opportunity to establish pool listeners.

   * `[dialect] [refactor]' ¶ cached TypeEngine classes are
     cached per-dialect class instead of per-dialect.

   * `[dialect] [refactor]' ¶ new UserDefinedType should be
     used as a base class for new types, which preserves the 0.5
     behavior of get_col_spec().

   * `[dialect] [refactor]' ¶. The result_processor() method
     of all type classes now accepts a second argument “coltype”, which
     is the DBAPI type argument from cursor.description.  This argument
     can help some types decide on the most efficient processing of
     result values.

   * `[dialect] [refactor]' ¶. Deprecated
     Dialect.get_params() removed.

   * `[dialect] [refactor]' ¶. Dialect.get_rowcount() has
     been renamed to a descriptor “rowcount”, and calls cursor.rowcount
     directly.  Dialects which need to hardwire a rowcount in for
     certain calls should override the method to provide different
     behavior.

   * `[dialect] [refactor]' ¶. DefaultRunner and subclasses
     have been removed.  The job of this object has been simplified and
     moved into ExecutionContext.  Dialects which support sequences
     should add a ‘fire_sequence()’ method to their execution context
     implementation.

     References: #1566(6)

   * `[dialect] [refactor]' ¶. Functions and operators
     generated by the compiler now use (almost) regular dispatch
     functions of the form “visit_<opname>” and “visit_<funcname>_fn” to
     provide customed processing.  This replaces the need to copy the
     “functions” and “operators” dictionaries in compiler subclasses
     with straightforward visitor methods, and also allows compiler
     subclasses complete control over rendering, as the full _Function
     or _BinaryExpression object is passed in.

   * `[types]' ¶. The construction of types within dialects
     has been totally overhauled.  Dialects now define publicly
     available types as UPPERCASE names exclusively, and internal
     implementation types using underscore identifiers (i.e.  are
     private).  The system by which types are expressed in SQL and DDL
     has been moved to the compiler system.  This has the effect that
     there are much fewer type objects within most dialects.  A detailed
     document on this architecture for dialect authors is in
     lib/sqlalchemy/dialects/type_migration_guidelines.txt .

   * `[types]' ¶. Types no longer make any guesses as to
     default parameters.  In particular, Numeric, Float, NUMERIC, FLOAT,
     DECIMAL don’t generate any length or scale unless specified.

   * `[types]' ¶ types.Binary is renamed to
     types.LargeBinary, it only produces BLOB, BYTEA, or a similar “long
     binary” type.  New base BINARY and VARBINARY types have been added
     to access these MySQL/MS-SQL specific types in an agnostic way.

     References: #1664(7)

   * `[types]' ¶. String/Text/Unicode types now skip the
     unicode() check on each result column value if the dialect has
     detected the DBAPI as returning Python unicode objects natively.
     This check is issued on first connect using “SELECT CAST ‘some
     text’ AS VARCHAR(10)” or equivalent, then checking if the returned
     object is a Python unicode.  This allows vast performance increases
     for native-unicode DBAPIs, including pysqlite/sqlite3, psycopg2,
     and pg8000.

   * `[types]' ¶. Most types result processors have been
     checked for possible speed improvements.  Specifically, the
     following generic types have been optimized, resulting in varying
     speed improvements: Unicode, PickleType, Interval, TypeDecorator,
     Binary.  Also the following dbapi-specific implementations have
     been improved: Time, Date and DateTime on Sqlite, ARRAY on
     PostgreSQL, Time on MySQL, Numeric(as_decimal=False) on MySQL,
     oursql and pypostgresql, DateTime on cx_oracle and LOB-based types
     on cx_oracle.

   * `[types]' ¶. Reflection of types now returns the exact
     UPPERCASE type within types.py, or the UPPERCASE type within the
     dialect itself if the type is not a standard SQL type.  This means
     reflection now returns more accurate information about reflected
     types.

   * `[types]' ¶. Added a new Enum generic type.  Enum is a
     schema-aware object to support databases which require specific DDL
     in order to use enum or equivalent; in the case of PG it handles
     the details of ‘CREATE TYPE’, and on other databases without native
     enum support will by generate VARCHAR + an inline CHECK constraint
     to enforce the enum.

     References: #1109(8), #1511(9)

   * `[types]' ¶. The Interval type includes a “native” flag
     which controls if native INTERVAL types (postgresql + oracle) are
     selected if available, or not.  “day_precision” and
     “second_precision” arguments are also added which propagate as
     appropriately to these native types.  Related to.

     References: #1467(10)

   * `[types]' ¶. The Boolean type, when used on a backend
     that doesn’t have native boolean support, will generate a CHECK
     constraint “col IN (0, 1)” along with the int/smallint- based
     column type.  This can be switched off if desired with
     create_constraint=False.  Note that MySQL has no native boolean
     `or' CHECK constraint support so this feature isn’t available on
     that platform.

     References: #1589(11)

   * `[types]' ¶. PickleType now uses == for comparison of
     values when mutable=True, unless the “comparator” argument with a
     comparison function is specified to the type.  Objects being
     pickled will be compared based on identity (which defeats the
     purpose of mutable=True) if __eq__() is not overridden or a
     comparison function is not provided.

   * `[types]' ¶. The default “precision” and “scale”
     arguments of Numeric and Float have been removed and now default to
     None.  NUMERIC and FLOAT will be rendered with no numeric arguments
     by default unless these values are provided.

   * `[types]' ¶. AbstractType.get_search_list() is removed
     - the games that was used for are no longer necessary.

   * `[types]' ¶. Added a generic BigInteger type, compiles
     to BIGINT or NUMBER(19).

     References: #1125(12)

   * `[types]' ¶ sqlsoup has been overhauled to explicitly
     support an 0.5 style session, using autocommit=False,
     autoflush=True.  Default behavior of SQLSoup now requires the usual
     usage of commit() and rollback(), which have been added to its
     interface.  An explicit Session or scoped_session can be passed to
     the constructor, allowing these arguments to be overridden.

   * `[types]' ¶ sqlsoup db.<sometable>.update() and
     delete() now call query(cls).update() and delete(), respectively.

   * `[types]' ¶ sqlsoup now has execute() and
     connection(), which call upon the Session methods of those names,
     ensuring that the bind is in terms of the SqlSoup object’s bind.

   * `[types]' ¶ sqlsoup objects no longer have the ‘query’
     attribute - it’s not needed for sqlsoup’s usage paradigm and it
     gets in the way of a column that is actually named ‘query’.

   * `[types]' ¶. The signature of the proxy_factory
     callable passed to association_proxy is now (lazy_collection,
     creator, value_attr, association_proxy), adding a fourth argument
     that is the parent AssociationProxy argument.  Allows
     serializability and subclassing of the built in collections.

     References: #1259(13)

   * `[types]' ¶ association_proxy now has basic comparator
     methods .any(), .has(), .contains(), ==, !=, thanks to Scott
     Torborg.

     References: #1372(14)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/443

   (2) http://www.sqlalchemy.org/trac/ticket/1630

   (3) http://www.sqlalchemy.org/trac/ticket/1586

   (4) http://www.sqlalchemy.org/trac/ticket/1554

   (5) http://www.sqlalchemy.org/trac/ticket/1621

   (6) http://www.sqlalchemy.org/trac/ticket/1566

   (7) http://www.sqlalchemy.org/trac/ticket/1664

   (8) http://www.sqlalchemy.org/trac/ticket/1109

   (9) http://www.sqlalchemy.org/trac/ticket/1511

   (10) http://www.sqlalchemy.org/trac/ticket/1467

   (11) http://www.sqlalchemy.org/trac/ticket/1589

   (12) http://www.sqlalchemy.org/trac/ticket/1125

   (13) http://www.sqlalchemy.org/trac/ticket/1259

   (14) http://www.sqlalchemy.org/trac/ticket/1372

8.3.10 0.5 Changelog
--------------------

8.3.10.1 0.5.9
..............

no release date

8.3.10.2 sql
............

   * `[sql]' ¶. Fixed erroneous self_group() call in
     expression package.

     References: #1661(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1661

8.3.10.3 0.5.8
..............

Released: Sat Jan 16 2010

8.3.10.4 sql
............

   * `[sql]' ¶. The copy() method on Column now supports
     uninitialized, unnamed Column objects.  This allows easy creation
     of declarative helpers which place common columns on multiple
     subclasses.

   * `[sql]' ¶. Default generators like Sequence() translate
     correctly across a copy() operation.

   * `[sql]' ¶. Sequence() and other DefaultGenerator
     objects are accepted as the value for the “default” and “onupdate”
     keyword arguments of Column, in addition to being accepted
     positionally.

   * `[sql]' ¶. Fixed a column arithmetic bug that affected
     column correspondence for cloned selectables which contain
     free-standing column expressions.  This bug is generally only
     noticeable when exercising newer ORM behavior only available in 0.6
     via, but is more correct at the SQL expression level as well.

     References: #1568(1), #1617(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1568

   (2) http://www.sqlalchemy.org/trac/ticket/1617

8.3.10.5 postgresql
...................

   * `[postgresql]' ¶. The extract() function, which was
     slightly improved in 0.5.7, needed a lot more work to generate the
     correct typecast (the typecasts appear to be necessary in PG’s
     EXTRACT quite a lot of the time).  The typecast is now generated
     using a rule dictionary based on PG’s documentation for
     date/time/interval arithmetic.  It also accepts text() constructs
     again, which was broken in 0.5.7.

     References: #1647(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1647

8.3.10.6 firebird
.................

   * `[firebird]' ¶. Recognize more errors as
     disconnections.

     References: #1646(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1646

8.3.10.7 0.5.7
..............

Released: Sat Dec 26 2009

8.3.10.8 orm
............

   * `[orm]' ¶ contains_eager() now works with the
     automatically generated subquery that results when you say
     “query(Parent).join(Parent.somejoinedsubclass)”, i.e.  when Parent
     joins to a joined-table-inheritance subclass.  Previously
     contains_eager() would erroneously add the subclass table to the
     query separately producing a cartesian product.  An example is in
     the ticket description.

     References: #1543(1)

   * `[orm]' ¶ query.options() now only propagate to loaded
     objects for potential further sub-loads only for options where such
     behavior is relevant, keeping various unserializable options like
     those generated by contains_eager() out of individual instance
     states.

     References: #1553(2)

   * `[orm]' ¶. Session.execute() now locates table- and
     mapper-specific binds based on a passed in expression which is an
     insert()/update()/delete() construct.

     References: #1054(3)

   * `[orm]' ¶. Session.merge() now properly overwrites a
     many-to-one or uselist=False attribute to None if the attribute is
     also None in the given object to be merged.

   * `[orm]' ¶. Fixed a needless select which would occur
     when merging transient objects that contained a null primary key
     identifier.

     References: #1618(4)

   * `[orm]' ¶. Mutable collection passed to the “extension”
     attribute of relation(), column_property() etc.  will not be
     mutated or shared among multiple instrumentation calls, preventing
     duplicate extensions, such as backref populators, from being
     inserted into the list.

     References: #1585(5)

   * `[orm]' ¶. Fixed the call to get_committed_value() on
     CompositeProperty.

     References: #1504(6)

   * `[orm]' ¶. Fixed bug where Query would crash if a
     join() with no clear “left” side were called when a non-mapped
     column entity appeared in the columns list.

     References: #1602(7)

   * `[orm]' ¶. Fixed bug whereby composite columns wouldn’t
     load properly when configured on a joined-table subclass,
     introduced in version 0.5.6 as a result of the fix for.  thx to
     Scott Torborg.

     References: #1480(8), #1616(9)

   * `[orm]' ¶. The “use get” behavior of many-to-one
     relations, i.e.  that a lazy load will fallback to the possibly
     cached query.get() value, now works across join conditions where
     the two compared types are not exactly the same class, but share
     the same “affinity” - i.e.  Integer and SmallInteger.  Also allows
     combinations of reflected and non-reflected types to work with 0.5
     style type reflection, such as PGText/Text (note 0.6 reflects types
     as their generic versions).

     References: #1556(10)

   * `[orm]' ¶. Fixed bug in query.update() when passing
     Cls.attribute as keys in the value dict and using
     synchronize_session=’expire’ (‘fetch’ in 0.6).

     References: #1436(11)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1543

   (2) http://www.sqlalchemy.org/trac/ticket/1553

   (3) http://www.sqlalchemy.org/trac/ticket/1054

   (4) http://www.sqlalchemy.org/trac/ticket/1618

   (5) http://www.sqlalchemy.org/trac/ticket/1585

   (6) http://www.sqlalchemy.org/trac/ticket/1504

   (7) http://www.sqlalchemy.org/trac/ticket/1602

   (8) http://www.sqlalchemy.org/trac/ticket/1480

   (9) http://www.sqlalchemy.org/trac/ticket/1616

   (10) http://www.sqlalchemy.org/trac/ticket/1556

   (11) http://www.sqlalchemy.org/trac/ticket/1436

8.3.10.9 sql
............

   * `[sql]' ¶. Fixed bug in two-phase transaction whereby
     commit() method didn’t set the full state which allows subsequent
     close() call to succeed.

     References: #1603(1)

   * `[sql]' ¶. Fixed the “numeric” paramstyle, which
     apparently is the default paramstyle used by Informixdb.

   * `[sql]' ¶. Repeat expressions in the columns clause of
     a select are deduped based on the identity of each clause element,
     not the actual string.  This allows positional elements to render
     correctly even if they all render identically, such as “qmark”
     style bind parameters.

     References: #1574(2)

   * `[sql]' ¶. The cursor associated with connection pool
     connections (i.e.  _CursorFairy) now proxies ‘__iter__()’ to the
     underlying cursor correctly.

     References: #1632(3)

   * `[sql]' ¶ types now support an “affinity comparison”
     operation, i.e.  that an Integer/SmallInteger are “compatible”, or
     a Text/String, PickleType/Binary, etc.  Part of.

     References: #1556(4)

   * `[sql]' ¶. Fixed bug preventing alias() of an alias()
     from being cloned or adapted (occurs frequently in ORM operations).

     References: #1641(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1603

   (2) http://www.sqlalchemy.org/trac/ticket/1574

   (3) http://www.sqlalchemy.org/trac/ticket/1632

   (4) http://www.sqlalchemy.org/trac/ticket/1556

   (5) http://www.sqlalchemy.org/trac/ticket/1641

8.3.10.10 postgresql
....................

   * `[postgresql]' ¶. Added support for reflecting the
     DOUBLE PRECISION type, via a new postgres.PGDoublePrecision object.
     This is postgresql.DOUBLE_PRECISION in 0.6.

     References: #1085(1)

   * `[postgresql]' ¶. Added support for reflecting the
     INTERVAL YEAR TO MONTH and INTERVAL DAY TO SECOND syntaxes of the
     INTERVAL type.

     References: #460(2)

   * `[postgresql]' ¶. Corrected the “has_sequence” query to
     take current schema, or explicit sequence-stated schema, into
     account.

     References: #1576(3)

   * `[postgresql]' ¶. Fixed the behavior of extract() to
     apply operator precedence rules to the “::” operator when applying
     the “timestamp” cast - ensures proper parenthesization.

     References: #1611(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1085

   (2) http://www.sqlalchemy.org/trac/ticket/460

   (3) http://www.sqlalchemy.org/trac/ticket/1576

   (4) http://www.sqlalchemy.org/trac/ticket/1611

8.3.10.11 sqlite
................

   * `[sqlite]' ¶ sqlite dialect properly generates CREATE
     INDEX for a table that is in an alternate schema.

     References: #1439(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1439

8.3.10.12 mssql
...............

   * `[mssql]' ¶. Changed the name of TrustedConnection to
     Trusted_Connection when constructing pyodbc connect arguments

     References: #1561(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1561

8.3.10.13 oracle
................

   * `[oracle]' ¶. The “table_names” dialect function, used
     by MetaData .reflect(), omits “index overflow tables”, a system
     table generated by Oracle when “index only tables” with overflow
     are used.  These tables aren’t accessible via SQL and can’t be
     reflected.

     References: #1637(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1637

8.3.10.14 misc
..............

   * `[ext]' ¶. A column can be added to a joined-table
     declarative superclass after the class has been constructed (i.e.
     via class-level attribute assignment), and the column will be
     propagated down to subclasses.  This is the reverse situation as
     that of, fixed in 0.5.6.

     References: #1523(1), #1570(2)

   * `[ext]' ¶. Fixed a slight inaccuracy in the sharding
     example.  Comparing equivalence of columns in the ORM is best
     accomplished using col1.shares_lineage(col2).

     References: #1491(3)

   * `[ext]' ¶. Removed unused ‘load()’ method from
     ShardedQuery.

     References: #1606(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1523

   (2) http://www.sqlalchemy.org/trac/ticket/1570

   (3) http://www.sqlalchemy.org/trac/ticket/1491

   (4) http://www.sqlalchemy.org/trac/ticket/1606

8.3.10.15 0.5.6
...............

Released: Sat Sep 12 2009

8.3.10.16 orm
.............

   * `[orm]' ¶. Fixed bug whereby inheritance discriminator
     part of a composite primary key would fail on updates.
     Continuation of.

     References: #1300(1)

   * `[orm]' ¶. Fixed bug which disallowed one side of a
     many-to-many bidirectional reference to declare itself as
     “viewonly”

     References: #1507(2)

   * `[orm]' ¶. Added an assertion that prevents a
     @validates function or other AttributeExtension from loading an
     unloaded collection such that internal state may be corrupted.

     References: #1526(3)

   * `[orm]' ¶. Fixed bug which prevented two entities from
     mutually replacing each other’s primary key values within a single
     flush() for some orderings of operations.

     References: #1519(4)

   * `[orm]' ¶. Fixed an obscure issue whereby a
     joined-table subclass with a self-referential eager load on the
     base class would populate the related object’s “subclass” table
     with data from the “subclass” table of the parent.

     References: #1485(5)

   * `[orm]' ¶ relations() now have greater ability to be
     “overridden”, meaning a subclass that explicitly specifies a
     relation() overriding that of the parent class will be honored
     during a flush.  This is currently to support many-to-many
     relations from concrete inheritance setups.  Outside of that use
     case, YMMV.

     References: #1477(6)

   * `[orm]' ¶. Squeezed a few more unnecessary “lazy loads”
     out of relation().  When a collection is mutated, many-to-one
     backrefs on the other side will not fire off to load the “old”
     value, unless “single_parent=True” is set.  A direct assignment of
     a many-to-one still loads the “old” value in order to update
     backref collections on that value, which may be present in the
     session already, thus maintaining the 0.5 behavioral contract.

     References: #1483(7)

   * `[orm]' ¶. Fixed bug whereby a load/refresh of joined
     table inheritance attributes which were based on column_property()
     or similar would fail to evaluate.

     References: #1480(8)

   * `[orm]' ¶. Improved support for MapperProperty objects
     overriding that of an inherited mapper for non-concrete inheritance
     setups - attribute extensions won’t randomly collide with each
     other.

     References: #1488(9)

   * `[orm]' ¶. UPDATE and DELETE do not support ORDER BY,
     LIMIT, OFFSET, etc.  in standard SQL. Query.update() and
     Query.delete() now raise an exception if any of limit(), offset(),
     order_by(), group_by(), or distinct() have been called.

     References: #1487(10)

   * `[orm]' ¶. Added AttributeExtension to
     sqlalchemy.orm.__all__

   * `[orm]' ¶. Improved error message when query() is
     called with a non-SQL /entity expression.

     References: #1476(11)

   * `[orm]' ¶. Using False or 0 as a polymorphic
     discriminator now works on the base class as well as a subclass.

     References: #1440(12)

   * `[orm]' ¶. Added enable_assertions(False) to Query
     which disables the usual assertions for expected state - used by
     Query subclasses to engineer custom state..  See
     ‘http://www.sqlalchemy.org/trac/wiki/UsageRecipes/PreFilteredQuery’
     for an example.

     References: #1424(13)

   * `[orm]' ¶. Fixed recursion issue which occurred if a
     mapped object’s ‘__len__()’ or ‘__nonzero__()’ method resulted in
     state changes.

     References: #1501(14)

   * `[orm]' ¶. Fixed incorrect exception raise in
     Weak/StrongIdentityMap.add()

     References: #1506(15)

   * `[orm]' ¶. Fixed the error message for “could not find
     a FROM clause” in query.join() which would fail to issue correctly
     if the query was against a pure SQL construct.

     References: #1522(16)

   * `[orm]' ¶. Fixed a somewhat hypothetical issue which
     would result in the wrong primary key being calculated for a mapper
     using the old polymorphic_union function - but this is old stuff.

     References: #1486(17)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1300

   (2) http://www.sqlalchemy.org/trac/ticket/1507

   (3) http://www.sqlalchemy.org/trac/ticket/1526

   (4) http://www.sqlalchemy.org/trac/ticket/1519

   (5) http://www.sqlalchemy.org/trac/ticket/1485

   (6) http://www.sqlalchemy.org/trac/ticket/1477

   (7) http://www.sqlalchemy.org/trac/ticket/1483

   (8) http://www.sqlalchemy.org/trac/ticket/1480

   (9) http://www.sqlalchemy.org/trac/ticket/1488

   (10) http://www.sqlalchemy.org/trac/ticket/1487

   (11) http://www.sqlalchemy.org/trac/ticket/1476

   (12) http://www.sqlalchemy.org/trac/ticket/1440

   (13) http://www.sqlalchemy.org/trac/ticket/1424

   (14) http://www.sqlalchemy.org/trac/ticket/1501

   (15) http://www.sqlalchemy.org/trac/ticket/1506

   (16) http://www.sqlalchemy.org/trac/ticket/1522

   (17) http://www.sqlalchemy.org/trac/ticket/1486

8.3.10.17 sql
.............

   * `[sql]' ¶. Fixed column.copy() to copy defaults and
     onupdates.

     References: #1373(1)

   * `[sql]' ¶. Fixed a bug in extract() introduced in 0.5.4
     whereby the string “field” argument was getting treated as a
     ClauseElement, causing various errors within more complex SQL
     transformations.

   * `[sql]' ¶. Unary expressions such as DISTINCT propagate
     their type handling to result sets, allowing conversions like
     unicode and such to take place.

     References: #1420(2)

   * `[sql]' ¶. Fixed bug in Table and Column whereby
     passing empty dict for “info” argument would raise an exception.

     References: #1482(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1373

   (2) http://www.sqlalchemy.org/trac/ticket/1420

   (3) http://www.sqlalchemy.org/trac/ticket/1482

8.3.10.18 oracle
................

   * `[oracle]' ¶. Backported 0.6 fix for Oracle alias names
     not getting truncated.

     References: #1309(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1309

8.3.10.19 misc
..............

   * `[ext]' ¶. The collection proxies produced by
     associationproxy are now pickleable.  A user-defined proxy_factory
     however is still not pickleable unless it defines __getstate__ and
     __setstate__.

     References: #1446(1)

   * `[ext]' ¶. Declarative will raise an informative
     exception if __table_args__ is passed as a tuple with no dict
     argument.  Improved documentation.

     References: #1468(2)

   * `[ext]' ¶. Table objects declared in the MetaData can
     now be used in string expressions sent to
     primaryjoin/secondaryjoin/ secondary - the name is pulled from the
     MetaData of the declarative base.

     References: #1527(3)

   * `[ext]' ¶. A column can be added to a joined-table
     subclass after the class has been constructed (i.e.  via
     class-level attribute assignment).  The column is added to the
     underlying Table as always, but now the mapper will rebuild its
     “join” to include the new column, instead of raising an error about
     “no such column, use column_property() instead”.

     References: #1523(4)

   * `[test]' ¶. Added examples into the test suite so they
     get exercised regularly and cleaned up a couple deprecation
     warnings.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1446

   (2) http://www.sqlalchemy.org/trac/ticket/1468

   (3) http://www.sqlalchemy.org/trac/ticket/1527

   (4) http://www.sqlalchemy.org/trac/ticket/1523

8.3.10.20 0.5.5
...............

Released: Mon Jul 13 2009

8.3.10.21 general
.................

   * `[general]' ¶ unit tests have been migrated from
     unittest to nose.  See README.unittests for information on how to
     run the tests.

     References: #970(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/970

8.3.10.22 orm
.............

   * `[orm]' ¶. The “foreign_keys” argument of relation()
     will now propagate automatically to the backref in the same way
     that primaryjoin and secondaryjoin do.  For the extremely rare use
     case where the backref of a relation() has intentionally different
     “foreign_keys” configured, both sides now need to be configured
     explicitly (if they do in fact require this setting, see the next
     note…).

   * `[orm]' ¶. …the only known (and really, really rare)
     use case where a different foreign_keys setting was used on the
     forwards/backwards side, a composite foreign key that partially
     points to its own columns, has been enhanced such that the
     fk->itself aspect of the relation won’t be used to determine
     relation direction.

   * `[orm]' ¶. Session.mapper is now `deprecated'.

     Call session.add() if you’d like a free-standing object to be part
     of your session.  Otherwise, a DIY version of Session.mapper is now
     documented at
     ‘http://www.sqlalchemy.org/trac/wiki/UsageRecipes/SessionAwareMapper’
     The method will remain deprecated throughout 0.6.

   * `[orm]' ¶. Fixed Query being able to join() from
     individual columns of a joined-table subclass entity, i.e.
     query(SubClass.foo, SubClass.bar).join(<anything>).  In most cases,
     an error “Could not find a FROM clause to join from” would be
     raised.  In a few others, the result would be returned in terms of
     the base class rather than the subclass - so applications which
     relied on this erroneous result need to be adjusted.

     References: #1431(1)

   * `[orm]' ¶. Fixed a bug involving contains_eager(),
     which would apply itself to a secondary (i.e.  lazy) load in a
     particular rare case, producing cartesian products.  improved the
     targeting of query.options() on secondary loads overall.

     References: #1461(2)

   * `[orm]' ¶. Fixed bug introduced in 0.5.4 whereby
     Composite types fail when default-holding columns are flushed.

   * `[orm]' ¶. Fixed another 0.5.4 bug whereby mutable
     attributes (i.e.  PickleType) wouldn’t be deserialized correctly
     when the whole object was serialized.

     References: #1426(3)

   * `[orm]' ¶. Fixed bug whereby session.is_modified()
     would raise an exception if any synonyms were in use.

   * `[orm]' ¶. Fixed potential memory leak whereby
     previously pickled objects placed back in a session would not be
     fully garbage collected unless the Session were explicitly closed
     out.

   * `[orm]' ¶. Fixed bug whereby list-based attributes,
     like pickletype and PGArray, failed to be merged() properly.

   * `[orm]' ¶. Repaired non-working
     attributes.set_committed_value function.

   * `[orm]' ¶. Trimmed the pickle format for InstanceState
     which should further reduce the memory footprint of pickled
     instances.  The format should be backwards compatible with that of
     0.5.4 and previous.

   * `[orm]' ¶ sqlalchemy.orm.join and
     sqlalchemy.orm.outerjoin are now added to __all__ in
     sqlalchemy.orm.*.

     References: #1463(4)

   * `[orm]' ¶. Fixed bug where Query exception raise would
     fail when a too-short composite primary key value were passed to
     get().

     References: #1458(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1431

   (2) http://www.sqlalchemy.org/trac/ticket/1461

   (3) http://www.sqlalchemy.org/trac/ticket/1426

   (4) http://www.sqlalchemy.org/trac/ticket/1463

   (5) http://www.sqlalchemy.org/trac/ticket/1458

8.3.10.23 sql
.............

   * `[sql]' ¶. Removed an obscure feature of execute()
     (including connection, engine, Session) whereby a bindparam()
     construct can be sent as a key to the params dictionary.  This
     usage is undocumented and is at the core of an issue whereby the
     bindparam() object created implicitly by a text() construct may
     have the same hash value as a string placed in the params
     dictionary and may result in an inappropriate match when computing
     the final bind parameters.  Internal checks for this condition
     would add significant latency to the critical task of parameter
     rendering, so the behavior is removed.  This is a backwards
     incompatible change for any application that may have been using
     this feature, however the feature has never been documented.

8.3.10.24 misc
..............

   * `[engine/pool]' ¶. Implemented recreate() for
     StaticPool.

8.3.10.25 0.5.4p2
.................

Released: Tue May 26 2009

8.3.10.26 sql
.............

   * `[sql]' ¶. Repaired the printing of SQL exceptions
     which are not based on parameters or are not executemany() style.

8.3.10.27 postgresql
....................

   * `[postgresql]' ¶. Deprecated the hardcoded TIMESTAMP
     function, which when used as func.TIMESTAMP(value) would render
     “TIMESTAMP value”.  This breaks on some platforms as PostgreSQL
     doesn’t allow bind parameters to be used in this context.  The
     hard-coded uppercase is also inappropriate and there’s lots of
     other PG casts that we’d need to support.  So instead, use text
     constructs i.e.  select([“timestamp ‘12/05/09’”]).

8.3.10.28 0.5.4p1
.................

Released: Mon May 18 2009

8.3.10.29 orm
.............

   * `[orm]' ¶. Fixed an attribute error introduced in 0.5.4
     which would occur when merge() was used with an incomplete object.

8.3.10.30 0.5.4
...............

Released: Sun May 17 2009

8.3.10.31 orm
.............

   * `[orm]' ¶. Significant performance enhancements
     regarding Sessions/flush() in conjunction with large mapper graphs,
     large numbers of objects:

        - Removed all* O(N) scanning behavior from the flush() process,
          i.e.  operations that were scanning the full session,
          including an extremely expensive one that was erroneously
          assuming primary key values were changing when this was not
          the case.

             * one edge case remains which may invoke a full scan, if an
               existing primary key attribute is modified to a new
               value.

        - The Session’s “weak referencing” behavior is now `full' - no
          strong references whatsoever are made to a mapped object or
          related items/collections in its __dict__.  Backrefs and other
          cycles in objects no longer affect the Session’s ability to
          lose all references to unmodified objects.  Objects with
          pending changes still are maintained strongly until flush.

          The implementation also improves performance by moving the
          “resurrection” process of garbage collected items to only be
          relevant for mappings that map “mutable” attributes (i.e.
          PickleType, composite attrs).  This removes overhead from the
          gc process and simplifies internal behavior.

          If a “mutable” attribute change is the sole change on an
          object which is then dereferenced, the mapper will not have
          access to other attribute state when the UPDATE is issued.
          This may present itself differently to some MapperExtensions.

          The change also affects the internal attribute API, but not
          the AttributeExtension interface nor any of the publicly
          documented attribute functions.

        - The unit of work no longer generates a graph of “dependency”
          processors for the full graph of mappers during flush(),
          instead creating such processors only for those mappers which
          represent objects with pending changes.  This saves a
          tremendous number of method calls in the context of a large
          interconnected graph of mappers.

        - Cached a wasteful “table sort” operation that previously
          occurred multiple times per flush, also removing significant
          method call count from flush().

        - Other redundant behaviors have been simplified in
          mapper._save_obj().

     References: #1398(1)

   * `[orm]' ¶. Modified query_cls on DynamicAttributeImpl
     to accept a full mixin version of the AppenderQuery, which allows
     subclassing the AppenderMixin.

   * `[orm]' ¶. The “polymorphic discriminator” column may
     be part of a primary key, and it will be populated with the correct
     discriminator value.

     References: #1300(2)

   * `[orm]' ¶. Fixed the evaluator not being able to
     evaluate IS NULL clauses.

   * `[orm]' ¶. Fixed the “set collection” function on
     “dynamic” relations to initiate events correctly.  Previously a
     collection could only be assigned to a pending parent instance,
     otherwise modified events would not be fired correctly.  Set
     collection is now compatible with merge(), fixes.

     References: #1352(3)

   * `[orm]' ¶. Allowed pickling of PropertyOption objects
     constructed with instrumented descriptors; previously, pickle
     errors would occur when pickling an object which was loaded with a
     descriptor-based option, such as
     query.options(eagerload(MyClass.foo)).

   * `[orm]' ¶. Lazy loader will not use get() if the “lazy
     load” SQL clause matches the clause used by get(), but contains
     some parameters hardcoded.  Previously the lazy strategy would fail
     with the get().  Ideally get() would be used with the hardcoded
     parameters but this would require further development.

     References: #1357(4)

   * `[orm]' ¶. MapperOptions and other state associated
     with query.options() is no longer bundled within callables
     associated with each lazy/deferred-loading attribute during a load.
     The options are now associated with the instance’s state object
     just once when it’s populated.  This removes the need in most cases
     for per-instance/attribute loader objects, improving load speed and
     memory overhead for individual instances.

     References: #1391(5)

   * `[orm]' ¶. Fixed another location where autoflush was
     interfering with session.merge().  autoflush is disabled completely
     for the duration of merge() now.

     References: #1360(6)

   * `[orm]' ¶. Fixed bug which prevented “mutable primary
     key” dependency logic from functioning properly on a one-to-one
     relation().

     References: #1406(7)

   * `[orm]' ¶. Fixed bug in relation(), introduced in
     0.5.3, whereby a self referential relation from a base class to a
     joined-table subclass would not configure correctly.

   * `[orm]' ¶. Fixed obscure mapper compilation issue when
     inheriting mappers are used which would result in un-initialized
     attributes.

   * `[orm]' ¶. Fixed documentation for session
     weak_identity_map - the default value is True, indicating a weak
     referencing map in use.

   * `[orm]' ¶. Fixed a unit of work issue whereby the
     foreign key attribute on an item contained within a collection
     owned by an object being deleted would not be set to None if the
     relation() was self-referential.

     References: #1376(8)

   * `[orm]' ¶. Fixed Query.update() and Query.delete()
     failures with eagerloaded relations.

     References: #1378(9)

   * `[orm]' ¶. It is now an error to specify both columns
     of a binary primaryjoin condition in the foreign_keys or
     remote_side collection.  Whereas previously it was just
     nonsensical, but would succeed in a non-deterministic way.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1398

   (2) http://www.sqlalchemy.org/trac/ticket/1300

   (3) http://www.sqlalchemy.org/trac/ticket/1352

   (4) http://www.sqlalchemy.org/trac/ticket/1357

   (5) http://www.sqlalchemy.org/trac/ticket/1391

   (6) http://www.sqlalchemy.org/trac/ticket/1360

   (7) http://www.sqlalchemy.org/trac/ticket/1406

   (8) http://www.sqlalchemy.org/trac/ticket/1376

   (9) http://www.sqlalchemy.org/trac/ticket/1378

8.3.10.32 sql
.............

   * `[sql]' ¶. Back-ported the “compiler” extension from
     SQLA 0.6.  This is a standardized interface which allows the
     creation of custom ClauseElement subclasses and compilers.  In
     particular it’s handy as an alternative to text() when you’d like
     to build a construct that has database-specific compilations.  See
     the extension docs for details.

   * `[sql]' ¶. Exception messages are truncated when the
     list of bound parameters is larger than 10, preventing enormous
     multi-page exceptions from filling up screens and logfiles for
     large executemany() statements.

     References: #1413(1)

   * `[sql]' ¶. ‘sqlalchemy.extract()’ is now dialect
     sensitive and can extract components of timestamps idiomatically
     across the supported databases, including SQLite.

   * `[sql]' ¶. Fixed __repr__() and other _get_colspec()
     methods on ForeignKey constructed from __clause_element__() style
     construct (i.e.  declarative columns).

     References: #1353(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1413

   (2) http://www.sqlalchemy.org/trac/ticket/1353

8.3.10.33 schema
................

   * `[schema] [1341] [ticket: 594]' ¶. Added a
     quote_schema() method to the IdentifierPreparer class so that
     dialects can override how schemas get handled.  This enables the
     MSSQL dialect to treat schemas as multipart identifiers, such as
     ‘database.owner’.

8.3.10.34 extensions
....................

   * `[extensions]' ¶. Fixed adding of deferred or other
     column properties to a declarative class.

     References: #1379(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1379

8.3.10.35 mysql
...............

   * `[mysql]' ¶. Reflecting a FOREIGN KEY construct will
     take into account a dotted schema.tablename combination, if the
     foreign key references a table in a remote schema.

     References: #1405(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1405

8.3.10.36 sqlite
................

   * `[sqlite]' ¶. Corrected the SLBoolean type so that it
     properly treats only 1 as True.

     References: #1402(1)

   * `[sqlite]' ¶. Corrected the float type so that it
     correctly maps to a SLFloat type when being reflected.

     References: #1273(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1402

   (2) http://www.sqlalchemy.org/trac/ticket/1273

8.3.10.37 mssql
...............

   * `[mssql]' ¶. Modified how savepoint logic works to
     prevent it from stepping on non-savepoint oriented routines.
     Savepoint support is still very experimental.

   * `[mssql]' ¶. Added in reserved words for MSSQL that
     covers version 2008 and all prior versions.

     References: #1310(1)

   * `[mssql]' ¶. Corrected problem with information schema
     not working with a binary collation based database.  Cleaned up
     information schema since it is only used by mssql now.

     References: #1343(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1310

   (2) http://www.sqlalchemy.org/trac/ticket/1343

8.3.10.38 0.5.3
...............

Released: Tue Mar 24 2009

8.3.10.39 orm
.............

   * `[orm]' ¶. The “objects” argument to session.flush() is
     deprecated.  State which represents the linkage between a parent
     and child object does not support “flushed” status on one side of
     the link and not the other, so supporting this operation leads to
     misleading results.

     References: #1315(1)

   * `[orm]' ¶. Query now implements __clause_element__()
     which produces its selectable, which means a Query instance can be
     accepted in many SQL expressions, including col.in_(query),
     union(query1, query2), select([foo]).select_from(query), etc.

   * `[orm]' ¶. Query.join() can now construct multiple FROM
     clauses, if needed.  Such as, query(A, B).join(A.x).join(B.y) might
     say SELECT A.*, B.* FROM A JOIN X, B JOIN Y. Eager loading can also
     tack its joins onto those multiple FROM clauses.

     References: #1337(2)

   * `[orm]' ¶. Fixed bug in dynamic_loader() where
     append/remove events after construction time were not being
     propagated to the UOW to pick up on flush().

     References: #1347(3)

   * `[orm]' ¶. Fixed bug where column_prefix wasn’t being
     checked before not mapping an attribute that already had
     class-level name present.

   * `[orm]' ¶ a session.expire() on a particular
     collection attribute will clear any pending backref additions as
     well, so that the next access correctly returns only what was
     present in the database.  Presents some degree of a workaround for,
     although we are considering removing the flush([objects]) feature
     altogether.

     References: #1315(4)

   * `[orm]' ¶. Session.scalar() now converts raw SQL
     strings to text() the same way Session.execute() does and accepts
     same alternative **kw args.

   * `[orm]' ¶ improvements to the “determine direction”
     logic of relation() such that the direction of tricky situations
     like mapper(A.join(B)) -> relation-> mapper(B) can be determined.

   * `[orm]' ¶. When flushing partial sets of objects using
     session.flush([somelist]), pending objects which remain pending
     after the operation won’t inadvertently be added as persistent.

     References: #1306(5)

   * `[orm]' ¶. Added “post_configure_attribute” method to
     InstrumentationManager, so that the “listen_for_events.py” example
     works again.

     References: #1314(6)

   * `[orm]' ¶ a forward and complementing backwards
     reference which are both of the same direction, i.e.  ONETOMANY or
     MANYTOONE, is now detected, and an error message is raised.  Saves
     crazy CircularDependencyErrors later on.

   * `[orm]' ¶. Fixed bugs in Query regarding simultaneous
     selection of multiple joined-table inheritance entities with common
     base classes:

        - previously the adaption applied to “B” on “A JOIN B” would be
          erroneously partially applied to “A”.

        - comparisons on relations (i.e.  A.related==someb) were not
          getting adapted when they should.

        - Other filterings, like
          query(A).join(A.bs).filter(B.foo==’bar’), were erroneously
          adapting “B.foo” as though it were an “A”.

   * `[orm]' ¶. Fixed adaptation of EXISTS clauses via
     any(), has(), etc.  in conjunction with an aliased object on the
     left and of_type() on the right.

     References: #1325(7)

   * `[orm]' ¶. Added an attribute helper method
     ‘set_committed_value’ in sqlalchemy.orm.attributes.  Given an
     object, attribute name, and value, will set the value on the object
     as part of its “committed” state, i.e.  state that is understood to
     have been loaded from the database.  Helps with the creation of
     homegrown collection loaders and such.

   * `[orm]' ¶. Query won’t fail with weakref error when a
     non-mapper/class instrumented descriptor is passed, raises “Invalid
     column expression”.

   * `[orm]' ¶. Query.group_by() properly takes into account
     aliasing applied to the FROM clause, such as with select_from(),
     using with_polymorphic(), or using from_self().

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1315

   (2) http://www.sqlalchemy.org/trac/ticket/1337

   (3) http://www.sqlalchemy.org/trac/ticket/1347

   (4) http://www.sqlalchemy.org/trac/ticket/1315

   (5) http://www.sqlalchemy.org/trac/ticket/1306

   (6) http://www.sqlalchemy.org/trac/ticket/1314

   (7) http://www.sqlalchemy.org/trac/ticket/1325

8.3.10.40 sql
.............

   * `[sql]' ¶. An alias() of a select() will convert to a
     “scalar subquery” when used in an unambiguously scalar context,
     i.e.  it’s used in a comparison operation.  This applies to the ORM
     when using query.subquery() as well.

   * `[sql]' ¶. Fixed missing _label attribute on Function
     object, others when used in a select() with use_labels (such as
     when used in an ORM column_property()).

     References: #1302(1)

   * `[sql]' ¶ anonymous alias names now truncate down to
     the max length allowed by the dialect.  More significant on DBs
     like Oracle with very small character limits.

     References: #1309(2)

   * `[sql]' ¶ the __selectable__() interface has been
     replaced entirely by __clause_element__().

   * `[sql]' ¶. The per-dialect cache used by TypeEngine to
     cache dialect-specific types is now a WeakKeyDictionary.  This to
     prevent dialect objects from being referenced forever for an
     application that creates an arbitrarily large number of engines or
     dialects.  There is a small performance penalty which will be
     resolved in 0.6.

     References: #1299(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1302

   (2) http://www.sqlalchemy.org/trac/ticket/1309

   (3) http://www.sqlalchemy.org/trac/ticket/1299

8.3.10.41 extensions
....................

   * `[extensions]' ¶. Fixed a recursive pickling issue in
     serializer, triggered by an EXISTS or other embedded FROM
     construct.

   * `[extensions]' ¶. Declarative locates the “inherits”
     class using a search through __bases__, to skip over mixins that
     are local to subclasses.

   * `[extensions]' ¶. Declarative figures out joined-table
     inheritance primary join condition even if “inherits” mapper
     argument is given explicitly.

   * `[extensions]' ¶. Declarative will properly interpret
     the “foreign_keys” argument on a backref() if it’s a string.

   * `[extensions]' ¶. Declarative will accept a table-bound
     column as a property when used in conjunction with __table__, if
     the column is already present in __table__.  The column will be
     remapped to the given key the same way as when added to the
     mapper() properties dict.

8.3.10.42 postgresql
....................

   * `[postgresql]' ¶. Index reflection won’t fail when an
     index with multiple expressions is encountered.

   * `[postgresql]' ¶. Added PGUuid and PGBit types to
     sqlalchemy.databases.postgres.

     References: #1327(1)

   * `[postgresql]' ¶. Refection of unknown PG types won’t
     crash when those types are specified within a domain.

     References: #1327(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1327

   (2) http://www.sqlalchemy.org/trac/ticket/1327

8.3.10.43 sqlite
................

   * `[sqlite]' ¶. Fixed SQLite reflection methods so that
     non-present cursor.description, which triggers an auto-cursor
     close, will be detected so that no results doesn’t fail on recent
     versions of pysqlite which raise an error when fetchone() called
     with no rows present.

8.3.10.44 mssql
...............

   * `[mssql]' ¶. Preliminary support for pymssql 1.0.1

   * `[mssql]' ¶. Corrected issue on mssql where
     max_identifier_length was not being respected.

8.3.10.45 0.5.2
...............

Released: Sat Jan 24 2009

8.3.10.46 orm
.............

   * `[orm]' ¶. Further refined 0.5.1’s warning about
     delete-orphan cascade placed on a many-to-many relation.  First,
     the bad news: the warning will apply to both many-to-many as well
     as many-to-one relations.  This is necessary since in both cases,
     SQLA does not scan the full set of potential parents when
     determining “orphan” status - for a persistent object it only
     detects an in-python de-association event to establish the object
     as an “orphan”.  Next, the good news: to support one-to-one via a
     foreign key or association table, or to support one-to-many via an
     association table, a new flag single_parent=True may be set which
     indicates objects linked to the relation are only meant to have a
     single parent.  The relation will raise an error if multiple
     parent-association events occur within Python.

   * `[orm]' ¶. Adjusted the attribute instrumentation
     change from 0.5.1 to fully establish instrumentation for subclasses
     where the mapper was created after the superclass had already been
     fully instrumented.

     References: #1292(1)

   * `[orm]' ¶. Fixed bug in delete-orphan cascade whereby
     two one-to-one relations from two different parent classes to the
     same target class would prematurely expunge the instance.

   * `[orm]' ¶. Fixed an eager loading bug whereby
     self-referential eager loading would prevent other eager loads,
     self referential or not, from joining to the parent JOIN properly.
     Thanks to Alex K for creating a great test case.

   * `[orm]' ¶ session.expire() and related methods will
     not expire() unloaded deferred attributes.  This prevents them from
     being needlessly loaded when the instance is refreshed.

   * `[orm]' ¶ query.join()/outerjoin() will now properly
     join an aliased() construct to the existing left side, even if
     query.from_self() or query.select_from(someselectable) has been
     called.

     References: #1293(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1292

   (2) http://www.sqlalchemy.org/trac/ticket/1293

8.3.10.47 sql
.............

   * `[sql]' ¶.

     Further fixes to the “percent signs and spaces in column/table

          names” functionality.

     References: #1284(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1284

8.3.10.48 mssql
...............

   * `[mssql]' ¶. Restored convert_unicode handling.
     Results were being passed on through without conversion.

     References: #1291(1)

   * `[mssql]' ¶. Really fixing the decimal handling this
     time..

     References: #1282(2)

   * `[mssql] [Ticket:1289]' ¶. Modified table reflection
     code to use only kwargs when constructing tables.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1291

   (2) http://www.sqlalchemy.org/trac/ticket/1282

8.3.10.49 0.5.1
...............

Released: Sat Jan 17 2009

8.3.10.50 orm
.............

   * `[orm]' ¶. Removed an internal join cache which could
     potentially leak memory when issuing query.join() repeatedly to
     ad-hoc selectables.

   * `[orm]' ¶. The “clear()”, “save()”, “update()”,
     “save_or_update()” Session methods have been deprecated, replaced
     by “expunge_all()” and “add()”.  “expunge_all()” has also been
     added to ScopedSession.

   * `[orm]' ¶. Modernized the “no mapped table” exception
     and added a more explicit __table__/__tablename__ exception to
     declarative.

   * `[orm]' ¶. Concrete inheriting mappers now instrument
     attributes which are inherited from the superclass, but are not
     defined for the concrete mapper itself, with an
     InstrumentedAttribute that issues a descriptive error when
     accessed.

     References: #1237(1)

   * `[orm]' ¶. Added a new ‘relation()’ keyword
     ‘back_populates’.  This allows configuration of backreferences
     using explicit relations.  This is required when creating
     bidirectional relations between a hierarchy of concrete mappers and
     another class.

     References: #1237(2), #781(3)

   * `[orm]' ¶. Test coverage added for ‘relation()’ objects
     specified on concrete mappers.

     References: #1237(4)

   * `[orm]' ¶. Query.from_self() as well as
     query.subquery() both disable the rendering of eager joins inside
     the subquery produced.  The “disable all eager joins” feature is
     available publicly via a new query.enable_eagerloads() generative.

     References: #1276(5)

   * `[orm]' ¶. Added a rudimental series of set operations
     to Query that receive Query objects as arguments, including
     union(), union_all(), intersect(), except_(), intersect_all(),
     except_all().  See the API documentation for Query.union() for
     examples.

   * `[orm]' ¶. Fixed bug that prevented Query.join() and
     eagerloads from attaching to a query that selected from a union or
     aliased union.

   * `[orm]' ¶. A short documentation example added for
     bidirectional relations specified on concrete mappers.

     References: #1237(6)

   * `[orm]' ¶. Mappers now instrument class attributes upon
     construction with the final InstrumentedAttribute object which
     remains persistent.  The ‘_CompileOnAttr’/‘__getattribute__()’
     methodology has been removed.  The net effect is that Column-based
     mapped class attributes can now be used fully at the class level
     without invoking a mapper compilation operation, greatly
     simplifying typical usage patterns within declarative.

     References: #1269(7)

   * `[orm]' ¶. ColumnProperty (and front-end helpers such
     as ‘deferred’) no longer ignores unknown **keyword arguments.

   * `[orm]' ¶. Fixed a bug with the unitofwork’s “row
     switch” mechanism, i.e.  the conversion of INSERT/DELETE into an
     UPDATE, when combined with joined-table inheritance and an object
     which contained no defined values for the child table where an
     UPDATE with no SET clause would be rendered.

   * `[orm]' ¶. Using delete-orphan on a many-to-many
     relation is deprecated.  This produces misleading or erroneous
     results since SQLA does not retrieve the full list of “parents” for
     m2m.  To get delete-orphan behavior with an m2m table, use an
     explicit association class so that the individual association row
     is treated as a parent.

     References: #1281(8)

   * `[orm]' ¶ delete-orphan cascade always requires delete
     cascade.  Specifying delete-orphan without delete now raises a
     deprecation warning.

     References: #1281(9)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1237

   (2) http://www.sqlalchemy.org/trac/ticket/1237

   (3) http://www.sqlalchemy.org/trac/ticket/781

   (4) http://www.sqlalchemy.org/trac/ticket/1237

   (5) http://www.sqlalchemy.org/trac/ticket/1276

   (6) http://www.sqlalchemy.org/trac/ticket/1237

   (7) http://www.sqlalchemy.org/trac/ticket/1269

   (8) http://www.sqlalchemy.org/trac/ticket/1281

   (9) http://www.sqlalchemy.org/trac/ticket/1281

8.3.10.51 sql
.............

   * `[sql]' ¶. Improved the methodology to handling percent
     signs in column names from.  Added more tests.  MySQL and
     PostgreSQL dialects still do not issue correct CREATE TABLE
     statements for identifiers with percent signs in them.

     References: #1256(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1256

8.3.10.52 schema
................

   * `[schema]' ¶. Index now accepts column-oriented
     InstrumentedAttributes (i.e.  column-based mapped class attributes)
     as column arguments.

     References: #1214(1)

   * `[schema]' ¶. Column with no name (as in declarative)
     won’t raise a NoneType error when its string output is requested
     (such as in a stack trace).

   * `[schema]' ¶. Fixed bug when overriding a Column with a
     ForeignKey on a reflected table, where derived columns (i.e.  the
     “virtual” columns of a select, etc.)  would inadvertently call upon
     schema-level cleanup logic intended only for the original column.

     References: #1278(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1214

   (2) http://www.sqlalchemy.org/trac/ticket/1278

8.3.10.53 mysql
...............

   * `[mysql]' ¶. Added the missing keywords from MySQL 4.1
     so they get escaped properly.

8.3.10.54 mssql
...............

   * `[mssql]' ¶. Corrected handling of large decimal values
     with more robust tests.  Removed string manipulation on floats.

     References: #1280(1)

   * `[mssql]' ¶. Modified the do_begin handling in mssql to
     use the Cursor not the Connection so it is DBAPI compatible.

   * `[mssql]' ¶. Corrected SAVEPOINT support on adodbapi by
     changing the handling of savepoint_release, which is unsupported on
     mssql.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1280

8.3.10.55 misc
..............

   * `[declarative]' ¶. Can now specify Column objects on
     subclasses which have no table of their own (i.e.  use single table
     inheritance).  The columns will be appended to the base table, but
     only mapped by the subclass.

   * `[declarative]' ¶. For both joined and single
     inheriting subclasses, the subclass will only map those columns
     which are already mapped on the superclass and those explicit on
     the subclass.  Other columns that are present on the ‘Table’ will
     be excluded from the mapping by default, which can be disabled by
     passing a blank ‘exclude_properties’ collection to the
     ‘__mapper_args__’.  This is so that single-inheriting classes which
     define their own columns are the only classes to map those columns.
     The effect is actually a more organized mapping than you’d normally
     get with explicit ‘mapper()’ calls unless you set up the
     ‘exclude_properties’ arguments explicitly.

   * `[declarative]' ¶. It’s an error to add new Column
     objects to a declarative class that specified an existing table
     using __table__.

8.3.10.56 0.5.0
...............

Released: Tue Jan 06 2009

8.3.10.57 general
.................

   * `[general]' ¶. Documentation has been converted to
     Sphinx.  In particular, the generated API documentation has been
     constructed into a full blown “API Reference” section which
     organizes editorial documentation combined with generated
     docstrings.  Cross linking between sections and API docs are vastly
     improved, a javascript-powered search feature is provided, and a
     full index of all classes, functions and members is provided.

   * `[general]' ¶ setup.py now imports setuptools only
     optionally.  If not present, distutils is used.  The new “pip”
     installer is recommended over easy_install as it installs in a more
     simplified way.

   * `[general]' ¶ added an extremely basic illustration of
     a PostGIS integration to the examples folder.

8.3.10.58 orm
.............

   * `[orm]' ¶. Query.with_polymorphic() now accepts a third
     argument “discriminator” which will replace the value of
     mapper.polymorphic_on for that query.  Mappers themselves no longer
     require polymorphic_on to be set, even if the mapper has a
     polymorphic_identity.  When not set, the mapper will load
     non-polymorphically by default.  Together, these two features allow
     a non-polymorphic concrete inheritance setup to use polymorphic
     loading on a per-query basis, since concrete setups are prone to
     many issues when used polymorphically in all cases.

   * `[orm]' ¶ dynamic_loader accepts a query_class= to
     customize the Query classes used for both the dynamic collection
     and the queries built from it.

   * `[orm]' ¶ query.order_by() accepts None which will
     remove any pending order_by state from the query, as well as cancel
     out any mapper/relation configured ordering.  This is primarily
     useful for overriding the ordering specified on a dynamic_loader().

     References: #1079(1)

   * `[orm]' ¶. Exceptions raised during compile_mappers()
     are now preserved to provide “sticky behavior” - if a hasattr()
     call on a pre-compiled mapped attribute triggers a failing compile
     and suppresses the exception, subsequent compilation is blocked and
     the exception will be reiterated on the next compile() call.  This
     issue occurs frequently when using declarative.

   * `[orm]' ¶ property.of_type() is now recognized on a
     single-table inheriting target, when used in the context of
     prop.of_type(..).any()/has(), as well as
     query.join(prop.of_type(…)).

   * `[orm]' ¶ query.join() raises an error when the target
     of the join doesn’t match the property-based attribute - while it’s
     unlikely anyone is doing this, the SQLAlchemy author was guilty of
     this particular loosey-goosey behavior.

   * `[orm]' ¶. Fixed bug when using weak_instance_map=False
     where modified events would not be intercepted for a flush().

     References: #1272(2)

   * `[orm]' ¶. Fixed some deep “column correspondence”
     issues which could impact a Query made against a selectable
     containing multiple versions of the same table, as well as unions
     and similar which contained the same table columns in different
     column positions at different levels.

     References: #1268(3)

   * `[orm]' ¶. Custom comparator classes used in
     conjunction with column_property(), relation() etc.  can define new
     comparison methods on the Comparator, which will become available
     via __getattr__() on the InstrumentedAttribute.  In the case of
     synonym() or comparable_property(), attributes are resolved first
     on the user-defined descriptor, then on the user-defined
     comparator.

   * `[orm]' ¶. Added ScopedSession.is_active accessor.

     References: #976(4)

   * `[orm]' ¶. Can pass mapped attributes and column
     objects as keys to query.update({}).

     References: #1262(5)

   * `[orm]' ¶. Mapped attributes passed to the values() of
     an expression level insert() or update() will use the keys of the
     mapped columns, not that of the mapped attribute.

   * `[orm]' ¶. Corrected problem with Query.delete() and
     Query.update() not working properly with bind parameters.

     References: #1242(6)

   * `[orm]' ¶. Query.select_from(), from_statement() ensure
     that the given argument is a FromClause, or Text/Select/Union,
     respectively.

   * `[orm]' ¶. Query() can be passed a “composite”
     attribute as a column expression and it will be expanded.  Somewhat
     related to.

     References: #1253(7)

   * `[orm]' ¶. Query() is a little more robust when passed
     various column expressions such as strings, clauselists, text()
     constructs (which may mean it just raises an error more nicely).

   * `[orm]' ¶ first() works as expected with
     Query.from_statement().

   * `[orm]' ¶. Fixed bug introduced in 0.5rc4 involving
     eager loading not functioning for properties which were added to a
     mapper post-compile using add_property() or equivalent.

   * `[orm]' ¶. Fixed bug where many-to-many relation() with
     viewonly=True would not correctly reference the link between
     secondary->remote.

   * `[orm]' ¶. Duplicate items in a list-based collection
     will be maintained when issuing INSERTs to a “secondary” table in a
     many-to-many relation.  Assuming the m2m table has a unique or
     primary key constraint on it, this will raise the expected
     constraint violation instead of silently dropping the duplicate
     entries.  Note that the old behavior remains for a one-to-many
     relation since collection entries in that case don’t result in
     INSERT statements and SQLA doesn’t manually police collections.

     References: #1232(8)

   * `[orm]' ¶. Query.add_column() can accept FromClause
     objects in the same manner as session.query() can.

   * `[orm]' ¶. Comparison of many-to-one relation to NULL
     is properly converted to IS NOT NULL based on not_().

   * `[orm]' ¶. Extra checks added to ensure explicit
     primaryjoin/secondaryjoin are ClauseElement instances, to prevent
     more confusing errors later on.

     References: #1087(9)

   * `[orm]' ¶. Improved mapper() check for non-class
     classes.

     References: #1236(10)

   * `[orm]' ¶ comparator_factory argument is now
     documented and supported by all MapperProperty types, including
     column_property(), relation(), backref(), and synonym().

     References: #5051(11)

   * `[orm]' ¶. Changed the name of PropertyLoader to
     RelationProperty, to be consistent with all the other names.
     PropertyLoader is still present as a synonym.

   * `[orm]' ¶ fixed “double iter()” call causing bus
     errors in shard API, removed errant result.close() left over from
     the 0.4 version.

     References: #1099(12), #1228(13)

   * `[orm]' ¶ made Session.merge cascades not trigger
     autoflush.  Fixes merged instances getting prematurely inserted
     with missing values.

   * `[orm]' ¶. Two fixes to help prevent out-of-band
     columns from being rendered in polymorphic_union inheritance
     scenarios (which then causes extra tables to be rendered in the
     FROM clause causing cartesian products):

             - improvements to “column adaption” for a->b->c inheritance
               situations to better locate columns that are related to
               one another via multiple levels of indirection, rather
               than rendering the non-adapted column.

             - the “polymorphic discriminator” column is only rendered
               for the actual mapper being queried against.  The column
               won’t be “pulled in” from a subclass or superclass mapper
               since it’s not needed.

   * `[orm]' ¶. Fixed shard_id argument on
     ShardedSession.execute().

     References: #1072(14)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1079

   (2) http://www.sqlalchemy.org/trac/ticket/1272

   (3) http://www.sqlalchemy.org/trac/ticket/1268

   (4) http://www.sqlalchemy.org/trac/ticket/976

   (5) http://www.sqlalchemy.org/trac/ticket/1262

   (6) http://www.sqlalchemy.org/trac/ticket/1242

   (7) http://www.sqlalchemy.org/trac/ticket/1253

   (8) http://www.sqlalchemy.org/trac/ticket/1232

   (9) http://www.sqlalchemy.org/trac/ticket/1087

   (10) http://www.sqlalchemy.org/trac/ticket/1236

   (11) http://www.sqlalchemy.org/trac/ticket/5051

   (12) http://www.sqlalchemy.org/trac/ticket/1099

   (13) http://www.sqlalchemy.org/trac/ticket/1228

   (14) http://www.sqlalchemy.org/trac/ticket/1072

8.3.10.59 sql
.............

   * `[sql]' ¶. RowProxy objects can be used in place of
     dictionary arguments sent to connection.execute() and friends.

     References: #935(1)

   * `[sql]' ¶. Columns can again contain percent signs
     within their names.

     References: #1256(2)

   * `[sql]' ¶ sqlalchemy.sql.expression.Function is now a
     public class.  It can be subclassed to provide user-defined SQL
     functions in an imperative style, including with pre-established
     behaviors.  The postgis.py example illustrates one usage of this.

   * `[sql]' ¶. PickleType now favors == comparison by
     default, if the incoming object (such as a dict) implements
     __eq__().  If the object does not implement __eq__() and
     mutable=True, a deprecation warning is raised.

   * `[sql]' ¶. Fixed the import weirdness in sqlalchemy.sql
     to not export __names__.

     References: #1215(3)

   * `[sql]' ¶. Using the same ForeignKey object repeatedly
     raises an error instead of silently failing later.

     References: #1238(4)

   * `[sql]' ¶. Added NotImplementedError for params()
     method on Insert/Update/Delete constructs.  These items currently
     don’t support this functionality, which also would be a little
     misleading compared to values().

   * `[sql]' ¶. Reflected foreign keys will properly locate
     their referenced column, even if the column was given a “key”
     attribute different from the reflected name.  This is achieved via
     a new flag on ForeignKey/ForeignKeyConstraint called
     “link_to_name”, if True means the given name is the referred-to
     column’s name, not its assigned key.

     References: #650(5)

   * `[sql]' ¶ select() can accept a ClauseList as a column
     in the same way as a Table or other selectable and the interior
     expressions will be used as column elements.

     References: #1253(6)

   * `[sql]' ¶ the “passive” flag on session.is_modified()
     is correctly propagated to the attribute manager.

   * `[sql]' ¶ union() and union_all() will not whack any
     order_by() that has been applied to the select()s inside.  If you
     union() a select() with order_by() (presumably to support
     LIMIT/OFFSET), you should also call self_group() on it to apply
     parenthesis.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/935

   (2) http://www.sqlalchemy.org/trac/ticket/1256

   (3) http://www.sqlalchemy.org/trac/ticket/1215

   (4) http://www.sqlalchemy.org/trac/ticket/1238

   (5) http://www.sqlalchemy.org/trac/ticket/650

   (6) http://www.sqlalchemy.org/trac/ticket/1253

8.3.10.60 mysql
...............

   * `[mysql]' ¶. ”%” signs in text() constructs are
     automatically escaped to “%%”.  Because of the backwards
     incompatible nature of this change, a warning is emitted if ‘%%’ is
     detected in the string.

   * `[mysql]' ¶. Fixed bug in exception raise when FK
     columns not present during reflection.

     References: #1241(1)

   * `[mysql]' ¶. Fixed bug involving reflection of a
     remote-schema table with a foreign key ref to another table in that
     schema.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1241

8.3.10.61 sqlite
................

   * `[sqlite]' ¶. Table reflection now stores the actual
     DefaultClause value for the column.

     References: #1266(1)

   * `[sqlite]' ¶ bugfixes, behavioral changes

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1266

8.3.10.62 mssql
...............

   * `[mssql]' ¶. Added in a new MSGenericBinary type.  This
     maps to the Binary type so it can implement the specialized
     behavior of treating length specified types as fixed-width Binary
     types and non-length types as an unbound variable length Binary
     type.

   * `[mssql]' ¶. Added in new types: MSVarBinary and
     MSImage.

     References: #1249(1)

   * `[mssql]' ¶. Added in the MSReal, MSNText,
     MSSmallDateTime, MSTime, MSDateTimeOffset, and MSDateTime2 types

   * `[mssql]' ¶. Refactored the Date/Time types.  The
     ‘smalldatetime’ data type no longer truncates to a date only, and
     will now be mapped to the MSSmallDateTime type.

     References: #1254(2)

   * `[mssql]' ¶. Corrected an issue with Numerics to accept
     an int.

   * `[mssql]' ¶. Mapped ‘char_length’ to the ‘LEN()’
     function.

   * `[mssql]' ¶. If an ‘INSERT’ includes a subselect the
     ‘INSERT’ is converted from an ‘INSERT INTO VALUES’ construct to a
     ‘INSERT INTO SELECT’ construct.

   * `[mssql]' ¶. If the column is part of a ‘primary_key’
     it will be ‘NOT NULL’ since MSSQL doesn’t allow ‘NULL’ in
     primary_key columns.

   * `[mssql]' ¶. ‘MSBinary’ now returns a ‘BINARY’ instead
     of an ‘IMAGE’.  This is a backwards incompatible change in that
     ‘BINARY’ is a fixed length data type whereas ‘IMAGE’ is a variable
     length data type.

     References: #1249(3)

   * `[mssql]' ¶. ‘get_default_schema_name’ is now reflected
     from the database based on the user’s default schema.  This only
     works with MSSQL 2005 and later.

     References: #1258(4)

   * `[mssql]' ¶. Added collation support through the use of
     a new collation argument.  This is supported on the following
     types: char, nchar, varchar, nvarchar, text, ntext.

     References: #1248(5)

   * `[mssql]' ¶. Changes to the connection string
     parameters favor DSN as the default specification for pyodbc.  See
     the mssql.py docstring for detailed usage instructions.

   * `[mssql]' ¶. Added experimental support of savepoints.
     It currently does not work fully with sessions.

   * `[mssql]' ¶. Support for three levels of column
     nullability: NULL, NOT NULL, and the database’s configured default.
     The default Column configuration (nullable=True) will now generate
     NULL in the DDL. Previously no specification was emitted and the
     database default would take effect (usually NULL, but not always).
     To explicitly request the database default, configure columns with
     nullable=None and no specification will be emitted in DDL. This is
     backwards incompatible behavior.

     References: #1243(6)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1249

   (2) http://www.sqlalchemy.org/trac/ticket/1254

   (3) http://www.sqlalchemy.org/trac/ticket/1249

   (4) http://www.sqlalchemy.org/trac/ticket/1258

   (5) http://www.sqlalchemy.org/trac/ticket/1248

   (6) http://www.sqlalchemy.org/trac/ticket/1243

8.3.10.63 oracle
................

   * `[oracle]' ¶. Adjusted the format of create_xid() to
     repair two-phase commit.  We now have field reports of Oracle
     two-phase commit working properly with this change.

   * `[oracle]' ¶. Added OracleNVarchar type, produces
     NVARCHAR2, and also subclasses Unicode so that convert_unicode=True
     by default.  NVARCHAR2 reflects into this type automatically so
     these columns pass unicode on a reflected table with no explicit
     convert_unicode=True flags.

     References: #1233(1)

   * `[oracle]' ¶. Fixed bug which was preventing out params
     of certain types from being received; thanks a ton to huddlej at
     wwu.edu !

     References: #1265(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1233

   (2) http://www.sqlalchemy.org/trac/ticket/1265

8.3.10.64 misc
..............

   * `[dialect]' ¶. Added a new description_encoding
     attribute on the dialect that is used for encoding the column name
     when processing the metadata.  This usually defaults to utf-8.

   * `[engine/pool]' ¶. Connection.invalidate() checks for
     closed status to avoid attribute errors.

     References: #1246(1)

   * `[engine/pool]' ¶. NullPool supports reconnect on
     failure behavior.

     References: #1094(2)

   * `[engine/pool]' ¶. Added a mutex for the initial pool
     creation when using pool.manage(dbapi).  This prevents a minor case
     of “dogpile” behavior which would otherwise occur upon a heavy load
     startup.

     References: #799(3)

   * `[engine/pool]' ¶. _execute_clauseelement() goes back
     to being a private method.  Subclassing Connection is not needed
     now that ConnectionProxy is available.

   * `[documentation]' ¶. Tickets.

     References: #1149(4), #1200(5)

   * `[documentation]' ¶. Added note about create_session()
     defaults.

   * `[documentation]' ¶. Added section about
     metadata.reflect().

   * `[documentation]' ¶. Updated ‘TypeDecorator’ section.

   * `[documentation]' ¶. Rewrote the “threadlocal” strategy
     section of the docs due to recent confusion over this feature.

   * `[documentation]' ¶. Removed badly out of date
     ‘polymorphic_fetch’ and ‘select_table’ docs from inheritance,
     reworked the second half of “joined table inheritance”.

   * `[documentation]' ¶. Documented ‘comparator_factory’
     kwarg, added new doc section “Custom Comparators”.

   * `[postgres]' ¶. ”%” signs in text() constructs are
     automatically escaped to “%%”.  Because of the backwards
     incompatible nature of this change, a warning is emitted if ‘%%’ is
     detected in the string.

     References: #1267(6)

   * `[postgres]' ¶. Calling alias.execute() in conjunction
     with server_side_cursors won’t raise AttributeError.

   * `[postgres]' ¶. Added Index reflection support to
     PostgreSQL, using a great patch we long neglected, submitted by Ken
     Kuhlman.

     References: #714(7)

   * `[associationproxy]' ¶. The association proxy
     properties are make themselves available at the class level, e.g.
     MyClass.aproxy.  Previously this evaluated to None.

   * `[declarative]' ¶. The full list of arguments accepted
     as string by backref() includes ‘primaryjoin’, ‘secondaryjoin’,
     ‘secondary’, ‘foreign_keys’, ‘remote_side’, ‘order_by’.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1246

   (2) http://www.sqlalchemy.org/trac/ticket/1094

   (3) http://www.sqlalchemy.org/trac/ticket/799

   (4) http://www.sqlalchemy.org/trac/ticket/1149

   (5) http://www.sqlalchemy.org/trac/ticket/1200

   (6) http://www.sqlalchemy.org/trac/ticket/1267

   (7) http://www.sqlalchemy.org/trac/ticket/714

8.3.10.65 0.5.0rc4
..................

Released: Fri Nov 14 2008

8.3.10.66 general
.................

   * `[general]' ¶ global “propigate”->”propagate” change.

8.3.10.67 orm
.............

   * `[orm]' ¶. Query.count() has been enhanced to do the
     “right thing” in a wider variety of cases.  It can now count
     multiple-entity queries, as well as column-based queries.  Note
     that this means if you say query(A, B).count() without any joining
     criterion, it’s going to count the cartesian product of A*B. Any
     query which is against column-based entities will automatically
     issue “SELECT count(1) FROM (SELECT…)” so that the real rowcount is
     returned, meaning a query such as query(func.count(A.name)).count()
     will return a value of one, since that query would return one row.

   * `[orm]' ¶. Lots of performance tuning.  A rough
     guesstimate over various ORM operations places it 10% faster over
     0.5.0rc3, 25-30% over 0.4.8.

   * `[orm]' ¶ bugfixes and behavioral changes

   * `[orm]' ¶. Adjustments to the enhanced garbage
     collection on InstanceState to better guard against errors due to
     lost state.

   * `[orm]' ¶. Query.get() returns a more informative error
     message when executed against multiple entities.

     References: #1220(1)

   * `[orm]' ¶. Restored NotImplementedError on
     Cls.relation.in_()

     References: #1140(2), #1221(3)

   * `[orm]' ¶. Fixed PendingDeprecationWarning involving
     order_by parameter on relation().

     References: #1226(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1220

   (2) http://www.sqlalchemy.org/trac/ticket/1140

   (3) http://www.sqlalchemy.org/trac/ticket/1221

   (4) http://www.sqlalchemy.org/trac/ticket/1226

8.3.10.68 sql
.............

   * `[sql]' ¶. Removed the ‘properties’ attribute of the
     Connection object, Connection.info should be used.

   * `[sql]' ¶. Restored “active rowcount” fetch before
     ResultProxy autocloses the cursor.  This was removed in 0.5rc3.

   * `[sql]' ¶. Rearranged the ‘load_dialect_impl()’ method
     in ‘TypeDecorator’ such that it will take effect even if the
     user-defined ‘TypeDecorator’ uses another ‘TypeDecorator’ as its
     impl.

8.3.10.69 mssql
...............

   * `[mssql]' ¶. Lots of cleanup and fixes to correct
     problems with limit and offset.

   * `[mssql]' ¶. Correct situation where subqueries as part
     of a binary expression need to be translated to use the IN and NOT
     IN syntax.

   * `[mssql]' ¶. Fixed E Notation issue that prevented the
     ability to insert decimal values less than 1E-6.

     References: #1216(1)

   * `[mssql]' ¶. Corrected problems with reflection when
     dealing with schemas, particularly when those schemas are the
     default schema.

     References: #1217(2)

   * `[mssql]' ¶. Corrected problem with casting a zero
     length item to a varchar.  It now correctly adjusts the CAST.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1216

   (2) http://www.sqlalchemy.org/trac/ticket/1217

8.3.10.70 misc
..............

   * `[access]' ¶. Added support for Currency type.

   * `[access]' ¶. Functions were not return their result.

     References: #1017(1)

   * `[access]' ¶. Corrected problem with joins.  Access
     only support LEFT OUTER or INNER not just JOIN by itself.

     References: #1017(2)

   * `[ext]' ¶. Can now use a custom “inherit_condition” in
     __mapper_args__ when using declarative.

   * `[ext]' ¶ fixed string-based “remote_side”, “order_by”
     and others not propagating correctly when used in backref().

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1017

   (2) http://www.sqlalchemy.org/trac/ticket/1017

8.3.10.71 0.5.0rc3
..................

Released: Fri Nov 07 2008

8.3.10.72 orm
.............

   * `[orm]' ¶. Added two new hooks to SessionExtension:
     after_bulk_delete() and after_bulk_update().  after_bulk_delete()
     is called after a bulk delete() operation on a query.
     after_bulk_update() is called after a bulk update() operation on a
     query.

   * `[orm]' ¶. ”not equals” comparisons of simple
     many-to-one relation to an instance will not drop into an EXISTS
     clause and will compare foreign key columns instead.

   * `[orm]' ¶. Removed not-really-working use cases of
     comparing a collection to an iterable.  Use contains() to test for
     collection membership.

   * `[orm]' ¶. Improved the behavior of aliased() objects
     such that they more accurately adapt the expressions generated,
     which helps particularly with self-referential comparisons.

     References: #1171(1)

   * `[orm]' ¶. Fixed bug involving
     primaryjoin/secondaryjoin conditions constructed from class-bound
     attributes (as often occurs when using declarative), which later
     would be inappropriately aliased by Query, particularly with the
     various EXISTS based comparators.

   * `[orm]' ¶. Fixed bug when using multiple query.join()
     with an aliased-bound descriptor which would lose the left alias.

   * `[orm]' ¶. Improved weakref identity map memory
     management to no longer require mutexing, resurrects garbage
     collected instance on a lazy basis for an InstanceState with
     pending changes.

   * `[orm]' ¶. InstanceState object now removes circular
     references to itself upon disposal to keep it outside of cyclic
     garbage collection.

   * `[orm]' ¶ relation() won’t hide unrelated ForeignKey
     errors inside of the “please specify primaryjoin” message when
     determining join condition.

   * `[orm]' ¶. Fixed bug in Query involving order_by() in
     conjunction with multiple aliases of the same class (will add tests
     in)

     References: #1218(2)

   * `[orm]' ¶. When using Query.join() with an explicit
     clause for the ON clause, the clause will be aliased in terms of
     the left side of the join, allowing scenarios like query(Source).
     from_self().join((Dest, Source.id==Dest.source_id)) to work
     properly.

   * `[orm]' ¶ polymorphic_union() function respects the
     “key” of each Column if they differ from the column’s name.

   * `[orm]' ¶. Repaired support for “passive-deletes” on a
     many-to-one relation() with “delete” cascade.

     References: #1183(3)

   * `[orm]' ¶. Fixed bug in composite types which prevented
     a primary-key composite type from being mutated.

     References: #1213(4)

   * `[orm]' ¶. Added more granularity to internal attribute
     access, such that cascade and flush operations will not initialize
     unloaded attributes and collections, leaving them intact for a
     lazy-load later on.  Backref events still initialize attributes and
     collections for pending instances.

     References: #1202(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1171

   (2) http://www.sqlalchemy.org/trac/ticket/1218

   (3) http://www.sqlalchemy.org/trac/ticket/1183

   (4) http://www.sqlalchemy.org/trac/ticket/1213

   (5) http://www.sqlalchemy.org/trac/ticket/1202

8.3.10.73 sql
.............

   * `[sql]' ¶. SQL compiler optimizations and complexity
     reduction.  The call count for compiling a typical select()
     construct is 20% less versus 0.5.0rc2.

   * `[sql]' ¶. Dialects can now generate label names of
     adjustable length.  Pass in the argument “label_length=<value>” to
     create_engine() to adjust how many characters max will be present
     in dynamically generated column labels, i.e.  “somecolumn AS
     somelabel”.  Any value less than 6 will result in a label of
     minimal size, consisting of an underscore and a numeric counter.
     The compiler uses the value of dialect.max_identifier_length as a
     default.

     References: #1211(1)

   * `[sql]' ¶. Simplified the check for ResultProxy
     “autoclose without results” to be based solely on presence of
     cursor.description.  All the regexp-based guessing about statements
     returning rows has been removed.

     References: #1212(2)

   * `[sql]' ¶. Direct execution of a union() construct will
     properly set up result-row processing.

     References: #1194(3)

   * `[sql]' ¶. The internal notion of an “OID” or “ROWID”
     column has been removed.  It’s basically not used by any dialect,
     and the possibility of its usage with psycopg2’s cursor.lastrowid
     is basically gone now that INSERT..RETURNING is available.

   * `[sql]' ¶. Removed “default_order_by()” method on all
     FromClause objects.

   * `[sql]' ¶. Repaired the table.tometadata() method so
     that a passed-in schema argument is propagated to ForeignKey
     constructs.

   * `[sql]' ¶. Slightly changed behavior of IN operator for
     comparing to empty collections.  Now results in inequality
     comparison against self.  More portable, but breaks with stored
     procedures that aren’t pure functions.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1211

   (2) http://www.sqlalchemy.org/trac/ticket/1212

   (3) http://www.sqlalchemy.org/trac/ticket/1194

8.3.10.74 mysql
...............

   * `[mysql]' ¶. Fixed foreign key reflection in the edge
     case where a Table’s explicit schema= is the same as the schema
     (database) the connection is attached to.

   * `[mysql]' ¶. No longer expects include_columns in table
     reflection to be lower case.

8.3.10.75 oracle
................

   * `[oracle]' ¶. Wrote a docstring for Oracle dialect.
     Apparently that Ohloh “few source code comments” label is starting
     to sting :).

   * `[oracle]' ¶. Removed FIRST_ROWS() optimize flag when
     using LIMIT/OFFSET, can be reenabled with optimize_limits=True
     create_engine() flag.

     References: #536(1)

   * `[oracle]' ¶ bugfixes and behavioral changes

   * `[oracle]' ¶. Setting the auto_convert_lobs to False on
     create_engine() will also instruct the OracleBinary type to return
     the cx_oracle LOB object unchanged.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/536

8.3.10.76 misc
..............

   * `[ext]' ¶. Added a new extension
     sqlalchemy.ext.serializer.  Provides Serializer/Deserializer
     “classes” which mirror Pickle/Unpickle, as well as dumps() and
     loads().  This serializer implements an “external object” pickler
     which keeps key context-sensitive objects, including engines,
     sessions, metadata, Tables/Columns, and mappers, outside of the
     pickle stream, and can later restore the pickle using any
     engine/metadata/session provider.  This is used not for pickling
     regular object instances, which are pickleable without any special
     logic, but for pickling expression objects and full Query objects,
     such that all mapper/engine/session dependencies can be restored at
     unpickle time.

   * `[ext]' ¶. Fixed bug preventing declarative-bound
     “column” objects from being used in column_mapped_collection().

     References: #1174(1)

   * `[misc]' ¶ util.flatten_iterator() func doesn’t
     interpret strings with __iter__() methods as iterators, such as in
     pypy.

     References: #1077(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1174

   (2) http://www.sqlalchemy.org/trac/ticket/1077

8.3.10.77 0.5.0rc2
..................

Released: Sun Oct 12 2008

8.3.10.78 orm
.............

   * `[orm]' ¶. Fixed bug involving read/write relation()s
     that contain literal or other non-column expressions within their
     primaryjoin condition equated to a foreign key column.

   * `[orm]' ¶. ”non-batch” mode in mapper(), a feature
     which allows mapper extension methods to be called as each instance
     is updated/inserted, now honors the insert order of the objects
     given.

   * `[orm]' ¶. Fixed RLock-related bug in mapper which
     could deadlock upon reentrant mapper compile() calls, something
     that occurs when using declarative constructs inside of ForeignKey
     objects.

   * `[orm]' ¶. ScopedSession.query_property now accepts a
     query_cls factory, overriding the session’s configured query_cls.

   * `[orm]' ¶. Fixed shared state bug interfering with
     ScopedSession.mapper’s ability to apply default __init__
     implementations on object subclasses.

   * `[orm]' ¶. Fixed up slices on Query (i.e.  query[x:y])
     to work properly for zero length slices, slices with None on either
     end.

     References: #1177(1)

   * `[orm]' ¶. Added an example illustrating Celko’s
     “nested sets” as a SQLA mapping.

   * `[orm]' ¶ contains_eager() with an alias argument
     works even when the alias is embedded in a SELECT, as when sent to
     the Query via query.select_from().

   * `[orm]' ¶ contains_eager() usage is now compatible
     with a Query that also contains a regular eager load and
     limit/offset, in that the columns are added to the Query-generated
     subquery.

     References: #1180(2)

   * `[orm]' ¶ session.execute() will execute a Sequence
     object passed to it (regression from 0.4).

   * `[orm]' ¶. Removed the “raiseerror” keyword argument
     from object_mapper() and class_mapper().  These functions raise in
     all cases if the given class/instance is not mapped.

   * `[orm]' ¶. Fixed session.transaction.commit() on a
     autocommit=False session not starting a new transaction.

   * `[orm]' ¶. Some adjustments to Session.identity_map’s
     weak referencing behavior to reduce asynchronous GC side effects.

   * `[orm]' ¶. Adjustment to Session’s post-flush
     accounting of newly “clean” objects to better protect against
     operating on objects as they’re asynchronously gc’ed.

     References: #1182(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1177

   (2) http://www.sqlalchemy.org/trac/ticket/1180

   (3) http://www.sqlalchemy.org/trac/ticket/1182

8.3.10.79 sql
.............

   * `[sql]' ¶ column.in_(someselect) can now be used as a
     columns-clause expression without the subquery bleeding into the
     FROM clause

     References: #1074(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1074

8.3.10.80 mysql
...............

   * `[mysql]' ¶. Temporary tables are now reflectable.

8.3.10.81 sqlite
................

   * `[sqlite]' ¶. Overhauled SQLite date/time bind/result
     processing to use regular expressions and format strings, rather
     than strptime/strftime, to generically support pre-1900 dates,
     dates with microseconds.

     References: #968(1)

   * `[sqlite]' ¶. String’s (and Unicode’s, UnicodeText’s,
     etc.)  convert_unicode logic disabled in the sqlite dialect, to
     adjust for pysqlite 2.5.0’s new requirement that only Python
     unicode objects are accepted;
     ‘http://itsystementwicklung.de/pipermail/list-pysqlite/2008-March/000018.html’

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/968

8.3.10.82 oracle
................

   * `[oracle]' ¶. Oracle will detect string-based
     statements which contain comments at the front before a SELECT as
     SELECT statements.

     References: #1187(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1187

8.3.10.83 0.5.0rc1
..................

Released: Thu Sep 11 2008

8.3.10.84 orm
.............

   * `[orm]' ¶. Query now has delete() and update(values)
     methods.  This allows to perform bulk deletes/updates with the
     Query object.

   * `[orm]' ¶. The RowTuple object returned by Query(*cols)
     now features keynames which prefer mapped attribute names over
     column keys, column keys over column names, i.e.  Query(Class.foo,
     Class.bar) will have names “foo” and “bar” even if those are not
     the names of the underlying Column objects.  Direct Column objects
     such as Query(table.c.col) will return the “key” attribute of the
     Column.

   * `[orm]' ¶. Added scalar() and value() methods to Query,
     each return a single scalar value.  scalar() takes no arguments and
     is roughly equivalent to first()[0], value() takes a single column
     expression and is roughly equivalent to values(expr).next()[0].

   * `[orm]' ¶. Improved the determination of the FROM
     clause when placing SQL expressions in the query() list of
     entities.  In particular scalar subqueries should not “leak” their
     inner FROM objects out into the enclosing query.

   * `[orm]' ¶. Joins along a relation() from a mapped class
     to a mapped subclass, where the mapped subclass is configured with
     single table inheritance, will include an IN clause which limits
     the subtypes of the joined class to those requested, within the ON
     clause of the join.  This takes effect for eager load joins as well
     as query.join().  Note that in some scenarios the IN clause will
     appear in the WHERE clause of the query as well since this
     discrimination has multiple trigger points.

   * `[orm]' ¶. AttributeExtension has been refined such
     that the event is fired before the mutation actually occurs.
     Additionally, the append() and set() methods must now return the
     given value, which is used as the value to be used in the mutation
     operation.  This allows creation of validating AttributeListeners
     which raise before the action actually occurs, and which can change
     the given value into something else before its used.

   * `[orm]' ¶ column_property(), composite_property(), and
     relation() now accept a single or list of AttributeExtensions using
     the “extension” keyword argument.

   * `[orm]' ¶ query.order_by().get() silently drops the
     “ORDER BY” from the query issued by GET but does not raise an
     exception.

   * `[orm]' ¶. Added a Validator AttributeExtension, as
     well as a @validates decorator which is used in a similar fashion
     as @reconstructor, and marks a method as validating one or more
     mapped attributes.

   * `[orm]' ¶ class.someprop.in_() raises
     NotImplementedError pending the implementation of “in_” for
     relation

     References: #1140(1)

   * `[orm]' ¶. Fixed primary key update for many-to-many
     collections where the collection had not been loaded yet

     References: #1127(2)

   * `[orm]' ¶. Fixed bug whereby deferred() columns with a
     group in conjunction with an otherwise unrelated synonym() would
     produce an AttributeError during deferred load.

   * `[orm]' ¶. The before_flush() hook on SessionExtension
     takes place before the list of new/dirty/deleted is calculated for
     the final time, allowing routines within before_flush() to further
     change the state of the Session before the flush proceeds.

     References: #1128(3)

   * `[orm]' ¶. The “extension” argument to Session and
     others can now optionally be a list, supporting events sent to
     multiple SessionExtension instances.  Session places
     SessionExtensions in Session.extensions.

   * `[orm]' ¶. Reentrant calls to flush() raise an error.
     This also serves as a rudimentary, but not foolproof, check against
     concurrent calls to Session.flush().

   * `[orm]' ¶. Improved the behavior of query.join() when
     joining to joined-table inheritance subclasses, using explicit join
     criteria (i.e.  not on a relation).

   * `[orm]' ¶. @orm.attributes.reconstitute and
     MapperExtension.reconstitute have been renamed to
     @orm.reconstructor and MapperExtension.reconstruct_instance

   * `[orm]' ¶. Fixed @reconstructor hook for subclasses
     which inherit from a base class.

     References: #1129(4)

   * `[orm]' ¶. The composite() property type now supports a
     __set_composite_values__() method on the composite class which is
     required if the class represents state using attribute names other
     than the column’s keynames; default-generated values now get
     populated properly upon flush.  Also, composites with attributes
     set to None compare correctly.

     References: #1132(5)

   * `[orm]' ¶. The 3-tuple of iterables returned by
     attributes.get_history() may now be a mix of lists and tuples.
     (Previously members were always lists.)

   * `[orm]' ¶. Fixed bug whereby changing a primary key
     attribute on an entity where the attribute’s previous value had
     been expired would produce an error upon flush().

     References: #1151(6)

   * `[orm]' ¶. Fixed custom instrumentation bug whereby
     get_instance_dict() was not called for newly constructed instances
     not loaded by the ORM.

   * `[orm]' ¶. Session.delete() adds the given object to
     the session if not already present.  This was a regression bug from
     0.4.

     References: #1150(7)

   * `[orm]' ¶. The ‘echo_uow’ flag on ‘Session’ is
     deprecated, and unit-of-work logging is now application-level only,
     not per-session level.

   * `[orm]' ¶. Removed conflicting ‘contains()’ operator
     from ‘InstrumentedAttribute’ which didn’t accept ‘escape’ kwaarg.

     References: #1153(8)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1140

   (2) http://www.sqlalchemy.org/trac/ticket/1127

   (3) http://www.sqlalchemy.org/trac/ticket/1128

   (4) http://www.sqlalchemy.org/trac/ticket/1129

   (5) http://www.sqlalchemy.org/trac/ticket/1132

   (6) http://www.sqlalchemy.org/trac/ticket/1151

   (7) http://www.sqlalchemy.org/trac/ticket/1150

   (8) http://www.sqlalchemy.org/trac/ticket/1153

8.3.10.85 sql
.............

   * `[sql]' ¶. Temporarily rolled back the “ORDER BY”
     enhancement from.  This feature is on hold pending further
     development.

     References: #1068(1)

   * `[sql]' ¶. The exists() construct won’t “export” its
     contained list of elements as FROM clauses, allowing them to be
     used more effectively in the columns clause of a SELECT.

   * `[sql]' ¶ and_() and or_() now generate a
     ColumnElement, allowing boolean expressions as result columns, i.e.
     select([and_(1, 0)]).

     References: #798(2)

   * `[sql]' ¶. Bind params now subclass ColumnElement which
     allows them to be selectable by orm.query (they already had most
     ColumnElement semantics).

   * `[sql]' ¶. Added select_from() method to exists()
     construct, which becomes more and more compatible with a regular
     select().

   * `[sql]' ¶. Added func.min(), func.max(), func.sum() as
     “generic functions”, which basically allows for their return type
     to be determined automatically.  Helps with dates on SQLite,
     decimal types, others.

     References: #1160(3)

   * `[sql]' ¶ added decimal.Decimal as an “auto-detect”
     type; bind parameters and generic functions will set their type to
     Numeric when a Decimal is used.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1068

   (2) http://www.sqlalchemy.org/trac/ticket/798

   (3) http://www.sqlalchemy.org/trac/ticket/1160

8.3.10.86 schema
................

   * `[schema]' ¶. Added “sorted_tables” accessor to
     MetaData, which returns Table objects sorted in order of dependency
     as a list.  This deprecates the MetaData.table_iterator() method.
     The “reverse=False” keyword argument has also been removed from
     util.sort_tables(); use the Python ‘reversed’ function to reverse
     the results.

     References: #1033(1)

   * `[schema]' ¶. The ‘length’ argument to all Numeric
     types has been renamed to ‘scale’.  ‘length’ is deprecated and is
     still accepted with a warning.

   * `[schema]' ¶. Dropped 0.3-compatibility for user
     defined types (convert_result_value, convert_bind_param).

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1033

8.3.10.87 mysql
...............

   * `[mysql]' ¶. The ‘length’ argument to MSInteger,
     MSBigInteger, MSTinyInteger, MSSmallInteger and MSYear has been
     renamed to ‘display_width’.

   * `[mysql]' ¶. Added MSMediumInteger type.

     References: #1146(1)

   * `[mysql]' ¶ the function func.utc_timestamp() compiles
     to UTC_TIMESTAMP, without the parenthesis, which seem to get in the
     way when using in conjunction with executemany().

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1146

8.3.10.88 oracle
................

   * `[oracle]' ¶ limit/offset no longer uses ROW NUMBER
     OVER to limit rows, and instead uses subqueries in conjunction with
     a special Oracle optimization comment.  Allows LIMIT/OFFSET to work
     in conjunction with DISTINCT.

     References: #536(1)

   * `[oracle]' ¶ has_sequence() now takes the current
     “schema” argument into account

     References: #1155(2)

   * `[oracle]' ¶ added BFILE to reflected type names

     References: #1121(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/536

   (2) http://www.sqlalchemy.org/trac/ticket/1155

   (3) http://www.sqlalchemy.org/trac/ticket/1121

8.3.10.89 misc
..............

   * `[declarative]' ¶. Fixed bug whereby mapper couldn’t
     initialize if a composite primary key referenced another table that
     was not defined yet.

     References: #1161(1)

   * `[declarative]' ¶. Fixed exception throw which would
     occur when string-based primaryjoin condition was used in
     conjunction with backref.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1161

8.3.10.90 0.5.0beta3
....................

Released: Mon Aug 04 2008

8.3.10.91 orm
.............

   * `[orm]' ¶. The “entity_name” feature of SQLAlchemy
     mappers has been removed.  For rationale, see
     ‘http://tinyurl.com/6nm2ne’

   * `[orm]' ¶ the “autoexpire” flag on Session,
     sessionmaker(), and scoped_session() has been renamed to
     “expire_on_commit”.  It does not affect the expiration behavior of
     rollback().

   * `[orm]' ¶ fixed endless loop bug which could occur
     within a mapper’s deferred load of inherited attributes.

   * `[orm]' ¶ a legacy-support flag
     “_enable_transaction_accounting” flag added to Session which when
     False, disables all transaction-level object accounting, including
     expire on rollback, expire on commit, new/deleted list maintenance,
     and autoflush on begin.

   * `[orm]' ¶. The ‘cascade’ parameter to relation()
     accepts None as a value, which is equivalent to no cascades.

   * `[orm]' ¶. A critical fix to dynamic relations allows
     the “modified” history to be properly cleared after a flush().

   * `[orm]' ¶ user-defined @properties on a class are
     detected and left in place during mapper initialization.  This
     means that a table-bound column of the same name will not be mapped
     at all if a @property is in the way (and the column is not remapped
     to a different name), nor will an instrumented attribute from an
     inherited class be applied.  The same rules apply for names
     excluded using the include_properties/exclude_properties
     collections.

   * `[orm]' ¶. Added a new SessionExtension hook called
     after_attach().  This is called at the point of attachment for
     objects via add(), add_all(), delete(), and merge().

   * `[orm]' ¶. A mapper which inherits from another, when
     inheriting the columns of its inherited mapper, will use any
     reassigned property names specified in that inheriting mapper.
     Previously, if “Base” had reassigned “base_id” to the name “id”,
     “SubBase(Base)” would still get an attribute called “base_id”.
     This could be worked around by explicitly stating the column in
     each submapper as well but this is fairly unworkable and also
     impossible when using declarative.

     References: #1111(1)

   * `[orm]' ¶. Fixed a series of potential race conditions
     in Session whereby asynchronous GC could remove unmodified, no
     longer referenced items from the session as they were present in a
     list of items to be processed, typically during
     session.expunge_all() and dependent methods.

   * `[orm]' ¶. Some improvements to the _CompileOnAttr
     mechanism which should reduce the probability of “Attribute x was
     not replaced during compile” warnings.  (this generally applies to
     SQLA hackers, like Elixir devs).

   * `[orm]' ¶. Fixed bug whereby the “unsaved, pending
     instance” FlushError raised for a pending orphan would not take
     superclass mappers into account when generating the list of
     relations responsible for the error.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1111

8.3.10.92 sql
.............

   * `[sql]' ¶ func.count() with no arguments renders as
     COUNT(*), equivalent to func.count(text(‘*’)).

   * `[sql]' ¶ simple label names in ORDER BY expressions
     render as themselves, and not as a re-statement of their
     corresponding expression.  This feature is currently enabled only
     for SQLite, MySQL, and PostgreSQL. It can be enabled on other
     dialects as each is shown to support this behavior.

     References: #1068(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1068

8.3.10.93 mysql
...............

   * `[mysql]' ¶. Quoting of MSEnum values for use in CREATE
     TABLE is now optional & will be quoted on demand as required.
     (Quoting was always optional for use with existing tables.)

     References: #1110(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1110

8.3.10.94 misc
..............

   * `[ext]' ¶. Class-bound attributes sent as arguments to
     relation()’s remote_side and foreign_keys parameters are now
     accepted, allowing them to be used with declarative.  Additionally
     fixed bugs involving order_by being specified as a class-bound
     attribute in conjunction with eager loading.

   * `[ext]' ¶ declarative initialization of Columns
     adjusted so that non-renamed columns initialize in the same way as
     a non declarative mapper.  This allows an inheriting mapper to set
     up its same-named “id” columns in particular such that the parent
     “id” column is favored over the child column, reducing database
     round trips when this value is requested.

8.3.10.95 0.5.0beta2
....................

Released: Mon Jul 14 2008

8.3.10.96 orm
.............

   * `[orm]' ¶. In addition to expired attributes, deferred
     attributes also load if their data is present in the result set.

     References: #870(1)

   * `[orm]' ¶ session.refresh() raises an informative
     error message if the list of attributes does not include any
     column-based attributes.

   * `[orm]' ¶ query() raises an informative error message
     if no columns or mappers are specified.

   * `[orm]' ¶ lazy loaders now trigger autoflush before
     proceeding.  This allows expire() of a collection or scalar
     relation to function properly in the context of autoflush.

   * `[orm]' ¶ column_property() attributes which represent
     SQL expressions or columns that are not present in the mapped
     tables (such as those from views) are automatically expired after
     an INSERT or UPDATE, assuming they have not been locally modified,
     so that they are refreshed with the most recent data upon access.

     References: #887(2)

   * `[orm]' ¶. Fixed explicit, self-referential joins
     between two joined-table inheritance mappers when using
     query.join(cls, aliased=True).

     References: #1082(3)

   * `[orm]' ¶. Fixed query.join() when used in conjunction
     with a columns-only clause and a SQL-expression ON clause in the
     join.

   * `[orm]' ¶. The “allow_column_override” flag from
     mapper() has been removed.  This flag is virtually always
     misunderstood.  Its specific functionality is available via the
     include_properties/exclude_properties mapper arguments.

   * `[orm]' ¶. Repaired ‘__str__()’ method on Query.

     References: #1066(4)

   * `[orm]' ¶. Session.bind gets used as a default even
     when table/mapper specific binds are defined.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/870

   (2) http://www.sqlalchemy.org/trac/ticket/887

   (3) http://www.sqlalchemy.org/trac/ticket/1082

   (4) http://www.sqlalchemy.org/trac/ticket/1066

8.3.10.97 sql
.............

   * `[sql]' ¶. Added new match() operator that performs a
     full-text search.  Supported on PostgreSQL, SQLite, MySQL, MS-SQL,
     and Oracle backends.

8.3.10.98 schema
................

   * `[schema]' ¶. Added prefixes option to ‘Table’ that
     accepts a list of strings to insert after CREATE in the CREATE
     TABLE statement.

     References: #1075(1)

   * `[schema]' ¶. Unicode, UnicodeText types now set
     “assert_unicode” and “convert_unicode” by default, but accept
     overriding **kwargs for these values.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1075

8.3.10.99 extensions
....................

   * `[extensions]' ¶. Declarative supports a __table_args__
     class variable, which is either a dictionary, or tuple of the form
     (arg1, arg2, …, {kwarg1:value, …}) which contains positional + kw
     arguments to be passed to the Table constructor.

     References: #1096(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1096

8.3.10.100 sqlite
.................

   * `[sqlite]' ¶. Modified SQLite’s representation of
     “microseconds” to match the output of str(somedatetime), i.e.  in
     that the microseconds are represented as fractional seconds in
     string format.  This makes SQLA’s SQLite date type compatible with
     datetimes that were saved directly using Pysqlite (which just calls
     str()).  Note that this is incompatible with the existing
     microseconds values in a SQLA 0.4 generated SQLite database file.

     To get the old behavior globally:

          from sqlalchemy.databases.sqlite import DateTimeMixin
          DateTimeMixin.__legacy_microseconds__ = True

     To get the behavior on individual DateTime types:

          t = sqlite.SLDateTime() t.__legacy_microseconds__ = True

     Then use “t” as the type on the Column.

     References: #1090(1)

   * `[sqlite]' ¶. SQLite Date, DateTime, and Time types
     only accept Python datetime objects now, not strings.  If you’d
     like to format dates as strings yourself with SQLite, use a String
     type.  If you’d like them to return datetime objects anyway despite
     their accepting strings as input, make a TypeDecorator around
     String - SQLA doesn’t encourage this pattern.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1090

8.3.10.101 0.5.0beta1
.....................

Released: Thu Jun 12 2008

8.3.10.102 general
..................

   * `[general]' ¶ global “propigate”->”propagate” change.

8.3.10.103 orm
..............

   * `[orm]' ¶ polymorphic_union() function respects the
     “key” of each Column if they differ from the column’s name.

   * `[orm]' ¶. Fixed 0.4-only bug preventing composite
     columns from working properly with inheriting mappers

     References: #1199(1)

   * `[orm]' ¶. Fixed RLock-related bug in mapper which
     could deadlock upon reentrant mapper compile() calls, something
     that occurs when using declarative constructs inside of ForeignKey
     objects.  Ported from 0.5.

   * `[orm]' ¶. Fixed bug in composite types which prevented
     a primary-key composite type from being mutated.

     References: #1213(2)

   * `[orm]' ¶. Added ScopedSession.is_active accessor.

     References: #976(3)

   * `[orm]' ¶. Class-bound accessor can be used as the
     argument to relation() order_by.

     References: #939(4)

   * `[orm]' ¶. Fixed shard_id argument on
     ShardedSession.execute().

     References: #1072(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1199

   (2) http://www.sqlalchemy.org/trac/ticket/1213

   (3) http://www.sqlalchemy.org/trac/ticket/976

   (4) http://www.sqlalchemy.org/trac/ticket/939

   (5) http://www.sqlalchemy.org/trac/ticket/1072

8.3.10.104 sql
..............

   * `[sql]' ¶. Connection.invalidate() checks for closed
     status to avoid attribute errors.

     References: #1246(1)

   * `[sql]' ¶. NullPool supports reconnect on failure
     behavior.

     References: #1094(2)

   * `[sql]' ¶. The per-dialect cache used by TypeEngine to
     cache dialect-specific types is now a WeakKeyDictionary.  This to
     prevent dialect objects from being referenced forever for an
     application that creates an arbitrarily large number of engines or
     dialects.  There is a small performance penalty which will be
     resolved in 0.6.

     References: #1299(3)

   * `[sql]' ¶. Fixed SQLite reflection methods so that
     non-present cursor.description, which triggers an auto-cursor
     close, will be detected so that no results doesn’t fail on recent
     versions of pysqlite which raise an error when fetchone() called
     with no rows present.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1246

   (2) http://www.sqlalchemy.org/trac/ticket/1094

   (3) http://www.sqlalchemy.org/trac/ticket/1299

8.3.10.105 mysql
................

   * `[mysql]' ¶. Fixed bug in exception raise when FK
     columns not present during reflection.

     References: #1241(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1241

8.3.10.106 oracle
.................

   * `[oracle]' ¶. Fixed bug which was preventing out params
     of certain types from being received; thanks a ton to huddlej at
     wwu.edu !

     References: #1265(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1265

8.3.10.107 firebird
...................

   * `[firebird]' ¶. Added support for returning values from
     inserts (2.0+ only), updates and deletes (2.1+ only).

8.3.10.108 misc
...............

   * `[no_tags]' ¶. The “__init__” trigger/decorator added
     by mapper now attempts to exactly mirror the argument signature of
     the original __init__.  The pass-through for ‘_sa_session’ is no
     longer implicit- you must allow for this keyword argument in your
     constructor.

   * `[no_tags]' ¶. ClassState is renamed to ClassManager.

   * `[no_tags]' ¶. Classes may supply their own
     InstrumentationManager by providing a
     __sa_instrumentation_manager__ property.

   * `[no_tags]' ¶. Custom instrumentation may use any
     mechanism to associate a ClassManager with a class and an
     InstanceState with an instance.  Attributes on those objects are
     still the default association mechanism used by SQLAlchemy’s native
     instrumentation.

   * `[no_tags]' ¶. Moved entity_name, _sa_session_id, and
     _instance_key from the instance object to the instance state.
     These values are still available in the old way, which is now
     deprecated, using descriptors attached to the class.  A deprecation
     warning will be issued when accessed.

   * `[no_tags]' ¶. The _prepare_instrumentation alias for
     prepare_instrumentation has been removed.

   * `[no_tags]' ¶ sqlalchemy.exceptions has been renamed
     to sqlalchemy.exc.  The module may be imported under either name.

   * `[no_tags]' ¶. ORM-related exceptions are now defined
     in sqlalchemy.orm.exc.  ConcurrentModificationError, FlushError,
     and UnmappedColumnError compatibility aliases are installed in
     sqlalchemy.exc during the import of sqlalchemy.orm.

   * `[no_tags]' ¶ sqlalchemy.logging has been renamed to
     sqlalchemy.log.

   * `[no_tags]' ¶. The transitional
     sqlalchemy.log.SADeprecationWarning alias for the warning’s
     definition in sqlalchemy.exc has been removed.

   * `[no_tags]' ¶ exc.AssertionError has been removed and
     usage replaced with Python’s built-in AssertionError.

   * `[no_tags]' ¶. The behavior of MapperExtensions
     attached to multiple, entity_name= primary mappers for a single
     class has been altered.  The first mapper() defined for a class is
     the only mapper eligible for the MapperExtension
     ‘instrument_class’, ‘init_instance’ and ‘init_failed’ events.  This
     is backwards incompatible; previously the extensions of last mapper
     defined would receive these events.

   * `[postgres]' ¶. Added Index reflection support to
     Postgres, using a great patch we long neglected, submitted by Ken
     Kuhlman.

     References: #714(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/714

8.3.11 0.4 Changelog
--------------------

8.3.11.1 0.4.8
..............

Released: Sun Oct 12 2008

8.3.11.2 orm
............

   * `[orm]' ¶. Fixed bug regarding inherit_condition passed
     with “A=B” versus “B=A” leading to errors

     References: #1039(1)

   * `[orm]' ¶. Changes made to new, dirty and deleted
     collections in SessionExtension.before_flush() will take effect for
     that flush.

   * `[orm]' ¶. Added label() method to
     InstrumentedAttribute to establish forwards compatibility with 0.5.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1039

8.3.11.3 sql
............

   * `[sql]' ¶ column.in_(someselect) can now be used as a
     columns-clause expression without the subquery bleeding into the
     FROM clause

     References: #1074(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1074

8.3.11.4 mysql
..............

   * `[mysql]' ¶. Added MSMediumInteger type.

     References: #1146(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1146

8.3.11.5 sqlite
...............

   * `[sqlite]' ¶. Supplied a custom strftime() function
     which handles dates before 1900.

     References: #968(1)

   * `[sqlite]' ¶. String’s (and Unicode’s, UnicodeText’s,
     etc.)  convert_unicode logic disabled in the sqlite dialect, to
     adjust for pysqlite 2.5.0’s new requirement that only Python
     unicode objects are accepted;
     ‘http://itsystementwicklung.de/pipermail/list-pysqlite/2008-March/000018.html’

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/968

8.3.11.6 oracle
...............

   * `[oracle]' ¶ has_sequence() now takes schema name into
     account

     References: #1155(1)

   * `[oracle]' ¶ added BFILE to the list of reflected
     types

     References: #1121(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1155

   (2) http://www.sqlalchemy.org/trac/ticket/1121

8.3.11.7 0.4.7p1
................

Released: Thu Jul 31 2008

8.3.11.8 orm
............

   * `[orm]' ¶. Added “add()” and “add_all()” to
     scoped_session methods.  Workaround for 0.4.7:

          from sqlalchemy.orm.scoping import ScopedSession, instrument
          setattr(ScopedSession, "add", instrument("add"))
          setattr(ScopedSession, "add_all", instrument("add_all"))

   * `[orm]' ¶. Fixed non-2.3 compatible usage of set() and
     generator expression within relation().

8.3.11.9 0.4.7
..............

Released: Sat Jul 26 2008

8.3.11.10 orm
.............

   * `[orm]' ¶. The contains() operator when used with
     many-to-many will alias() the secondary (association) table so that
     multiple contains() calls will not conflict with each other

     References: #1058(1)

   * `[orm]' ¶ fixed bug preventing merge() from
     functioning in conjunction with a comparable_property()

   * `[orm]' ¶ the enable_typechecks=False setting on
     relation() now only allows subtypes with inheriting mappers.
     Totally unrelated types, or subtypes not set up with mapper
     inheritance against the target mapper are still not allowed.

   * `[orm]' ¶. Added is_active flag to Sessions to detect
     when a transaction is in progress.  This flag is always True with a
     “transactional” (in 0.5 a non-“autocommit”) Session.

     References: #976(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1058

   (2) http://www.sqlalchemy.org/trac/ticket/976

8.3.11.11 sql
.............

   * `[sql]' ¶. Fixed bug when calling
     select([literal(‘foo’)]) or select([bindparam(‘foo’)]).

8.3.11.12 schema
................

   * `[schema]' ¶ create_all(), drop_all(), create(),
     drop() all raise an error if the table name or schema name contains
     more characters than that dialect’s configured character limit.
     Some DB’s can handle too-long table names during usage, and SQLA
     can handle this as well.  But various reflection/
     checkfirst-during-create scenarios fail since we are looking for
     the name within the DB’s catalog tables.

     References: #571(1)

   * `[schema]' ¶. The index name generated when you say
     “index=True” on a Column is truncated to the length appropriate for
     the dialect.  Additionally, an Index with a too- long name cannot
     be explicitly dropped with Index.drop(), similar to.

     References: #571(2), #820(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/571

   (2) http://www.sqlalchemy.org/trac/ticket/571

   (3) http://www.sqlalchemy.org/trac/ticket/820

8.3.11.13 mysql
...............

   * `[mysql]' ¶. Added ‘CALL’ to the list of SQL keywords
     which return result rows.

8.3.11.14 oracle
................

   * `[oracle]' ¶. Oracle get_default_schema_name()
     “normalizes” the name before returning, meaning it returns a
     lower-case name when the identifier is detected as case
     insensitive.

   * `[oracle]' ¶ creating/dropping tables takes schema
     name into account when searching for the existing table, so that
     tables in other owner namespaces with the same name do not conflict

     References: #709(1)

   * `[oracle]' ¶. Cursors now have “arraysize” set to 50 by
     default on them, the value of which is configurable using the
     “arraysize” argument to create_engine() with the Oracle dialect.
     This to account for cx_oracle’s default setting of “1”, which has
     the effect of many round trips being sent to Oracle.  This actually
     works well in conjunction with BLOB/CLOB-bound cursors, of which
     there are any number available but only for the life of that row
     request (so BufferedColumnRow is still needed, but less so).

     References: #1062(2)

   * `[oracle]' ¶.

     sqlite

             - add SLFloat type, which matches the SQLite REAL type
               affinity.  Previously, only SLNumeric was provided which
               fulfills NUMERIC affinity, but that’s not the same as
               REAL.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/709

   (2) http://www.sqlalchemy.org/trac/ticket/1062

8.3.11.15 misc
..............

   * `[postgres]' ¶. Repaired server_side_cursors to
     properly detect text() clauses.

   * `[postgres]' ¶. Added PGCidr type.

     References: #1092(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1092

8.3.11.16 0.4.6
...............

Released: Sat May 10 2008

8.3.11.17 orm
.............

   * `[orm]' ¶. Fix to the recent relation() refactoring
     which fixes exotic viewonly relations which join between local and
     remote table multiple times, with a common column shared between
     the joins.

   * `[orm]' ¶. Also re-established viewonly relation()
     configurations that join across multiple tables.

   * `[orm]' ¶. Added experimental relation() flag to help
     with primaryjoins across functions, etc.,
     _local_remote_pairs=[tuples].  This complements a complex
     primaryjoin condition allowing you to provide the individual column
     pairs which comprise the relation’s local and remote sides.  Also
     improved lazy load SQL generation to handle placing bind params
     inside of functions and other expressions.  (partial progress
     towards)

     References: #610(1)

   * `[orm]' ¶ repaired single table inheritance such that
     you can single-table inherit from a joined-table inheriting mapper
     without issue.

     References: #1036(2)

   * `[orm]' ¶. Fixed “concatenate tuple” bug which could
     occur with Query.order_by() if clause adaption had taken place.

     References: #1027(3)

   * `[orm]' ¶. Removed ancient assertion that mapped
     selectables require “alias names” - the mapper creates its own
     alias now if none is present.  Though in this case you need to use
     the class, not the mapped selectable, as the source of column
     attributes - so a warning is still issued.

   * `[orm]' ¶ fixes to the “exists” function involving
     inheritance (any(), has(), ~contains()); the full target join will
     be rendered into the EXISTS clause for relations that link to
     subclasses.

   * `[orm]' ¶ restored usage of append_result() extension
     method for primary query rows, when the extension is present and
     only a single- entity result is being returned.

   * `[orm]' ¶. Also re-established viewonly relation()
     configurations that join across multiple tables.

   * `[orm]' ¶ removed ancient assertion that mapped
     selectables require “alias names” - the mapper creates its own
     alias now if none is present.  Though in this case you need to use
     the class, not the mapped selectable, as the source of column
     attributes - so a warning is still issued.

   * `[orm]' ¶ refined mapper._save_obj() which was
     unnecessarily calling __ne__() on scalar values during flush

     References: #1015(4)

   * `[orm]' ¶ added a feature to eager loading whereby
     subqueries set as column_property() with explicit label names
     (which is not necessary, btw) will have the label anonymized when
     the instance is part of the eager join, to prevent conflicts with a
     subquery or column of the same name on the parent object.

     References: #1019(5)

   * `[orm]' ¶ set-based collections |=, -=, ^= and &= are
     stricter about their operands and only operate on sets, frozensets
     or subclasses of the collection type.  Previously, they would
     accept any duck-typed set.

   * `[orm]' ¶ added an example
     dynamic_dict/dynamic_dict.py, illustrating a simple way to place
     dictionary behavior on top of a dynamic_loader.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/610

   (2) http://www.sqlalchemy.org/trac/ticket/1036

   (3) http://www.sqlalchemy.org/trac/ticket/1027

   (4) http://www.sqlalchemy.org/trac/ticket/1015

   (5) http://www.sqlalchemy.org/trac/ticket/1019

8.3.11.18 sql
.............

   * `[sql]' ¶. Added COLLATE support via the
     .collate(<collation>) expression operator and collate(<expr>,
     <collation>) sql function.

   * `[sql]' ¶. Fixed bug with union() when applied to
     non-Table connected select statements

   * `[sql]' ¶ improved behavior of text() expressions when
     used as FROM clauses, such as
     select().select_from(text(“sometext”))

     References: #1014(1)

   * `[sql]' ¶. Column.copy() respects the value of
     “autoincrement”, fixes usage with Migrate

     References: #1021(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1014

   (2) http://www.sqlalchemy.org/trac/ticket/1021

8.3.11.19 mssql
...............

   * `[mssql]' ¶. Added “odbc_autotranslate” parameter to
     engine / dburi parameters.  Any given string will be passed through
     to the ODBC connection string as:

          ”AutoTranslate=%s” % odbc_autotranslate

     References: #1005(1)

   * `[mssql]' ¶. Added “odbc_options” parameter to engine /
     dburi parameters.  The given string is simply appended to the
     SQLAlchemy-generated odbc connection string.

     This should obviate the need of adding a myriad of ODBC options in
     the future.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1005

8.3.11.20 firebird
..................

   * `[firebird]' ¶. Handle the “SUBSTRING(:string FROM
     :start FOR :length)” builtin.

8.3.11.21 misc
..............

   * `[declarative] [extension]' ¶. Joined table inheritance
     mappers use a slightly relaxed function to create the “inherit
     condition” to the parent table, so that other foreign keys to
     not-yet-declared Table objects don’t trigger an error.

   * `[declarative] [extension]' ¶ fixed reentrant mapper
     compile hang when a declared attribute is used within ForeignKey,
     ie.  ForeignKey(MyOtherClass.someattribute)

   * `[engines]' ¶. Pool listeners can now be provided as a
     dictionary of callables or a (possibly partial) duck-type of
     PoolListener, your choice.

   * `[engines]' ¶ added “rollback_returned” option to Pool
     which will disable the rollback() issued when connections are
     returned.  This flag is only safe to use with a database which does
     not support transactions (i.e.  MySQL/MyISAM).

   * `[ext]' ¶ set-based association proxies |=, -=, ^= and
     &= are stricter about their operands and only operate on sets,
     frozensets or other association proxies.  Previously, they would
     accept any duck-typed set.

8.3.11.22 0.4.5
...............

Released: Fri Apr 04 2008

8.3.11.23 orm
.............

   * `[orm]' ¶. A small change in behavior to
     session.merge() - existing objects are checked for based on primary
     key attributes, not necessarily _instance_key.  So the widely
     requested capability, that:

          x = MyObject(id=1) x = sess.merge(x)

     will in fact load MyObject with id #1 from the database if present,
     is now available.  merge() still copies the state of the given
     object to the persistent one, so an example like the above would
     typically have copied “None” from all attributes of “x” onto the
     persistent copy.  These can be reverted using session.expire(x).

   * `[orm]' ¶. Also fixed behavior in merge() whereby
     collection elements present on the destination but not the merged
     collection were not being removed from the destination.

   * `[orm]' ¶. Added a more aggressive check for
     “uncompiled mappers”, helps particularly with declarative layer

     References: #995(1)

   * `[orm]' ¶. The methodology behind
     “primaryjoin”/”secondaryjoin” has been refactored.  Behavior should
     be slightly more intelligent, primarily in terms of error messages
     which have been pared down to be more readable.  In a slight number
     of scenarios it can better resolve the correct foreign key than
     before.

   * `[orm]' ¶. Added comparable_property(), adds query
     Comparator behavior to regular, unmanaged Python properties

   * `[orm] [‘machines’] [Company.employees.of_type(Engineer)]' ¶
     the functionality of query.with_polymorphic() has been added
     to mapper() as a configuration option.

     It’s set via several forms:

          with_polymorphic=’*’ with_polymorphic=[mappers]
          with_polymorphic=(‘*’, selectable)
          with_polymorphic=([mappers], selectable)

     This controls the default polymorphic loading strategy for
     inherited mappers.  When a selectable is not given, outer joins are
     created for all joined-table inheriting mappers requested.  Note
     that the auto-create of joins is not compatible with concrete table
     inheritance.

     The existing select_table flag on mapper() is now deprecated and is
     synonymous with with_polymorphic(‘*’, select_table).  Note that the
     underlying “guts” of select_table have been completely removed and
     replaced with the newer, more flexible approach.

     The new approach also automatically allows eager loads to work for
     subclasses, if they are present, for example:

          sess.query(Company).options(
           eagerload_all(
          ))

     to load Company objects, their employees, and the ‘machines’
     collection of employees who happen to be Engineers.  A
     “with_polymorphic” Query option should be introduced soon as well
     which would allow per-Query control of with_polymorphic() on
     relations.

   * `[orm]' ¶ added two “experimental” features to Query,
     “experimental” in that their specific name/behavior is not carved
     in stone just yet: _values() and _from_self().  We’d like feedback
     on these.

        - _values(*columns) is given a list of column expressions, and
          returns a new Query that only returns those columns.  When
          evaluated, the return value is a list of tuples just like when
          using add_column() or add_entity(), the only difference is
          that “entity zero”, i.e.  the mapped class, is not included in
          the results.  This means it finally makes sense to use
          group_by() and having() on Query, which have been sitting
          around uselessly until now.

          A future change to this method may include that its ability to
          join, filter and allow other options not related to a
          “resultset” are removed, so the feedback we’re looking for is
          how people want to use _values()…i.e.  at the very end, or do
          people prefer to continue generating after it’s called.

        - _from_self() compiles the SELECT statement for the Query
          (minus any eager loaders), and returns a new Query that
          selects from that SELECT. So basically you can query from a
          Query without needing to extract the SELECT statement
          manually.  This gives meaning to operations like
          query[3:5]._from_self().filter(some criterion).  There’s not
          much controversial here except that you can quickly create
          highly nested queries that are less efficient, and we want
          feedback on the naming choice.

   * `[orm]' ¶ query.order_by() and query.group_by() will
     accept multiple arguments using *args (like select() already does).

   * `[orm]' ¶. Added some convenience descriptors to Query:
     query.statement returns the full SELECT construct,
     query.whereclause returns just the WHERE part of the SELECT
     construct.

   * `[orm]' ¶. Fixed/covered case when using a False/0
     value as a polymorphic discriminator.

   * `[orm]' ¶. Fixed bug which was preventing synonym()
     attributes from being used with inheritance

   * `[orm]' ¶. Fixed SQL function truncation of trailing
     underscores

     References: #996(2)

   * `[orm]' ¶. When attributes are expired on a pending
     instance, an error will not be raised when the “refresh” action is
     triggered and no result is found.

   * `[orm]' ¶. Session.execute can now find binds from
     metadata

   * `[orm]' ¶. Adjusted the definition of
     “self-referential” to be any two mappers with a common parent (this
     affects whether or not aliased=True is required when joining with
     Query).

   * `[orm]' ¶. Made some fixes to the “from_joinpoint”
     argument to query.join() so that if the previous join was aliased
     and this one isn’t, the join still happens successfully.

   * `[orm]' ¶.

     Assorted “cascade deletes” fixes:

             - Fixed “cascade delete” operation of dynamic relations,
               which had only been implemented for foreign-key nulling
               behavior in 0.4.2 and not actual cascading deletes

             - Delete cascade without delete-orphan cascade on a
               many-to-one will not delete orphans which were
               disconnected from the parent before session.delete() is
               called on the parent (one-to-many already had this).

             - Delete cascade with delete-orphan will delete orphans
               whether or not it remains attached to its also-deleted
               parent.

             - delete-orphan cascade is properly detected on relations
               that are present on superclasses when using inheritance.

     References: #895(3)

   * `[orm]' ¶. Fixed order_by calculation in Query to
     properly alias mapper-config’ed order_by when using select_from()

   * `[orm]' ¶. Refactored the diffing logic that kicks in
     when replacing one collection with another into
     collections.bulk_replace, useful to anyone building multi-level
     collections.

   * `[orm]' ¶. Cascade traversal algorithm converted from
     recursive to iterative to support deep object graphs.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/995

   (2) http://www.sqlalchemy.org/trac/ticket/996

   (3) http://www.sqlalchemy.org/trac/ticket/895

8.3.11.24 sql
.............

   * `[sql]' ¶ schema-qualified tables now will place the
     schemaname ahead of the tablename in all column expressions as well
     as when generating column labels.  This prevents cross- schema name
     collisions in all cases

     References: #999(1)

   * `[sql]' ¶ can now allow selects which correlate all
     FROM clauses and have no FROM themselves.  These are typically used
     in a scalar context, i.e.  SELECT x, (SELECT x WHERE y) FROM table.
     Requires explicit correlate() call.

   * `[sql]' ¶. ’name’ is no longer a required constructor
     argument for Column().  It (and .key) may now be deferred until the
     column is added to a Table.

   * `[sql]' ¶ like(), ilike(), contains(), startswith(),
     endswith() take an optional keyword argument “escape=<somestring>”,
     which is set as the escape character using the syntax “x LIKE y
     ESCAPE ‘<somestring>’”.

     References: #791(2), #993(3)

   * `[sql]' ¶ random() is now a generic sql function and
     will compile to the database’s random implementation, if any.

   * `[sql]' ¶ update().values() and insert().values() take
     keyword arguments.

   * `[sql]' ¶. Fixed an issue in select() regarding its
     generation of FROM clauses, in rare circumstances two clauses could
     be produced when one was intended to cancel out the other.  Some
     ORM queries with lots of eager loads might have seen this symptom.

   * `[sql]' ¶. The case() function now also takes a
     dictionary as its whens parameter.  It also interprets the “THEN”
     expressions as values by default, meaning case([(x==y, “foo”)])
     will interpret “foo” as a bound value, not a SQL expression.  use
     text(expr) for literal SQL expressions in this case.  For the
     criterion itself, these may be literal strings only if the “value”
     keyword is present, otherwise SA will force explicit usage of
     either text() or literal().

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/999

   (2) http://www.sqlalchemy.org/trac/ticket/791

   (3) http://www.sqlalchemy.org/trac/ticket/993

8.3.11.25 mysql
...............

   * `[mysql]' ¶. The connection.info keys the dialect uses
     to cache server settings have changed and are now namespaced.

8.3.11.26 mssql
...............

   * `[mssql]' ¶. Reflected tables will now automatically
     load other tables which are referenced by Foreign keys in the
     auto-loaded table,.

     References: #979(1)

   * `[mssql]' ¶. Added executemany check to skip identity
     fetch,.

     References: #916(2)

   * `[mssql]' ¶. Added stubs for small date type.

     References: #884(3)

   * `[mssql]' ¶. Added a new ‘driver’ keyword parameter for
     the pyodbc dialect.  Will substitute into the ODBC connection
     string if given, defaults to ‘SQL Server’.

   * `[mssql]' ¶. Added a new ‘max_identifier_length’
     keyword parameter for the pyodbc dialect.

   * `[mssql]' ¶. Improvements to pyodbc + Unix.  If you
     couldn’t get that combination to work before, please try again.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/979

   (2) http://www.sqlalchemy.org/trac/ticket/916

   (3) http://www.sqlalchemy.org/trac/ticket/884

8.3.11.27 oracle
................

   * `[oracle]' ¶. The “owner” keyword on Table is now
     deprecated, and is exactly synonymous with the “schema” keyword.
     Tables can now be reflected with alternate “owner” attributes,
     explicitly stated on the Table object or not using “schema”.

   * `[oracle]' ¶. All of the “magic” searching for
     synonyms, DBLINKs etc.  during table reflection are disabled by
     default unless you specify “oracle_resolve_synonyms=True” on the
     Table object.  Resolving synonyms necessarily leads to some messy
     guessing which we’d rather leave off by default.  When the flag is
     set, tables and related tables will be resolved against synonyms in
     all cases, meaning if a synonym exists for a particular table,
     reflection will use it when reflecting related tables.  This is
     stickier behavior than before which is why it’s off by default.

8.3.11.28 misc
..............

   * `[declarative] [extension]' ¶. The “synonym” function
     is now directly usable with “declarative”.  Pass in the decorated
     property using the “descriptor” keyword argument, e.g.: somekey =
     synonym(‘_somekey’, descriptor=property(g, s))

   * `[declarative] [extension]' ¶. The “deferred” function
     is usable with “declarative”.  Simplest usage is to declare
     deferred and Column together, e.g.: data = deferred(Column(Text))

   * `[declarative] [extension]' ¶. Declarative also gained
     @synonym_for(…) and @comparable_using(…), front-ends for synonym
     and comparable_property.

   * `[declarative] [extension]' ¶. Improvements to mapper
     compilation when using declarative; already-compiled mappers will
     still trigger compiles of other uncompiled mappers when used

     References: #995(1)

   * `[declarative] [extension]' ¶. Declarative will
     complete setup for Columns lacking names, allows a more DRY syntax.

          class Foo(Base):

               __tablename__ = ‘foos’ id = Column(Integer,
               primary_key=True)

   * `[declarative] [extension]' ¶ inheritance in
     declarative can be disabled when sending “inherits=None” to
     __mapper_args__.

   * `[declarative] [extension]' ¶ declarative_base() takes
     optional kwarg “mapper”, which is any callable/class/method that
     produces a mapper, such as
     declarative_base(mapper=scopedsession.mapper).  This property can
     also be set on individual declarative classes using the
     “__mapper_cls__” property.

   * `[postgres]' ¶. Got PG server side cursors back into
     shape, added fixed unit tests as part of the default test suite.
     Added better uniqueness to the cursor ID

     References: #1001(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/995

   (2) http://www.sqlalchemy.org/trac/ticket/1001

8.3.11.29 0.4.4
...............

Released: Wed Mar 12 2008

8.3.11.30 orm
.............

   * `[orm]' ¶ any(), has(), contains(), ~contains(),
     attribute level == and != now work properly with self-referential
     relations - the clause inside the EXISTS is aliased on the “remote”
     side to distinguish it from the parent table.  This applies to
     single table self-referential as well as inheritance-based
     self-referential.

   * `[orm]' ¶. Repaired behavior of == and != operators at
     the relation() level when compared against NULL for one-to-one
     relations

     References: #985(1)

   * `[orm]' ¶. Fixed bug whereby session.expire()
     attributes were not loading on an polymorphically-mapped instance
     mapped by a select_table mapper.

   * `[orm]' ¶. Added query.with_polymorphic() - specifies a
     list of classes which descend from the base class, which will be
     added to the FROM clause of the query.  Allows subclasses to be
     used within filter() criterion as well as eagerly loads the
     attributes of those subclasses.

   * `[orm]' ¶. Your cries have been heard: removing a
     pending item from an attribute or collection with delete-orphan
     expunges the item from the session; no FlushError is raised.  Note
     that if you session.save()’ed the pending item explicitly, the
     attribute/collection removal still knocks it out.

   * `[orm]' ¶ session.refresh() and session.expire() raise
     an error when called on instances which are not persistent within
     the session

   * `[orm]' ¶. Fixed potential generative bug when the same
     Query was used to generate multiple Query objects using join().

   * `[orm]' ¶. Fixed bug which was introduced in 0.4.3,
     whereby loading an already-persistent instance mapped with joined
     table inheritance would trigger a useless “secondary” load from its
     joined table, when using the default “select” polymorphic_fetch.
     This was due to attributes being marked as expired during its first
     load and not getting unmarked from the previous “secondary” load.
     Attributes are now unexpired based on presence in __dict__ after
     any load or commit operation succeeds.

   * `[orm]' ¶. Deprecated Query methods apply_sum(),
     apply_max(), apply_min(), apply_avg().  Better methodologies are
     coming….

   * `[orm]' ¶ relation() can accept a callable for its
     first argument, which returns the class to be related.  This is in
     place to assist declarative packages to define relations without
     classes yet being in place.

   * `[orm]' ¶. Added a new “higher level” operator called
     “of_type()”: used in join() as well as with any() and has(),
     qualifies the subclass which will be used in filter criterion,
     e.g.:

          query.filter(Company.employees.of_type(Engineer).

               any(Engineer.name==’foo’))

          or

          query.join(Company.employees.of_type(Engineer)).

               filter(Engineer.name==’foo’)

   * `[orm]' ¶. Preventive code against a potential
     lost-reference bug in flush().

   * `[orm]' ¶. Expressions used in filter(), filter_by()
     and others, when they make usage of a clause generated from a
     relation using the identity of a child object (e.g.,
     filter(Parent.child==<somechild>)), evaluate the actual primary key
     value of <somechild> at execution time so that the autoflush step
     of the Query can complete, thereby populating the PK value of
     <somechild> in the case that <somechild> was pending.

   * `[orm]' ¶ setting the relation()-level order by to a
     column in the many-to-many “secondary” table will now work with
     eager loading, previously the “order by” wasn’t aliased against the
     secondary table’s alias.

   * `[orm]' ¶. Synonyms riding on top of existing
     descriptors are now full proxies to those descriptors.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/985

8.3.11.31 sql
.............

   * `[sql]' ¶. Can again create aliases of selects against
     textual FROM clauses.

     References: #975(1)

   * `[sql]' ¶. The value of a bindparam() can be a
     callable, in which case it’s evaluated at statement execution time
     to get the value.

   * `[sql]' ¶. Added exception wrapping/reconnect support
     to result set fetching.  Reconnect works for those databases that
     raise a catchable data error during results (i.e.  doesn’t work on
     MySQL)

     References: #978(2)

   * `[sql]' ¶. Implemented two-phase API for “threadlocal”
     engine, via engine.begin_twophase(), engine.prepare()

     References: #936(3)

   * `[sql]' ¶. Fixed bug which was preventing UNIONS from
     being cloneable.

     References: #986(4)

   * `[sql]' ¶. Added “bind” keyword argument to insert(),
     update(), delete() and DDL().  The .bind property is now assignable
     on those statements as well as on select().

   * `[sql]' ¶. Insert statements can now be compiled with
     extra “prefix” words between INSERT and INTO, for vendor extensions
     like MySQL’s INSERT IGNORE INTO table.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/975

   (2) http://www.sqlalchemy.org/trac/ticket/978

   (3) http://www.sqlalchemy.org/trac/ticket/936

   (4) http://www.sqlalchemy.org/trac/ticket/986

8.3.11.32 extensions
....................

   * `[extensions]' ¶ a new super-small “declarative”
     extension has been added, which allows Table and mapper()
     configuration to take place inline underneath a class declaration.
     This extension differs from ActiveMapper and Elixir in that it does
     not redefine any SQLAlchemy semantics at all; literal Column, Table
     and relation() constructs are used to define the class behavior and
     table definition.

8.3.11.33 misc
..............

   * `[dialects]' ¶. Invalid SQLite connection URLs now
     raise an error.

   * `[dialects]' ¶ postgres TIMESTAMP renders correctly

     References: #981(1)

   * `[dialects]' ¶ postgres PGArray is a “mutable” type by
     default; when used with the ORM, mutable-style equality/
     copy-on-write techniques are used to test for changes.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/981

8.3.11.34 0.4.3
...............

Released: Thu Feb 14 2008

8.3.11.35 general
.................

   * `[general]' ¶. Fixed a variety of hidden and some
     not-so-hidden compatibility issues for Python 2.3, thanks to new
     support for running the full test suite on 2.3.

   * `[general]' ¶. Warnings are now issued as type
     exceptions.SAWarning.

8.3.11.36 orm
.............

   * `[orm]' ¶. Every Session.begin() must now be
     accompanied by a corresponding commit() or rollback() unless the
     session is closed with Session.close().  This also includes the
     begin() which is implicit to a session created with
     transactional=True.  The biggest change introduced here is that
     when a Session created with transactional=True raises an exception
     during flush(), you must call Session.rollback() or Session.close()
     in order for that Session to continue after an exception.

   * `[orm]' ¶. Fixed merge() collection-doubling bug when
     merging transient entities with backref’ed collections.

     References: #961(1)

   * `[orm]' ¶ merge(dont_load=True) does not accept
     transient entities, this is in continuation with the fact that
     merge(dont_load=True) does not accept any “dirty” objects either.

   * `[orm]' ¶. Added standalone “query” class attribute
     generated by a scoped_session.  This provides MyClass.query without
     using Session.mapper.  Use via:

          MyClass.query = Session.query_property()

   * `[orm]' ¶. The proper error message is raised when
     trying to access expired instance attributes with no session
     present

   * `[orm]' ¶ dynamic_loader() / lazy=”dynamic” now
     accepts and uses the order_by parameter in the same way in which it
     works with relation().

   * `[orm]' ¶. Added expire_all() method to Session.  Calls
     expire() for all persistent instances.  This is handy in
     conjunction with…

   * `[orm]' ¶. Instances which have been partially or fully
     expired will have their expired attributes populated during a
     regular Query operation which affects those objects, preventing a
     needless second SQL statement for each instance.

   * `[orm]' ¶. Dynamic relations, when referenced, create a
     strong reference to the parent object so that the query still has a
     parent to call against even if the parent is only created (and
     otherwise dereferenced) within the scope of a single expression.

     References: #938(2)

   * `[orm]' ¶. Added a mapper() flag “eager_defaults”.
     When set to True, defaults that are generated during an INSERT or
     UPDATE operation are post-fetched immediately, instead of being
     deferred until later.  This mimics the old 0.3 behavior.

   * `[orm]' ¶ query.join() can now accept class-mapped
     attributes as arguments.  These can be used in place or in any
     combination with strings.  In particular this allows construction
     of joins to subclasses on a polymorphic relation, i.e.:

          query(Company).join([‘employees’, Engineer.name])

   * `[orm] [(‘employees’] [Engineer.name] [people.join(engineer))]'
     ¶ query.join() can also accept tuples of attribute
     name/some selectable as arguments.  This allows construction of
     joins `from' subclasses of a polymorphic relation, i.e.:

          query(Company).join(

          )

   * `[orm]' ¶. General improvements to the behavior of
     join() in conjunction with polymorphic mappers, i.e.  joining
     from/to polymorphic mappers and properly applying aliases.

   * `[orm]' ¶. Fixed/improved behavior when a mapper
     determines the natural “primary key” of a mapped join, it will more
     effectively reduce columns which are equivalent via foreign key
     relation.  This affects how many arguments need to be sent to
     query.get(), among other things.

     References: #933(3)

   * `[orm]' ¶. The lazy loader can now handle a join
     condition where the “bound” column (i.e.  the one that gets the
     parent id sent as a bind parameter) appears more than once in the
     join condition.  Specifically this allows the common task of a
     relation() which contains a parent-correlated subquery, such as
     “select only the most recent child item”.

     References: #946(4)

   * `[orm]' ¶. Fixed bug in polymorphic inheritance where
     an incorrect exception is raised when base polymorphic_on column
     does not correspond to any columns within the local selectable of
     an inheriting mapper more than one level deep

   * `[orm]' ¶. Fixed bug in polymorphic inheritance which
     made it difficult to set a working “order_by” on a polymorphic
     mapper.

   * `[orm]' ¶. Fixed a rather expensive call in Query that
     was slowing down polymorphic queries.

   * `[orm]' ¶. ”Passive defaults” and other “inline”
     defaults can now be loaded during a flush() call if needed; in
     particular, this allows constructing relations() where a foreign
     key column references a server-side-generated, non-primary-key
     column.

     References: #954(5)

   * `[orm]' ¶.

     Additional Session transaction fixes/changes:

             - Fixed bug with session transaction management: parent
               transactions weren’t started on the connection when
               adding a connection to a nested transaction.

             - session.transaction now always refers to the innermost
               active transaction, even when commit/rollback are called
               directly on the session transaction object.

             - Two-phase transactions can now be prepared.

             - When preparing a two-phase transaction fails on one
               connection, all the connections are rolled back.

             - session.close() didn’t close all transactions when nested
               transactions were used.

             - rollback() previously erroneously set the current
               transaction directly to the parent of the transaction
               that could be rolled back to.  Now it rolls back the next
               transaction up that can handle it, but sets the current
               transaction to its parent and inactivates the
               transactions in between.  Inactive transactions can only
               be rolled back or closed, any other call results in an
               error.

             - autoflush for commit() wasn’t flushing for simple
               subtransactions.

             - unitofwork flush didn’t close the failed transaction when
               the session was not in a transaction and committing the
               transaction failed.

   * `[orm]' ¶. Miscellaneous tickets:

     References: #940(6), #964(7)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/961

   (2) http://www.sqlalchemy.org/trac/ticket/938

   (3) http://www.sqlalchemy.org/trac/ticket/933

   (4) http://www.sqlalchemy.org/trac/ticket/946

   (5) http://www.sqlalchemy.org/trac/ticket/954

   (6) http://www.sqlalchemy.org/trac/ticket/940

   (7) http://www.sqlalchemy.org/trac/ticket/964

8.3.11.37 sql
.............

   * `[sql]' ¶. Added “schema.DDL”, an executable free-form
     DDL statement.  DDLs can be executed in isolation or attached to
     Table or MetaData instances and executed automatically when those
     objects are created and/or dropped.

   * `[sql]' ¶. Table columns and constraints can be
     overridden on a an existing table (such as a table that was already
     reflected) using the ‘useexisting=True’ flag, which now takes into
     account the arguments passed along with it.

   * `[sql]' ¶. Added a callable-based DDL events interface,
     adds hooks before and after Tables and MetaData create and drop.

   * `[sql]' ¶. Added generative where(<criterion>) method
     to delete() and update() constructs which return a new object with
     criterion joined to existing criterion via AND, just like
     select().where().

   * `[sql]' ¶. Added “ilike()” operator to column
     operations.  Compiles to ILIKE on postgres, lower(x) LIKE lower(y)
     on all others.

     References: #727(1)

   * `[sql]' ¶. Added “now()” as a generic function; on
     SQLite, Oracle and MSSQL compiles as “CURRENT_TIMESTAMP”; “now()”
     on all others.

     References: #943(2)

   * `[sql]' ¶. The startswith(), endswith(), and contains()
     operators now concatenate the wildcard operator with the given
     operand in SQL, i.e.  “’%’ || <bindparam>” in all cases, accept
     text(‘something’) operands properly

     References: #962(3)

   * `[sql]' ¶ cast() accepts text(‘something’) and other
     non-literal operands properly

     References: #962(4)

   * `[sql]' ¶ fixed bug in result proxy where anonymously
     generated column labels would not be accessible using their
     straight string name

   * `[sql]' ¶. Deferrable constraints can now be defined.

   * `[sql]' ¶. Added “autocommit=True” keyword argument to
     select() and text(), as well as generative autocommit() method on
     select(); for statements which modify the database through some
     user-defined means other than the usual INSERT/UPDATE/ DELETE etc.
     This flag will enable “autocommit” behavior during execution if no
     transaction is in progress.

     References: #915(5)

   * `[sql]' ¶. The ‘.c.’ attribute on a selectable now gets
     an entry for every column expression in its columns clause.
     Previously, “unnamed” columns like functions and CASE statements
     weren’t getting put there.  Now they will, using their full string
     representation if no ‘name’ is available.

   * `[sql]' ¶ a CompositeSelect, i.e.  any union(),
     union_all(), intersect(), etc.  now asserts that each selectable
     contains the same number of columns.  This conforms to the
     corresponding SQL requirement.

   * `[sql]' ¶. The anonymous ‘label’ generated for
     otherwise unlabeled functions and expressions now propagates
     outwards at compile time for expressions like
     select([select([func.foo()])]).

   * `[sql]' ¶. Building on the above ideas,
     CompositeSelects now build up their “.c.” collection based on the
     names present in the first selectable only; corresponding_column()
     now works fully for all embedded selectables.

   * `[sql]' ¶. Oracle and others properly encode SQL used
     for defaults like sequences, etc., even if no unicode idents are
     used since identifier preparer may return a cached unicode
     identifier.

   * `[sql]' ¶. Column and clause comparisons to datetime
     objects on the left hand side of the expression now work (d <
     table.c.col).  (datetimes on the RHS have always worked, the LHS
     exception is a quirk of the datetime implementation.)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/727

   (2) http://www.sqlalchemy.org/trac/ticket/943

   (3) http://www.sqlalchemy.org/trac/ticket/962

   (4) http://www.sqlalchemy.org/trac/ticket/962

   (5) http://www.sqlalchemy.org/trac/ticket/915

8.3.11.38 misc
..............

   * `[dialects]' ¶. Better support for schemas in SQLite
     (linked in by ATTACH DATABASE … AS name).  In some cases in the
     past, schema names were omitted from generated SQL for SQLite.
     This is no longer the case.

   * `[dialects]' ¶ table_names on SQLite now picks up
     temporary tables as well.

   * `[dialects]' ¶. Auto-detect an unspecified MySQL
     ANSI_QUOTES mode during reflection operations, support for changing
     the mode midstream.  Manual mode setting is still required if no
     reflection is used.

   * `[dialects]' ¶. Fixed reflection of TIME columns on
     SQLite.

   * `[dialects]' ¶. Finally added PGMacAddr type to
     postgres

     References: #580(1)

   * `[dialects]' ¶. Reflect the sequence associated to a PK
     field (typically with a BEFORE INSERT trigger) under Firebird

   * `[dialects]' ¶. Oracle assembles the correct columns in
     the result set column mapping when generating a LIMIT/OFFSET
     subquery, allows columns to map properly to result sets even if
     long-name truncation kicks in

     References: #941(2)

   * `[dialects]' ¶. MSSQL now includes EXEC in the
     _is_select regexp, which should allow row-returning stored
     procedures to be used.

   * `[dialects]' ¶. MSSQL now includes an experimental
     implementation of LIMIT/OFFSET using the ANSI SQL row_number()
     function, so it requires MSSQL-2005 or higher.  To enable the
     feature, add “has_window_funcs” to the keyword arguments for
     connect, or add “?has_window_funcs=1” to your dburi query
     arguments.

   * `[ext]' ¶. Changed ext.activemapper to use a
     non-transactional session for the objectstore.

   * `[ext]' ¶. Fixed output order of “[‘a’] + obj.proxied”
     binary operation on association-proxied lists.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/580

   (2) http://www.sqlalchemy.org/trac/ticket/941

8.3.11.39 0.4.2p3
.................

Released: Wed Jan 09 2008

8.3.11.40 general
.................

   * `[general]' ¶ sub version numbering scheme changed to
     suite setuptools version number rules; easy_install -u should now
     get this version over 0.4.2.

8.3.11.41 orm
.............

   * `[orm]' ¶ fixed bug with session.dirty when using
     “mutable scalars” (such as PickleTypes)

   * `[orm]' ¶ added a more descriptive error message when
     flushing on a relation() that has non-locally-mapped columns in its
     primary or secondary join condition

   * `[orm]' ¶ suppressing `all' errors in
     InstanceState.__cleanup() now.

   * `[orm]' ¶ fixed an attribute history bug whereby
     assigning a new collection to a collection-based attribute which
     already had pending changes would generate incorrect history

     References: #922(1)

   * `[orm]' ¶ fixed delete-orphan cascade bug whereby
     setting the same object twice to a scalar attribute could log it as
     an orphan

     References: #925(2)

   * `[orm]' ¶. Fixed cascades on a += assignment to a
     list-based relation.

   * `[orm]' ¶ synonyms can now be created against props
     that don’t exist yet, which are later added via add_property().
     This commonly includes backrefs.  (i.e.  you can make synonyms for
     backrefs without worrying about the order of operations)

     References: #919(3)

   * `[orm]' ¶ fixed bug which could occur with polymorphic
     “union” mapper which falls back to “deferred” loading of inheriting
     tables

   * `[orm]' ¶ the “columns” collection on a mapper/mapped
     class (i.e.  ‘c’) is against the mapped table, not the select_table
     in the case of polymorphic “union” loading (this shouldn’t be
     noticeable).

   * `[orm]' ¶ fixed fairly critical bug whereby the same
     instance could be listed more than once in the unitofwork.new
     collection; most typically reproduced when using a combination of
     inheriting mappers and ScopedSession.mapper, as the multiple
     __init__ calls per instance could save() the object with distinct
     _state objects

   * `[orm]' ¶ added very rudimentary yielding iterator
     behavior to Query.  Call query.yield_per(<number of rows>) and
     evaluate the Query in an iterative context; every collection of N
     rows will be packaged up and yielded.  Use this method with extreme
     caution since it does not attempt to reconcile eagerly loaded
     collections across result batch boundaries, nor will it behave
     nicely if the same instance occurs in more than one batch.  This
     means that an eagerly loaded collection will get cleared out if
     it’s referenced in more than one batch, and in all cases attributes
     will be overwritten on instances that occur in more than one batch.

   * `[orm]' ¶. Fixed in-place set mutation operators for
     set collections and association proxied sets.

     References: #920(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/922

   (2) http://www.sqlalchemy.org/trac/ticket/925

   (3) http://www.sqlalchemy.org/trac/ticket/919

   (4) http://www.sqlalchemy.org/trac/ticket/920

8.3.11.42 sql
.............

   * `[sql]' ¶. Text type is properly exported now and does
     not raise a warning on DDL create; String types with no length only
     raise warnings during CREATE TABLE

     References: #912(1)

   * `[sql]' ¶ new UnicodeText type is added, to specify an
     encoded, unlengthed Text type

   * `[sql]' ¶ fixed bug in union() so that select()
     statements which don’t derive from FromClause objects can be
     unioned

   * `[sql]' ¶ changed name of TEXT to Text since its a
     “generic” type; TEXT name is deprecated until 0.5.  The “upgrading”
     behavior of String to Text when no length is present is also
     deprecated until 0.5; will issue a warning when used for CREATE
     TABLE statements (String with no length for SQL expression purposes
     is still fine)

     References: #912(2)

   * `[sql]' ¶ generative select.order_by(None) /
     group_by(None) was not managing to reset order by/group by
     criterion, fixed

     References: #924(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/912

   (2) http://www.sqlalchemy.org/trac/ticket/912

   (3) http://www.sqlalchemy.org/trac/ticket/924

8.3.11.43 misc
..............

   * `[dialects]' ¶. Fixed reflection of mysql empty string
     column defaults.

   * `[ext]' ¶. ’+’, ‘*’, ‘+=’ and ‘*=’ support for
     association proxied lists.

   * `[dialects]' ¶ mssql - narrowed down the test for
     “date”/”datetime” in MSDate/ MSDateTime subclasses so that incoming
     “datetime” objects don’t get mis-interpreted as “date” objects and
     vice versa.

     References: #923(1)

   * `[dialects]' ¶. Fixed the missing call to subtype
     result processor for the PGArray type.

     References: #913(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/923

   (2) http://www.sqlalchemy.org/trac/ticket/913

8.3.11.44 0.4.2
...............

Released: Wed Jan 02 2008

8.3.11.45 orm
.............

   * `[orm]' ¶ a major behavioral change to
     collection-based backrefs: they no longer trigger lazy loads !
     “reverse” adds and removes are queued up and are merged with the
     collection when it is actually read from and loaded; but do not
     trigger a load beforehand.  For users who have noticed this
     behavior, this should be much more convenient than using dynamic
     relations in some cases; for those who have not, you might notice
     your apps using a lot fewer queries than before in some situations.

     References: #871(1)

   * `[orm]' ¶ mutable primary key support is added.
     primary key columns can be changed freely, and the identity of the
     instance will change upon flush.  In addition, update cascades of
     foreign key referents (primary key or not) along relations are
     supported, either in tandem with the database’s ON UPDATE CASCADE
     (required for DB’s like Postgres) or issued directly by the ORM in
     the form of UPDATE statements, by setting the flag
     “passive_cascades=False”.

   * `[orm]' ¶ inheriting mappers now inherit the
     MapperExtensions of their parent mapper directly, so that all
     methods for a particular MapperExtension are called for subclasses
     as well.  As always, any MapperExtension can return either
     EXT_CONTINUE to continue extension processing or EXT_STOP to stop
     processing.  The order of mapper resolution is: <extensions
     declared on the classes mapper> <extensions declared on the
     classes’ parent mapper> <globally declared extensions>.

     Note that if you instantiate the same extension class separately
     and then apply it individually for two mappers in the same
     inheritance chain, the extension will be applied twice to the
     inheriting class, and each method will be called twice.

     To apply a mapper extension explicitly to each inheriting class but
     have each method called only once per operation, use the same
     instance of the extension for both mappers.

     References: #490(2)

   * `[orm]' ¶. MapperExtension.before_update() and
     after_update() are now called symmetrically; previously, an
     instance that had no modified column attributes (but had a
     relation() modification) could be called with before_update() but
     not after_update()

     References: #907(3)

   * `[orm]' ¶ columns which are missing from a Query’s
     select statement now get automatically deferred during load.

   * `[orm]' ¶ mapped classes which extend “object” and do
     not provide an __init__() method will now raise TypeError if
     non-empty *args or **kwargs are present at instance construction
     time (and are not consumed by any extensions such as the
     scoped_session mapper), consistent with the behavior of normal
     Python classes

     References: #908(4)

   * `[orm]' ¶ fixed Query bug when filter_by() compares a
     relation against None

     References: #899(5)

   * `[orm]' ¶ improved support for pickling of mapped
     entities.  Per-instance lazy/deferred/expired callables are now
     serializable so that they serialize and deserialize with _state.

   * `[orm]' ¶ new synonym() behavior: an attribute will be
     placed on the mapped class, if one does not exist already, in all
     cases.  if a property already exists on the class, the synonym will
     decorate the property with the appropriate comparison operators so
     that it can be used in column expressions just like any other
     mapped attribute (i.e.  usable in filter(), etc.)  the “proxy=True”
     flag is deprecated and no longer means anything.  Additionally, the
     flag “map_column=True” will automatically generate a ColumnProperty
     corresponding to the name of the synonym, i.e.:
     ‘somename’:synonym(‘_somename’, map_column=True) will map the
     column named ‘somename’ to the attribute ‘_somename’.  See the
     example in the mapper docs.

     References: #801(6)

   * `[orm]' ¶. Query.select_from() now replaces all
     existing FROM criterion with the given argument; the previous
     behavior of constructing a list of FROM clauses was generally not
     useful as is required filter() calls to create join criterion, and
     new tables introduced within filter() already add themselves to the
     FROM clause.  The new behavior allows not just joins from the main
     table, but select statements as well.  Filter criterion, order bys,
     eager load clauses will be “aliased” against the given statement.

   * `[orm]' ¶ this month’s refactoring of attribute
     instrumentation changes the “copy-on-load” behavior we’ve had since
     midway through 0.3 with “copy-on-modify” in most cases.  This takes
     a sizable chunk of latency out of load operations and overall does
     less work as only attributes which are actually modified get their
     “committed state” copied.  Only “mutable scalar” attributes (i.e.
     a pickled object or other mutable item), the reason for the
     copy-on-load change in the first place, retain the old behavior.

   * `[orm] [attrname]' ¶ a slight behavioral change to
     attributes is, del’ing an attribute does `not' cause the lazyloader
     of that attribute to fire off again; the “del” makes the effective
     value of the attribute “None”.  To re-trigger the “loader” for an
     attribute, use session.expire(instance,).

   * `[orm]' ¶ query.filter(SomeClass.somechild == None),
     when comparing a many-to-one property to None, properly generates
     “id IS NULL” including that the NULL is on the right side.

   * `[orm]' ¶ query.order_by() takes into account aliased
     joins, i.e.  query.join(‘orders’, aliased=True).order_by(Order.id)

   * `[orm]' ¶ eagerload(), lazyload(), eagerload_all()
     take an optional second class-or-mapper argument, which will select
     the mapper to apply the option towards.  This can select among
     other mappers which were added using add_entity().

   * `[orm]' ¶ eagerloading will work with mappers added
     via add_entity().

   * `[orm]' ¶ added “cascade delete” behavior to “dynamic”
     relations just like that of regular relations.  if passive_deletes
     flag (also just added) is not set, a delete of the parent item will
     trigger a full load of the child items so that they can be deleted
     or updated accordingly.

   * `[orm]' ¶ also with dynamic, implemented correct
     count() behavior as well as other helper methods.

   * `[orm]' ¶ fix to cascades on polymorphic relations,
     such that cascades from an object to a polymorphic collection
     continue cascading along the set of attributes specific to each
     element in the collection.

   * `[orm]' ¶ query.get() and query.load() do not take
     existing filter or other criterion into account; these methods
     `always' look up the given id in the database or return the current
     instance from the identity map, disregarding any existing filter,
     join, group_by or other criterion which has been configured.

     References: #893(7)

   * `[orm]' ¶ added support for version_id_col in
     conjunction with inheriting mappers.  version_id_col is typically
     set on the base mapper in an inheritance relationship where it
     takes effect for all inheriting mappers.

     References: #883(8)

   * `[orm]' ¶ relaxed rules on column_property()
     expressions having labels; any ColumnElement is accepted now, as
     the compiler auto-labels non-labeled ColumnElements now.  a
     selectable, like a select() statement, still requires conversion to
     ColumnElement via as_scalar() or label().

   * `[orm]' ¶ fixed backref bug where you could not del
     instance.attr if attr was None

   * `[orm]' ¶ several ORM attributes have been removed or
     made private: mapper.get_attr_by_column(),
     mapper.set_attr_by_column(), mapper.pks_by_table,
     mapper.cascade_callable(), MapperProperty.cascade_callable(),
     mapper.canload(), mapper.save_obj(), mapper.delete_obj(),
     mapper._mapper_registry, attributes.AttributeManager

   * `[orm]' ¶. Assigning an incompatible collection type to
     a relation attribute now raises TypeError instead of sqlalchemy’s
     ArgumentError.

   * `[orm]' ¶. Bulk assignment of a MappedCollection now
     raises an error if a key in the incoming dictionary does not match
     the key that the collection’s keyfunc would use for that value.

     References: #886(9)

   * `[orm] [newval1] [newval2]' ¶. Custom collections can
     now specify a @converter method to translate objects used in “bulk”
     assignment into a stream of values, as in:

          obj.col =
          # or
          obj.dictcol = {'foo': newval1, 'bar': newval2}

     The MappedCollection uses this hook to ensure that incoming
     key/value pairs are sane from the collection’s perspective.

   * `[orm]' ¶ fixed endless loop issue when using
     lazy=”dynamic” on both sides of a bi-directional relationship

     References: #872(10)

   * `[orm]' ¶ more fixes to the LIMIT/OFFSET aliasing
     applied with Query + eagerloads, in this case when mapped against a
     select statement

     References: #904(11)

   * `[orm]' ¶ fix to self-referential eager loading such
     that if the same mapped instance appears in two or more distinct
     sets of columns in the same result set, its eagerly loaded
     collection will be populated regardless of whether or not all of
     the rows contain a set of “eager” columns for that collection.
     this would also show up as a KeyError when fetching results with
     join_depth turned on.

   * `[orm]' ¶ fixed bug where Query would not apply a
     subquery to the SQL when LIMIT was used in conjunction with an
     inheriting mapper where the eager loader was only in the parent
     mapper.

   * `[orm]' ¶ clarified the error message which occurs
     when you try to update() an instance with the same identity key as
     an instance already present in the session.

   * `[orm]' ¶ some clarifications and fixes to
     merge(instance, dont_load=True).  fixed bug where lazy loaders were
     getting disabled on returned instances.  Also, we currently do not
     support merging an instance which has uncommitted changes on it, in
     the case that dont_load=True is used….this will now raise an error.
     This is due to complexities in merging the “committed state” of the
     given instance to correctly correspond to the newly copied
     instance, as well as other modified state.  Since the use case for
     dont_load=True is caching, the given instances shouldn’t have any
     uncommitted changes on them anyway.  We also copy the instances
     over without using any events now, so that the ‘dirty’ list on the
     new session remains unaffected.

   * `[orm]' ¶ fixed bug which could arise when using
     session.begin_nested() in conjunction with more than one level deep
     of enclosing session.begin() statements

   * `[orm]' ¶ fixed session.refresh() with instance that
     has custom entity_name

     References: #914(12)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/871

   (2) http://www.sqlalchemy.org/trac/ticket/490

   (3) http://www.sqlalchemy.org/trac/ticket/907

   (4) http://www.sqlalchemy.org/trac/ticket/908

   (5) http://www.sqlalchemy.org/trac/ticket/899

   (6) http://www.sqlalchemy.org/trac/ticket/801

   (7) http://www.sqlalchemy.org/trac/ticket/893

   (8) http://www.sqlalchemy.org/trac/ticket/883

   (9) http://www.sqlalchemy.org/trac/ticket/886

   (10) http://www.sqlalchemy.org/trac/ticket/872

   (11) http://www.sqlalchemy.org/trac/ticket/904

   (12) http://www.sqlalchemy.org/trac/ticket/914

8.3.11.46 sql
.............

   * `[sql]' ¶ generic functions !  we introduce a database
     of known SQL functions, such as current_timestamp, coalesce, and
     create explicit function objects representing them.  These objects
     have constrained argument lists, are type aware, and can compile in
     a dialect-specific fashion.  So saying func.char_length(“foo”,
     “bar”) raises an error (too many args),
     func.coalesce(datetime.date(2007, 10, 5), datetime.date(2005, 10,
     15)) knows that its return type is a Date.  We only have a few
     functions represented so far but will continue to add to the system

     References: #615(1)

   * `[sql]' ¶ auto-reconnect support improved; a
     Connection can now automatically reconnect after its underlying
     connection is invalidated, without needing to connect() again from
     the engine.  This allows an ORM session bound to a single
     Connection to not need a reconnect.  Open transactions on the
     Connection must be rolled back after an invalidation of the
     underlying connection else an error is raised.  Also fixed bug
     where disconnect detect was not being called for cursor(),
     rollback(), or commit().

   * `[sql]' ¶ added new flag to String and
     create_engine(), assert_unicode=(True|False|’warn’|None).  Defaults
     to ‘False’ or ‘None’ on create_engine() and String, ‘‘warn’’ on the
     Unicode type.  When ‘True’, results in all unicode conversion
     operations raising an exception when a non-unicode bytestring is
     passed as a bind parameter.  ‘warn’ results in a warning.  It is
     strongly advised that all unicode-aware applications make proper
     use of Python unicode objects (i.e.  u’hello’ and not ‘hello’) so
     that data round trips accurately.

   * `[sql]' ¶ generation of “unique” bind parameters has
     been simplified to use the same “unique identifier” mechanisms as
     everything else.  This doesn’t affect user code, except any code
     that might have been hardcoded against the generated names.
     Generated bind params now have the form “<paramname>_<num>”,
     whereas before only the second bind of the same name would have
     this form.

   * `[sql]' ¶ select().as_scalar() will raise an exception
     if the select does not have exactly one expression in its columns
     clause.

   * `[sql]' ¶ bindparam() objects themselves can be used
     as keys for execute(), i.e.  statement.execute({bind1:’foo’,
     bind2:’bar’})

   * `[sql]' ¶ added new methods to TypeDecorator,
     process_bind_param() and process_result_value(), which
     automatically take advantage of the processing of the underlying
     type.  Ideal for using with Unicode or Pickletype.  TypeDecorator
     should now be the primary way to augment the behavior of any
     existing type including other TypeDecorator subclasses such as
     PickleType.

   * `[sql]' ¶ selectables (and others) will issue a
     warning when two columns in their exported columns collection
     conflict based on name.

   * `[sql]' ¶ tables with schemas can still be used in
     sqlite, firebird, schema name just gets dropped

     References: #890(2)

   * `[sql]' ¶ changed the various “literal” generation
     functions to use an anonymous bind parameter.  not much changes
     here except their labels now look like “:param_1”, “:param_2”
     instead of “:literal”

   * `[sql]' ¶ column labels in the form
     “tablename.columname”, i.e.  with a dot, are now supported.

   * `[sql]' ¶ from_obj keyword argument to select() can be
     a scalar or a list.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/615

   (2) http://www.sqlalchemy.org/trac/ticket/890

8.3.11.47 firebird
..................

   * `[firebird] [backend]' ¶ does properly reflect domains
     (partially fixing) and PassiveDefaults

     References: #410(1)

   * `[firebird] [3562] [backend]' ¶ reverted to use
     default poolclass (was set to SingletonThreadPool in 0.4.0 for test
     purposes)

   * `[firebird] [backend]' ¶ map func.length() to
     ‘char_length’ (easily overridable with the UDF ‘strlen’ on old
     versions of Firebird)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/410

8.3.11.48 misc
..............

   * `[dialects]' ¶ sqlite SLDate type will not erroneously
     render “microseconds” portion of a datetime or time object.

   * `[dialects]' ¶.

     oracle

             - added disconnect detection support for Oracle

             - some cleanup to binary/raw types so that cx_oracle.LOB is
               detected on an ad-hoc basis

     References: #902(1)

   * `[dialects]' ¶.

     MSSQL

             - PyODBC no longer has a global “set nocount on”.

             - Fix non-identity integer PKs on autoload

             - Better support for convert_unicode

             - Less strict date conversion for pyodbc/adodbapi

             - Schema-qualified tables / autoload

     References: #824(2), #839(3), #842(4), #901(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/902

   (2) http://www.sqlalchemy.org/trac/ticket/824

   (3) http://www.sqlalchemy.org/trac/ticket/839

   (4) http://www.sqlalchemy.org/trac/ticket/842

   (5) http://www.sqlalchemy.org/trac/ticket/901

8.3.11.49 0.4.1
...............

Released: Sun Nov 18 2007

8.3.11.50 orm
.............

   * `[orm]' ¶ eager loading with LIMIT/OFFSET applied no
     longer adds the primary table joined to a limited subquery of
     itself; the eager loads now join directly to the subquery which
     also provides the primary table’s columns to the result set.  This
     eliminates a JOIN from all eager loads with LIMIT/OFFSET.

     References: #843(1)

   * `[orm]' ¶ session.refresh() and session.expire() now
     support an additional argument “attribute_names”, a list of
     individual attribute keynames to be refreshed or expired, allowing
     partial reloads of attributes on an already-loaded instance.

     References: #802(2)

   * `[orm]' ¶ added op() operator to instrumented
     attributes; i.e.  User.name.op(‘ilike’)(‘%somename%’)

     References: #767(3)

   * `[orm]' ¶. Mapped classes may now define __eq__,
     __hash__, and __nonzero__ methods with arbitrary semantics.  The
     orm now handles all mapped instances on an identity-only basis.
     (e.g.  ‘is’ vs ‘==’)

     References: #676(4)

   * `[orm]' ¶ the “properties” accessor on Mapper is
     removed; it now throws an informative exception explaining the
     usage of mapper.get_property() and mapper.iterate_properties

   * `[orm]' ¶ added having() method to Query, applies
     HAVING to the generated statement in the same way as filter()
     appends to the WHERE clause.

   * `[orm]' ¶. The behavior of query.options() is now fully
     based on paths, i.e.  an option such as eagerload_all(‘x.y.z.y.x’)
     will apply eagerloading to only those paths, i.e.  and not ‘x.y.x’;
     eagerload(‘children.children’) applies only to exactly two-levels
     deep, etc.

     References: #777(5)

   * `[orm]' ¶. PickleType will compare using ‘==’ when set
     up with mutable=False, and not the ‘is’ operator.  To use ‘is’ or
     any other comparator, send in a custom comparison function using
     PickleType(comparator=my_custom_comparator).

   * `[orm]' ¶ query doesn’t throw an error if you use
     distinct() and an order_by() containing UnaryExpressions (or other)
     together

     References: #848(6)

   * `[orm]' ¶ order_by() expressions from joined tables
     are properly added to columns clause when using distinct()

     References: #786(7)

   * `[orm]' ¶ fixed error where Query.add_column() would
     not accept a class-bound attribute as an argument; Query also
     raises an error if an invalid argument was sent to add_column() (at
     instances() time)

     References: #858(8)

   * `[orm]' ¶ added a little more checking for
     garbage-collection dereferences in InstanceState.__cleanup() to
     reduce “gc ignored” errors on app shutdown

   * `[orm]' ¶. The session API has been solidified:

   * `[orm]' ¶. It’s an error to session.save() an object
     which is already persistent

     References: #840(9)

   * `[orm]' ¶. It’s an error to session.delete() an object
     which is `not' persistent.

   * `[orm]' ¶ session.update() and session.delete() raise
     an error when updating or deleting an instance that is already in
     the session with a different identity.

   * `[orm]' ¶. The session checks more carefully when
     determining “object X already in another session”; e.g.  if you
     pickle a series of objects and unpickle (i.e.  as in a Pylons HTTP
     session or similar), they can go into a new session without any
     conflict

   * `[orm]' ¶ merge() includes a keyword argument
     “dont_load=True”.  setting this flag will cause the merge operation
     to not load any data from the database in response to incoming
     detached objects, and will accept the incoming detached object as
     though it were already present in that session.  Use this to merge
     detached objects from external caching systems into the session.

   * `[orm]' ¶. Deferred column attributes no longer trigger
     a load operation when the attribute is assigned to.  In those
     cases, the newly assigned value will be present in the flushes’
     UPDATE statement unconditionally.

   * `[orm]' ¶. Fixed a truncation error when re-assigning a
     subset of a collection (obj.relation = obj.relation[1:])

     References: #834(10)

   * `[orm]' ¶. De-cruftified backref configuration code,
     backrefs which step on existing properties now raise an error

     References: #832(11)

   * `[orm]' ¶. Improved behavior of add_property() etc.,
     fixed involving synonym/deferred.

     References: #831(12)

   * `[orm]' ¶. Fixed clear_mappers() behavior to better
     clean up after itself.

   * `[orm]' ¶. Fix to “row switch” behavior, i.e.  when an
     INSERT/DELETE is combined into a single UPDATE; many-to-many
     relations on the parent object update properly.

     References: #841(13)

   * `[orm]' ¶. Fixed __hash__ for association proxy- these
     collections are unhashable, just like their mutable Python
     counterparts.

   * `[orm]' ¶. Added proxying of save_or_update,
     __contains__ and __iter__ methods for scoped sessions.

   * `[orm]' ¶ fixed very hard-to-reproduce issue where by
     the FROM clause of Query could get polluted by certain generative
     calls

     References: #852(14)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/843

   (2) http://www.sqlalchemy.org/trac/ticket/802

   (3) http://www.sqlalchemy.org/trac/ticket/767

   (4) http://www.sqlalchemy.org/trac/ticket/676

   (5) http://www.sqlalchemy.org/trac/ticket/777

   (6) http://www.sqlalchemy.org/trac/ticket/848

   (7) http://www.sqlalchemy.org/trac/ticket/786

   (8) http://www.sqlalchemy.org/trac/ticket/858

   (9) http://www.sqlalchemy.org/trac/ticket/840

   (10) http://www.sqlalchemy.org/trac/ticket/834

   (11) http://www.sqlalchemy.org/trac/ticket/832

   (12) http://www.sqlalchemy.org/trac/ticket/831

   (13) http://www.sqlalchemy.org/trac/ticket/841

   (14) http://www.sqlalchemy.org/trac/ticket/852

8.3.11.51 sql
.............

   * `[sql]' ¶ the “shortname” keyword parameter on
     bindparam() has been deprecated.

   * `[sql]' ¶. Added contains operator (generates a “LIKE
     %<other>%” clause).

   * `[sql]' ¶ anonymous column expressions are
     automatically labeled.  e.g.  select([x* 5]) produces “SELECT x * 5
     AS anon_1”.  This allows the labelname to be present in the
     cursor.description which can then be appropriately matched to
     result-column processing rules.  (we can’t reliably use positional
     tracking for result-column matches since text() expressions may
     represent multiple columns).

   * `[sql]' ¶ operator overloading is now controlled by
     TypeEngine objects - the one built-in operator overload so far is
     String types overloading ‘+’ to be the string concatenation
     operator.  User-defined types can also define their own operator
     overloading by overriding the adapt_operator(self, op) method.

   * `[sql]' ¶ untyped bind parameters on the right side of
     a binary expression will be assigned the type of the left side of
     the operation, to better enable the appropriate bind parameter
     processing to take effect

     References: #819(1)

   * `[sql]' ¶. Removed regular expression step from most
     statement compilations.  Also fixes

     References: #833(2)

   * `[sql]' ¶. Fixed empty (zero column) sqlite inserts,
     allowing inserts on autoincrementing single column tables.

   * `[sql]' ¶. Fixed expression translation of text()
     clauses; this repairs various ORM scenarios where literal text is
     used for SQL expressions

   * `[sql]' ¶. Removed ClauseParameters object;
     compiled.params returns a regular dictionary now, as well as
     result.last_inserted_params() / last_updated_params().

   * `[sql]' ¶. Fixed INSERT statements w.r.t.  primary key
     columns that have SQL-expression based default generators on them;
     SQL expression executes inline as normal but will not trigger a
     “postfetch” condition for the column, for those DB’s who provide it
     via cursor.lastrowid

   * `[sql]' ¶ func.  objects can be pickled/unpickled

     References: #844(3)

   * `[sql]' ¶ rewrote and simplified the system used to
     “target” columns across selectable expressions.  On the SQL side
     this is represented by the “corresponding_column()” method.  This
     method is used heavily by the ORM to “adapt” elements of an
     expression to similar, aliased expressions, as well as to target
     result set columns originally bound to a table or selectable to an
     aliased, “corresponding” expression.  The new rewrite features
     completely consistent and accurate behavior.

   * `[sql]' ¶. Added a field (“info”) for storing arbitrary
     data on schema items

     References: #573(4)

   * `[sql]' ¶. The “properties” collection on Connections
     has been renamed “info” to match schema’s writable collections.
     Access is still available via the “properties” name until 0.5.

   * `[sql]' ¶ fixed the close() method on Transaction when
     using strategy=’threadlocal’

   * `[sql]' ¶ fix to compiled bind parameters to not
     mistakenly populate None

     References: #853(5)

   * `[sql]' ¶. <Engine|Connection>._execute_clauseelement
     becomes a public method Connectable.execute_clauseelement

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/819

   (2) http://www.sqlalchemy.org/trac/ticket/833

   (3) http://www.sqlalchemy.org/trac/ticket/844

   (4) http://www.sqlalchemy.org/trac/ticket/573

   (5) http://www.sqlalchemy.org/trac/ticket/853

8.3.11.52 misc
..............

   * `[dialects]' ¶. Added experimental support for MaxDB
     (versions >= 7.6.03.007 only).

   * `[dialects]' ¶ oracle will now reflect “DATE” as an
     OracleDateTime column, not OracleDate

   * `[dialects]' ¶ added awareness of schema name in
     oracle table_names() function, fixes
     metadata.reflect(schema=’someschema’)

     References: #847(1)

   * `[dialects]' ¶. MSSQL anonymous labels for selection of
     functions made deterministic

   * `[dialects]' ¶ sqlite will reflect “DECIMAL” as a
     numeric column.

   * `[dialects]' ¶. Made access dao detection more reliable

     References: #828(2)

   * `[dialects]' ¶. Renamed the Dialect attribute
     ‘preexecute_sequences’ to ‘preexecute_pk_sequences’.  An attribute
     proxy is in place for out-of-tree dialects using the old name.

   * `[dialects]' ¶. Added test coverage for unknown type
     reflection.  Fixed sqlite/mysql handling of type reflection for
     unknown types.

   * `[dialects]' ¶. Added REAL for mysql dialect (for folks
     exploiting the REAL_AS_FLOAT sql mode).

   * `[dialects]' ¶ mysql Float, MSFloat and MSDouble
     constructed without arguments now produce no-argument DDL,
     e.g.’FLOAT’.

   * `[misc]' ¶. Removed unused util.hash().

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/847

   (2) http://www.sqlalchemy.org/trac/ticket/828

8.3.11.53 0.4.0
...............

Released: Wed Oct 17 2007

   * `[no_tags]' ¶. (see 0.4.0beta1 for the start of major
     changes against 0.3, as well as
     ‘http://www.sqlalchemy.org/trac/wiki/WhatsNewIn04’ )

   * `[no_tags]' ¶. Added initial Sybase support (mxODBC so
     far)

     References: #785(1)

   * `[no_tags]' ¶. Added partial index support for
     PostgreSQL. Use the postgres_where keyword on the Index.

   * `[no_tags]' ¶ string-based query param parsing/config
     file parser understands wider range of string values for booleans

     References: #817(2)

   * `[no_tags]' ¶ backref remove object operation doesn’t
     fail if the other-side collection doesn’t contain the item,
     supports noload collections

     References: #813(3)

   * `[no_tags]' ¶ removed __len__ from “dynamic”
     collection as it would require issuing a SQL “count()” operation,
     thus forcing all list evaluations to issue redundant SQL

     References: #818(4)

   * `[no_tags]' ¶ inline optimizations added to
     locate_dirty() which can greatly speed up repeated calls to
     flush(), as occurs with autoflush=True

     References: #816(5)

   * `[no_tags]' ¶. The IdentifierPreprarer’s
     _requires_quotes test is now regex based.  Any out-of-tree dialects
     that provide custom sets of legal_characters or
     illegal_initial_characters will need to move to regexes or override
     _requires_quotes.

   * `[no_tags]' ¶. Firebird has supports_sane_rowcount and
     supports_sane_multi_rowcount set to False due to ticket #370 (right
     way).

   * `[no_tags]' ¶.

     Improvements and fixes on Firebird reflection:

             * FBDialect now mimics OracleDialect, regarding
               case-sensitivity of TABLE and COLUMN names (see
               ‘case_sensitive remotion’ topic on this current file).

             * FBDialect.table_names() doesn’t bring system tables
               (ticket:796).

             * FB now reflects Column’s nullable property correctly.

   * `[no_tags]' ¶. Fixed SQL compiler’s awareness of
     top-level column labels as used in result-set processing; nested
     selects which contain the same column names don’t affect the result
     or conflict with result-column metadata.

   * `[no_tags]' ¶ query.get() and related functions (like
     many-to-one lazyloading) use compile-time-aliased bind parameter
     names, to prevent name conflicts with bind parameters that already
     exist in the mapped selectable.

   * `[no_tags]' ¶. Fixed three- and multi-level select and
     deferred inheritance loading (i.e.  abc inheritance with no
     select_table).

     References: #795(6)

   * `[no_tags]' ¶. Ident passed to id_chooser in shard.py
     always a list.

   * `[no_tags]' ¶. The no-arg ResultProxy._row_processor()
     is now the class attribute ‘_process_row’.

   * `[no_tags]' ¶. Added support for returning values from
     inserts and updates for PostgreSQL 8.2+.

     References: #797(7)

   * `[no_tags]' ¶. PG reflection, upon seeing the default
     schema name being used explicitly as the “schema” argument in a
     Table, will assume that this is the user’s desired convention, and
     will explicitly set the “schema” argument in foreign-key-related
     reflected tables, thus making them match only with Table
     constructors that also use the explicit “schema” argument (even
     though its the default schema).  In other words, SA assumes the
     user is being consistent in this usage.

   * `[no_tags]' ¶ fixed sqlite reflection of BOOL/BOOLEAN

     References: #808(8)

   * `[no_tags]' ¶. Added support for UPDATE with LIMIT on
     mysql.

   * `[no_tags]' ¶ null foreign key on a m2o doesn’t
     trigger a lazyload

     References: #803(9)

   * `[no_tags]' ¶ oracle does not implicitly convert to
     unicode for non-typed result sets (i.e.  when no
     TypeEngine/String/Unicode type is even being used; previously it
     was detecting DBAPI types and converting regardless).  should fix

     References: #800(10)

   * `[no_tags]' ¶ fix to anonymous label generation of
     long table/column names

     References: #806(11)

   * `[no_tags]' ¶. Firebird dialect now uses
     SingletonThreadPool as poolclass.

   * `[no_tags]' ¶. Firebird now uses dialect.preparer to
     format sequences names

   * `[no_tags]' ¶. Fixed breakage with postgres and
     multiple two-phase transactions.  Two-phase commits and rollbacks
     didn’t automatically end up with a new transaction as the usual
     dbapi commits/rollbacks do.

     References: #810(12)

   * `[no_tags]' ¶. Added an option to the _ScopedExt mapper
     extension to not automatically save new objects to session on
     object initialization.

   * `[no_tags]' ¶ fixed Oracle non-ansi join syntax

   * `[no_tags]' ¶. PickleType and Interval types (on db not
     supporting it natively) are now slightly faster.

   * `[no_tags]' ¶. Added Float and Time types to Firebird
     (FBFloat and FBTime).  Fixed BLOB SUB_TYPE for TEXT and Binary
     types.

   * `[no_tags]' ¶. Changed the API for the in_ operator.
     in_() now accepts a single argument that is a sequence of values or
     a selectable.  The old API of passing in values as varargs still
     works but is deprecated.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/785

   (2) http://www.sqlalchemy.org/trac/ticket/817

   (3) http://www.sqlalchemy.org/trac/ticket/813

   (4) http://www.sqlalchemy.org/trac/ticket/818

   (5) http://www.sqlalchemy.org/trac/ticket/816

   (6) http://www.sqlalchemy.org/trac/ticket/795

   (7) http://www.sqlalchemy.org/trac/ticket/797

   (8) http://www.sqlalchemy.org/trac/ticket/808

   (9) http://www.sqlalchemy.org/trac/ticket/803

   (10) http://www.sqlalchemy.org/trac/ticket/800

   (11) http://www.sqlalchemy.org/trac/ticket/806

   (12) http://www.sqlalchemy.org/trac/ticket/810

8.3.11.54 0.4.0beta6
....................

Released: Thu Sep 27 2007

   * `[no_tags]' ¶. The Session identity map is now `weak
     referencing' by default, use weak_identity_map=False to use a
     regular dict.  The weak dict we are using is customized to detect
     instances which are “dirty” and maintain a temporary strong
     reference to those instances until changes are flushed.

   * `[no_tags]' ¶. Mapper compilation has been reorganized
     such that most compilation occurs upon mapper construction.  This
     allows us to have fewer calls to mapper.compile() and also to allow
     class-based properties to force a compilation (i.e.  User.addresses
     == 7 will compile all mappers; this is).  The only caveat here is
     that an inheriting mapper now looks for its inherited mapper upon
     construction; so mappers within inheritance relationships need to
     be constructed in inheritance order (which should be the normal
     case anyway).

     References: #758(1)

   * `[no_tags]' ¶ added “FETCH” to the keywords detected
     by Postgres to indicate a result-row holding statement (i.e.  in
     addition to “SELECT”).

   * `[no_tags]' ¶. Added full list of SQLite reserved
     keywords so that they get escaped properly.

   * `[no_tags]' ¶. Tightened up the relationship between
     the Query’s generation of “eager load” aliases, and
     Query.instances() which actually grabs the eagerly loaded rows.  If
     the aliases were not specifically generated for that statement by
     EagerLoader, the EagerLoader will not take effect when the rows are
     fetched.  This prevents columns from being grabbed accidentally as
     being part of an eager load when they were not meant for such,
     which can happen with textual SQL as well as some inheritance
     situations.  It’s particularly important since the “anonymous
     aliasing” of columns uses simple integer counts now to generate
     labels.

   * `[no_tags]' ¶. Removed “parameters” argument from
     clauseelement.compile(), replaced with “column_keys”.  The
     parameters sent to execute() only interact with the insert/update
     statement compilation process in terms of the column names present
     but not the values for those columns.  Produces more consistent
     execute/executemany behavior, simplifies things a bit internally.

   * `[no_tags]' ¶. Added ‘comparator’ keyword argument to
     PickleType.  By default, “mutable” PickleType does a “deep compare”
     of objects using their dumps() representation.  But this doesn’t
     work for dictionaries.  Pickled objects which provide an adequate
     __eq__() implementation can be set up with
     “PickleType(comparator=operator.eq)”

     References: #560(2)

   * `[no_tags]' ¶. Added session.is_modified(obj) method;
     performs the same “history” comparison operation as occurs within a
     flush operation; setting include_collections=False gives the same
     result as is used when the flush determines whether or not to issue
     an UPDATE for the instance’s row.

   * `[no_tags]' ¶. Added “schema” argument to Sequence; use
     this with Postgres /Oracle when the sequence is located in an
     alternate schema.  Implements part of, should fix.

     References: #584(3), #761(4)

   * `[no_tags]' ¶. Fixed reflection of the empty string for
     mysql enums.

   * `[no_tags]' ¶. Changed MySQL dialect to use the older
     LIMIT <offset>, <limit> syntax instead of LIMIT <l> OFFSET <o> for
     folks using 3.23.

     References: #794(5)

   * `[no_tags]' ¶. Added ‘passive_deletes=”all”’ flag to
     relation(), disables all nulling-out of foreign key attributes
     during a flush where the parent object is deleted.

   * `[no_tags]' ¶. Column defaults and onupdates, executing
     inline, will add parenthesis for subqueries and other
     parenthesis-requiring expressions

   * `[no_tags]' ¶. The behavior of String/Unicode types
     regarding that they auto-convert to TEXT/CLOB when no length is
     present now occurs `only' for an exact type of String or Unicode
     with no arguments.  If you use VARCHAR or NCHAR (subclasses of
     String/Unicode) with no length, they will be interpreted by the
     dialect as VARCHAR/NCHAR; no “magic” conversion happens there.
     This is less surprising behavior and in particular this helps
     Oracle keep string-based bind parameters as VARCHARs and not CLOBs.

     References: #793(6)

   * `[no_tags]' ¶. Fixes to ShardedSession to work with
     deferred columns.

     References: #771(7)

   * `[no_tags]' ¶. User-defined shard_chooser() function
     must accept “clause=None” argument; this is the ClauseElement
     passed to session.execute(statement) and can be used to determine
     correct shard id (since execute() doesn’t take an instance.)

   * `[no_tags]' ¶. Adjusted operator precedence of NOT to
     match ‘==’ and others, so that ~(x <operator> y) produces NOT (x
     <op> y), which is better compatible with older MySQL versions..
     This doesn’t apply to “~(x==y)” as it does in 0.3 since ~(x==y)
     compiles to “x != y”, but still applies to operators like BETWEEN.

     References: #764(8)

   * `[no_tags]' ¶. Other tickets:,,.

     References: #728(9), #757(10), #768(11), #779(12)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/758

   (2) http://www.sqlalchemy.org/trac/ticket/560

   (3) http://www.sqlalchemy.org/trac/ticket/584

   (4) http://www.sqlalchemy.org/trac/ticket/761

   (5) http://www.sqlalchemy.org/trac/ticket/794

   (6) http://www.sqlalchemy.org/trac/ticket/793

   (7) http://www.sqlalchemy.org/trac/ticket/771

   (8) http://www.sqlalchemy.org/trac/ticket/764

   (9) http://www.sqlalchemy.org/trac/ticket/728

   (10) http://www.sqlalchemy.org/trac/ticket/757

   (11) http://www.sqlalchemy.org/trac/ticket/768

   (12) http://www.sqlalchemy.org/trac/ticket/779

8.3.11.55 0.4.0beta5
....................

no release date

   * `[no_tags]' ¶. Connection pool fixes; the better
     performance of beta4 remains but fixes “connection overflow” and
     other bugs which were present (like).

     References: #754(1)

   * `[no_tags]' ¶. Fixed bugs in determining proper sync
     clauses from custom inherit conditions.

     References: #769(2)

   * `[no_tags]' ¶. Extended ‘engine_from_config’ coercion
     for QueuePool size / overflow.

     References: #763(3)

   * `[no_tags]' ¶ mysql views can be reflected again.

     References: #748(4)

   * `[no_tags]' ¶. AssociationProxy can now take custom
     getters and setters.

   * `[no_tags]' ¶. Fixed malfunctioning BETWEEN in orm
     queries.

   * `[no_tags]' ¶. Fixed OrderedProperties pickling

     References: #762(5)

   * `[no_tags]' ¶. SQL-expression defaults and sequences
     now execute “inline” for all non-primary key columns during an
     INSERT or UPDATE, and for all columns during an executemany()-style
     call.  inline=True flag on any insert/update statement also forces
     the same behavior with a single execute().  result.postfetch_cols()
     is a collection of columns for which the previous single insert or
     update statement contained a SQL-side default expression.

   * `[no_tags]' ¶. Fixed PG executemany() behavior.

     References: #759(6)

   * `[no_tags]' ¶ postgres reflects tables with
     autoincrement=False for primary key columns which have no defaults.

   * `[no_tags]' ¶ postgres no longer wraps executemany()
     with individual execute() calls, instead favoring performance.
     “rowcount”/”concurrency” checks with deleted items (which use
     executemany) are disabled with PG since psycopg2 does not report
     proper rowcount for executemany().

   * `[fixed] [tickets]' ¶. References: #742(7)

   * `[fixed] [tickets]' ¶. References: #748(8)

   * `[fixed] [tickets]' ¶. References: #760(9)

   * `[fixed] [tickets]' ¶. References: #762(10)

   * `[fixed] [tickets]' ¶. References: #763(11)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/754

   (2) http://www.sqlalchemy.org/trac/ticket/769

   (3) http://www.sqlalchemy.org/trac/ticket/763

   (4) http://www.sqlalchemy.org/trac/ticket/748

   (5) http://www.sqlalchemy.org/trac/ticket/762

   (6) http://www.sqlalchemy.org/trac/ticket/759

   (7) http://www.sqlalchemy.org/trac/ticket/742

   (8) http://www.sqlalchemy.org/trac/ticket/748

   (9) http://www.sqlalchemy.org/trac/ticket/760

   (10) http://www.sqlalchemy.org/trac/ticket/762

   (11) http://www.sqlalchemy.org/trac/ticket/763

8.3.11.56 0.4.0beta4
....................

Released: Wed Aug 22 2007

   * `[no_tags]' ¶. Tidied up what ends up in your namespace
     when you ‘from sqlalchemy import *’:

   * `[no_tags]' ¶. ’table’ and ‘column’ are no longer
     imported.  They remain available by direct reference (as in
     ‘sql.table’ and ‘sql.column’) or a glob import from the sql
     package.  It was too easy to accidentally use a
     sql.expressions.table instead of schema.Table when just starting
     out with SQLAlchemy, likewise column.

   * `[no_tags]' ¶. Internal-ish classes like ClauseElement,
     FromClause, NullTypeEngine, etc., are also no longer imported into
     your namespace

   * `[no_tags]' ¶. The ‘Smallinteger’ compatibility name
     (small i!)  is no longer imported, but remains in schema.py for
     now.  SmallInteger (big I!) is still imported.

   * `[no_tags]' ¶. The connection pool uses a “threadlocal”
     strategy internally to return the same connection already bound to
     a thread, for “contextual” connections; these are the connections
     used when you do a “connectionless” execution like
     insert().execute().  This is like a “partial” version of the
     “threadlocal” engine strategy but without the thread-local
     transaction part of it.  We’re hoping it reduces connection pool
     overhead as well as database usage.  However, if it proves to
     impact stability in a negative way, we’ll roll it right back.

   * `[no_tags]' ¶. Fix to bind param processing such that
     “False” values (like blank strings) still get processed/encoded.

   * `[no_tags]' ¶. Fix to select() “generative” behavior,
     such that calling column(), select_from(), correlate(), and
     with_prefix() does not modify the original select object

     References: #752(1)

   * `[no_tags]' ¶. Added a “legacy” adapter to types, such
     that user-defined TypeEngine and TypeDecorator classes which define
     convert_bind_param() and/or convert_result_value() will continue to
     function.  Also supports calling the super() version of those
     methods.

   * `[no_tags]' ¶. Added session.prune(), trims away
     instances cached in a session that are no longer referenced
     elsewhere.  (A utility for strong-ref identity maps).

   * `[no_tags]' ¶. Added close() method to Transaction.
     Closes out a transaction using rollback if it’s the outermost
     transaction, otherwise just ends without affecting the outer
     transaction.

   * `[no_tags]' ¶. Transactional and non-transactional
     Session integrates better with bound connection; a close() will
     ensure that connection transactional state is the same as that
     which existed on it before being bound to the Session.

   * `[no_tags]' ¶. Modified SQL operator functions to be
     module-level operators, allowing SQL expressions to be pickleable.

     References: #735(2)

   * `[no_tags]' ¶. Small adjustment to mapper
     class.__init__ to allow for Py2.6 object.__init__() behavior.

   * `[no_tags]' ¶. Fixed ‘prefix’ argument for select()

   * `[no_tags]' ¶. Connection.begin() no longer accepts
     nested=True, this logic is now all in begin_nested().

   * `[no_tags]' ¶. Fixes to new “dynamic” relation loader
     involving cascades

   * `[fixed] [tickets]' ¶. References: #735(3)

   * `[fixed] [tickets]' ¶. References: #752(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/752

   (2) http://www.sqlalchemy.org/trac/ticket/735

   (3) http://www.sqlalchemy.org/trac/ticket/735

   (4) http://www.sqlalchemy.org/trac/ticket/752

8.3.11.57 0.4.0beta3
....................

Released: Thu Aug 16 2007

   * `[no_tags]' ¶. SQL types optimization:

   * `[no_tags]' ¶. New performance tests show a combined
     mass-insert/mass-select test as having 68% fewer function calls
     than the same test run against 0.3.

   * `[no_tags]' ¶. General performance improvement of
     result set iteration is around 10-20%.

   * `[no_tags]' ¶. In types.AbstractType,
     convert_bind_param() and convert_result_value() have migrated to
     callable-returning bind_processor() and result_processor() methods.
     If no callable is returned, no pre/post processing function is
     called.

   * `[no_tags]' ¶. Hooks added throughout base/sql/defaults
     to optimize the calling of bind param/result processors so that
     method call overhead is minimized.

   * `[no_tags]' ¶. Support added for executemany()
     scenarios such that unneeded “last row id” logic doesn’t kick in,
     parameters aren’t excessively traversed.

   * `[no_tags]' ¶. Added ‘inherit_foreign_keys’ arg to
     mapper().

   * `[no_tags]' ¶. Added support for string date
     passthrough in sqlite.

   * `[fixed] [tickets]' ¶. References: #738(1)

   * `[fixed] [tickets]' ¶. References: #739(2)

   * `[fixed] [tickets]' ¶. References: #743(3)

   * `[fixed] [tickets]' ¶. References: #744(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/738

   (2) http://www.sqlalchemy.org/trac/ticket/739

   (3) http://www.sqlalchemy.org/trac/ticket/743

   (4) http://www.sqlalchemy.org/trac/ticket/744

8.3.11.58 0.4.0beta2
....................

Released: Tue Aug 14 2007

8.3.11.59 oracle
................

   * `[oracle] [improvements.]'  See ¶. Auto-commit after LOAD
     DATA INFILE for mysql.

   * `[oracle] [improvements.]'  See ¶. A rudimental
     SessionExtension class has been added, allowing user-defined
     functionality to take place at flush(), commit(), and rollback()
     boundaries.

   * `[oracle] [improvements.]'  See ¶. Added
     engine_from_config() function for helping to create_engine() from
     an .ini style config.

   * `[oracle] [improvements.]'  ¶ base_mapper() becomes a
     plain attribute.

   * `[oracle] [improvements.]'  ¶ session.execute() and
     scalar() can search for a Table with which to bind from using the
     given ClauseElement.

   * `[oracle] [improvements.]'  See ¶. Session automatically
     extrapolates tables from mappers with binds, also uses base_mapper
     so that inheritance hierarchies bind automatically.

   * `[oracle] [improvements.]'  See ¶. Moved ClauseVisitor
     traversal back to inlined non-recursive.

8.3.11.60 misc
..............

   * `[fixed] [tickets]' ¶. References: #730(1)

   * `[fixed] [tickets]' ¶. References: #732(2)

   * `[fixed] [tickets]' ¶. References: #733(3)

   * `[fixed] [tickets]' ¶. References: #734(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/730

   (2) http://www.sqlalchemy.org/trac/ticket/732

   (3) http://www.sqlalchemy.org/trac/ticket/733

   (4) http://www.sqlalchemy.org/trac/ticket/734

8.3.11.61 0.4.0beta1
....................

Released: Sun Aug 12 2007

8.3.11.62 orm
.............

   * `[orm]' ¶. Speed!  Along with recent speedups to
     ResultProxy, total number of function calls significantly reduced
     for large loads.

   * `[orm]' ¶ test/perf/masseagerload.py reports 0.4 as
     having the fewest number of function calls across all SA versions
     (0.1, 0.2, and 0.3).

   * `[orm]' ¶. New collection_class api and implementation.
     Collections are now instrumented via decorations rather than
     proxying.  You can now have collections that manage their own
     membership, and your class instance will be directly exposed on the
     relation property.  The changes are transparent for most users.

     References: #213(1)

   * `[orm]' ¶. InstrumentedList (as it was) is removed, and
     relation properties no longer have ‘clear()’, ‘.data’, or any other
     added methods beyond those provided by the collection type.  You
     are free, of course, to add them to a custom class.

   * `[orm]' ¶. __setitem__-like assignments now fire remove
     events for the existing value, if any.

   * `[orm]' ¶ dict-likes used as collection classes no
     longer need to change __iter__ semantics- itervalues() is used by
     default instead.  This is a backwards incompatible change.

   * `[orm]' ¶. Subclassing dict for a mapped collection is
     no longer needed in most cases.  orm.collections provides canned
     implementations that key objects by a specified column or a custom
     function of your choice.

   * `[orm]' ¶. Collection assignment now requires a
     compatible type- assigning None to clear a collection or assigning
     a list to a dict collection will now raise an argument error.

   * `[orm]' ¶. AttributeExtension moved to interfaces, and
     .delete is now .remove The event method signature has also been
     swapped around.

   * `[orm]' ¶. Major overhaul for Query:

   * `[orm]' ¶. All selectXXX methods are deprecated.
     Generative methods are now the standard way to do things, i.e.
     filter(), filter_by(), all(), one(), etc.  Deprecated methods are
     docstring’ed with their new replacements.

   * `[orm]' ¶. Class-level properties are now usable as
     query elements… no more ‘.c.’!  “Class.c.propname” is now
     superseded by “Class.propname”.  All clause operators are
     supported, as well as higher level operators such as
     Class.prop==<some instance> for scalar attributes,
     Class.prop.contains(<some instance>) and Class.prop.any(<some
     expression>) for collection-based attributes (all are also
     negatable).  Table-based column expressions as well as columns
     mounted on mapped classes via ‘c’ are of course still fully
     available and can be freely mixed with the new attributes.

     References: #643(2)

   * `[orm]' ¶. Removed ancient
     query.select_by_attributename() capability.

   * `[orm]' ¶. The aliasing logic used by eager loading has
     been generalized, so that it also adds full automatic aliasing
     support to Query.  It’s no longer necessary to create an explicit
     Alias to join to the same tables multiple times; `even for
     self-referential relationships'.

        - join() and outerjoin() take arguments “aliased=True”.  Yhis
          causes their joins to be built on aliased tables; subsequent
          calls to filter() and filter_by() will translate all table
          expressions (yes, real expressions using the original mapped
          Table) to be that of the Alias for the duration of that join()
          (i.e.  until reset_joinpoint() or another join() is called).

        - join() and outerjoin() take arguments “id=<somestring>”.  When
          used with “aliased=True”, the id can be referenced by
          add_entity(cls, id=<somestring>) so that you can select the
          joined instances even if they’re from an alias.

        - join() and outerjoin() now work with self-referential
          relationships!  Using “aliased=True”, you can join as many
          levels deep as desired, i.e.  query.join([‘children’,
          ‘children’], aliased=True); filter criterion will be against
          the rightmost joined table

   * `[orm]' ¶. Added query.populate_existing(), marks the
     query to reload all attributes and collections of all instances
     touched in the query, including eagerly-loaded entities.

     References: #660(3)

   * `[orm]' ¶. Added eagerload_all(), allows
     eagerload_all(‘x.y.z’) to specify eager loading of all properties
     in the given path.

   * `[orm]' ¶. Major overhaul for Session:

   * `[orm]' ¶. New function which “configures” a session
     called “sessionmaker()”.  Send various keyword arguments to this
     function once, returns a new class which creates a Session against
     that stereotype.

   * `[orm]' ¶. SessionTransaction removed from “public”
     API. You now can call begin()/ commit()/rollback() on the Session
     itself.

   * `[orm]' ¶. Session also supports SAVEPOINT
     transactions; call begin_nested().

   * `[orm]' ¶. Session supports two-phase commit behavior
     when vertically or horizontally partitioning (i.e., using more than
     one engine).  Use twophase=True.

   * `[orm]' ¶. Session flag “transactional=True” produces a
     session which always places itself into a transaction when first
     used.  Upon commit(), rollback() or close(), the transaction ends;
     but begins again on the next usage.

   * `[orm]' ¶. Session supports “autoflush=True”.  This
     issues a flush() before each query.  Use in conjunction with
     transactional, and you can just save()/update() and then query, the
     new objects will be there.  Use commit() at the end (or flush() if
     non-transactional) to flush remaining changes.

   * `[orm]' ¶. New scoped_session() function replaces
     SessionContext and assignmapper.  Builds onto “sessionmaker()”
     concept to produce a class whos Session() construction returns the
     thread-local session.  Or, call all Session methods as class
     methods, i.e.  Session.save(foo); Session.commit().  just like the
     old “objectstore” days.

   * `[orm]' ¶. Added new “binds” argument to Session to
     support configuration of multiple binds with sessionmaker()
     function.

   * `[orm]' ¶. A rudimental SessionExtension class has been
     added, allowing user-defined functionality to take place at
     flush(), commit(), and rollback() boundaries.

   * `[orm]' ¶. Query-based relation()s available with
     dynamic_loader().  This is a `writable' collection (supporting
     append() and remove()) which is also a live Query object when
     accessed for reads.  Ideal for dealing with very large collections
     where only partial loading is desired.

   * `[orm]' ¶ flush()-embedded inline INSERT/UPDATE
     expressions.  Assign any SQL expression, like “sometable.c.column +
     1”, to an instance’s attribute.  Upon flush(), the mapper detects
     the expression and embeds it directly in the INSERT or UPDATE
     statement; the attribute gets deferred on the instance so it loads
     the new value the next time you access it.

   * `[orm]' ¶. A rudimental sharding (horizontal scaling)
     system is introduced.  This system uses a modified Session which
     can distribute read and write operations among multiple databases,
     based on user-defined functions defining the “sharding strategy”.
     Instances and their dependents can be distributed and queried among
     multiple databases based on attribute values, round-robin
     approaches or any other user-defined system.

     References: #618(4)

   * `[orm]' ¶. Eager loading has been enhanced to allow
     even more joins in more places.  It now functions at any arbitrary
     depth along self-referential and cyclical structures.  When loading
     cyclical structures, specify “join_depth” on relation() indicating
     how many times you’d like the table to join to itself; each level
     gets a distinct table alias.  The alias names themselves are
     generated at compile time using a simple counting scheme now and
     are a lot easier on the eyes, as well as of course completely
     deterministic.

     References: #659(5)

   * `[orm]' ¶. Added composite column properties.  This
     allows you to create a type which is represented by more than one
     column, when using the ORM. Objects of the new type are fully
     functional in query expressions, comparisons, query.get() clauses,
     etc.  and act as though they are regular single-column scalars…
     except they’re not!  Use the function composite(cls, *columns)
     inside of the mapper’s “properties” dict, and instances of cls will
     be created/mapped to a single attribute, comprised of the values
     corresponding to *columns.

     References: #211(6)

   * `[orm]' ¶. Improved support for custom
     column_property() attributes which feature correlated subqueries,
     works better with eager loading now.

   * `[orm]' ¶. Primary key “collapse” behavior; the mapper
     will analyze all columns in its given selectable for primary key
     “equivalence”, that is, columns which are equivalent via foreign
     key relationship or via an explicit inherit_condition.  primarily
     for joined-table inheritance scenarios where different named PK
     columns in inheriting tables should “collapse” into a single-valued
     (or fewer-valued) primary key.  Fixes things like.

     References: #611(7)

   * `[orm]' ¶. Joined-table inheritance will now generate
     the primary key columns of all inherited classes against the root
     table of the join only.  This implies that each row in the root
     table is distinct to a single instance.  If for some rare reason
     this is not desirable, explicit primary_key settings on individual
     mappers will override it.

   * `[orm]' ¶. When “polymorphic” flags are used with
     joined-table or single-table inheritance, all identity keys are
     generated against the root class of the inheritance hierarchy; this
     allows query.get() to work polymorphically using the same caching
     semantics as a non-polymorphic get.  Note that this currently does
     not work with concrete inheritance.

   * `[orm]' ¶. Secondary inheritance loading: polymorphic
     mappers can be constructed `without' a select_table argument.
     inheriting mappers whose tables were not represented in the initial
     load will issue a second SQL query immediately, once per instance
     (i.e.  not very efficient for large lists), in order to load the
     remaining columns.

   * `[orm]' ¶. Secondary inheritance loading can also move
     its second query into a column-level “deferred” load, via the
     “polymorphic_fetch” argument, which can be set to ‘select’ or
     ‘deferred’

   * `[orm]' ¶. It’s now possible to map only a subset of
     available selectable columns onto mapper properties, using
     include_columns/exclude_columns..

     References: #696(8)

   * `[orm]' ¶. Added undefer_group() MapperOption, sets a
     set of “deferred” columns joined by a “group” to load as
     “undeferred”.

   * `[orm]' ¶. Rewrite of the “deterministic alias name”
     logic to be part of the SQL layer, produces much simpler alias and
     label names more in the style of Hibernate

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/213

   (2) http://www.sqlalchemy.org/trac/ticket/643

   (3) http://www.sqlalchemy.org/trac/ticket/660

   (4) http://www.sqlalchemy.org/trac/ticket/618

   (5) http://www.sqlalchemy.org/trac/ticket/659

   (6) http://www.sqlalchemy.org/trac/ticket/211

   (7) http://www.sqlalchemy.org/trac/ticket/611

   (8) http://www.sqlalchemy.org/trac/ticket/696

8.3.11.63 sql
.............

   * `[sql]' ¶. Speed!  Clause compilation as well as the
     mechanics of SQL constructs have been streamlined and simplified to
     a significant degree, for a 20-30% improvement of the statement
     construction/compilation overhead of 0.3.

   * `[sql]' ¶. All “type” keyword arguments, such as those
     to bindparam(), column(), Column(), and func.<something>(), renamed
     to “type_”.  Those objects still name their “type” attribute as
     “type”.

   * `[sql]' ¶ case_sensitive=(True|False) setting removed
     from schema items, since checking this state added a lot of method
     call overhead and there was no decent reason to ever set it to
     False.  Table and column names which are all lower case will be
     treated as case-insensitive (yes we adjust for Oracle’s UPPERCASE
     style too).

8.3.11.64 extensions
....................

   * `[extensions]' ¶ proxyengine is temporarily removed,
     pending an actually working replacement.

   * `[extensions]' ¶. SelectResults has been replaced by
     Query.  SelectResults / SelectResultsExt still exist but just
     return a slightly modified Query object for
     backwards-compatibility.  join_to() method from SelectResults isn’t
     present anymore, need to use join().

8.3.11.65 mysql
...............

   * `[mysql]' ¶. Table and column names loaded via
     reflection are now Unicode.

   * `[mysql]' ¶. All standard column types are now
     supported, including SET.

   * `[mysql]' ¶. Table reflection can now be performed in
     as little as one round-trip.

   * `[mysql]' ¶. ANSI and ANSI_QUOTES sql modes are now
     supported.

   * `[mysql]' ¶. Indexes are now reflected.

8.3.11.66 oracle
................

   * `[oracle]' ¶. Very rudimental support for OUT
     parameters added; use sql.outparam(name, type) to set up an OUT
     parameter, just like bindparam(); after execution, values are
     available via result.out_parameters dictionary.

     References: #507(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/507

8.3.11.67 misc
..............

   * `[transactions]' ¶. Added context manager (with
     statement) support for transactions.

   * `[transactions]' ¶. Added support for two phase commit,
     works with mysql and postgres so far.

   * `[transactions]' ¶. Added a subtransaction
     implementation that uses savepoints.

   * `[transactions]' ¶. Added support for savepoints.

   * `[metadata]' ¶. Tables can be reflected from the
     database en-masse without declaring them in advance.
     MetaData(engine, reflect=True) will load all tables present in the
     database, or use metadata.reflect() for finer control.

   * `[metadata]' ¶. DynamicMetaData has been renamed to
     ThreadLocalMetaData

   * `[metadata]' ¶. The ThreadLocalMetaData constructor now
     takes no arguments.

   * `[metadata]' ¶. BoundMetaData has been removed- regular
     MetaData is equivalent

   * `[metadata]' ¶. Numeric and Float types now have an
     “asdecimal” flag; defaults to True for Numeric, False for Float.
     When True, values are returned as decimal.Decimal objects; when
     False, values are returned as float().  The defaults of True/False
     are already the behavior for PG and MySQL’s DBAPI modules.

     References: #646(1)

   * `[metadata]' ¶. New SQL operator implementation which
     removes all hardcoded operators from expression structures and
     moves them into compilation; allows greater flexibility of operator
     compilation; for example, “+” compiles to “||” when used in a
     string context, or “concat(a,b)” on MySQL; whereas in a numeric
     context it compiles to “+”.  Fixes.

     References: #475(2)

   * `[metadata]' ¶. ”Anonymous” alias and label names are
     now generated at SQL compilation time in a completely deterministic
     fashion… no more random hex IDs

   * `[metadata]' ¶. Significant architectural overhaul to
     SQL elements (ClauseElement).  All elements share a common
     “mutability” framework which allows a consistent approach to
     in-place modifications of elements as well as generative behavior.
     Improves stability of the ORM which makes heavy usage of mutations
     to SQL expressions.

   * `[metadata]' ¶ select() and union()’s now have
     “generative” behavior.  Methods like order_by() and group_by()
     return a `new' instance - the original instance is left unchanged.
     Non-generative methods remain as well.

   * `[metadata]' ¶. The internals of select/union vastly
     simplified- all decision making regarding “is subquery” and
     “correlation” pushed to SQL generation phase.  select() elements
     are now `never' mutated by their enclosing containers or by any
     dialect’s compilation process

     References: #52(3), #569(4)

   * `[metadata]' ¶ select(scalar=True) argument is
     deprecated; use select(..).as_scalar().  The resulting object obeys
     the full “column” interface and plays better within expressions.

   * `[metadata]' ¶. Added select().with_prefix(‘foo’)
     allowing any set of keywords to be placed before the columns clause
     of the SELECT

     References: #504(5)

   * `[metadata]' ¶. Added array slice support to
     row[<index>]

     References: #686(6)

   * `[metadata]' ¶. Result sets make a better attempt at
     matching the DBAPI types present in cursor.description to the
     TypeEngine objects defined by the dialect, which are then used for
     result-processing.  Note this only takes effect for textual SQL;
     constructed SQL statements always have an explicit type map.

   * `[metadata]' ¶. Result sets from CRUD operations close
     their underlying cursor immediately and will also autoclose the
     connection if defined for the operation; this allows more efficient
     usage of connections for successive CRUD operations with less
     chance of “dangling connections”.

   * `[metadata]' ¶. Column defaults and onupdate Python
     functions (i.e.  passed to ColumnDefault) may take zero or one
     arguments; the one argument is the ExecutionContext, from which you
     can call “context.parameters[someparam]” to access the other bind
     parameter values affixed to the statement.  The connection used for
     the execution is available as well so that you can pre-execute
     statements.

     References: #559(7)

   * `[metadata]' ¶. Added “explicit” create/drop/execute
     support for sequences (i.e.  you can pass a “connectable” to each
     of those methods on Sequence).

   * `[metadata]' ¶. Better quoting of identifiers when
     manipulating schemas.

   * `[metadata]' ¶. Standardized the behavior for table
     reflection where types can’t be located; NullType is substituted
     instead, warning is raised.

   * `[metadata]' ¶. ColumnCollection (i.e.  the ‘c’
     attribute on tables) follows dictionary semantics for
     “__contains__”

     References: #606(8)

   * `[engines]' ¶. Speed!  The mechanics of result
     processing and bind parameter processing have been overhauled,
     streamlined and optimized to issue as little method calls as
     possible.  Bench tests for mass INSERT and mass rowset iteration
     both show 0.4 to be over twice as fast as 0.3, using 68% fewer
     function calls.

   * `[engines]' ¶. You can now hook into the pool lifecycle
     and run SQL statements or other logic at new each DBAPI connection,
     pool check-out and check-in.

   * `[engines]' ¶. Connections gain a .properties
     collection, with contents scoped to the lifetime of the underlying
     DBAPI connection

   * `[engines]' ¶. Removed auto_close_cursors and
     disallow_open_cursors arguments from Pool; reduces overhead as
     cursors are normally closed by ResultProxy and Connection.

   * `[postgres]' ¶. Added PGArray datatype for using
     postgres array datatypes.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/646

   (2) http://www.sqlalchemy.org/trac/ticket/475

   (3) http://www.sqlalchemy.org/trac/ticket/52

   (4) http://www.sqlalchemy.org/trac/ticket/569

   (5) http://www.sqlalchemy.org/trac/ticket/504

   (6) http://www.sqlalchemy.org/trac/ticket/686

   (7) http://www.sqlalchemy.org/trac/ticket/559

   (8) http://www.sqlalchemy.org/trac/ticket/606

8.3.12 0.3 Changelog
--------------------

8.3.12.1 0.3.11
...............

Released: Sun Oct 14 2007

8.3.12.2 orm
............

   * `[orm]' ¶ added a check for joining from A->B using
     join(), along two different m2m tables.  this raises an error in
     0.3 but is possible in 0.4 when aliases are used.

     References: #687(1)

   * `[orm]' ¶ fixed small exception throw bug in
     Session.merge()

   * `[orm]' ¶ fixed bug where mapper, being linked to a
     join where one table had no PK columns, would not detect that the
     joined table had no PK.

   * `[orm]' ¶ fixed bugs in determining proper sync
     clauses from custom inherit conditions

     References: #769(2)

   * `[orm]' ¶ backref remove object operation doesn’t fail
     if the other-side collection doesn’t contain the item, supports
     noload collections

     References: #813(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/687

   (2) http://www.sqlalchemy.org/trac/ticket/769

   (3) http://www.sqlalchemy.org/trac/ticket/813

8.3.12.3 engine
...............

   * `[engine]' ¶ fixed another occasional race condition
     which could occur when using pool with threadlocal setting

8.3.12.4 sql
............

   * `[sql]' ¶ tweak DISTINCT precedence for clauses like
     ‘func.count(t.c.col.distinct())’

   * `[sql]' ¶. Fixed detection of internal ‘$’ characters
     in :bind$params

     References: #719(1)

   * `[sql]' ¶ don’t assume join criterion consists only of
     column objects

     References: #768(2)

   * `[sql]' ¶ adjusted operator precedence of NOT to match
     ‘==’ and others, so that ~(x==y) produces NOT (x=y), which is
     compatible with MySQL < 5.0 (doesn’t like “NOT x=y”)

     References: #764(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/719

   (2) http://www.sqlalchemy.org/trac/ticket/768

   (3) http://www.sqlalchemy.org/trac/ticket/764

8.3.12.5 mysql
..............

   * `[mysql]' ¶ fixed specification of YEAR columns when
     generating schema

8.3.12.6 sqlite
...............

   * `[sqlite]' ¶ passthrough for stringified dates

8.3.12.7 mssql
..............

   * `[mssql]' ¶ added support for TIME columns (simulated
     using DATETIME)

     References: #679(1)

   * `[mssql]' ¶ added support for BIGINT, MONEY,
     SMALLMONEY, UNIQUEIDENTIFIER and SQL_VARIANT

     References: #721(2)

   * `[mssql]' ¶ index names are now quoted when dropping
     from reflected tables

     References: #684(3)

   * `[mssql]' ¶ can now specify a DSN for PyODBC, using a
     URI like mssql:///?dsn=bob

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/679

   (2) http://www.sqlalchemy.org/trac/ticket/721

   (3) http://www.sqlalchemy.org/trac/ticket/684

8.3.12.8 oracle
...............

   * `[oracle]' ¶ removed LONG_STRING, LONG_BINARY from
     “binary” types, so type objects don’t try to read their values as
     LOB.

     References: #622(1), #751(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/622

   (2) http://www.sqlalchemy.org/trac/ticket/751

8.3.12.9 firebird
.................

   * `[firebird]' ¶ supports_sane_rowcount() set to False
     due to ticket #370 (right way).

   * `[firebird]' ¶ fixed reflection of Column’s nullable
     property.

8.3.12.10 misc
..............

   * `[postgres]' ¶ when reflecting tables from alternate
     schemas, the “default” placed upon the primary key, i.e.  usually a
     sequence name, has the “schema” name unconditionally quoted, so
     that schema names which need quoting are fine.  its slightly
     unnecessary for schema names which don’t need quoting but not
     harmful.

8.3.12.11 0.3.10
................

Released: Fri Jul 20 2007

8.3.12.12 general
.................

   * `[general]' ¶ a new mutex that was added in 0.3.9
     causes the pool_timeout feature to fail during a race condition;
     threads would raise TimeoutError immediately with no delay if many
     threads push the pool into overflow at the same time.  this issue
     has been fixed.

8.3.12.13 orm
.............

   * `[orm]' ¶ cleanup to connection-bound sessions,
     SessionTransaction

8.3.12.14 sql
.............

   * `[sql]' ¶ got connection-bound metadata to work with
     implicit execution

   * `[sql]' ¶ foreign key specs can have any character in
     their identifiers

     References: #667(1)

   * `[sql]' ¶ added commutativity-awareness to binary
     clause comparisons to each other, improves ORM lazy load
     optimization

     References: #664(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/667

   (2) http://www.sqlalchemy.org/trac/ticket/664

8.3.12.15 misc
..............

   * `[postgres]' ¶ fixed max identifier length (63)

     References: #571(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/571

8.3.12.16 0.3.9
...............

Released: Sun Jul 15 2007

8.3.12.17 general
.................

   * `[general]' ¶ better error message for
     NoSuchColumnError

     References: #607(1)

   * `[general]' ¶ finally figured out how to get
     setuptools version in, available as sqlalchemy.__version__

     References: #428(2)

   * `[general]' ¶ the various “engine” arguments, such as
     “engine”, “connectable”, “engine_or_url”, “bind_to”, etc.  are all
     present, but deprecated.  they all get replaced by the single term
     “bind”.  you also set the “bind” of MetaData using metadata.bind =
     <engine or connection>

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/607

   (2) http://www.sqlalchemy.org/trac/ticket/428

8.3.12.18 orm
.............

   * `[orm]' ¶ forwards-compatibility with 0.4: added
     one(), first(), and all() to Query.  almost all Query functionality
     from 0.4 is present in 0.3.9 for forwards-compat purposes.

   * `[orm]' ¶ reset_joinpoint() really really works this
     time, promise !  lets you re-join from the root: query.join([‘a’,
     ‘b’]).filter(<crit>).reset_joinpoint().join([‘a’,
     ‘c’]).filter(<some other crit>).all() in 0.4 all join() calls start
     from the “root”

   * `[orm]' ¶ added synchronization to the mapper()
     construction step, to avoid thread collisions when pre-existing
     mappers are compiling in a different thread

     References: #613(1)

   * `[orm]' ¶ a warning is issued by Mapper when two
     primary key columns of the same name are munged into a single
     attribute.  this happens frequently when mapping to joins (or
     inheritance).

   * `[orm]' ¶ synonym() properties are fully supported by
     all Query joining/ with_parent operations

     References: #598(2)

   * `[orm]' ¶ fixed very stupid bug when deleting items
     with many-to-many uselist=False relations

   * `[orm]' ¶ remember all that stuff about
     polymorphic_union ?  for joined table inheritance ?  Funny thing…
     You sort of don’t need it for joined table inheritance, you can
     just string all the tables together via outerjoin().  The UNION
     still applies if concrete tables are involved, though (since
     nothing to join them on).

   * `[orm]' ¶ small fix to eager loading to better work
     with eager loads to polymorphic mappers that are using a straight
     “outerjoin” clause

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/613

   (2) http://www.sqlalchemy.org/trac/ticket/598

8.3.12.19 sql
.............

   * `[sql]' ¶. ForeignKey to a table in a schema that’s not
     the default schema requires the schema to be explicit; i.e.
     ForeignKey(‘alt_schema.users.id’)

   * `[sql]' ¶. MetaData can now be constructed with an
     engine or url as the first argument, just like BoundMetaData

   * `[sql]' ¶. BoundMetaData is now deprecated, and
     MetaData is a direct substitute.

   * `[sql]' ¶. DynamicMetaData has been renamed to
     ThreadLocalMetaData.  the DynamicMetaData name is deprecated and is
     an alias for ThreadLocalMetaData or a regular MetaData if
     threadlocal=False

   * `[sql]' ¶ composite primary key is represented as a
     non-keyed set to allow for composite keys consisting of cols with
     the same name; occurs within a Join.  helps inheritance scenarios
     formulate correct PK.

   * `[sql]' ¶ improved ability to get the “correct” and
     most minimal set of primary key columns from a join, equating
     foreign keys and otherwise equated columns.  this is also mostly to
     help inheritance scenarios formulate the best choice of primary key
     columns.

     References: #185(1)

   * `[sql]' ¶ added ‘bind’ argument to
     Sequence.create()/drop(), ColumnDefault.execute()

   * `[sql]' ¶ columns can be overridden in a reflected
     table with a “key” attribute different than the column’s name,
     including for primary key columns

     References: #650(2)

   * `[sql]' ¶ fixed “ambiguous column” result detection,
     when dupe col names exist in a result

     References: #657(3)

   * `[sql]' ¶ some enhancements to “column targeting”, the
     ability to match a column to a “corresponding” column in another
     selectable.  this affects mostly ORM ability to map to complex
     joins

   * `[sql]' ¶. MetaData and all SchemaItems are safe to use
     with pickle.  slow table reflections can be dumped into a pickled
     file to be reused later.  Just reconnect the engine to the metadata
     after unpickling.

     References: #619(4)

   * `[sql]' ¶ added a mutex to QueuePool’s “overflow”
     calculation to prevent a race condition that can bypass
     max_overflow

   * `[sql]' ¶ fixed grouping of compound selects to give
     correct results.  will break on sqlite in some cases, but those
     cases were producing incorrect results anyway, sqlite doesn’t
     support grouped compound selects

     References: #623(5)

   * `[sql]' ¶ fixed precedence of operators so that
     parenthesis are correctly applied

     References: #620(6)

   * `[sql]' ¶ calling <column>.in_() (i.e.  with no
     arguments) will return “CASE WHEN (<column> IS NULL) THEN NULL ELSE
     0 END = 1)”, so that NULL or False is returned in all cases, rather
     than throwing an error

     References: #545(7)

   * `[sql]' ¶ fixed “where”/”from” criterion of select()
     to accept a unicode string in addition to regular string - both
     convert to text()

   * `[sql]' ¶ added standalone distinct() function in
     addition to column.distinct()

     References: #558(8)

   * `[sql]' ¶ result.last_inserted_ids() should return a
     list that is identically sized to the primary key constraint of the
     table.  values that were “passively” created and not available via
     cursor.lastrowid will be None.

   * `[sql]' ¶ long-identifier detection fixed to use >
     rather than >= for max ident length

     References: #589(9)

   * `[sql]' ¶ fixed bug where
     selectable.corresponding_column(selectable.c.col) would not return
     selectable.c.col, if the selectable is a join of a table and
     another join involving the same table.  messed up ORM decision
     making

     References: #593(10)

   * `[sql]' ¶ added Interval type to types.py

     References: #595(11)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/185

   (2) http://www.sqlalchemy.org/trac/ticket/650

   (3) http://www.sqlalchemy.org/trac/ticket/657

   (4) http://www.sqlalchemy.org/trac/ticket/619

   (5) http://www.sqlalchemy.org/trac/ticket/623

   (6) http://www.sqlalchemy.org/trac/ticket/620

   (7) http://www.sqlalchemy.org/trac/ticket/545

   (8) http://www.sqlalchemy.org/trac/ticket/558

   (9) http://www.sqlalchemy.org/trac/ticket/589

   (10) http://www.sqlalchemy.org/trac/ticket/593

   (11) http://www.sqlalchemy.org/trac/ticket/595

8.3.12.20 mysql
...............

   * `[mysql]' ¶ fixed catching of some errors that imply a
     dropped connection

     References: #625(1)

   * `[mysql]' ¶ fixed escaping of the modulo operator

     References: #624(2)

   * `[mysql]' ¶ added ‘fields’ to reserved words

     References: #590(3)

   * `[mysql]' ¶ various reflection enhancement/fixes

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/625

   (2) http://www.sqlalchemy.org/trac/ticket/624

   (3) http://www.sqlalchemy.org/trac/ticket/590

8.3.12.21 sqlite
................

   * `[sqlite]' ¶ rearranged dialect initialization so it
     has time to warn about pysqlite1 being too old.

   * `[sqlite]' ¶ sqlite better handles datetime/date/time
     objects mixed and matched with various Date/Time/DateTime columns

   * `[sqlite]' ¶ string PK column inserts don’t get
     overwritten with OID

     References: #603(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/603

8.3.12.22 mssql
...............

   * `[mssql]' ¶ fix port option handling for pyodbc

     References: #634(1)

   * `[mssql]' ¶ now able to reflect start and increment
     values for identity columns

   * `[mssql]' ¶ preliminary support for using
     scope_identity() with pyodbc

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/634

8.3.12.23 oracle
................

   * `[oracle]' ¶ datetime fixes: got subsecond TIMESTAMP
     to work, added OracleDate which supports types.Date with only
     year/month/day

     References: #604(1)

   * `[oracle]' ¶ added dialect flag “auto_convert_lobs”,
     defaults to True; will cause any LOB objects detected in a result
     set to be forced into OracleBinary so that the LOB is read()
     automatically, if no typemap was present (i.e., if a textual
     execute() was issued).

   * `[oracle]' ¶ mod operator ‘%’ produces MOD

     References: #624(2)

   * `[oracle]' ¶ converts cx_oracle datetime objects to
     Python datetime.datetime when Python 2.3 used

     References: #542(3)

   * `[oracle]' ¶ fixed unicode conversion in Oracle TEXT
     type

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/604

   (2) http://www.sqlalchemy.org/trac/ticket/624

   (3) http://www.sqlalchemy.org/trac/ticket/542

8.3.12.24 misc
..............

   * `[ext]' ¶ iteration over dict association proxies is
     now dict-like, not InstrumentedList-like (e.g.  over keys instead
     of values)

   * `[ext]' ¶ association proxies no longer bind tightly
     to source collections, and are constructed with a thunk instead

     References: #597(1)

   * `[ext]' ¶ added selectone_by() to assignmapper

   * `[postgres]' ¶ fixed escaping of the modulo operator

     References: #624(2)

   * `[postgres]' ¶ added support for reflection of domains

     References: #570(3)

   * `[postgres]' ¶ types which are missing during
     reflection resolve to Null type instead of raising an error

   * `[postgres]' ¶ the fix in “schema” above fixes
     reflection of foreign keys from an alt-schema table to a public
     schema table

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/597

   (2) http://www.sqlalchemy.org/trac/ticket/624

   (3) http://www.sqlalchemy.org/trac/ticket/570

8.3.12.25 0.3.8
...............

Released: Sat Jun 02 2007

8.3.12.26 orm
.............

   * `[orm]' ¶ added reset_joinpoint() method to Query,
     moves the “join point” back to the starting mapper.  0.4 will
     change the behavior of join() to reset the “join point” in all
     cases so this is an interim method.  for forwards compatibility,
     ensure joins across multiple relations are specified using a single
     join(), i.e.  join([‘a’, ‘b’, ‘c’]).

   * `[orm]' ¶ fixed bug in query.instances() that wouldn’t
     handle more than on additional mapper or one additional column.

   * `[orm]' ¶. ”delete-orphan” no longer implies “delete”.
     ongoing effort to separate the behavior of these two operations.

   * `[orm]' ¶ many-to-many relationships properly set the
     type of bind params for delete operations on the association table

   * `[orm]' ¶ many-to-many relationships check that the
     number of rows deleted from the association table by a delete
     operation matches the expected results

   * `[orm]' ¶ session.get() and session.load() propagate
     **kwargs through to query

   * `[orm]' ¶ fix to polymorphic query which allows the
     original polymorphic_union to be embedded into a correlated
     subquery

     References: #577(1)

   * `[orm]' ¶ fix to select_by(<propname>=<object
     instance>) -style joins in conjunction with many-to-many
     relationships, bug introduced in r2556

   * `[orm]' ¶ the “primary_key” argument to mapper() is
     propagated to the “polymorphic” mapper.  primary key columns in
     this list get normalized to that of the mapper’s local table.

   * `[orm]' ¶ restored logging of “lazy loading clause”
     under sa.orm.strategies logger, got removed in 0.3.7

   * `[orm]' ¶ improved support for eagerloading of
     properties off of mappers that are mapped to select() statements;
     i.e.  eagerloader is better at locating the correct selectable with
     which to attach its LEFT OUTER JOIN.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/577

8.3.12.27 sql
.............

   * `[sql]' ¶. _Label class overrides compare_self to
     return its ultimate object.  meaning, if you say
     someexpr.label(‘foo’) == 5, it produces the correct “someexpr ==
     5”.

   * `[sql]' ¶. _Label propagates “_hide_froms()” so that
     scalar selects behave more properly with regards to FROM clause
     #574

   * `[sql]' ¶ fix to long name generation when using
     oid_column as an order by (oids used heavily in mapper queries)

   * `[sql]' ¶ significant speed improvement to
     ResultProxy, pre-caches TypeEngine dialect implementations and
     saves on function calls per column

   * `[sql]' ¶ parenthesis are applied to clauses via a new
     _Grouping construct.  uses operator precedence to more
     intelligently apply parenthesis to clauses, provides cleaner
     nesting of clauses (doesn’t mutate clauses placed in other clauses,
     i.e.  no ‘parens’ flag)

   * `[sql]' ¶ added ‘modifier’ keyword, works like
     func.<foo> except does not add parenthesis.  e.g.
     select([modifier.DISTINCT(…)]) etc.

   * `[sql]' ¶ removed “no group by’s in a select that’s
     part of a UNION” restriction

     References: #578(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/578

8.3.12.28 mysql
...............

   * `[mysql]' ¶. Nearly all MySQL column types are now
     supported for declaration and reflection.  Added NCHAR, NVARCHAR,
     VARBINARY, TINYBLOB, LONGBLOB, YEAR

   * `[mysql]' ¶. The sqltypes.Binary passthrough now always
     builds a BLOB, avoiding problems with very old database versions

   * `[mysql]' ¶ support for column-level CHARACTER SET and
     COLLATE declarations, as well as ASCII, UNICODE, NATIONAL and
     BINARY shorthand.

8.3.12.29 firebird
..................

   * `[firebird]' ¶ set max identifier length to 31

   * `[firebird]' ¶ supports_sane_rowcount() set to False
     due to ticket #370.  versioned_id_col feature wont work in FB.

   * `[firebird]' ¶ some execution fixes

   * `[firebird]' ¶ new association proxy implementation,
     implementing complete proxies to list, dict and set-based relation
     collections

   * `[firebird]' ¶ added orderinglist, a custom list class
     that synchronizes an object attribute with that object’s position
     in the list

   * `[firebird]' ¶ small fix to SelectResultsExt to not
     bypass itself during select().

   * `[firebird]' ¶ added filter(), filter_by() to
     assignmapper

8.3.12.30 misc
..............

   * `[engines]' ¶ added detach() to Connection, allows
     underlying DBAPI connection to be detached from its pool, closing
     on dereference/close() instead of being reused by the pool.

   * `[engines]' ¶ added invalidate() to Connection,
     immediately invalidates the Connection and its underlying DBAPI
     connection.

8.3.12.31 0.3.7
...............

Released: Sun Apr 29 2007

8.3.12.32 orm
.............

   * `[orm]' ¶ fixed critical issue when, after
     options(eagerload()) is used, the mapper would then always apply
     query “wrapping” behavior for all subsequent LIMIT/OFFSET/DISTINCT
     queries, even if no eager loading was applied on those subsequent
     queries.

   * `[orm]' ¶ added query.with_parent(someinstance)
     method.  searches for target instance using lazy join criterion
     from parent instance.  takes optional string “property” to isolate
     the desired relation.  also adds static
     Query.query_from_parent(instance, property) version.

     References: #541(1)

   * `[orm]' ¶ improved query.XXX_by(someprop=someinstance)
     querying to use similar methodology to with_parent, i.e.  using the
     “lazy” clause which prevents adding the remote instance’s table to
     the SQL, thereby making more complex conditions possible

     References: #554(2)

   * `[orm]' ¶ added generative versions of aggregates,
     i.e.  sum(), avg(), etc.  to query.  used via query.apply_max(),
     apply_sum(), etc.  #552

   * `[orm]' ¶ fix to using distinct() or distinct=True in
     combination with join() and similar

   * `[orm]' ¶ corresponding to label/bindparam name
     generation, eager loaders generate deterministic names for the
     aliases they create using md5 hashes.

   * `[orm]' ¶ improved/fixed custom collection classes
     when giving it “set”/ “sets.Set” classes or subclasses (was still
     looking for append() methods on them during lazy loads)

   * `[orm]' ¶ restored old “column_property()” ORM
     function (used to be called “column()”) to force any column
     expression to be added as a property on a mapper, particularly
     those that aren’t present in the mapped selectable.  this allows
     “scalar expressions” of any kind to be added as relations (though
     they have issues with eager loads).

   * `[orm]' ¶ fix to many-to-many relationships targeting
     polymorphic mappers

     References: #533(3)

   * `[orm]' ¶ making progress with session.merge() as well
     as combining its usage with entity_name

     References: #543(4)

   * `[orm]' ¶ the usual adjustments to relationships
     between inheriting mappers, in this case establishing relation()s
     to subclass mappers where the join conditions come from the
     superclass’ table

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/541

   (2) http://www.sqlalchemy.org/trac/ticket/554

   (3) http://www.sqlalchemy.org/trac/ticket/533

   (4) http://www.sqlalchemy.org/trac/ticket/543

8.3.12.33 sql
.............

   * `[sql]' ¶ keys() of result set columns are not
     lowercased, come back exactly as they’re expressed in
     cursor.description.  note this causes colnames to be all caps in
     oracle.

   * `[sql]' ¶ preliminary support for unicode table names,
     column names and SQL statements added, for databases which can
     support them.  Works with sqlite and postgres so far.  MySQL
     `mostly' works except the has_table() function does not work.
     Reflection works too.

   * `[sql]' ¶ the Unicode type is now a direct subclass of
     String, which now contains all the “convert_unicode” logic.  This
     helps the variety of unicode situations that occur in db’s such as
     MS-SQL to be better handled and allows subclassing of the Unicode
     datatype.

     References: #522(1)

   * `[sql]' ¶. ClauseElements can be used in in_() clauses
     now, such as bind parameters, etc.  #476

   * `[sql]' ¶ reverse operators implemented for
     ‘CompareMixin’ elements, allows expressions like “5 + somecolumn”
     etc.  #474

   * `[sql]' ¶ the “where” criterion of an update() and
     delete() now correlates embedded select() statements against the
     table being updated or deleted.  this works the same as nested
     select() statement correlation, and can be disabled via the
     correlate=False flag on the embedded select().

   * `[sql]' ¶ column labels are now generated in the
     compilation phase, which means their lengths are dialect-dependent.
     So on oracle a label that gets truncated to 30 chars will go out to
     63 characters on postgres.  Also, the true labelname is always
     attached as the accessor on the parent Selectable so there’s no
     need to be aware of the “truncated” label names.

     References: #512(2)

   * `[sql]' ¶ column label and bind param “truncation”
     also generate deterministic names now, based on their ordering
     within the full statement being compiled.  this means the same
     statement will produce the same string across application restarts
     and allowing DB query plan caching to work better.

   * `[sql]' ¶ the “mini” column labels generated when
     using subqueries, which are to work around glitchy SQLite behavior
     that doesn’t understand “foo.id” as equivalent to “id”, are now
     only generated in the case that those named columns are selected
     from (part of)

     References: #513(3)

   * `[sql]' ¶ the label() method on ColumnElement will
     properly propagate the TypeEngine of the base element out to the
     label, including a label() created from a scalar=True select()
     statement.

   * `[sql]' ¶. MS-SQL better detects when a query is a
     subquery and knows not to generate ORDER BY phrases for those

     References: #513(4)

   * `[sql]' ¶ fix for fetchmany() “size” argument being
     positional in most dbapis

     References: #505(5)

   * `[sql]' ¶ sending None as an argument to
     func.<something> will produce an argument of NULL

   * `[sql]' ¶ query strings in unicode URLs get keys
     encoded to ascii for **kwargs compat

   * `[sql]' ¶ slight tweak to raw execute() change to also
     support tuples for positional parameters, not just lists

     References: #523(6)

   * `[sql]' ¶ fix to case() construct to propagate the
     type of the first WHEN condition as the return type of the case
     statement

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/522

   (2) http://www.sqlalchemy.org/trac/ticket/512

   (3) http://www.sqlalchemy.org/trac/ticket/513

   (4) http://www.sqlalchemy.org/trac/ticket/513

   (5) http://www.sqlalchemy.org/trac/ticket/505

   (6) http://www.sqlalchemy.org/trac/ticket/523

8.3.12.34 extensions
....................

   * `[extensions]' ¶ big fix to AssociationProxy so that
     multiple AssociationProxy objects can be associated with a single
     association collection.

   * `[extensions]' ¶ assign_mapper names methods according
     to their keys (i.e.  __name__) #551

8.3.12.35 mysql
...............

   * `[mysql]' ¶ support for SSL arguments given as inline
     within URL query string, prefixed with “ssl_”, courtesy
     <terjeros@gmail.com>.

   * `[mysql] [<schemaname>]' ¶ mysql uses
     “DESCRIBE.<tablename>”, catching exceptions if table doesn’t exist,
     in order to determine if a table exists.  this supports unicode
     table names as well as schema names.  tested with MySQL5 but should
     work with 4.1 series as well.  (#557)

8.3.12.36 sqlite
................

   * `[sqlite]' ¶ removed silly behavior where sqlite would
     reflect UNIQUE indexes as part of the primary key (?!)

8.3.12.37 mssql
...............

   * `[mssql]' ¶ pyodbc is now the preferred DB-API for
     MSSQL, and if no module is specifically requested, will be loaded
     first on a module probe.

   * `[mssql]' ¶. The @@SCOPE_IDENTITY is now used instead
     of @@IDENTITY. This behavior may be overridden with the
     engine_connect “use_scope_identity” keyword parameter, which may
     also be specified in the dburi.

8.3.12.38 oracle
................

   * `[oracle]' ¶ small fix to allow successive compiles of
     the same SELECT object which features LIMIT/OFFSET. oracle dialect
     needs to modify the object to have ROW_NUMBER OVER and wasn’t
     performing the full series of steps on successive compiles.

8.3.12.39 misc
..............

   * `[engines]' ¶ warnings module used for issuing
     warnings (instead of logging)

   * `[engines]' ¶ cleanup of DBAPI import strategies
     across all engines

     References: #480(1)

   * `[engines]' ¶ refactoring of engine internals which
     reduces complexity, number of codepaths; places more state inside
     of ExecutionContext to allow more dialect control of cursor
     handling, result sets.  ResultProxy totally refactored and also has
     two versions of “buffered” result sets used for different purposes.

   * `[engines]' ¶ server side cursor support fully
     functional in postgres.

     References: #514(2)

   * `[engines]' ¶ improved framework for auto-invalidation
     of connections that have lost their underlying database, via
     dialect-specific detection of exceptions corresponding to that
     database’s disconnect related error messages.  Additionally, when a
     “connection no longer open” condition is detected, the entire
     connection pool is discarded and replaced with a new instance.
     #516

   * `[engines]' ¶ the dialects within sqlalchemy.databases
     become a setuptools entry points.  loading the built-in database
     dialects works the same as always, but if none found will fall back
     to trying pkg_resources to load an external module

     References: #521(3)

   * `[engines]' ¶. Engine contains a “url” attribute
     referencing the url.URL object used by create_engine().

   * `[informix]' ¶ informix support added !  courtesy
     James Zhang, who put a ton of effort in.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/480

   (2) http://www.sqlalchemy.org/trac/ticket/514

   (3) http://www.sqlalchemy.org/trac/ticket/521

8.3.12.40 0.3.6
...............

Released: Fri Mar 23 2007

8.3.12.41 orm
.............

   * `[orm]' ¶ the full featureset of the SelectResults
     extension has been merged into a new set of methods available off
     of Query.  These methods all provide “generative” behavior, whereby
     the Query is copied and a new one returned with additional
     criterion added.  The new methods include:

             * filter() - applies select criterion to the query

             * filter_by() - applies “by”-style criterion to the query

             * avg() - return the avg() function on the given column

             * join() - join to a property (or across a list of
               properties)

             * outerjoin() - like join() but uses LEFT OUTER JOIN

             * limit()/offset() - apply LIMIT/OFFSET range-based access
               which applies limit/offset: session.query(Foo)[3:5]

             * distinct() - apply DISTINCT

             * list() - evaluate the criterion and return results

     no incompatible changes have been made to Query’s API and no
     methods have been deprecated.  Existing methods like select(),
     select_by(), get(), get_by() all execute the query at once and
     return results like they always did.  join_to()/join_via() are
     still there although the generative join()/outerjoin() methods are
     easier to use.

   * `[orm]' ¶ the return value for multiple mappers used
     with instances() now returns a cartesian product of the requested
     list of mappers, represented as a list of tuples.  this corresponds
     to the documented behavior.  So that instances match up properly,
     the “uniquing” is disabled when this feature is used.

   * `[orm]' ¶. Query has add_entity() and add_column()
     generative methods.  these will add the given mapper/class or
     ColumnElement to the query at compile time, and apply them to the
     instances() method.  the user is responsible for constructing
     reasonable join conditions (otherwise you can get full cartesian
     products).  result set is the list of tuples, non-uniqued.

   * `[orm]' ¶ strings and columns can also be sent to the
     *args of instances() where those exact result columns will be part
     of the result tuples.

   * `[orm]' ¶ a full select() construct can be passed to
     query.select() (which worked anyway), but also query.selectfirst(),
     query.selectone() which will be used as is (i.e.  no query is
     compiled).  works similarly to sending the results to instances().

   * `[orm]' ¶ eager loading will not “aliasize” “order by”
     clauses that were placed in the select statement by something other
     than the eager loader itself, to fix possibility of dupe columns as
     illustrated in.  however, this means you have to be more careful
     with the columns placed in the “order by” of Query.select(), that
     you have explicitly named them in your criterion (i.e.  you cant
     rely on the eager loader adding them in for you)

     References: #495(1)

   * `[orm]' ¶ added a handy multi-use “identity_key()”
     method to Session, allowing the generation of identity keys for
     primary key values, instances, and rows, courtesy Daniel Miller

   * `[orm]' ¶ many-to-many table will be properly handled
     even for operations that occur on the “backref” side of the
     operation

     References: #249(2)

   * `[orm]' ¶ added “refresh-expire” cascade.  allows
     refresh() and expire() calls to propagate along relationships.

     References: #492(3)

   * `[orm]' ¶ more fixes to polymorphic relations,
     involving proper lazy-clause generation on many-to-one
     relationships to polymorphic mappers.  also fixes to detection of
     “direction”, more specific targeting of columns that belong to the
     polymorphic union vs.  those that don’t.

     References: #493(4)

   * `[orm]' ¶ some fixes to relationship calcs when using
     “viewonly=True” to pull in other tables into the join condition
     which aren’t parent of the relationship’s parent/child mappings

   * `[orm]' ¶ flush fixes on cyclical-referential
     relationships that contain references to other instances outside of
     the cyclical chain, when some of the objects in the cycle are not
     actually part of the flush

   * `[orm]' ¶ put an aggressive check for “flushing object
     A with a collection of B’s, but you put a C in the collection”
     error condition - `even if C is a subclass of B', unless B’s mapper
     loads polymorphically.  Otherwise, the collection will later load a
     “B” which should be a “C” (since its not polymorphic) which breaks
     in bi-directional relationships (i.e.  C has its A, but A’s backref
     will lazyload it as a different instance of type “B”) This check is
     going to bite some of you who do this without issues, so the error
     message will also document a flag “enable_typechecks=False” to
     disable this checking.  But be aware that bi-directional
     relationships in particular become fragile without this check.

     References: #500(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/495

   (2) http://www.sqlalchemy.org/trac/ticket/249

   (3) http://www.sqlalchemy.org/trac/ticket/492

   (4) http://www.sqlalchemy.org/trac/ticket/493

   (5) http://www.sqlalchemy.org/trac/ticket/500

8.3.12.42 sql
.............

   * `[sql]' ¶ bindparam() names are now repeatable!
     specify two distinct bindparam()s with the same name in a single
     statement, and the key will be shared.  proper positional/named
     args translate at compile time.  for the old behavior of “aliasing”
     bind parameters with conflicting names, specify “unique=True” -
     this option is still used internally for all the auto-generated
     (value-based) bind parameters.

   * `[sql]' ¶ slightly better support for bind params as
     column clauses, either via bindparam() or via literal(), i.e.
     select([literal(‘foo’)])

   * `[sql]' ¶. MetaData can bind to an engine either via
     “url” or “engine” kwargs to constructor, or by using connect()
     method.  BoundMetaData is identical to MetaData except
     engine_or_url param is required.  DynamicMetaData is the same and
     provides thread-local connections be default.

   * `[sql]' ¶ exists() becomes useable as a standalone
     selectable, not just in a WHERE clause, i.e.  exists([columns],
     criterion).select()

   * `[sql]' ¶ correlated subqueries work inside of ORDER
     BY, GROUP BY

   * `[sql]' ¶ fixed function execution with explicit
     connections, i.e.  conn.execute(func.dosomething())

   * `[sql]' ¶ use_labels flag on select() wont auto-create
     labels for literal text column elements, since we can make no
     assumptions about the text.  to create labels for literal columns,
     you can say “somecol AS somelabel”, or use
     literal_column(“somecol”).label(“somelabel”)

   * `[sql]' ¶ quoting wont occur for literal columns when
     they are “proxied” into the column collection for their selectable
     (is_literal flag is propagated).  literal columns are specified via
     literal_column(“somestring”).

   * `[sql]' ¶ added “fold_equivalents” boolean argument to
     Join.select(), which removes ‘duplicate’ columns from the resulting
     column clause that are known to be equivalent based on the join
     condition.  this is of great usage when constructing subqueries of
     joins which Postgres complains about if duplicate column names are
     present.

   * `[sql]' ¶ fixed use_alter flag on ForeignKeyConstraint

     References: #503(1)

   * `[sql]' ¶ fixed usage of 2.4-only “reversed” in
     topological.py

     References: #506(2)

   * `[sql]' ¶ for hackers, refactored the “visitor” system
     of ClauseElement and SchemaItem so that the traversal of items is
     controlled by the ClauseVisitor itself, using the method
     visitor.traverse(item).  accept_visitor() methods can still be
     called directly but will not do any traversal of child items.
     ClauseElement/SchemaItem now have a configurable get_children()
     method to return the collection of child elements for each parent
     object.  This allows the full traversal of items to be clear and
     unambiguous (as well as loggable), with an easy method of limiting
     a traversal (just pass flags which are picked up by appropriate
     get_children() methods).

     References: #501(3)

   * `[sql]' ¶ the “else_” parameter to the case statement
     now properly works when set to zero.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/503

   (2) http://www.sqlalchemy.org/trac/ticket/506

   (3) http://www.sqlalchemy.org/trac/ticket/501

8.3.12.43 extensions
....................

   * `[extensions]' ¶ options() method on SelectResults now
     implemented “generatively” like the rest of the SelectResults
     methods.  But you’re going to just use Query now anyway.

     References: #472(1)

   * `[extensions]' ¶ query() method is added by
     assignmapper.  this helps with navigating to all the new generative
     methods on Query.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/472

8.3.12.44 mysql
...............

   * `[mysql]' ¶ added a catchall **kwargs to MSString, to
     help reflection of obscure types (like “varchar() binary” in MS
     4.0)

   * `[mysql]' ¶ added explicit MSTimeStamp type which
     takes effect when using types.TIMESTAMP.

8.3.12.45 oracle
................

   * `[oracle]' ¶ got binary working for any size input !
     cx_oracle works fine, it was my fault as BINARY was being passed
     and not BLOB for setinputsizes (also unit tests weren’t even
     setting input sizes).

   * `[oracle]' ¶ also fixed CLOB read/write on a separate
     changeset.

   * `[oracle]' ¶ auto_setinputsizes defaults to True for
     Oracle, fixed cases where it improperly propagated bad types.

8.3.12.46 misc
..............

   * `[ms-sql]' ¶.

     removed seconds input on DATE column types (probably

          should remove the time altogether)

   * `[ms-sql]' ¶ null values in float fields no longer
     raise errors

   * `[ms-sql]' ¶. LIMIT with OFFSET now raises an error
     (MS-SQL has no OFFSET support)

   * `[ms-sql]' ¶ added an facility to use the MSSQL type
     VARCHAR(max) instead of TEXT for large unsized string fields.  Use
     the new “text_as_varchar” to turn it on.

     References: #509(1)

   * `[ms-sql]' ¶. ORDER BY clauses without a LIMIT are now
     stripped in subqueries, as MS-SQL forbids this usage

   * `[ms-sql]' ¶ cleanup of module importing code;
     specifiable DB-API module; more explicit ordering of module
     preferences.

     References: #480(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/509

   (2) http://www.sqlalchemy.org/trac/ticket/480

8.3.12.47 0.3.5
...............

Released: Thu Feb 22 2007

8.3.12.48 orm
.............

   * `[orm] [bugs]' ¶ another refactoring to relationship
     calculation.  Allows more accurate ORM behavior with relationships
     from/to/between mappers, particularly polymorphic mappers, also
     their usage with Query, SelectResults.  tickets include,,.

     References: #439(1), #441(2), #448(3)

   * `[orm] [bugs]' ¶ removed deprecated method of
     specifying custom collections on classes; you must now use the
     “collection_class” option.  the old way was beginning to produce
     conflicts when people used assign_mapper(), which now patches an
     “options” method, in conjunction with a relationship named
     “options”.  (relationships take precedence over monkeypatched
     assign_mapper methods).

   * `[orm] [bugs]' ¶ extension() query option propagates
     to Mapper._instance() method so that all loading-related methods
     get called

     References: #454(4)

   * `[orm] [bugs]' ¶ eager relation to an inheriting
     mapper wont fail if no rows returned for the relationship.

   * `[orm] [bugs]' ¶ eager relation loading bug fixed for
     eager relation on multiple descendant classes

     References: #486(5)

   * `[orm] [bugs]' ¶ fix for very large topological sorts,
     courtesy ants.aasma at gmail

     References: #423(6)

   * `[orm] [bugs]' ¶ eager loading is slightly more strict
     about detecting “self-referential” relationships, specifically
     between polymorphic mappers.  this results in an “eager degrade” to
     lazy loading.

   * `[orm] [bugs]' ¶ improved support for complex queries
     embedded into “where” criterion for query.select()

     References: #449(7)

   * `[orm] [bugs]' ¶ mapper options like eagerload(),
     lazyload(), deferred(), will work for “synonym()” relationships

     References: #485(8)

   * `[orm] [bugs]' ¶ fixed bug where cascade operations
     incorrectly included deleted collection items in the cascade

     References: #445(9)

   * `[orm] [bugs]' ¶ fixed relationship deletion error
     when one-to-many child item is moved to a new parent in a single
     unit of work

     References: #478(10)

   * `[orm] [bugs]' ¶ fixed relationship deletion error
     where parent/child with a single column as PK/FK on the child would
     raise a “blank out the primary key” error, if manually deleted or
     “delete” cascade without “delete-orphan” was used

   * `[orm] [bugs]' ¶ fix to deferred so that load
     operation doesn’t mistakenly occur when only PK col attributes are
     set

   * `[orm] [enhancements]' ¶ implemented foreign_keys
     argument to mapper.  use in conjunction with
     primaryjoin/secondaryjoin arguments to specify/override foreign
     keys defined on the Table instance.

     References: #385(11)

   * `[orm] [enhancements]' ¶ contains_eager(‘foo’)
     automatically implies eagerload(‘foo’)

   * `[orm] [enhancements]' ¶ added “alias” argument to
     contains_eager().  use it to specify the string name or Alias
     instance of an alias used in the query for the eagerly loaded child
     items.  easier to use than “decorator”

   * `[orm] [enhancements]' ¶ added “contains_alias()”
     option for result set mapping to an alias of the mapped table

   * `[orm] [enhancements]' ¶ added support for py2.5
     “with” statement with SessionTransaction

     References: #468(12)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/439

   (2) http://www.sqlalchemy.org/trac/ticket/441

   (3) http://www.sqlalchemy.org/trac/ticket/448

   (4) http://www.sqlalchemy.org/trac/ticket/454

   (5) http://www.sqlalchemy.org/trac/ticket/486

   (6) http://www.sqlalchemy.org/trac/ticket/423

   (7) http://www.sqlalchemy.org/trac/ticket/449

   (8) http://www.sqlalchemy.org/trac/ticket/485

   (9) http://www.sqlalchemy.org/trac/ticket/445

   (10) http://www.sqlalchemy.org/trac/ticket/478

   (11) http://www.sqlalchemy.org/trac/ticket/385

   (12) http://www.sqlalchemy.org/trac/ticket/468

8.3.12.49 sql
.............

   * `[sql]' ¶ the value of “case_sensitive” defaults to
     True now, regardless of the casing of the identifier, unless
     specifically set to False.  this is because the object might be
     label’ed as something else which does contain mixed case, and
     propagating “case_sensitive=False” breaks that.  Other fixes to
     quoting when using labels and “fake” column objects

   * `[sql]' ¶ added a “supports_execution()” method to
     ClauseElement, so that individual kinds of clauses can express if
     they are appropriate for executing…such as, you can execute a
     “select”, but not a “Table” or a “Join”.

   * `[sql]' ¶ fixed argument passing to straight textual
     execute() on engine, connection.  can handle *args or a list
     instance for positional, **kwargs or a dict instance for named
     args, or a list of list or dicts to invoke executemany()

   * `[sql]' ¶ small fix to BoundMetaData to accept unicode
     or string URLs

   * `[sql]' ¶ fixed named PrimaryKeyConstraint generation
     courtesy andrija at gmail

     References: #466(1)

   * `[sql]' ¶ fixed generation of CHECK constraints on
     columns

     References: #464(2)

   * `[sql]' ¶ fixes to tometadata() operation to propagate
     Constraints at column and table level

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/466

   (2) http://www.sqlalchemy.org/trac/ticket/464

8.3.12.50 extensions
....................

   * `[extensions]' ¶ added distinct() method to
     SelectResults.  generally should only make a difference when using
     count().

   * `[extensions]' ¶ added options() method to
     SelectResults, equivalent to query.options()

     References: #472(1)

   * `[extensions]' ¶ added optional __table_opts__
     dictionary to ActiveMapper, will send kw options to Table objects

     References: #462(2)

   * `[extensions]' ¶ added selectfirst(), selectfirst_by()
     to assign_mapper

     References: #467(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/472

   (2) http://www.sqlalchemy.org/trac/ticket/462

   (3) http://www.sqlalchemy.org/trac/ticket/467

8.3.12.51 mysql
...............

   * `[mysql]' ¶ fix to reflection on older DB’s that might
     return array() type for “show variables like” statements

8.3.12.52 mssql
...............

   * `[mssql]' ¶ preliminary support for pyodbc (Yay!)

     References: #419(1)

   * `[mssql]' ¶ better support for NVARCHAR types added

     References: #298(2)

   * `[mssql]' ¶ fix for commit logic on pymssql

   * `[mssql]' ¶ fix for query.get() with schema

     References: #456(3)

   * `[mssql]' ¶ fix for non-integer relationships

     References: #473(4)

   * `[mssql]' ¶. DB-API module now selectable at run-time

     References: #419(5)

   * `[mssql] [415] [481] [tickets:422]' ¶ now passes many
     more unit tests

   * `[mssql]' ¶ better unittest compatibility with ANSI
     functions

     References: #479(6)

   * `[mssql]' ¶ improved support for implicit sequence PK
     columns with auto-insert

     References: #415(7)

   * `[mssql]' ¶ fix for blank password in adodbapi

     References: #371(8)

   * `[mssql]' ¶ fixes to get unit tests working with
     pyodbc

     References: #481(9)

   * `[mssql]' ¶ fix to auto_identity_insert on db-url
     query

   * `[mssql]' ¶ added query_timeout to db-url query parms.
     currently works only for pymssql

   * `[mssql]' ¶ tested with pymssql 0.8.0 (which is now
     LGPL)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/419

   (2) http://www.sqlalchemy.org/trac/ticket/298

   (3) http://www.sqlalchemy.org/trac/ticket/456

   (4) http://www.sqlalchemy.org/trac/ticket/473

   (5) http://www.sqlalchemy.org/trac/ticket/419

   (6) http://www.sqlalchemy.org/trac/ticket/479

   (7) http://www.sqlalchemy.org/trac/ticket/415

   (8) http://www.sqlalchemy.org/trac/ticket/371

   (9) http://www.sqlalchemy.org/trac/ticket/481

8.3.12.53 oracle
................

   * `[oracle]' ¶ when returning “rowid” as the ORDER BY
     column or in use with ROW_NUMBER OVER, oracle dialect checks the
     selectable its being applied to and will switch to table PK if not
     applicable, i.e.  for a UNION. checking for DISTINCT, GROUP BY
     (other places that rowid is invalid) still a TODO. allows
     polymorphic mappings to function.

     References: #436(1)

   * `[oracle]' ¶ sequences on a non-pk column will
     properly fire off on INSERT

   * `[oracle]' ¶ added PrefetchingResultProxy support to
     pre-fetch LOB columns when they are known to be present, fixes

     References: #435(2)

   * `[oracle]' ¶ implemented reflection of tables based on
     synonyms, including across dblinks

     References: #379(3)

   * `[oracle]' ¶ issues a log warning when a related table
     cant be reflected due to certain permission errors

     References: #363(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/436

   (2) http://www.sqlalchemy.org/trac/ticket/435

   (3) http://www.sqlalchemy.org/trac/ticket/379

   (4) http://www.sqlalchemy.org/trac/ticket/363

8.3.12.54 misc
..............

   * `[postgres]' ¶ better reflection of sequences for
     alternate-schema Tables

     References: #442(1)

   * `[postgres]' ¶ sequences on a non-pk column will
     properly fire off on INSERT

   * `[postgres]' ¶ added PGInterval type, PGInet type

     References: #444(2), #460(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/442

   (2) http://www.sqlalchemy.org/trac/ticket/444

   (3) http://www.sqlalchemy.org/trac/ticket/460

8.3.12.55 0.3.4
...............

Released: Tue Jan 23 2007

8.3.12.56 general
.................

   * `[general]' ¶ global “insure”->”ensure” change.  in US
     english “insure” is actually largely interchangeable with “ensure”
     (so says the dictionary), so I’m not completely illiterate, but its
     definitely sub-optimal to “ensure” which is non-ambiguous.

8.3.12.57 orm
.............

   * `[orm]' ¶ poked the first hole in the can of worms:
     saying query.select_by(somerelationname=someinstance) will create
     the join of the primary key columns represented by
     “somerelationname“‘s mapper to the actual primary key in
     “someinstance”.

   * `[orm]' ¶ reworked how relations interact with
     “polymorphic” mappers, i.e.  mappers that have a select_table as
     well as polymorphic flags.  better determination of proper join
     conditions, interaction with user- defined join conditions, and
     support for self-referential polymorphic mappers.

   * `[orm]' ¶ related to polymorphic mapping relations,
     some deeper error checking when compiling relations, to detect an
     ambiguous “primaryjoin” in the case that both sides of the
     relationship have foreign key references in the primary join
     condition.  also tightened down conditions used to locate “relation
     direction”, associating the “foreignkey” of the relationship with
     the “primaryjoin”

   * `[orm]' ¶ a little bit of improvement to the concept
     of a “concrete” inheritance mapping, though that concept is not
     well fleshed out yet (added test case to support concrete mappers
     on top of a polymorphic base).

   * `[orm]' ¶ fix to “proxy=True” behavior on synonym()

   * `[orm]' ¶ fixed bug where delete-orphan basically
     didn’t work with many-to-many relationships, backref presence
     generally hid the symptom

     References: #427(1)

   * `[orm]' ¶ added a mutex to the mapper compilation
     step.  ive been reluctant to add any kind of threading anything to
     SA but this is one spot that its really needed since mappers are
     typically “global”, and while their state does not change during
     normal operation, the initial compilation step does modify internal
     state significantly, and this step usually occurs not at
     module-level initialization time (unless you call compile()) but at
     first-request time

   * `[orm]' ¶ basic idea of “session.merge()” actually
     implemented.  needs more testing.

   * `[orm]' ¶ added “compile_mappers()” function as a
     shortcut to compiling all mappers

   * `[orm]' ¶ fix to MapperExtension create_instance so
     that entity_name properly associated with new instance

   * `[orm]' ¶ speed enhancements to ORM object
     instantiation, eager loading of rows

   * `[orm]' ¶ invalid options sent to ‘cascade’ string
     will raise an exception

     References: #406(2)

   * `[orm]' ¶ fixed bug in mapper refresh/expire whereby
     eager loaders didn’t properly re-populate item lists

     References: #407(3)

   * `[orm]' ¶ fix to post_update to ensure rows are
     updated even for non insert/delete scenarios

     References: #413(4)

   * `[orm]' ¶ added an error message if you actually try
     to modify primary key values on an entity and then flush it

     References: #412(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/427

   (2) http://www.sqlalchemy.org/trac/ticket/406

   (3) http://www.sqlalchemy.org/trac/ticket/407

   (4) http://www.sqlalchemy.org/trac/ticket/413

   (5) http://www.sqlalchemy.org/trac/ticket/412

8.3.12.58 sql
.............

   * `[sql]' ¶ added “fetchmany()” support to ResultProxy

   * `[sql]' ¶ added support for column “key” attribute to
     be useable in row[<key>]/row.<key>

   * `[sql]' ¶ changed “BooleanExpression” to subclass from
     “BinaryExpression”, so that boolean expressions can also follow
     column-clause behaviors (i.e.  label(), etc).

   * `[sql]' ¶ trailing underscores are trimmed from
     func.<xxx> calls, such as func.if_()

   * `[sql]' ¶ fix to correlation of subqueries when the
     column list of the select statement is constructed with individual
     calls to append_column(); this fixes an ORM bug whereby nested
     select statements were not getting correlated with the main select
     generated by the Query object.

   * `[sql]' ¶ another fix to subquery correlation so that
     a subquery which has only one FROM element will `not' correlate
     that single element, since at least one FROM element is required in
     a query.

   * `[sql]' ¶ default “timezone” setting is now False.
     this corresponds to Python’s datetime behavior as well as Postgres’
     timestamp/time types (which is the only timezone-sensitive dialect
     at the moment)

     References: #414(1)

   * `[sql]' ¶ the “op()” function is now treated as an
     “operation”, rather than a “comparison”.  the difference is, an
     operation produces a BinaryExpression from which further operations
     can occur whereas comparison produces the more restrictive
     BooleanExpression

   * `[sql]' ¶ trying to redefine a reflected primary key
     column as non-primary key raises an error

   * `[sql]' ¶ type system slightly modified to support
     TypeDecorators that can be overridden by the dialect (ok, that’s
     not very clear, it allows the mssql tweak below to be possible)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/414

8.3.12.59 extensions
....................

   * `[extensions]' ¶ added “validate=False” argument to
     assign_mapper, if True will ensure that only mapped attributes are
     named

     References: #426(1)

   * `[extensions]' ¶ assign_mapper gets “options”,
     “instances” functions added (i.e.  MyClass.instances())

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/426

8.3.12.60 mysql
...............

   * `[mysql]' ¶ mysql is inconsistent with what kinds of
     quotes it uses in foreign keys during a SHOW CREATE TABLE,
     reflection updated to accommodate for all three styles

     References: #420(1)

   * `[mysql]' ¶ mysql table create options work on a
     generic passthru now, i.e.  Table(…, mysql_engine=’InnoDB’,
     mysql_collate=”latin1_german2_ci”, mysql_auto_increment=”5”,
     mysql_<somearg>…), helps

     References: #418(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/420

   (2) http://www.sqlalchemy.org/trac/ticket/418

8.3.12.61 mssql
...............

   * `[mssql]' ¶ added an NVarchar type (produces
     NVARCHAR), also MSUnicode which provides Unicode-translation for
     the NVarchar regardless of dialect convert_unicode setting.

8.3.12.62 oracle
................

   * `[oracle]' ¶. `slight' support for binary, but still
     need to figure out how to insert reasonably large values (over 4K).
     requires auto_setinputsizes=True sent to create_engine(), rows must
     be fully fetched individually, etc.

8.3.12.63 firebird
..................

   * `[firebird]' ¶ order of constraint creation puts
     primary key first before all other constraints; required for
     firebird, not a bad idea for others

     References: #408(1)

   * `[firebird]' ¶. Firebird fix to autoload multifield
     foreign keys

     References: #409(2)

   * `[firebird]' ¶. Firebird NUMERIC type properly handles
     a type without precision

     References: #409(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/408

   (2) http://www.sqlalchemy.org/trac/ticket/409

   (3) http://www.sqlalchemy.org/trac/ticket/409

8.3.12.64 misc
..............

   * `[postgres]' ¶ fix to the initial checkfirst for
     tables to take current schema into account

     References: #424(1)

   * `[postgres]' ¶ postgres has an optional
     “server_side_cursors=True” flag which will utilize server side
     cursors.  these are appropriate for fetching only partial results
     and are necessary for working with very large unbounded result
     sets.  While we’d like this to be the default behavior, different
     environments seem to have different results and the causes have not
     been isolated so we are leaving the feature off by default for now.
     Uses an apparently undocumented psycopg2 behavior recently
     discovered on the psycopg mailing list.

   * `[postgres]' ¶ added “BIGSERIAL” support for postgres
     table with PGBigInteger/autoincrement

   * `[postgres]' ¶ fixes to postgres reflection to better
     handle when schema names are present; thanks to jason (at)
     ncsmags.com

     References: #402(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/424

   (2) http://www.sqlalchemy.org/trac/ticket/402

8.3.12.65 0.3.3
...............

Released: Fri Dec 15 2006

   * `[no_tags]' ¶ string-based FROM clauses fixed, i.e.
     select(…, from_obj=[“sometext”])

   * `[no_tags]' ¶ fixes to passive_deletes flag, lazy=None
     (noload) flag

   * `[no_tags]' ¶ added example/docs for dealing with
     large collections

   * `[no_tags]' ¶ added object_session() method to
     sqlalchemy namespace

   * `[no_tags]' ¶ fixed QueuePool bug whereby its better
     able to reconnect to a database that was not reachable (thanks to
     SÃ©bastien Lelong), also fixed dispose() method

   * `[no_tags]' ¶ patch that makes MySQL rowcount work
     correctly!

     References: #396(1)

   * `[no_tags]' ¶ fix to MySQL catch of 2006/2014 errors
     to properly re-raise OperationalError exception

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/396

8.3.12.66 0.3.2
...............

Released: Sun Dec 10 2006

   * `[no_tags]' ¶ major connection pool bug fixed.  fixes
     MySQL out of sync errors, will also prevent transactions getting
     rolled back accidentally in all DBs

     References: #387(1)

   * `[no_tags]' ¶ major speed enhancements vs.  0.3.1, to
     bring speed back to 0.2.8 levels

   * `[no_tags]' ¶ made conditional dozens of debug log
     calls that were time-intensive to generate log messages

   * `[no_tags]' ¶ fixed bug in cascade rules whereby the
     entire object graph could be unnecessarily cascaded on the
     save/update cascade

   * `[no_tags]' ¶ various speedups in attributes module

   * `[no_tags]' ¶ identity map in Session is by default
     `no longer weak referencing'.  to have it be weak referencing, use
     create_session(weak_identity_map=True) fixes

     References: #388(2)

   * `[no_tags]' ¶. MySQL detects errors 2006 (server has
     gone away) and 2014 (commands out of sync) and invalidates the
     connection on which it occurred.

   * `[no_tags]' ¶. MySQL bool type fix:

     References: #307(3)

   * `[no_tags]' ¶ postgres reflection fixes:

     References: #349(4), #382(5)

   * `[no_tags]' ¶ added keywords for EXCEPT, INTERSECT,
     EXCEPT ALL, INTERSECT ALL

     References: #247(6)

   * `[no_tags]' ¶ assign_mapper in assignmapper extension
     returns the created mapper

     References: #2110(7)

   * `[no_tags]' ¶ added label() function to Select class,
     when scalar=True is used to create a scalar subquery i.e.  “select
     x, y, (select max(foo) from table) AS foomax from table”

   * `[no_tags]' ¶ added onupdate and ondelete keyword
     arguments to ForeignKey; propagate to underlying
     ForeignKeyConstraint if present.  (don’t propagate in the other
     direction, however)

   * `[no_tags]' ¶ fix to session.update() to preserve
     “dirty” status of incoming object

   * `[no_tags]' ¶ sending a selectable to an IN via the
     in_() function no longer creates a “union” out of multiple selects;
     only one selectable to a the in_() function is allowed now (make a
     union yourself if union is needed)

   * `[no_tags]' ¶ improved support for disabling
     save-update cascade via cascade=”none” etc.

   * `[no_tags]' ¶ added “remote_side” argument to
     relation(), used only with self-referential mappers to force the
     direction of the parent/child relationship.  replaces the usage of
     the “foreignkey” parameter for “switching” the direction.
     “foreignkey” argument is deprecated for all uses and will
     eventually be replaced by an argument dedicated to ForeignKey
     specification on mappers.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/387

   (2) http://www.sqlalchemy.org/trac/ticket/388

   (3) http://www.sqlalchemy.org/trac/ticket/307

   (4) http://www.sqlalchemy.org/trac/ticket/349

   (5) http://www.sqlalchemy.org/trac/ticket/382

   (6) http://www.sqlalchemy.org/trac/ticket/247

   (7) http://www.sqlalchemy.org/trac/ticket/2110

8.3.12.67 0.3.1
...............

Released: Mon Nov 13 2006

8.3.12.68 orm
.............

   * `[orm]' ¶ the “delete” cascade will load in all child
     objects, if they were not loaded already.  this can be turned off
     (i.e.  the old behavior) by setting passive_deletes=True on a
     relation().

   * `[orm]' ¶ adjustments to reworked eager query
     generation to not fail on circular eager-loaded relationships (like
     backrefs)

   * `[orm]' ¶ fixed bug where eagerload() (nor lazyload())
     option didn’t properly instruct the Query whether or not to use
     “nesting” when producing a LIMIT query.

   * `[orm]' ¶ fixed bug in circular dependency sorting at
     flush time; if object A contained a cyclical many-to-one
     relationship to object B, and object B was just attached to object
     A, `but' object B itself wasn’t changed, the many-to-one
     synchronize of B’s primary key attribute to A’s foreign key
     attribute wouldn’t occur.

     References: #360(1)

   * `[orm]' ¶ implemented from_obj argument for
     query.count, improves count function on selectresults

     References: #325(2)

   * `[orm]' ¶ added an assertion within the “cascade” step
     of ORM relationships to check that the class of object attached to
     a parent object is appropriate (i.e.  if A.items stores B objects,
     raise an error if a C is appended to A.items)

   * `[orm]' ¶ new extension
     sqlalchemy.ext.associationproxy, provides transparent “association
     object” mappings.  new example
     examples/association/proxied_association.py illustrates.

   * `[orm]' ¶ improvement to single table inheritance to
     load full hierarchies beneath the target class

   * `[orm]' ¶ fix to subtle condition in topological sort
     where a node could appear twice, for

     References: #362(3)

   * `[orm]' ¶ additional rework to topological sort,
     refactoring, for

     References: #365(4)

   * `[orm]' ¶. ”delete-orphan” for a certain type can be
     set on more than one parent class; the instance is an “orphan” only
     if its not attached to `any' of those parents

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/360

   (2) http://www.sqlalchemy.org/trac/ticket/325

   (3) http://www.sqlalchemy.org/trac/ticket/362

   (4) http://www.sqlalchemy.org/trac/ticket/365

8.3.12.69 misc
..............

   * `[engine/pool]' ¶ some new Pool utility classes,
     updated docs

   * `[engine/pool]' ¶. ”use_threadlocal” on Pool defaults
     to False (same as create_engine)

   * `[engine/pool]' ¶ fixed direct execution of Compiled
     objects

   * `[engine/pool]' ¶ create_engine() reworked to be
     strict about incoming **kwargs.  all keyword arguments must be
     consumed by one of the dialect, connection pool, and engine
     constructors, else a TypeError is thrown which describes the full
     set of invalid kwargs in relation to the selected
     dialect/pool/engine configuration.

   * `[databases/types]' ¶. MySQL catches exception on
     “describe” and reports as NoSuchTableError

   * `[databases/types]' ¶ further fixes to sqlite
     booleans, weren’t working as defaults

   * `[databases/types]' ¶ fix to postgres sequence quoting
     when using schemas

8.3.12.70 0.3.0
...............

Released: Sun Oct 22 2006

8.3.12.71 general
.................

   * `[general]' ¶ logging is now implemented via standard
     python “logging” module.  “echo” keyword parameters are still
     functional but set/unset log levels for their respective
     classes/instances.  all logging can be controlled directly through
     the Python API by setting INFO and DEBUG levels for loggers in the
     “sqlalchemy” namespace.  class-level logging is under
     “sqlalchemy.<module>.<classname>”, instance-level logging under
     “sqlalchemy.<module>.<classname>.0x..<00-FF>”.  Test suite includes
     “–log-info” and “–log-debug” arguments which work independently of
     –verbose/–quiet.  Logging added to orm to allow tracking of mapper
     configurations, row iteration.

   * `[general]' ¶ the documentation-generation system has
     been overhauled to be much simpler in design and more integrated
     with Markdown

8.3.12.72 orm
.............

   * `[orm]' ¶ attribute tracking modified to be more
     intelligent about detecting changes, particularly with mutable
     types.  TypeEngine objects now take a greater role in defining how
     to compare two scalar instances, including the addition of a
     MutableType mixin which is implemented by PickleType.  unit-of-work
     now tracks the “dirty” list as an expression of all persistent
     objects where the attribute manager detects changes.  The basic
     issue that’s fixed is detecting changes on PickleType objects, but
     also generalizes type handling and “modified” object checking to be
     more complete and extensible.

   * `[orm]' ¶ a wide refactoring to “attribute loader” and
     “options” architectures.  ColumnProperty and PropertyLoader define
     their loading behavior via switchable “strategies”, and
     MapperOptions no longer use mapper/property copying in order to
     function; they are instead propagated via QueryContext and
     SelectionContext objects at query/instances time.  All of the
     internal copying of mappers and properties that was used to handle
     inheritance as well as options() has been removed; the structure of
     mappers and properties is much simpler than before and is clearly
     laid out in the new ‘interfaces’ module.

   * `[orm]' ¶ related to the mapper/property overhaul,
     internal refactoring to mapper instances() method to use a
     SelectionContext object to track state during the operation.
     SLIGHT API BREAKAGE: the append_result() and populate_instances()
     methods on MapperExtension have a slightly different method
     signature now as a result of the change; hoping that these methods
     are not in widespread use as of yet.

   * `[orm]' ¶ instances() method moved to Query now,
     backwards-compatible version remains on Mapper.

   * `[orm]' ¶ added contains_eager() MapperOption, used in
     conjunction with instances() to specify properties that should be
     eagerly loaded from the result set, using their plain column names
     by default, or translated given an custom row-translation function.

   * `[orm]' ¶ more rearrangements of unit-of-work commit
     scheme to better allow dependencies within circular flushes to work
     properly…updated task traversal/logging implementation

   * `[orm]' ¶ polymorphic mappers (i.e.  using
     inheritance) now produces INSERT statements in order of tables
     across all inherited classes

     References: #321(1)

   * `[orm]' ¶ added an automatic “row switch” feature to
     mapping, which will detect a pending instance/deleted instance pair
     with the same identity key and convert the INSERT/DELETE to a
     single UPDATE

   * `[orm]' ¶. ”association” mappings simplified to take
     advantage of automatic “row switch” feature

   * `[orm]' ¶. ”custom list classes” is now implemented via
     the “collection_class” keyword argument to relation().  the old way
     still works but is deprecated

     References: #212(2)

   * `[orm]' ¶ added “viewonly” flag to relation(), allows
     construction of relations that have no effect on the flush()
     process.

   * `[orm]' ¶ added “lockmode” argument to base Query
     select/get functions, including “with_lockmode” function to get a
     Query copy that has a default locking mode.  Will translate
     “read”/”update” arguments into a for_update argument on the select
     side.

     References: #292(3)

   * `[orm]' ¶ implemented “version check” logic in
     Query/Mapper, used when version_id_col is in effect and
     query.with_lockmode() is used to get() an instance that’s already
     loaded

   * `[orm]' ¶ post_update behavior improved; does a better
     job at not updating too many rows, updates only required columns

     References: #208(4)

   * `[orm]' ¶ adjustments to eager loading so that its
     “eager chain” is kept separate from the normal mapper setup,
     thereby preventing conflicts with lazy loader operation, fixes

     References: #308(5)

   * `[orm]' ¶ fix to deferred group loading

   * `[orm]' ¶ session.flush() wont close a connection it
     opened

     References: #346(6)

   * `[orm]' ¶ added “batch=True” flag to mapper; if False,
     save_obj will fully save one object at a time including calls to
     before_XXXX and after_XXXX

   * `[orm]' ¶ added “column_prefix=None” argument to
     mapper; prepends the given string (typically ‘_’) to column-based
     attributes automatically set up from the mapper’s Table

   * `[orm]' ¶ specifying joins in the from_obj argument of
     query.select() will replace the main table of the query, if the
     table is somewhere within the given from_obj.  this makes it
     possible to produce custom joins and outerjoins in queries without
     the main table getting added twice.

     References: #315(7)

   * `[orm]' ¶ eagerloading is adjusted to more
     thoughtfully attach its LEFT OUTER JOINs to the given query,
     looking for custom “FROM” clauses that may have already been set
     up.

   * `[orm]' ¶ added join_to and outerjoin_to
     transformative methods to SelectResults, to build up join/outerjoin
     conditions based on property names.  also added select_from to
     explicitly set from_obj parameter.

   * `[orm]' ¶ removed “is_primary” flag from mapper.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/321

   (2) http://www.sqlalchemy.org/trac/ticket/212

   (3) http://www.sqlalchemy.org/trac/ticket/292

   (4) http://www.sqlalchemy.org/trac/ticket/208

   (5) http://www.sqlalchemy.org/trac/ticket/308

   (6) http://www.sqlalchemy.org/trac/ticket/346

   (7) http://www.sqlalchemy.org/trac/ticket/315

8.3.12.73 sql
.............

   * `[sql] [construction]' ¶ changed “for_update”
     parameter to accept False/True/”nowait” and “read”, the latter two
     of which are interpreted only by Oracle and MySQL

     References: #292(1)

   * `[sql] [construction]' ¶ added extract() function to
     sql dialect (SELECT extract(field FROM expr))

   * `[sql] [construction]' ¶. BooleanExpression includes
     new “negate” argument to specify the appropriate negation operator
     if one is available.

   * `[sql] [construction]' ¶ calling a negation on an “IN”
     or “IS” clause will result in “NOT IN”, “IS NOT” (as opposed to NOT
     (x IN y)).

   * `[sql] [construction]' ¶. Function objects know what to
     do in a FROM clause now.  their behavior should be the same, except
     now you can also do things like select([‘*’],
     from_obj=[func.my_function()]) to get multiple columns from the
     result, or even use sql.column() constructs to name the return
     columns

     References: #172(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/292

   (2) http://www.sqlalchemy.org/trac/ticket/172

8.3.12.74 schema
................

   * `[schema]' ¶ a fair amount of cleanup to the schema
     package, removal of ambiguous methods, methods that are no longer
     needed.  slightly more constrained usage, greater emphasis on
     explicitness

   * `[schema]' ¶ the “primary_key” attribute of Table and
     other selectables becomes a setlike ColumnCollection object; is
     ordered but not numerically indexed.  a comparison clause between
     two pks that are derived from the same underlying tables (i.e.
     such as two Alias objects) can be generated via
     table1.primary_key==table2.primary_key

   * `[schema]' ¶. ForeignKey(Constraint) supports
     “use_alter=True”, to create/drop a foreign key via ALTER. this
     allows circular foreign key relationships to be set up.

   * `[schema]' ¶ append_item() methods removed from Table
     and Column; preferably construct Table/Column/related objects
     inline, but if needed use append_column(), append_foreign_key(),
     append_constraint(), etc.

   * `[schema]' ¶ table.create() no longer returns the
     Table object, instead has no return value.  the usual case is that
     tables are created via metadata, which is preferable since it will
     handle table dependencies.

   * `[schema]' ¶ added UniqueConstraint (goes at Table
     level), CheckConstraint (goes at Table or Column level).

   * `[schema]' ¶ index=False/unique=True on Column now
     creates a UniqueConstraint, index=True/unique=False creates a plain
     Index, index=True/unique=True on Column creates a unique Index.
     ‘index’ and ‘unique’ keyword arguments to column are now boolean
     only; for explicit names and groupings of indexes or unique
     constraints, use the UniqueConstraint/Index constructs explicitly.

   * `[schema]' ¶ added autoincrement=True to Column; will
     disable schema generation of SERIAL/AUTO_INCREMENT/identity seq for
     postgres/mysql/mssql if explicitly set to False

   * `[schema]' ¶. TypeEngine objects now have methods to
     deal with copying and comparing values of their specific type.
     Currently used by the ORM, see below.

   * `[schema]' ¶ fixed condition that occurred during
     reflection when a primary key column was explicitly overridden,
     where the PrimaryKeyConstraint would get both the reflected and the
     programmatic column doubled up

   * `[schema]' ¶ the “foreign_key” attribute on Column and
     ColumnElement in general is deprecated, in favor of the
     “foreign_keys” list/set-based attribute, which takes into account
     multiple foreign keys on one column.  “foreign_key” will return the
     first element in the “foreign_keys” list/set or None if the list is
     empty.

8.3.12.75 sqlite
................

   * `[sqlite]' ¶ sqlite boolean datatype converts
     False/True to 0/1 by default

   * `[sqlite]' ¶ fixes to Date/Time (SLDate/SLTime) types;
     works as good as postgres now

     References: #335(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/335

8.3.12.76 oracle
................

   * `[oracle]' ¶. Oracle has experimental support for
     cx_Oracle.TIMESTAMP, which requires a setinputsizes() call on the
     cursor that is now enabled via the ‘auto_setinputsizes’ flag to the
     oracle dialect.

8.3.12.77 firebird
..................

   * `[firebird]' ¶ aliases do not use “AS”

   * `[firebird]' ¶ correctly raises NoSuchTableError when
     reflecting non-existent table

8.3.12.78 misc
..............

   * `[ms-sql]' ¶ fixes bug 261 (table reflection broken
     for MS-SQL case-sensitive databases)

   * `[ms-sql]' ¶ can now specify port for pymssql

   * `[ms-sql]' ¶ introduces new “auto_identity_insert”
     option for auto-switching between “SET IDENTITY_INSERT” mode when
     values specified for IDENTITY columns

   * `[ms-sql]' ¶ now supports multi-column foreign keys

   * `[ms-sql]' ¶ fix to reflecting date/datetime columns

   * `[ms-sql]' ¶. NCHAR and NVARCHAR type support added

   * `[connections/pooling/execution]' ¶ connection pool
     tracks open cursors and automatically closes them if connection is
     returned to pool with cursors still opened.  Can be affected by
     options which cause it to raise an error instead, or to do nothing.
     fixes issues with MySQL, others

   * `[connections/pooling/execution]' ¶ fixed bug where
     Connection wouldn’t lose its Transaction after commit/rollback

   * `[connections/pooling/execution]' ¶ added scalar()
     method to ComposedSQLEngine, ResultProxy

   * `[connections/pooling/execution]' ¶. ResultProxy will
     close() the underlying cursor when the ResultProxy itself is
     closed.  this will auto-close cursors for ResultProxy objects that
     have had all their rows fetched (or had scalar() called).

   * `[connections/pooling/execution]' ¶.
     ResultProxy.fetchall() internally uses DBAPI fetchall() for better
     efficiency, added to mapper iteration as well (courtesy Michael
     Twomey)

8.3.13 0.2 Changelog
--------------------

8.3.13.1 0.2.8
..............

Released: Tue Sep 05 2006

   * `[no_tags]' ¶ cleanup on connection methods +
     documentation.  custom DBAPI arguments specified in query string,
     ‘connect_args’ argument to ‘create_engine’, or custom creation
     function via ‘creator’ function to ‘create_engine’.

   * `[no_tags]' ¶ added “recycle” argument to Pool, is
     “pool_recycle” on create_engine, defaults to 3600 seconds;
     connections after this age will be closed and replaced with a new
     one, to handle db’s that automatically close stale connections

     References: #274(1)

   * `[no_tags]' ¶ changed “invalidate” semantics with
     pooled connection; will instruct the underlying connection record
     to reconnect the next time its called.  “invalidate” will also
     automatically be called if any error is thrown in the underlying
     call to connection.cursor().  this will hopefully allow the
     connection pool to reconnect to a database that had been stopped
     and started without restarting the connecting application

     References: #121(2)

   * `[no_tags]' ¶ eesh !  the tutorial doctest was broken
     for quite some time.

   * `[no_tags]' ¶ add_property() method on mapper does a
     “compile all mappers” step in case the given property references a
     non-compiled mapper (as it did in the case of the tutorial !)

   * `[no_tags]' ¶ check for pg sequence already existing
     before create

     References: #277(3)

   * `[no_tags]' ¶ if a contextual session is established
     via MapperExtension.get_session (as it is using the sessioncontext
     plugin, etc), a lazy load operation will use that session by
     default if the parent object is not persistent with a session
     already.

   * `[no_tags]' ¶ lazy loads will not fire off for an
     object that does not have a database identity (why?  see
     ‘http://www.sqlalchemy.org/trac/wiki/WhyDontForeignKeysLoadData’)

   * `[no_tags]' ¶ unit-of-work does a better check for
     “orphaned” objects that are part of a “delete-orphan” cascade, for
     certain conditions where the parent isn’t available to cascade
     from.

   * `[no_tags]' ¶ mappers can tell if one of their objects
     is an “orphan” based on interactions with the attribute package.
     this check is based on a status flag maintained for each
     relationship when objects are attached and detached from each
     other.

   * `[no_tags]' ¶ it is now invalid to declare a
     self-referential relationship with “delete-orphan” (as the
     abovementioned check would make them impossible to save)

   * `[no_tags]' ¶ improved the check for objects being
     part of a session when the unit of work seeks to flush() them as
     part of a relationship..

   * `[no_tags]' ¶ statement execution supports using the
     same BindParam object more than once in an expression; simplified
     handling of positional parameters.  nice job by Bill Noon figuring
     out the basic idea.

     References: #280(4)

   * `[no_tags]' ¶ postgres reflection moved to use
     pg_schema tables, can be overridden with
     use_information_schema=True argument to create_engine.

     References: #60(5), #71(6)

   * `[no_tags]' ¶ added case_sensitive argument to
     MetaData, Table, Column, determines itself automatically based on
     if a parent schemaitem has a non-None setting for the flag, or if
     not, then whether the identifier name is all lower case or not.
     when set to True, quoting is applied to identifiers with mixed or
     uppercase identifiers.  quoting is also applied automatically in
     all cases to identifiers that are known to be reserved words or
     contain other non-standard characters.  various database dialects
     can override all of this behavior, but currently they are all using
     the default behavior.  tested with postgres, mysql, sqlite, oracle.
     needs more testing with firebird, ms-sql.  part of the ongoing work
     with

     References: #155(7)

   * `[no_tags]' ¶ unit tests updated to run without any
     pysqlite installed; pool test uses a mock DBAPI

   * `[no_tags]' ¶ urls support escaped characters in
     passwords

     References: #281(8)

   * `[no_tags]' ¶ added limit/offset to UNION queries
     (though not yet in oracle)

   * `[no_tags]' ¶ added “timezone=True” flag to DateTime
     and Time types.  postgres so far will convert this to “TIME[STAMP]
     (WITH|WITHOUT) TIME ZONE”, so that control over timezone presence
     is more controllable (psycopg2 returns datetimes with tzinfo’s if
     available, which can create confusion against datetimes that
     don’t).

   * `[no_tags]' ¶ fix to using query.count() with
     distinct, **kwargs with SelectResults count()

     References: #287(9)

   * `[no_tags]' ¶ deregister Table from MetaData when
     autoload fails;

     References: #289(10)

   * `[no_tags]' ¶ import of py2.5s sqlite3

     References: #293(11)

   * `[no_tags]' ¶ unicode fix for startswith()/endswith()

     References: #296(12)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/274

   (2) http://www.sqlalchemy.org/trac/ticket/121

   (3) http://www.sqlalchemy.org/trac/ticket/277

   (4) http://www.sqlalchemy.org/trac/ticket/280

   (5) http://www.sqlalchemy.org/trac/ticket/60

   (6) http://www.sqlalchemy.org/trac/ticket/71

   (7) http://www.sqlalchemy.org/trac/ticket/155

   (8) http://www.sqlalchemy.org/trac/ticket/281

   (9) http://www.sqlalchemy.org/trac/ticket/287

   (10) http://www.sqlalchemy.org/trac/ticket/289

   (11) http://www.sqlalchemy.org/trac/ticket/293

   (12) http://www.sqlalchemy.org/trac/ticket/296

8.3.13.2 0.2.7
..............

Released: Sat Aug 12 2006

   * `[no_tags]' ¶ quoting facilities set up so that
     database-specific quoting can be turned on for individual table,
     schema, and column identifiers when used in all
     queries/creates/drops.  Enabled via “quote=True” in Table or
     Column, as well as “quote_schema=True” in Table.  Thanks to Aaron
     Spike for the excellent efforts.

   * `[no_tags]' ¶ assignmapper was setting
     is_primary=True, causing all sorts of mayhem by not raising an
     error when redundant mappers were set up, fixed

   * `[no_tags]' ¶ added allow_null_pks option to Mapper,
     allows rows where some primary key columns are null (i.e.  when
     mapping to outer joins etc)

   * `[no_tags]' ¶ modification to unitofwork to not
     maintain ordering within the “new” list or within the UOWTask
     “objects” list; instead, new objects are tagged with an ordering
     identifier as they are registered as new with the session, and the
     INSERT statements are then sorted within the mapper save_obj.  the
     INSERT ordering has basically been pushed all the way to the end of
     the flush cycle.  that way the various sorts and organizations
     occurring within UOWTask (particularly the circular task sort)
     don’t have to worry about maintaining order (which they weren’t
     anyway)

   * `[no_tags]' ¶ fixed reflection of foreign keys to
     autoload the referenced table if it was not loaded already

   * `[no_tags]' ¶.

        - pass URL query string arguments to connect() function

     References: #256(1)

   * `[no_tags]' ¶.

        - oracle boolean type

     References: #257(2)

   * `[no_tags]' ¶ custom primary/secondary join conditions
     in a relation `will' be propagated to backrefs by default.
     specifying a backref() will override this behavior.

   * `[no_tags]' ¶ better check for ambiguous join
     conditions in sql.Join; propagates to a better error message in
     PropertyLoader (i.e.  relation()/backref()) for when the join
     condition can’t be reasonably determined.

   * `[no_tags]' ¶ sqlite creates ForeignKeyConstraint
     objects properly upon table reflection.

   * `[no_tags]' ¶ adjustments to pool stemming from
     changes made for.  overflow counter should only be decremented if
     the connection actually succeeded.  added a test script to attempt
     testing this.

     References: #224(3)

   * `[no_tags]' ¶ fixed mysql reflection of default values
     to be PassiveDefault

   * `[no_tags]' ¶ added reflected ‘tinyint’, ‘mediumint’
     type to MS-SQL.

     References: #263(4), #264(5)

   * `[no_tags]' ¶. SingletonThreadPool has a size and does
     a cleanup pass, so that only a given number of thread-local
     connections stay around (needed for sqlite applications that
     dispose of threads en masse)

   * `[no_tags]' ¶ fixed small pickle bug(s) with lazy
     loaders

     References: #265(6), #267(7)

   * `[no_tags]' ¶ fixed possible error in mysql reflection
     where certain versions return an array instead of string for SHOW
     CREATE TABLE call

   * `[no_tags]' ¶ fix to lazy loads when mapping to joins

     References: #1770(8)

   * `[no_tags]' ¶ all create()/drop() calls have a keyword
     argument of “connectable”.  “engine” is deprecated.

   * `[no_tags]' ¶ fixed ms-sql connect() to work with
     adodbapi

   * `[no_tags]' ¶ added “nowait” flag to Select()

   * `[no_tags]' ¶ inheritance check uses issubclass()
     instead of direct __mro__ check to make sure class A inherits from
     B, allowing mapper inheritance to more flexibly correspond to class
     inheritance

     References: #271(9)

   * `[no_tags]' ¶. SelectResults will use a subselect, when
     calling an aggregate (i.e.  max, min, etc.)  on a SelectResults
     that has an ORDER BY clause

     References: #252(10)

   * `[no_tags]' ¶ fixes to types so that database-specific
     types more easily used; fixes to mysql text types to work with this
     methodology

     References: #269(11)

   * `[no_tags]' ¶ some fixes to sqlite date type
     organization

   * `[no_tags]' ¶ added MSTinyInteger to MS-SQL

     References: #263(12)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/256

   (2) http://www.sqlalchemy.org/trac/ticket/257

   (3) http://www.sqlalchemy.org/trac/ticket/224

   (4) http://www.sqlalchemy.org/trac/ticket/263

   (5) http://www.sqlalchemy.org/trac/ticket/264

   (6) http://www.sqlalchemy.org/trac/ticket/265

   (7) http://www.sqlalchemy.org/trac/ticket/267

   (8) http://www.sqlalchemy.org/trac/ticket/1770

   (9) http://www.sqlalchemy.org/trac/ticket/271

   (10) http://www.sqlalchemy.org/trac/ticket/252

   (11) http://www.sqlalchemy.org/trac/ticket/269

   (12) http://www.sqlalchemy.org/trac/ticket/263

8.3.13.3 0.2.6
..............

Released: Thu Jul 20 2006

   * `[no_tags]' ¶ big overhaul to schema to allow truly
     composite primary and foreign key constraints, via new
     ForeignKeyConstraint and PrimaryKeyConstraint objects.  Existing
     methods of primary/foreign key creation have not been changed but
     use these new objects behind the scenes.  table creation and
     reflection is now more table oriented rather than column oriented.

     References: #76(1)

   * `[no_tags]' ¶ overhaul to MapperExtension calling
     scheme, wasn’t working very well previously

   * `[no_tags]' ¶ tweaks to ActiveMapper, supports
     self-referential relationships

   * `[no_tags]' ¶ slight rearrangement to objectstore (in
     activemapper/threadlocal) so that the SessionContext is referenced
     by ‘.context’ instead of subclassed directly.

   * `[no_tags]' ¶ activemapper will use threadlocal’s
     objectstore if the mod is activated when activemapper is imported

   * `[no_tags]' ¶ small fix to URL regexp to allow
     filenames with ‘@’ in them

   * `[no_tags]' ¶ fixes to Session
     expunge/update/etc…needs more cleanup.

   * `[no_tags]' ¶ select_table mappers `still' weren’t
     always compiling

   * `[no_tags]' ¶ fixed up Boolean datatype

   * `[no_tags]' ¶ added count()/count_by() to list of
     methods proxied by assignmapper; this also adds them to
     activemapper

   * `[no_tags]' ¶ connection exceptions wrapped in
     DBAPIError

   * `[no_tags]' ¶. ActiveMapper now supports autoloading
     column definitions from the database if you supply a __autoload__ =
     True attribute in your mapping inner-class.  Currently this does
     not support reflecting any relationships.

   * `[no_tags]' ¶ deferred column load could screw up the
     connection status in a flush() under some circumstances, this was
     fixed

   * `[no_tags]' ¶ expunge() was not working with cascade,
     fixed.

   * `[no_tags]' ¶ potential endless loop in cascading
     operations fixed.

   * `[no_tags]' ¶ added “synonym()” function, applied to
     properties to have a propname the same as another, for the purposes
     of overriding props and allowing the original propname to be
     accessible in select_by().

   * `[no_tags]' ¶ fix to typing in clause construction
     which specifically helps type issues with polymorphic_union
     (CAST/ColumnClause propagates its type to proxy columns)

   * `[no_tags]' ¶ mapper compilation work ongoing, someday
     it’ll work….moved around the initialization of MapperProperty
     objects to be after all mappers are created to better handle
     circular compilations.  do_init() method is called on all
     properties now which are more aware of their “inherited” status if
     so.

   * `[no_tags]' ¶ eager loads explicitly disallowed on
     self-referential relationships, or relationships to an inheriting
     mapper (which is also self-referential)

   * `[no_tags]' ¶ reduced bind param size in query._get to
     appease the picky oracle

     References: #244(2)

   * `[no_tags]' ¶ added ‘checkfirst’ argument to
     table.create()/table.drop(), as well as table.exists()

     References: #234(3)

   * `[no_tags]' ¶ some other ongoing fixes to inheritance

     References: #245(4)

   * `[no_tags]' ¶.
     attribute/backref/orphan/history-tracking tweaks as usual…

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/76

   (2) http://www.sqlalchemy.org/trac/ticket/244

   (3) http://www.sqlalchemy.org/trac/ticket/234

   (4) http://www.sqlalchemy.org/trac/ticket/245

8.3.13.4 0.2.5
..............

Released: Sat Jul 08 2006

   * `[no_tags]' ¶ fixed endless loop bug in select_by(),
     if the traversal hit two mappers that referenced each other

   * `[no_tags]' ¶ upgraded all unittests to insert
     ‘./lib/’ into sys.path, working around new setuptools
     PYTHONPATH-killing behavior

   * `[no_tags]' ¶ further fixes with
     attributes/dependencies/etc….

   * `[no_tags]' ¶ improved error handling for when
     DynamicMetaData is not connected

   * `[no_tags]' ¶. MS-SQL support largely working (tested
     with pymssql)

   * `[no_tags]' ¶ ordering of UPDATE and DELETE statements
     within groups is now in order of primary key values, for more
     deterministic ordering

   * `[no_tags]' ¶ after_insert/delete/update mapper
     extensions now called per object, not per-object-per-table

   * `[no_tags]' ¶ further fixes/refactorings to mapper
     compilation

8.3.13.5 0.2.4
..............

Released: Tue Jun 27 2006

   * `[no_tags]' ¶ try/except when the mapper sets
     init.__name__ on a mapped class, supports python 2.3

   * `[no_tags]' ¶ fixed bug where threadlocal engine would
     still autocommit despite a transaction in progress

   * `[no_tags]' ¶ lazy load and deferred load operations
     require the parent object to be in a Session to do the operation;
     whereas before the operation would just return a blank list or
     None, it now raises an exception.

   * `[no_tags]' ¶. Session.update() is slightly more
     lenient if the session to which the given object was formerly
     attached to was garbage collected; otherwise still requires you
     explicitly remove the instance from the previous Session.

   * `[no_tags]' ¶ fixes to mapper compilation, checking
     for more error conditions

   * `[no_tags]' ¶ small fix to eager loading combined with
     ordering/limit/offset

   * `[no_tags]' ¶ utterly remarkable: added a single space
     between ‘CREATE TABLE’ and ‘(<the rest of it>’ since `that’s how
     MySQL indicates a non- reserved word tablename…..'

     References: #206(1)

   * `[no_tags]' ¶ more fixes to inheritance, related to
     many-to-many relations properly saving

   * `[no_tags]' ¶ fixed bug when specifying explicit
     module to mysql dialect

   * `[no_tags]' ¶ when QueuePool times out it raises a
     TimeoutError instead of erroneously making another connection

   * `[no_tags]' ¶. Queue.Queue usage in pool has been
     replaced with a locally modified version (works in py2.3/2.4!)
     that uses a threading.RLock for a mutex.  this is to fix a reported
     case where a ConnectionFairy’s __del__() method got called within
     the Queue’s get() method, which then returns its connection to the
     Queue via the put() method, causing a reentrant hang unless
     threading.RLock is used.

   * `[no_tags]' ¶ postgres will not place SERIAL keyword
     on a primary key column if it has a foreign key constraint

   * `[no_tags]' ¶ cursor() method on ConnectionFairy
     allows db-specific extension arguments to be propagated

     References: #221(2)

   * `[no_tags]' ¶ lazy load bind params properly propagate
     column type

     References: #225(3)

   * `[no_tags]' ¶ new MySQL types: MSEnum, MSTinyText,
     MSMediumText, MSLongText, etc.  more support for MS-specific
     length/precision params in numeric types patch courtesy Mike
     Bernson

   * `[no_tags]' ¶ some fixes to connection pool
     invalidate()

     References: #224(4)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/206

   (2) http://www.sqlalchemy.org/trac/ticket/221

   (3) http://www.sqlalchemy.org/trac/ticket/225

   (4) http://www.sqlalchemy.org/trac/ticket/224

8.3.13.6 0.2.3
..............

Released: Sat Jun 17 2006

   * `[no_tags]' ¶ overhaul to mapper compilation to be
     deferred.  this allows mappers to be constructed in any order, and
     their relationships to each other are compiled when the mappers are
     first used.

   * `[no_tags]' ¶ fixed a pretty big speed bottleneck in
     cascading behavior particularly when backrefs were in use

   * `[no_tags]' ¶ the attribute instrumentation module has
     been completely rewritten; its now a large degree simpler and
     clearer, slightly faster.  the “history” of an attribute is no
     longer micromanaged with each change and is instead part of a
     “CommittedState” object created when the instance is first loaded.
     HistoryArraySet is gone, the behavior of list attributes is now
     more open ended (i.e.  they’re not sets anymore).

   * `[no_tags]' ¶ py2.4 “set” construct used internally,
     falls back to sets.Set when “set” not available/ordering is needed.

   * `[no_tags]' ¶ fix to transaction control, so that
     repeated rollback() calls don’t fail (was failing pretty badly when
     flush() would raise an exception in a larger try/except transaction
     block)

   * `[no_tags]' ¶. ”foreignkey” argument to relation() can
     also be a list.  fixed auto-foreignkey detection

     References: #151(1)

   * `[no_tags]' ¶ fixed bug where tables with schema names
     weren’t getting indexed in the MetaData object properly

   * `[no_tags]' ¶ fixed bug where Column with redefined
     “key” property wasn’t getting type conversion happening in the
     ResultProxy

     References: #207(2)

   * `[no_tags]' ¶ fixed ‘port’ attribute of URL to be an
     integer if present

   * `[no_tags]' ¶ fixed old bug where if a many-to-many
     table mapped as “secondary” had extra columns, delete operations
     didn’t work

   * `[no_tags]' ¶ bugfixes for mapping against UNION
     queries

   * `[no_tags]' ¶ fixed incorrect exception class thrown
     when no DB driver present

   * `[no_tags]' ¶ added NonExistentTable exception thrown
     when reflecting a table that doesn’t exist

     References: #138(3)

   * `[no_tags]' ¶ small fix to ActiveMapper regarding
     one-to-one backrefs, other refactorings

   * `[no_tags]' ¶ overridden constructor in mapped classes
     gets __name__ and __doc__ from the original class

   * `[no_tags]' ¶ fixed small bug in selectresult.py
     regarding mapper extension

     References: #200(4)

   * `[no_tags]' ¶ small tweak to cascade_mappers, not very
     strongly supported function at the moment

   * `[no_tags]' ¶ some fixes to between(),
     column.between() to propagate typing information better

     References: #202(5)

   * `[no_tags]' ¶ if an object fails to be constructed, is
     not added to the session

     References: #203(6)

   * `[no_tags]' ¶. CAST function has been made into its own
     clause object with its own compilation function in ansicompiler;
     allows MySQL to silently ignore most CAST calls since MySQL seems
     to only support the standard CAST syntax with Date types.
     MySQL-compatible CAST support for strings, ints, etc.  a TODO

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/151

   (2) http://www.sqlalchemy.org/trac/ticket/207

   (3) http://www.sqlalchemy.org/trac/ticket/138

   (4) http://www.sqlalchemy.org/trac/ticket/200

   (5) http://www.sqlalchemy.org/trac/ticket/202

   (6) http://www.sqlalchemy.org/trac/ticket/203

8.3.13.7 0.2.2
..............

Released: Mon Jun 05 2006

   * `[no_tags]' ¶ big improvements to polymorphic
     inheritance behavior, enabling it to work with adjacency list table
     structures

     References: #190(1)

   * `[no_tags]' ¶ major fixes and refactorings to
     inheritance relationships overall, more unit tests

   * `[no_tags]' ¶ fixed “echo_pool” flag on
     create_engine()

   * `[no_tags]' ¶ fix to docs, removed incorrect info that
     close() is unsafe to use with threadlocal strategy (its totally
     safe !)

   * `[no_tags]' ¶ create_engine() can take URLs as string
     or unicode

     References: #188(2)

   * `[no_tags]' ¶ firebird support partially completed;
     thanks to James Ralston and Brad Clements for their efforts.

   * `[no_tags]' ¶. Oracle url translation was broken,
     fixed, will feed host/port/sid into cx_oracle makedsn() if
     ‘database’ field is present, else uses straight TNS name from the
     ‘host’ field

   * `[no_tags]' ¶ fix to using unicode criterion for
     query.get()/query.load()

   * `[no_tags]' ¶ count() function on selectables now uses
     table primary key or first column instead of “1” for criterion,
     also uses label “rowcount” instead of “count”.

   * `[no_tags]' ¶ got rudimental “mapping to multiple
     tables” functionality cleaned up, more correctly documented

   * `[no_tags]' ¶ restored global_connect() function,
     attaches to a DynamicMetaData instance called “default_metadata”.
     leaving MetaData arg to Table out will use the default metadata.

   * `[no_tags]' ¶ fixes to session cascade behavior,
     entity_name propagation

   * `[no_tags]' ¶ reorganized unittests into
     subdirectories

   * `[no_tags]' ¶ more fixes to threadlocal connection
     nesting patterns

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/190

   (2) http://www.sqlalchemy.org/trac/ticket/188

8.3.13.8 0.2.1
..............

Released: Mon May 29 2006

   * `[no_tags]' ¶. ”pool” argument to create_engine()
     properly propagates

   * `[no_tags]' ¶ fixes to URL, raises exception if not
     parsed, does not pass blank fields along to the DB connect string
     (a string such as user:host@/db was breaking on postgres)

   * `[no_tags]' ¶ small fixes to Mapper when it inserts
     and tries to get new primary key values back

   * `[no_tags]' ¶ rewrote half of TLEngine, the
     ComposedSQLEngine used with ‘strategy=”threadlocal”’.  it now
     properly implements engine.begin()/ engine.commit(), which nest
     fully with connection.begin()/trans.commit().  added about six
     unittests.

   * `[no_tags]' ¶ major “duh” in pool.Pool, forgot to put
     back the WeakValueDictionary.  unittest which was supposed to check
     for this was also silently missing it.  fixed unittest to ensure
     that ConnectionFairy properly falls out of scope.

   * `[no_tags]' ¶ placeholder dispose() method added to
     SingletonThreadPool, doesn’t do anything yet

   * `[no_tags]' ¶ rollback() is automatically called when
     an exception is raised, but only if there’s no transaction in
     process (i.e.  works more like autocommit).

   * `[no_tags]' ¶ fixed exception raise in sqlite if no
     sqlite module present

   * `[no_tags]' ¶ added extra example detail for
     association object doc

   * `[no_tags]' ¶. Connection adds checks for already being
     closed

8.3.13.9 0.2.0
..............

Released: Sat May 27 2006

   * `[no_tags]' ¶ overhaul to Engine system so that what
     was formerly the SQLEngine is now a ComposedSQLEngine which
     consists of a variety of components, including a Dialect,
     ConnectionProvider, etc.  This impacted all the db modules as well
     as Session and Mapper.

   * `[no_tags]' ¶ create_engine now takes only
     RFC-1738-style strings: driver://user:password@host:port/database

   * `[no_tags]' ¶ total rewrite of connection-scoping
     methodology, Connection objects can now execute clause elements
     directly, added explicit “close” as well as support throughout
     Engine/ORM to handle closing properly, no longer relying upon
     __del__ internally to return connections to the pool.

     References: #152(1)

   * `[no_tags]' ¶ overhaul to Session interface and
     scoping.  uses hibernate-style methods, including query(class),
     save(), save_or_update(), etc.  no threadlocal scope is installed
     by default.  Provides a binding interface to specific Engines
     and/or Connections so that underlying Schema objects do not need to
     be bound to an Engine.  Added a basic SessionTransaction object
     that can simplistically aggregate transactions across multiple
     engines.

   * `[no_tags]' ¶ overhaul to mapper’s dependency and
     “cascade” behavior; dependency logic factored out of properties.py
     into a separate module “dependency.py”.  “cascade” behavior is now
     explicitly controllable, proper implementation of “delete”,
     “delete-orphan”, etc.  dependency system can now determine at flush
     time if a child object has a parent or not so that it makes better
     decisions on how that child should be updated in the DB with
     regards to deletes.

   * `[no_tags]' ¶ overhaul to Schema to build upon
     MetaData object instead of an Engine.  Entire SQL/Schema system can
     be used with no Engines whatsoever, executed solely by an explicit
     Connection object.  the “bound” methodology exists via the
     BoundMetaData for schema objects.  ProxyEngine is generally not
     needed anymore and is replaced by DynamicMetaData.

   * `[no_tags]' ¶ true polymorphic behavior implemented,
     fixes

     References: #167(2)

   * `[no_tags]' ¶. ”oid” system has been totally moved into
     compile-time behavior; if they are used in an order_by where they
     are not available, the order_by doesn’t get compiled, fixes

     References: #147(3)

   * `[no_tags]' ¶ overhaul to packaging; “mapping” is now
     “orm”, “objectstore” is now “session”, the old “objectstore”
     namespace gets loaded in via the “threadlocal” mod if used

   * `[no_tags]' ¶ mods now called in via “import
     <modname>”.  extensions favored over mods as mods are
     globally-monkeypatching

   * `[no_tags]' ¶ fix to add_property so that it
     propagates properties to inheriting mappers

     References: #154(4)

   * `[no_tags]' ¶ backrefs create themselves against
     primary mapper of its originating property, primary/secondary join
     arguments can be specified to override.  helps their usage with
     polymorphic mappers

   * `[no_tags]' ¶. ”table exists” function has been
     implemented

     References: #31(5)

   * `[no_tags]' ¶. ”create_all/drop_all” added to MetaData
     object

     References: #98(6)

   * `[no_tags]' ¶ improvements and fixes to topological
     sort algorithm, as well as more unit tests

   * `[no_tags]' ¶ tutorial page added to docs which also
     can be run with a custom doctest runner to ensure its properly
     working.  docs generally overhauled to deal with new code patterns

   * `[no_tags]' ¶ many more fixes, refactorings.

   * `[no_tags]' ¶ migration guide is available on the Wiki
     at ‘http://www.sqlalchemy.org/trac/wiki/02Migration’

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/152

   (2) http://www.sqlalchemy.org/trac/ticket/167

   (3) http://www.sqlalchemy.org/trac/ticket/147

   (4) http://www.sqlalchemy.org/trac/ticket/154

   (5) http://www.sqlalchemy.org/trac/ticket/31

   (6) http://www.sqlalchemy.org/trac/ticket/98

8.3.14 0.1 Changelog
--------------------

8.3.14.1 0.1.7
..............

Released: Fri May 05 2006

   * `[no_tags]' ¶ some fixes to topological sort algorithm

   * `[no_tags]' ¶ added DISTINCT ON support to Postgres
     (just supply distinct=[col1,col2..])

   * `[no_tags]' ¶ added __mod__ (% operator) to sql
     expressions

   * `[no_tags]' ¶. ”order_by” mapper property inherited
     from inheriting mapper

   * `[no_tags]' ¶ fix to column type used when mapper
     UPDATES/DELETEs

   * `[no_tags]' ¶ with convert_unicode=True, reflection
     was failing, has been fixed

   * `[no_tags]' ¶ types types types!  still weren’t
     working….have to use TypeDecorator again :(

   * `[no_tags]' ¶ mysql binary type converts array output
     to buffer, fixes PickleType

   * `[no_tags]' ¶ fixed the attributes.py memory leak once
     and for all

   * `[no_tags]' ¶ unittests are qualified based on the
     databases that support each one

   * `[no_tags]' ¶ fixed bug where column defaults would
     clobber VALUES clause of insert objects

   * `[no_tags]' ¶ fixed bug where table def w/ schema name
     would force engine connection

   * `[no_tags]' ¶ fix for parenthesis to work correctly
     with subqueries in INSERT/UPDATE

   * `[no_tags]' ¶. HistoryArraySet gets extend() method

   * `[no_tags]' ¶ fixed lazyload support for other
     comparison operators besides =

   * `[no_tags]' ¶ lazyload fix where two comparisons in
     the join condition point to the samem column

   * `[no_tags]' ¶ added “construct_new” flag to mapper,
     will use __new__ to create instances instead of __init__ (standard
     in 0.2)

   * `[no_tags]' ¶ added selectresults.py to SVN, missed it
     last time

   * `[no_tags]' ¶ tweak to allow a many-to-many
     relationship from a table to itself via an association table

   * `[no_tags]' ¶ small fix to “translate_row” function
     used by polymorphic example

   * `[no_tags]' ¶ create_engine uses cgi.parse_qsl to read
     query string (out the window in 0.2)

   * `[no_tags]' ¶ tweaks to CAST operator

   * `[no_tags]' ¶ fixed function names
     LOCAL_TIME/LOCAL_TIMESTAMP -> LOCALTIME/LOCALTIMESTAMP

   * `[no_tags]' ¶ fixed order of ORDER BY/HAVING in
     compile

8.3.14.2 0.1.6
..............

Released: Wed Apr 12 2006

   * `[no_tags]' ¶ support for MS-SQL added courtesy Rick
     Morrison, Runar Petursson

   * `[no_tags]' ¶ the latest SQLSoup from J. Ellis

   * `[no_tags]' ¶. ActiveMapper has preliminary support for
     inheritance (Jeff Watkins)

   * `[no_tags]' ¶ added a “mods” system which allows
     pluggable modules that modify/augment core functionality, using the
     function “install_mods(*modnames)”.

   * `[no_tags]' ¶ added the first “mod”, SelectResults,
     which modifies mapper selects to return generators that turn ranges
     into LIMIT/OFFSET queries (Jonas Borgstr?

   * `[no_tags]' ¶ factored out querying capabilities of
     Mapper into a separate Query object which is Session-centric.  this
     improves the performance of mapper.using(session) and makes other
     things possible.

   * `[no_tags]' ¶ objectstore/Session refactored, the
     official way to save objects is now via the flush() method.  The
     begin/commit functionality of Session is factored into
     LegacySession which is still established as the default behavior,
     until the 0.2 series.

   * `[no_tags]' ¶ types system is bound to an engine at
     query compile time, not schema construction time.  this simplifies
     the types system as well as the ProxyEngine.

   * `[no_tags]' ¶ added ‘version_id’ keyword argument to
     mapper.  this keyword should reference a Column object with type
     Integer, preferably non-nullable, which will be used on the mapped
     table to track version numbers.  this number is incremented on each
     save operation and is specified in the UPDATE/DELETE conditions so
     that it factors into the returned row count, which results in a
     ConcurrencyError if the value received is not the expected count.

   * `[no_tags]' ¶ added ‘entity_name’ keyword argument to
     mapper.  a mapper is now associated with a class via the class
     object as well as an optional entity_name parameter, which is a
     string defaulting to None.  any number of primary mappers can be
     created for a class, qualified by the entity name.  instances of
     those classes will issue all of their load and save operations
     through their entity_name-qualified mapper, and maintain separate a
     identity in the identity map for an otherwise equivalent object.

   * `[no_tags]' ¶ overhaul to the attributes system.  code
     has been clarified, and also fixed to support proper polymorphic
     behavior on object attributes.

   * `[no_tags]' ¶ added “for_update” flag to Select
     objects

   * `[no_tags]' ¶ some fixes for backrefs

   * `[no_tags]' ¶ fix for postgres1 DateTime type

   * `[no_tags]' ¶ documentation pages mostly switched over
     to Markdown syntax

8.3.14.3 0.1.5
..............

Released: Mon Mar 27 2006

   * `[no_tags]' ¶ added SQLSession concept to SQLEngine.
     this object keeps track of retrieving a connection from the
     connection pool as well as an in-progress transaction.  methods
     push_session() and pop_session() added to SQLEngine which push/pop
     a new SQLSession onto the engine, allowing operation upon a second
     connection “nested” within the previous one, allowing nested
     transactions.  Other tricks are sure to come later regarding
     SQLSession.

   * `[no_tags]' ¶ added nest_on argument to
     objectstore.Session.  This is a single SQLEngine or list of engines
     for which push_session()/pop_session() will be called each time
     this Session becomes the active session (via
     objectstore.push_session() or equivalent).  This allows a unit of
     work Session to take advantage of the nested transaction feature
     without explicitly calling push_session/pop_session on the engine.

   * `[no_tags]' ¶ factored apart objectstore/unitofwork to
     separate “Session scoping” from “uow commit heavy lifting”

   * `[no_tags]' ¶ added populate_instance() method to
     MapperExtension.  allows an extension to modify the population of
     object attributes.  this method can call the populate_instance()
     method on another mapper to proxy the attribute population from one
     mapper to another; some row translation logic is also built in to
     help with this.

   * `[no_tags]' ¶ fixed Oracle8-compatibility “use_ansi”
     flag which converts JOINs to comparisons with the = and (+)
     operators, passes basic unittests

   * `[no_tags]' ¶ tweaks to Oracle LIMIT/OFFSET support

   * `[no_tags]' ¶. Oracle reflection uses ALL_** views
     instead of USER_** to get larger list of stuff to reflect from

   * `[no_tags]' ¶ fixes to Oracle foreign key reflection

     References: #105(1)

   * `[no_tags]' ¶ objectstore.commit(obj1, obj2,…) adds an
     extra step to seek out private relations on properties and delete
     child objects, even though its not a global commit

   * `[no_tags]' ¶ lots and lots of fixes to mappers which
     use inheritance, strengthened the concept of relations on a mapper
     being made towards the “local” table for that mapper, not the
     tables it inherits.  allows more complex compositional patterns to
     work with lazy/eager loading.

   * `[no_tags]' ¶ added support for mappers to inherit
     from others based on the same table, just specify the same table as
     that of both parent/child mapper.

   * `[no_tags]' ¶ some minor speed improvements to the
     attributes system with regards to instantiating and populating new
     objects.

   * `[no_tags]' ¶ fixed MySQL binary unit test

   * `[no_tags]' ¶. INSERTs can receive clause elements as
     VALUES arguments, not just literal values

   * `[no_tags]' ¶ support for calling multi-tokened
     functions, i.e.  schema.mypkg.func()

   * `[no_tags]' ¶ added J. Ellis’ SQLSoup module to
     extensions package

   * `[no_tags]' ¶ added “polymorphic” examples
     illustrating methods to load multiple object types from one mapper,
     the second of which uses the new populate_instance() method.  small
     improvements to mapper, UNION construct to help the examples along

   * `[no_tags]' ¶ improvements/fixes to
     session.refresh()/session.expire() (which may have been called
     “invalidate” earlier..)

   * `[no_tags]' ¶ added session.expunge() which totally
     removes an object from the current session

   * `[no_tags]' ¶ added *args, **kwargs pass-thru to
     engine.transaction(func) allowing easier creation of
     transactionalizing decorator functions

   * `[no_tags]' ¶ added iterator interface to ResultProxy:
     “for row in result:…”

   * `[no_tags]' ¶ added assertion to tx = session.begin();
     tx.rollback(); tx.begin(), i.e.  cant use it after a rollback()

   * `[no_tags]' ¶ added date conversion on bind parameter
     fix to SQLite enabling dates to work with pysqlite1

   * `[no_tags]' ¶ improvements to subqueries to more
     intelligently construct their FROM clauses

     References: #116(2)

   * `[no_tags]' ¶ added PickleType to types.

   * `[no_tags]' ¶ fixed two bugs with column labels with
     regards to bind parameters: bind param keynames they are now
     generated from a column “label” in all relevant cases to take
     advantage of excess-name-length rules, and checks for a peculiar
     collision against a column named the same as “tablename_colname”
     added

   * `[no_tags]' ¶ major overhaul to unit of work
     documentation, other documentation sections.

   * `[no_tags]' ¶ fixed attributes bug where if an object
     is committed, its lazy-loaded list got blown away if it hadn’t been
     loaded

   * `[no_tags]' ¶ added unique_connection() method to
     engine, connection pool to return a connection that is not part of
     the thread-local context or any current transaction

   * `[no_tags]' ¶ added invalidate() function to pooled
     connection.  will remove the connection from the pool.  still need
     work for engines to auto-reconnect to a stale DB though.

   * `[no_tags]' ¶ added distinct() function to column
     elements so you can do func.count(mycol.distinct())

   * `[no_tags]' ¶ added “always_refresh” flag to Mapper,
     creates a mapper that will always refresh the attributes of objects
     it gets/selects from the DB, overwriting any changes made.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/105

   (2) http://www.sqlalchemy.org/trac/ticket/116

8.3.14.4 0.1.4
..............

Released: Mon Mar 13 2006

   * `[no_tags]' ¶ create_engine() now uses genericized
     parameters; host/hostname, db/dbname/database, password/passwd,
     etc.  for all engine connections.  makes engine URIs much more
     “universal”

   * `[no_tags]' ¶ added support for SELECT statements
     embedded into a column clause, using the flag “scalar=True”

   * `[no_tags]' ¶ another overhaul to EagerLoading when
     used in conjunction with mappers that inherit; improvements to
     eager loads figuring out their aliased queries correctly, also
     relations set up against a mapper with inherited mappers will
     create joins against the table that is specific to the mapper
     itself (i.e.  and not any tables that are inherited/are further
     down the inheritance chain), this can be overridden by using custom
     primary/secondary joins.

   * `[no_tags]' ¶ added J.Ellis patch to mapper.py so that
     selectone() throws an exception if query returns more than one
     object row, selectfirst() to not throw the exception.  also adds
     selectfirst_by (synonymous with get_by) and selectone_by

   * `[no_tags]' ¶ added onupdate parameter to Column, will
     exec SQL/python upon an update statement.Also adds
     “for_update=True” to all DefaultGenerator subclasses

   * `[no_tags]' ¶ added support for Oracle table
     reflection contributed by Andrija Zaric; still some bugs to work
     out regarding composite primary keys/dictionary selection

   * `[no_tags]' ¶ checked in an initial Firebird module,
     awaiting testing.

   * `[no_tags]' ¶ added sql.ClauseParameters dictionary
     object as the result for compiled.get_params(), does
     late-typeprocessing of bind parameters so that the original values
     are easier to access

   * `[no_tags]' ¶ more docs for indexes, column defaults,
     connection pooling, engine construction

   * `[no_tags]' ¶ overhaul to the construction of the
     types system.  uses a simpler inheritance pattern so that any of
     the generic types can be easily subclassed, with no need for
     TypeDecorator.

   * `[no_tags]' ¶ added “convert_unicode=False” parameter
     to SQLEngine, will cause all String types to perform unicode
     encoding/decoding (makes Strings act like Unicodes)

   * `[no_tags]' ¶ added ‘encoding=”utf8”’ parameter to
     engine.  the given encoding will be used for all encode/decode
     calls within Unicode types as well as Strings when
     convert_unicode=True.

   * `[no_tags]' ¶ improved support for mapping against
     UNIONs, added polymorph.py example to illustrate multi-class
     mapping against a UNION

   * `[no_tags]' ¶ fix to SQLite LIMIT/OFFSET syntax

   * `[no_tags]' ¶ fix to Oracle LIMIT syntax

   * `[no_tags]' ¶ added backref() function, allows
     backreferences to have keyword arguments that will be passed to the
     backref.

   * `[no_tags]' ¶. Sequences and ColumnDefault objects can
     do execute()/scalar() standalone

   * `[no_tags]' ¶. SQL functions (i.e.  func.foo()) can do
     execute()/scalar() standalone

   * `[no_tags]' ¶ fix to SQL functions so that the
     ANSI-standard functions, i.e.  current_timestamp etc., do not
     specify parenthesis.  all other functions do.

   * `[no_tags]' ¶ added settattr_clean and append_clean to
     SmartProperty, which set attributes without triggering a “dirty”
     event or any history.  used as:
     myclass.prop1.setattr_clean(myobject, ‘hi’)

   * `[no_tags]' ¶ improved support to column defaults when
     used by mappers; mappers will pull pre-executed defaults from
     statement’s executed bind parameters (pre-conversion) to populate
     them into a saved object’s attributes; if any PassiveDefaults have
     fired off, will instead post-fetch the row from the DB to populate
     the object.

   * `[no_tags]' ¶ added ‘get_session().invalidate(*obj)’
     method to objectstore, instances will refresh() themselves upon the
     next attribute access.

   * `[no_tags]' ¶ improvements to SQL func calls including
     an “engine” keyword argument so they can be execute()d or
     scalar()ed standalone, also added func accessor to SQLEngine

   * `[no_tags]' ¶ fix to MySQL4 custom table engines, i.e.
     TYPE instead of ENGINE

   * `[no_tags]' ¶ slightly enhanced logging, includes
     timestamps and a somewhat configurable formatting system, in lieu
     of a full-blown logging system

   * `[no_tags]' ¶ improvements to the ActiveMapper class
     from the TG gang, including many-to-many relationships

   * `[no_tags]' ¶ added Double and TinyInt support to
     mysql

8.3.14.5 0.1.3
..............

Released: Thu Mar 02 2006

   * `[no_tags]' ¶ completed “post_update” feature, will
     add a second update statement before inserts and after deletes in
     order to reconcile a relationship without any dependencies being
     created; used when persisting two rows that are dependent on each
     other

   * `[no_tags]' ¶ completed mapper.using(session)
     function, localized per-object Session functionality; objects can
     be declared and manipulated as local to any user-defined Session

   * `[no_tags]' ¶ fix to Oracle “row_number over” clause
     with multiple tables

   * `[no_tags]' ¶ mapper.get() was not selecting
     multiple-keyed objects if the mapper’s table was a join, such as in
     an inheritance relationship, this is fixed.

   * `[no_tags]' ¶ overhaul to sql/schema packages so that
     the sql package can run all on its own, producing selects, inserts,
     etc.  without any engine dependencies.  builds upon new
     TableClause/ColumnClause lexical objects.  Schema’s Table/Column
     objects are the “physical” subclasses of them.  simplifies
     schema/sql relationship, extensions (like proxyengine), and speeds
     overall performance by a large margin.  removes the entire
     getattr() behavior that plagued 0.1.1.

   * `[no_tags]' ¶ refactoring of how the mapper
     “synchronizes” data between two objects into a separate module,
     works better with properties attached to a mapper that has an
     additional inheritance relationship to one of the related tables,
     also the same methodology used to synchronize parent/child objects
     now used by mapper to synchronize between inherited and inheriting
     mappers.

   * `[no_tags]' ¶ made objectstore “check for
     out-of-identitymap” more aggressive, will perform the check when
     object attributes are modified or the object is deleted

   * `[no_tags]' ¶. Index object fully implemented, can be
     constructed standalone, or via “index” and “unique” arguments on
     Columns.

   * `[no_tags]' ¶ added “convert_unicode” flag to
     SQLEngine, will treat all String/CHAR types as Unicode types, with
     raw-byte/utf-8 translation on the bind parameter and result set
     side.

   * `[no_tags]' ¶ postgres maintains a list of ANSI
     functions that must have no parenthesis so function calls with no
     arguments work consistently

   * `[no_tags]' ¶ tables can be created with no engine
     specified.  this will default their engine to a module-scoped
     “default engine” which is a ProxyEngine.  this engine can be
     connected via the function “global_connect”.

   * `[no_tags]' ¶ added “refresh(*obj)” method to
     objectstore / Session to reload the attributes of any set of
     objects from the database unconditionally

8.3.14.6 0.1.2
..............

Released: Fri Feb 24 2006

   * `[no_tags]' ¶ fixed a recursive call in schema that
     was somehow running 994 times then returning normally.  broke
     nothing, slowed down everything.  thanks to jpellerin for finding
     this.

8.3.14.7 0.1.1
..............

Released: Thu Feb 23 2006

   * `[no_tags]' ¶ small fix to Function class so that
     expressions with a func.foo() use the type of the Function object
     (i.e.  the left side) as the type of the boolean expression, not
     the other side which is more of a moving target (changeset 1020).

   * `[no_tags]' ¶ creating self-referring mappers with
     backrefs slightly easier (but still not that easy - changeset 1019)

   * `[no_tags]' ¶ fixes to one-to-one mappings (changeset
     1015)

   * `[no_tags]' ¶ psycopg1 date/time issue with None fixed
     (changeset 1005)

   * `[no_tags]' ¶ two issues related to postgres, which
     doesn’t want to give you the “lastrowid” since oids are deprecated:

             * postgres database-side defaults that are on primary key
               cols `do' execute explicitly beforehand, even though
               that’s not the idea of a PassiveDefault.  this is because
               sequences on columns get reflected as PassiveDefaults,
               but need to be explicitly executed on a primary key col
               so we know what we just inserted.

             * if you did add a row that has a bunch of database-side
               defaults on it, and the PassiveDefault thing was working
               the old way, i.e.  they just execute on the DB side, the
               “cant get the row back without an OID” exception that
               occurred also will not happen unless someone (usually the
               ORM) explicitly asks for it.

   * `[no_tags]' ¶ fixed a glitch with
     engine.execute_compiled where it was making a second ResultProxy
     that just got thrown away.

   * `[no_tags]' ¶ began to implement newer logic in object
     properties.  you can now say myclass.attr.property, which will give
     you the PropertyLoader corresponding to that attribute, i.e.
     myclass.mapper.props[‘attr’]

   * `[no_tags]' ¶ eager loading has been internally
     overhauled to use aliases at all times.  more complicated chains of
     eager loads can now be created without any need for explicit “use
     aliases”-type instructions.  EagerLoader code is also much simpler
     now.

   * `[no_tags]' ¶ a new somewhat experimental flag
     “use_update” added to relations, indicates that this relationship
     should be handled by a second UPDATE statement, either after a
     primary INSERT or before a primary DELETE. handles circular row
     dependencies.

   * `[no_tags]' ¶ added exceptions module, all raised
     exceptions (except for some KeyError/AttributeError exceptions)
     descend from these classes.

   * `[no_tags]' ¶ fix to date types with MySQL, returned
     timedelta converted to datetime.time

   * `[no_tags]' ¶ two-phase objectstore.commit operations
     (i.e.  begin/commit) now return a transactional object
     (SessionTrans), to more clearly indicate transaction boundaries.

   * `[no_tags]' ¶. Index object with create/drop support
     added to schema

   * `[no_tags]' ¶ fix to postgres, where it will
     explicitly pre-execute a PassiveDefault on a table if it is a
     primary key column, pursuant to the ongoing “we cant get inserted
     rows back from postgres” issue

   * `[no_tags]' ¶ change to information_schema query that
     gets back postgres table defs, now uses explicit JOIN keyword,
     since one user had faster performance with 8.1

   * `[no_tags]' ¶ fix to engine.process_defaults so it
     works correctly with a table that has different column name/column
     keys (changeset 982)

   * `[no_tags]' ¶ a column can only be attached to one
     table - this is now asserted

   * `[no_tags]' ¶ postgres time types descend from Time
     type

   * `[no_tags]' ¶ fix to alltests so that it runs types
     test (now named testtypes)

   * `[no_tags]' ¶ fix to Join object so that it correctly
     exports its foreign keys (cs 973)

   * `[no_tags]' ¶ creating relationships against mappers
     that use inheritance fixed (cs 973)

8.4 Older Migration Guides
==========================

8.4.1 What’s New in SQLAlchemy 1.3?
-----------------------------------

     About this Document: This document describes changes between
     SQLAlchemy version 1.2 and SQLAlchemy version 1.3.

8.4.1.1 Introduction
....................

This guide introduces what’s new in SQLAlchemy version 1.3 and also
documents changes which affect users migrating their applications from
the 1.2 series of SQLAlchemy to 1.3.

Please carefully review the sections on behavioral changes for
potentially backwards-incompatible changes in behavior.

8.4.1.2 General
...............

8.4.1.3 Deprecation warnings are emitted for all deprecated elements; new deprecations added
............................................................................................

Release 1.3 ensures that all behaviors and APIs that are deprecated,
including all those that have been long listed as “legacy” for years,
are emitting ‘DeprecationWarning’ warnings.  This includes when making
use of parameters such as Session.weak_identity_map and
classes such as ‘MapperExtension’.  While all deprecations have been
noted in the documentation, often they did not use a proper restructured
text directive, or include in what version they were deprecated.
Whether or not a particular API feature actually emitted a deprecation
warning was not consistent.  The general attitude was that most or all
of these deprecated features were treated as long-term legacy features
with no plans to remove them.

The change includes that all documented deprecations now use a proper
restructured text directive in the documentation with a version number,
the verbiage that the feature or use case will be removed in a future
release is made explicit (e.g., no more legacy forever use cases), and
that use of any such feature or use case will definitely emit a
‘DeprecationWarning’, which in Python 3 as well as when using modern
testing tools like Pytest are now made more explicit in the standard
error stream.  The goal is that these long deprecated features, going
back as far as version 0.7 or 0.6, should start being removed entirely,
rather than keeping them around as “legacy” features.  Additionally,
some major new deprecations are being added as of version 1.3.  As
SQLAlchemy has 14 years of real world use by thousands of developers,
it’s possible to point to a single stream of use cases that blend
together well, and to trim away features and patterns that work against
this single way of working.

The larger context is that SQLAlchemy seeks to adjust to the coming
Python 3-only world, as well as a type-annotated world, and towards this
goal there are `tentative' plans for a major rework of SQLAlchemy which
would hopefully greatly reduce the cognitive load of the API as well as
perform a major pass over the great many differences in implementation
and use between Core and ORM. As these two systems evolved dramatically
after SQLAlchemy’s first release, in particular the ORM still retains
lots of “bolted on” behaviors that keep the wall of separation between
Core and ORM too high.  By focusing the API ahead of time on a single
pattern for each supported use case, the eventual job of migrating to a
significantly altered API becomes simpler.

For the most major deprecations being added in 1.3, see the linked
sections below.

See also
........

See “threadlocal” engine strategy deprecated.

See convert_unicode parameters deprecated.

See Relationship to AliasedClass replaces the need for non primary mappers.

#4393(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4393

8.4.1.4 New Features and Improvements - ORM
...........................................

8.4.1.5 Relationship to AliasedClass replaces the need for non primary mappers
..............................................................................

The “non primary mapper” is a mapper() created in the
Imperative (a.k.a. Classical) Mappings style, which acts as an
additional mapper against an already mapped class against a different
kind of selectable.  The non primary mapper has its roots in the 0.1,
0.2 series of SQLAlchemy where it was anticipated that the
mapper() object was to be the primary query construction
interface, before the Query object existed.

With the advent of Query and later the AliasedClass
construct, most use cases for the non primary mapper went away.
This was a good thing since SQLAlchemy also moved away from “classical”
mappings altogether around the 0.5 series in favor of the declarative
system.

One use case remained around for non primary mappers when it was
realized that some very hard-to-define relationship()
configurations could be made possible when a non-primary mapper with an
alternative selectable was made as the mapping target, rather than
trying to construct a relationship.primaryjoin that
encompassed all the complexity of a particular inter-object
relationship.

As this use case became more popular, its limitations became apparent,
including that the non primary mapper is difficult to configure against
a selectable that adds new columns, that the mapper does not inherit the
relationships of the original mapping, that relationships which are
configured explicitly on the non primary mapper do not function well
with loader options, and that the non primary mapper also doesn’t
provide a fully functional namespace of column-based attributes which
can be used in queries (which again, in the old 0.1 - 0.4 days, one
would use Table objects directly with the ORM).

The missing piece was to allow the relationship() to refer
directly to the AliasedClass.  The AliasedClass
already does everything we want the non primary mapper to do; it allows
an existing mapped class to be loaded from an alternative selectable, it
inherits all the attributes and relationships of the existing mapper, it
works extremely well with loader options, and it provides a class-like
object that can be mixed into queries just like the class itself.  With
this change, the recipes that were formerly for non primary mappers at
Configuring how Relationship Joins are changed to aliased
class.

At Relationship to Aliased Class, the original non primary
mapper looked like:

     j = join(B, D, D.b_id == B.id).join(C, C.id == D.c_id)

     B_viacd = mapper(
         B, j, non_primary=True, primary_key=[j.c.b_id],
         properties={
             "id": j.c.b_id,  # so that 'id' looks the same as before
             "c_id": j.c.c_id,   # needed for disambiguation
             "d_c_id": j.c.d_c_id,  # needed for disambiguation
             "b_id": [j.c.b_id, j.c.d_b_id],
             "d_id": j.c.d_id,
         }
     )

     A.b = relationship(B_viacd, primaryjoin=A.b_id == B_viacd.c.b_id)

The properties were necessary in order to re-map the additional columns
so that they did not conflict with the existing columns mapped to ‘B’,
as well as it was necessary to define a new primary key.

With the new approach, all of this verbosity goes away, and the
additional columns are referred towards directly when making the
relationship:

     j = join(B, D, D.b_id == B.id).join(C, C.id == D.c_id)

     B_viacd = aliased(B, j, flat=True)

     A.b = relationship(B_viacd, primaryjoin=A.b_id == j.c.b_id)

The non primary mapper is now deprecated with the eventual goal to be
that classical mappings as a feature go away entirely.  The Declarative
API would become the single means of mapping which hopefully will allow
internal improvements and simplifications, as well as a clearer
documentation story.

#4423(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4423

8.4.1.6 selectin loading no longer uses JOIN for simple one-to-many
...................................................................

The “selectin” loading feature added in 1.2 introduced an extremely
performant new way to eagerly load collections, in many cases much
faster than that of “subquery” eager loading, as it does not rely upon
restating the original SELECT query and instead uses a simple IN clause.
However, the “selectin” load still relied upon rendering a JOIN between
the parent and related tables, since it needs the parent primary key
values in the row in order to match rows up.  In 1.3, a new optimization
is added which will omit this JOIN in the most common case of a simple
one-to-many load, where the related row already contains the primary key
of the parent row expressed in its foreign key columns.  This again
provides for a dramatic performance improvement as the ORM now can load
large numbers of collections all in one query without using JOIN or
subqueries at all.

Given a mapping:

     class A(Base):
         __tablename__ = 'a'

         id = Column(Integer, primary_key=True)
         bs = relationship("B", lazy="selectin")

     class B(Base):
         __tablename__ = 'b'
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey("a.id"))

In the 1.2 version of “selectin” loading, a load of A to B looks like:

     SELECT a.id AS a_id FROM a
     SELECT a_1.id AS a_1_id, b.id AS b_id, b.a_id AS b_a_id
     FROM a AS a_1 JOIN b ON a_1.id = b.a_id
     WHERE a_1.id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ORDER BY a_1.id
     (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

With the new behavior, the load looks like:

     SELECT a.id AS a_id FROM a
     SELECT b.a_id AS b_a_id, b.id AS b_id FROM b
     WHERE b.a_id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ORDER BY b.a_id
     (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

The behavior is being released as automatic, using a similar heuristic
that lazy loading uses in order to determine if related entities can be
fetched directly from the identity map.  However, as with most querying
features, the feature’s implementation became more complex as a result
of advanced scenarios regarding polymorphic loading.  If problems are
encountered, users should report a bug, however the change also includes
a flag relationship.omit_join which can be set to ‘False’ on
the relationship() to disable the optimization.

#4340(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4340

8.4.1.7 Improvement to the behavior of many-to-one query expressions
....................................................................

When building a query that compares a many-to-one relationship to an
object value, such as:

     u1 = session.query(User).get(5)

     query = session.query(Address).filter(Address.user == u1)

The above expression ‘Address.user == u1’, which ultimately compiles to
a SQL expression normally based on the primary key columns of the ‘User’
object like ‘"address.user_id = 5"’, uses a deferred callable in order
to retrieve the value ‘5’ within the bound expression until as late as
possible.  This is to suit both the use case where the ‘Address.user ==
u1’ expression may be against a ‘User’ object that isn’t flushed yet
which relies upon a server- generated primary key value, as well as that
the expression always returns the correct result even if the primary key
value of ‘u1’ has been changed since the expression was created.

However, a side effect of this behavior is that if ‘u1’ ends up being
expired by the time the expression is evaluated, it results in an
additional SELECT statement, and in the case that ‘u1’ was also detached
from the Session, it would raise an error:

     u1 = session.query(User).get(5)

     query = session.query(Address).filter(Address.user == u1)

     session.expire(u1)
     session.expunge(u1)

     query.all()  # <-- would raise DetachedInstanceError

The expiration / expunging of the object can occur implicitly when the
Session is committed and the ‘u1’ instance falls out of
scope, as the ‘Address.user == u1’ expression does not strongly
reference the object itself, only its InstanceState.

The fix is to allow the ‘Address.user == u1’ expression to evaluate the
value ‘5’ based on attempting to retrieve or load the value normally at
expression compilation time as it does now, but if the object is
detached and has been expired, it is retrieved from a new mechanism upon
the InstanceState which will memoize the last known value
for a particular attribute on that state when that attribute is expired.
This mechanism is only enabled for a specific attribute / see
InstanceState when needed by the expression feature to conserve
performance / memory overhead.

Originally, simpler approaches such as evaluating the expression
immediately with various arrangements for trying to load the value later
if not present were attempted, however the difficult edge case is that
of the value of a column attribute (typically a natural primary key)
that is being changed.  In order to ensure that an expression like
‘Address.user == u1’ always returns the correct answer for the current
state of ‘u1’, it will return the current database-persisted value for a
persistent object, unexpiring via SELECT query if necessary, and for a
detached object it will return the most recent known value, regardless
of when the object was expired using a new feature within the
InstanceState that tracks the last known value of a column
attribute whenever the attribute is to be expired.

Modern attribute API features are used to indicate specific error
messages when the value cannot be evaluated, the two cases of which are
when the column attributes have never been set, and when the object was
already expired when the first evaluation was made and is now detached.
In all cases, see DetachedInstanceError is no longer raised.

#4359(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4359

8.4.1.8 Many-to-one replacement won’t raise for “raiseload” or detached for “old” object
........................................................................................

Given the case where a lazy load would proceed on a many-to-one
relationship in order to load the “old” value, if the relationship does
not specify the relationship.active_history flag, an
assertion will not be raised for a detached object:

     a1 = session.query(Address).filter_by(id=5).one()

     session.expunge(a1)

     a1.user = some_user

Above, when the ‘.user’ attribute is replaced on the detached ‘a1’
object, a DetachedInstanceError would be raised as the
attribute is attempting to retrieve the previous value of ‘.user’ from
the identity map.  The change is that the operation now proceeds without
the old value being loaded.

The same change is also made to the ‘lazy="raise"’ loader strategy:

     class Address(Base):
         # ...

         user = relationship("User", ..., lazy="raise")

Previously, the association of ‘a1.user’ would invoke the “raiseload”
exception as a result of the attribute attempting to retrieve the
previous value.  This assertion is now skipped in the case of loading
the “old” value.

#4353(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4353

8.4.1.9 “del” implemented for ORM attributes
............................................

The Python ‘del’ operation was not really usable for mapped attributes,
either scalar columns or object references.  Support has been added for
this to work correctly, where the ‘del’ operation is roughly equivalent
to setting the attribute to the ‘None’ value:

     some_object = session.query(SomeObject).get(5)

     del some_object.some_attribute   # from a SQL perspective, works like "= None"

#4354(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4354

8.4.1.10 info dictionary added to InstanceState
...............................................

Added the ‘.info’ dictionary to the InstanceState class, the
object that comes from calling inspect() on a mapped object.
This allows custom recipes to add additional information about an object
that will be carried along with that object’s full lifecycle in memory:

     from sqlalchemy import inspect

     u1 = User(id=7, name='ed')

     inspect(u1).info['user_info'] = '7|ed'

#4257(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4257

8.4.1.11 Horizontal Sharding extension supports bulk update and delete methods
..............................................................................

The ShardedQuery extension object supports the
Query.update() and Query.delete() bulk update/delete
methods.  The ‘query_chooser’ callable is consulted when they are called
in order to run the update/delete across multiple shards based on given
criteria.

#4196(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4196

8.4.1.12 Association Proxy Improvements
.......................................

While not for any particular reason, the Association Proxy extension had
many improvements this cycle.

8.4.1.13 Association proxy has new cascade_scalar_deletes flag
..............................................................

Given a mapping as:

     class A(Base):
         __tablename__ = 'test_a'
         id = Column(Integer, primary_key=True)
         ab = relationship(
             'AB', backref='a', uselist=False)
         b = association_proxy(
             'ab', 'b', creator=lambda b: AB(b=b),
             cascade_scalar_deletes=True)

     class B(Base):
         __tablename__ = 'test_b'
         id = Column(Integer, primary_key=True)
         ab = relationship('AB', backref='b', cascade='all, delete-orphan')

     class AB(Base):
         __tablename__ = 'test_ab'
         a_id = Column(Integer, ForeignKey(A.id), primary_key=True)
         b_id = Column(Integer, ForeignKey(B.id), primary_key=True)

An assignment to ‘A.b’ will generate an ‘AB’ object:

     a.b = B()

The ‘A.b’ association is scalar, and includes a new flag
AssociationProxy.cascade_scalar_deletes.  When set, setting ‘A.b’
to ‘None’ will remove ‘A.ab’ as well.  The default behavior remains that
it leaves ‘a.ab’ in place:

     a.b = None
     assert a.ab is None

While it at first seemed intuitive that this logic should just look at
the “cascade” attribute of the existing relationship, it’s not clear
from that alone if the proxied object should be removed, hence the
behavior is made available as an explicit option.

Additionally, ‘del’ now works for scalars in a similar manner as setting
to ‘None’:

     del a.b
     assert a.ab is None

#4308(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4308

8.4.1.14 AssociationProxy stores class-specific state on a per-class basis
..........................................................................

The AssociationProxy object makes lots of decisions based on
the parent mapped class it is associated with.  While the
AssociationProxy historically began as a relatively simple
“getter”, it became apparent early on that it also needed to make
decisions about what kind of attribute it is referring towards, e.g.
scalar or collection, mapped object or simple value, and similar.  To
achieve this, it needs to inspect the mapped attribute or other
descriptor or attribute that it refers towards, as referenced from its
parent class.  However in Python descriptor mechanics, a descriptor only
learns about its “parent” class when it is accessed in the context of
that class, such as calling ‘MyClass.some_descriptor’, which calls the
‘__get__()’ method which passes in the class.  The
AssociationProxy object would therefore store state that is
specific to that class, but only once this method were called; trying to
inspect this state ahead of time without first accessing the
AssociationProxy as a descriptor would raise an error.
Additionally, it would assume that the first class to be seen by
‘__get__()’ would be the only parent class it needed to know about.
This is despite the fact that if a particular class has inheriting
subclasses, the association proxy is really working on behalf of more
than one parent class even though it was not explicitly re-used.  While
even with this shortcoming, the association proxy would still get pretty
far with its current behavior, it still leaves shortcomings in some
cases as well as the complex problem of determining the best “owner”
class.

These problems are now solved in that AssociationProxy no
longer modifies its own internal state when ‘__get__()’ is called;
instead, a new object is generated per-class known as
AssociationProxyInstance which handles all the state specific to a
particular mapped parent class (when the parent class is not mapped, no
AssociationProxyInstance is generated).  The concept of a
single “owning class” for the association proxy, which was nonetheless
improved in 1.1, has essentially been replaced with an approach where
the AP now can treat any number of “owning” classes equally.

To accommodate for applications that want to inspect this state for an
AssociationProxy without necessarily calling ‘__get__()’, a
new method AssociationProxy.for_class() is added that
provides direct access to a class-specific
AssociationProxyInstance, demonstrated as:

     class User(Base):
         # ...

         keywords = association_proxy('kws', 'keyword')

     proxy_state = inspect(User).all_orm_descriptors["keywords"].for_class(User)

Once we have the AssociationProxyInstance object, in the
above example stored in the ‘proxy_state’ variable, we can look at
attributes specific to the ‘User.keywords’ proxy, such as
‘target_class’:

     >>> proxy_state.target_class
     Keyword

#3423(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3423

8.4.1.15 AssociationProxy now provides standard column operators for a column-oriented target
.............................................................................................

Given an AssociationProxy where the target is a database
column, and is `not' an object reference or another association proxy:

     class User(Base):
         # ...

         elements = relationship("Element")

         # column-based association proxy
         values = association_proxy("elements", "value")

     class Element(Base):
         # ...

         value = Column(String)

The ‘User.values’ association proxy refers to the ‘Element.value’
column.  Standard column operations are now available, such as ‘like’:

     >>> print(s.query(User).filter(User.values.like('%foo%')))
     SELECT "user".id AS user_id
     FROM "user"
     WHERE EXISTS (SELECT 1
     FROM element
     WHERE "user".id = element.user_id AND element.value LIKE :value_1)

‘equals’:

     >>> print(s.query(User).filter(User.values == 'foo'))
     SELECT "user".id AS user_id
     FROM "user"
     WHERE EXISTS (SELECT 1
     FROM element
     WHERE "user".id = element.user_id AND element.value = :value_1)

When comparing to ‘None’, the ‘IS NULL’ expression is augmented with a
test that the related row does not exist at all; this is the same
behavior as before:

     >>> print(s.query(User).filter(User.values == None))
     SELECT "user".id AS user_id
     FROM "user"
     WHERE (EXISTS (SELECT 1
     FROM element
     WHERE "user".id = element.user_id AND element.value IS NULL)) OR NOT (EXISTS (SELECT 1
     FROM element
     WHERE "user".id = element.user_id))

Note that the ColumnOperators.contains() operator is in fact
a string comparison operator; `this is a change in behavior' in that
previously, the association proxy used ‘.contains’ as a list containment
operator only.  With a column-oriented comparison, it now behaves like a
“like”:

     >>> print(s.query(User).filter(User.values.contains('foo')))
     SELECT "user".id AS user_id
     FROM "user"
     WHERE EXISTS (SELECT 1
     FROM element
     WHERE "user".id = element.user_id AND (element.value LIKE '%' || :value_1 || '%'))

In order to test the ‘User.values’ collection for simple membership of
the value ‘"foo"’, the equals operator (e.g.  ‘User.values == 'foo'’)
should be used; this works in previous versions as well.

When using an object-based association proxy with a collection, the
behavior is as before, that of testing for collection membership, e.g.
given a mapping:

     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         user_elements = relationship("UserElement")

         # object-based association proxy
         elements = association_proxy("user_elements", "element")

     class UserElement(Base):
         __tablename__ = 'user_element'

         id = Column(Integer, primary_key=True)
         user_id = Column(ForeignKey("user.id"))
         element_id = Column(ForeignKey("element.id"))
         element = relationship("Element")

     class Element(Base):
         __tablename__ = 'element'

         id = Column(Integer, primary_key=True)
         value = Column(String)

The ‘.contains()’ method produces the same expression as before, testing
the list of ‘User.elements’ for the presence of an ‘Element’ object:

     >>> print(s.query(User).filter(User.elements.contains(Element(id=1))))
     SELECT "user".id AS user_id
     FROM "user"
     WHERE EXISTS (SELECT 1
     FROM user_element
     WHERE "user".id = user_element.user_id AND :param_1 = user_element.element_id)

Overall, the change is enabled based on the architectural change that is
part of AssociationProxy stores class-specific state on a per-class basis;
as the proxy now spins off additional state when
an expression is generated, there is both an object-target and a
column-target version of the AssociationProxyInstance class.

#4351(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4351

8.4.1.16 Association Proxy now Strong References the Parent Object
..................................................................

The long-standing behavior of the association proxy collection
maintaining only a weak reference to the parent object is reverted; the
proxy will now maintain a strong reference to the parent for as long as
the proxy collection itself is also in memory, eliminating the “stale
association proxy” error.  This change is being made on an experimental
basis to see if any use cases arise where it causes side effects.

As an example, given a mapping with association proxy:

     class A(Base):
         __tablename__ = 'a'

         id = Column(Integer, primary_key=True)
         bs = relationship("B")
         b_data = association_proxy('bs', 'data')

     class B(Base):
         __tablename__ = 'b'
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey("a.id"))
         data = Column(String)

     a1 = A(bs=[B(data='b1'), B(data='b2')])

     b_data = a1.b_data

Previously, if ‘a1’ were deleted out of scope:

     del a1

Trying to iterate the ‘b_data’ collection after ‘a1’ is deleted from
scope would raise the error ‘"stale association proxy, parent object has
gone out of scope"’.  This is because the association proxy needs to
access the actual ‘a1.bs’ collection in order to produce a view, and
prior to this change it maintained only a weak reference to ‘a1’.  In
particular, users would frequently encounter this error when performing
an inline operation such as:

     collection = session.query(A).filter_by(id=1).first().b_data

Above, because the ‘A’ object would be garbage collected before the
‘b_data’ collection were actually used.

The change is that the ‘b_data’ collection is now maintaining a strong
reference to the ‘a1’ object, so that it remains present:

     assert b_data == ['b1', 'b2']

This change introduces the side effect that if an application is passing
around the collection as above, `the parent object won’t be garbage
collected' until the collection is also discarded.  As always, if ‘a1’
is persistent inside a particular Session, it will remain part
of that session’s state until it is garbage collected.

Note that this change may be revised if it leads to problems.

#4268(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4268

8.4.1.17 Implemented bulk replace for sets, dicts with AssociationProxy
.......................................................................

Assignment of a set or dictionary to an association proxy collection
should now work correctly, whereas before it would re-create association
proxy members for existing keys, leading to the issue of potential flush
failures due to the delete+insert of the same object it now should only
create new association objects where appropriate:

     class A(Base):
         __tablename__ = "test_a"

         id = Column(Integer, primary_key=True)
         b_rel = relationship(
             "B", collection_class=set, cascade="all, delete-orphan",
         )
         b = association_proxy("b_rel", "value", creator=lambda x: B(value=x))

     class B(Base):
         __tablename__ = "test_b"
         __table_args__ = (UniqueConstraint("a_id", "value"),)

         id = Column(Integer, primary_key=True)
         a_id = Column(Integer, ForeignKey("test_a.id"), nullable=False)
         value = Column(String)

     # ...

     s = Session(e)
     a = A(b={"x", "y", "z"})
     s.add(a)
     s.commit()

     # re-assign where one B should be deleted, one B added, two
     # B's maintained
     a.b = {"x", "z", "q"}

     # only 'q' was added, so only one new B object.  previously
     # all three would have been re-created leading to flush conflicts
     # against the deleted ones.
     assert len(s.new) == 1

#2642(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2642

8.4.1.18 Many-to-one backref checks for collection duplicates during remove operation
.....................................................................................

When an ORM-mapped collection that existed as a Python sequence,
typically a Python ‘list’ as is the default for relationship(),
contained duplicates, and the object were removed from one of its
positions but not the other(s), a many-to-one backref would set its
attribute to ‘None’ even though the one-to-many side still represented
the object as present.  Even though one-to-many collections cannot have
duplicates in the relational model, an ORM-mapped relationship()
that uses a sequence collection can have duplicates inside of it in
memory, with the restriction that this duplicate state can neither be
persisted nor retrieved from the database.  In particular, having a
duplicate temporarily present in the list is intrinsic to a Python
“swap” operation.  Given a standard one-to-many/many-to-one setup:

     class A(Base):
         __tablename__ = 'a'

         id = Column(Integer, primary_key=True)
         bs = relationship("B", backref="a")

     class B(Base):
         __tablename__ = 'b'
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey("a.id"))

If we have an ‘A’ object with two ‘B’ members, and perform a swap:

     a1 = A(bs=[B(), B()])

     a1.bs[0], a1.bs[1] = a1.bs[1], a1.bs[0]

During the above operation, interception of the standard Python
‘__setitem__’ ‘__delitem__’ methods delivers an interim state where the
second ‘B()’ object is present twice in the collection.  When the ‘B()’
object is removed from one of the positions, the ‘B.a’ backref would set
the reference to ‘None’, causing the link between the ‘A’ and ‘B’ object
to be removed during the flush.  The same issue can be demonstrated
using plain duplicates:

     >>> a1 = A()
     >>> b1 = B()
     >>> a1.bs.append(b1)
     >>> a1.bs.append(b1)  # append the same b1 object twice
     >>> del a1.bs[1]
     >>> a1.bs  # collection is unaffected so far...
     [<__main__.B object at 0x7f047af5fb70>]
     >>> b1.a   # however b1.a is None
     >>>
     >>> session.add(a1)
     >>> session.commit()  # so upon flush + expire....
     >>> a1.bs  # the value is gone
     []

The fix ensures that when the backref fires off, which is before the
collection is mutated, the collection is checked for exactly one or zero
instances of the target item before unsetting the many-to-one side,
using a linear search which at the moment makes use of ‘list.search’ and
‘list.__contains__’.

Originally it was thought that an event-based reference counting scheme
would need to be used within the collection internals so that all
duplicate instances could be tracked throughout the lifecycle of the
collection, which would have added a performance/memory/complexity
impact to all collection operations, including the very frequent
operations of loading and appending.  The approach that is taken instead
limits the additional expense to the less common operations of
collection removal and bulk replacement, and the observed overhead of
the linear scan is negligible; linear scans of relationship-bound
collections are already used within the unit of work as well as when a
collection is bulk replaced.

#1103(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1103

8.4.1.19 Key Behavioral Changes - ORM
.....................................

8.4.1.20 Query.join() handles ambiguity in deciding the “left” side more explicitly
...................................................................................

Historically, given a query like the following:

     u_alias = aliased(User)
     session.query(User, u_alias).join(Address)

given the standard tutorial mappings, the query would produce a FROM
clause as:

     SELECT ...
     FROM users AS users_1, users JOIN addresses ON users.id = addresses.user_id

That is, the JOIN would implicitly be against the first entity that
matches.  The new behavior is that an exception requests that this
ambiguity be resolved:

     sqlalchemy.exc.InvalidRequestError: Can't determine which FROM clause to
     join from, there are multiple FROMS which can join to this entity.
     Try adding an explicit ON clause to help resolve the ambiguity.

The solution is to provide an ON clause, either as an expression:

     # join to User
     session.query(User, u_alias).join(Address, Address.user_id == User.id)

     # join to u_alias
     session.query(User, u_alias).join(Address, Address.user_id == u_alias.id)

Or to use the relationship attribute, if available:

     # join to User
     session.query(User, u_alias).join(Address, User.addresses)

     # join to u_alias
     session.query(User, u_alias).join(Address, u_alias.addresses)

The change includes that a join can now correctly link to a FROM clause
that is not the first element in the list if the join is otherwise
non-ambiguous:

     session.query(func.current_timestamp(), User).join(Address)

Prior to this enhancement, the above query would raise:

     sqlalchemy.exc.InvalidRequestError: Don't know how to join from
     CURRENT_TIMESTAMP; please use select_from() to establish the
     left entity/selectable of this join

Now the query works fine:

     SELECT CURRENT_TIMESTAMP AS current_timestamp_1, users.id AS users_id,
     users.name AS users_name, users.fullname AS users_fullname,
     users.password AS users_password
     FROM users JOIN addresses ON users.id = addresses.user_id

Overall the change is directly towards Python’s “explicit is better than
implicit” philosophy.

#4365(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4365

8.4.1.21 FOR UPDATE clause is rendered within the joined eager load subquery as well as outside
...............................................................................................

This change applies specifically to the use of the joinedload()
loading strategy in conjunction with a row limited query, e.g.
using Query.first() or Query.limit(), as well as
with use of the Query.with_for_update() method.

Given a query as:

     session.query(A).options(joinedload(A.b)).limit(5)

The Query object renders a SELECT of the following form when
joined eager loading is combined with LIMIT:

     SELECT subq.a_id, subq.a_data, b_alias.id, b_alias.data FROM (
         SELECT a.id AS a_id, a.data AS a_data FROM a LIMIT 5
     ) AS subq LEFT OUTER JOIN b ON subq.a_id=b.a_id

This is so that the limit of rows takes place for the primary entity
without affecting the joined eager load of related items.  When the
above query is combined with “SELECT..FOR UPDATE”, the behavior has been
this:

     SELECT subq.a_id, subq.a_data, b_alias.id, b_alias.data FROM (
         SELECT a.id AS a_id, a.data AS a_data FROM a LIMIT 5
     ) AS subq LEFT OUTER JOIN b ON subq.a_id=b.a_id FOR UPDATE

However, MySQL due to ‘https://bugs.mysql.com/bug.php?id=90693’ does not
lock the rows inside the subquery, unlike that of PostgreSQL and other
databases.  So the above query now renders as:

     SELECT subq.a_id, subq.a_data, b_alias.id, b_alias.data FROM (
         SELECT a.id AS a_id, a.data AS a_data FROM a LIMIT 5 FOR UPDATE
     ) AS subq LEFT OUTER JOIN b ON subq.a_id=b.a_id FOR UPDATE

On the Oracle dialect, the inner “FOR UPDATE” is not rendered as Oracle
does not support this syntax and the dialect skips any “FOR UPDATE” that
is against a subquery; it isn’t necessary in any case since Oracle, like
PostgreSQL, correctly locks all elements of the returned row.

When using the Query.with_for_update.of modifier, typically
on PostgreSQL, the outer “FOR UPDATE” is omitted, and the OF is now
rendered on the inside; previously, the OF target would not be converted
to accommodate for the subquery correctly.  So given:

     session.query(A).options(joinedload(A.b)).with_for_update(of=A).limit(5)

The query would now render as:

     SELECT subq.a_id, subq.a_data, b_alias.id, b_alias.data FROM (
         SELECT a.id AS a_id, a.data AS a_data FROM a LIMIT 5 FOR UPDATE OF a
     ) AS subq LEFT OUTER JOIN b ON subq.a_id=b.a_id

The above form should be helpful on PostgreSQL additionally since
PostgreSQL will not allow the FOR UPDATE clause to be rendered after the
LEFT OUTER JOIN target.

Overall, FOR UPDATE remains highly specific to the target database in
use and can’t easily be generalized for more complex queries.

#4246(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4246

8.4.1.22 passive_deletes=’all’ will leave FK unchanged for object removed from collection
.........................................................................................

The relationship.passive_deletes option accepts the value
‘"all"’ to indicate that no foreign key attributes should be modified
when the object is flushed, even if the relationship’s collection /
reference has been removed.  Previously, this did not take place for
one-to-many, or one-to-one relationships, in the following situation:

     class User(Base):
         __tablename__ = 'users'

         id = Column(Integer, primary_key=True)
         addresses = relationship(
             "Address",
             passive_deletes="all")

     class Address(Base):
         __tablename__ = 'addresses'
         id = Column(Integer, primary_key=True)
         email = Column(String)

         user_id = Column(Integer, ForeignKey('users.id'))
         user = relationship("User")

     u1 = session.query(User).first()
     address = u1.addresses[0]
     u1.addresses.remove(address)
     session.commit()

     # would fail and be set to None
     assert address.user_id == u1.id

The fix now includes that ‘address.user_id’ is left unchanged as per
‘passive_deletes="all"’.  This kind of thing is useful for building
custom “version table” schemes and such where rows are archived instead
of deleted.

#3844(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3844

8.4.1.23 New Features and Improvements - Core
.............................................

8.4.1.24 New multi-column naming convention tokens, long name truncation
........................................................................

To suit the case where a MetaData naming convention needs to
disambiguate between multiple-column constraints and wishes to use all
the columns within the generated constraint name, a new series of naming
convention tokens are added, including ‘column_0N_name’,
‘column_0_N_name’, ‘column_0N_key’, ‘column_0_N_key’,
‘referred_column_0N_name’, ‘referred_column_0_N_name’, etc., which
render the column name (or key or label) for all columns in the
constraint, joined together either with no separator or with an
underscore separator.  Below we define a convention that will name
UniqueConstraint constraints with a name that joins together the
names of all columns:

     metadata = MetaData(naming_convention={
         "uq": "uq_%(table_name)s_%(column_0_N_name)s"
     })

     table = Table(
         'info', metadata,
         Column('a', Integer),
         Column('b', Integer),
         Column('c', Integer),
         UniqueConstraint('a', 'b', 'c')
     )

The CREATE TABLE for the above table will render as:

     CREATE TABLE info (
         a INTEGER,
         b INTEGER,
         c INTEGER,
         CONSTRAINT uq_info_a_b_c UNIQUE (a, b, c)
     )

In addition, long-name truncation logic is now applied to the names
generated by naming conventions, in particular to accommodate for
multi-column labels that can produce very long names.  This logic, which
is the same as that used for truncating long label names in a SELECT
statement, replaces excess characters that go over the identifier-length
limit for the target database with a deterministically generated
4-character hash.  For example, on PostgreSQL where identifiers cannot
be longer than 63 characters, a long constraint name would normally be
generated from the table definition below:

     long_names = Table(
         'long_names', metadata,
         Column('information_channel_code', Integer, key='a'),
         Column('billing_convention_name', Integer, key='b'),
         Column('product_identifier', Integer, key='c'),
         UniqueConstraint('a', 'b', 'c')
     )

The truncation logic will ensure a too-long name isn’t generated for the
UNIQUE constraint:

     CREATE TABLE long_names (
         information_channel_code INTEGER,
         billing_convention_name INTEGER,
         product_identifier INTEGER,
         CONSTRAINT uq_long_names_information_channel_code_billing_conventi_a79e
         UNIQUE (information_channel_code, billing_convention_name, product_identifier)
     )

The above suffix ‘a79e’ is based on the md5 hash of the long name and
will generate the same value every time to produce consistent names for
a given schema.

Note that the truncation logic also raises IdentifierError
when a constraint name is explicitly too large for a given dialect.
This has been the behavior for an Index object for a long
time, but is now applied to other kinds of constraints as well:

     from sqlalchemy import Column
     from sqlalchemy import Integer
     from sqlalchemy import MetaData
     from sqlalchemy import Table
     from sqlalchemy import UniqueConstraint
     from sqlalchemy.dialects import postgresql
     from sqlalchemy.schema import AddConstraint

     m = MetaData()
     t = Table("t", m, Column("x", Integer))
     uq = UniqueConstraint(
         t.c.x,
         name="this_is_too_long_of_a_name_for_any_database_backend_even_postgresql",
     )

     print(AddConstraint(uq).compile(dialect=postgresql.dialect()))

will output:

     sqlalchemy.exc.IdentifierError: Identifier
     'this_is_too_long_of_a_name_for_any_database_backend_even_postgresql'
     exceeds maximum length of 63 characters

The exception raise prevents the production of non-deterministic
constraint names truncated by the database backend which are then not
compatible with database migrations later on.

To apply SQLAlchemy-side truncation rules to the above identifier, use
the conv() construct:

     uq = UniqueConstraint(
         t.c.x,
         name=conv("this_is_too_long_of_a_name_for_any_database_backend_even_postgresql"),
     )

This will again output deterministically truncated SQL as in:

     ALTER TABLE t ADD CONSTRAINT this_is_too_long_of_a_name_for_any_database_backend_eve_ac05 UNIQUE (x)

There is not at the moment an option to have the names pass through to
allow database-side truncation.  This has already been the case for
Index names for some time and issues have not been raised.

The change also repairs two other issues.  One is that the
‘column_0_key’ token wasn’t available even though this token was
documented, the other was that the ‘referred_column_0_name’ token would
inadvertently render the ‘.key’ and not the ‘.name’ of the column if
these two values were different.

See also
........

See Configuring Constraint Naming Conventions.

See MetaData.naming_convention.

#3989(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3989

8.4.1.25 Binary comparison interpretation for SQL functions
...........................................................

This enhancement is implemented at the Core level, however is applicable
primarily to the ORM.

A SQL function that compares two elements can now be used as a
“comparison” object, suitable for usage in an ORM relationship(),
by first creating the function as usual using the func
factory, then when the function is complete calling upon the
FunctionElement.as_comparison() modifier to produce a
BinaryExpression that has a “left” and a “right” side:

     class Venue(Base):
         __tablename__ = 'venue'
         id = Column(Integer, primary_key=True)
         name = Column(String)

         descendants = relationship(
             "Venue",
             primaryjoin=func.instr(
                 remote(foreign(name)), name + "/"
             ).as_comparison(1, 2) == 1,
             viewonly=True,
             order_by=name
         )

Above, the relationship.primaryjoin of the “descendants”
relationship will produce a “left” and a “right” expression based on the
first and second arguments passed to ‘instr()’.  This allows features
like the ORM lazyload to produce SQL like:

     SELECT venue.id AS venue_id, venue.name AS venue_name
     FROM venue
     WHERE instr(venue.name, (? || ?)) = ? ORDER BY venue.name
     ('parent1', '/', 1)

and a joinedload, such as:

     v1 = s.query(Venue).filter_by(name="parent1").options(
         joinedload(Venue.descendants)).one()

to work as:

     SELECT venue.id AS venue_id, venue.name AS venue_name,
       venue_1.id AS venue_1_id, venue_1.name AS venue_1_name
     FROM venue LEFT OUTER JOIN venue AS venue_1
       ON instr(venue_1.name, (venue.name || ?)) = ?
     WHERE venue.name = ? ORDER BY venue_1.name
     ('/', 1, 'parent1')

This feature is expected to help with situations such as making use of
geometric functions in relationship join conditions, or any case where
the ON clause of the SQL join is expressed in terms of a SQL function.

#3831(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3831

8.4.1.26 Expanding IN feature now supports empty lists
......................................................

The “expanding IN” feature introduced in version 1.2 at
Late-expanded IN parameter sets allow IN expressions with cached statements
now supports empty lists passed to the
ColumnOperators.in_() operator.  The implementation for an empty
list will produce an “empty set” expression that is specific to a target
backend, such as “SELECT CAST(NULL AS INTEGER) WHERE 1!=1” for
PostgreSQL, “SELECT 1 FROM (SELECT 1) as _empty_set WHERE 1!=1” for
MySQL:

     >>> from sqlalchemy import create_engine
     >>> from sqlalchemy import select, literal_column, bindparam
     >>> e = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
     >>> with e.connect() as conn:
     ...      conn.execute(
     ...          select([literal_column('1')]).
     ...          where(literal_column('1').in_(bindparam('q', expanding=True))),
     ...          q=[]
     ...      )
     ...
     SELECT 1 WHERE 1 IN (SELECT CAST(NULL AS INTEGER) WHERE 1!=1)

The feature also works for tuple-oriented IN statements, where the
“empty IN” expression will be expanded to support the elements given
inside the tuple, such as on PostgreSQL:

     >>> from sqlalchemy import create_engine
     >>> from sqlalchemy import select, literal_column, tuple_, bindparam
     >>> e = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
     >>> with e.connect() as conn:
     ...      conn.execute(
     ...          select([literal_column('1')]).
     ...          where(tuple_(50, "somestring").in_(bindparam('q', expanding=True))),
     ...          q=[]
     ...      )
     ...
     SELECT 1 WHERE (%(param_1)s, %(param_2)s)
     IN (SELECT CAST(NULL AS INTEGER), CAST(NULL AS VARCHAR) WHERE 1!=1)

#4271(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4271

8.4.1.27 TypeEngine methods bind_expression, column_expression work with Variant, type-specific types
.....................................................................................................

The TypeEngine.bind_expression() and
TypeEngine.column_expression() methods now work when they are
present on the “impl” of a particular datatype, allowing these methods
to be used by dialects as well as for TypeDecorator and
Variant use cases.

The following example illustrates a TypeDecorator that
applies SQL-time conversion functions to a LargeBinary.  In
order for this type to work in the context of a Variant, the
compiler needs to drill into the “impl” of the variant expression in
order to locate these methods:

     from sqlalchemy import TypeDecorator, LargeBinary, func

     class CompressedLargeBinary(TypeDecorator):
         impl = LargeBinary

         def bind_expression(self, bindvalue):
             return func.compress(bindvalue, type_=self)

         def column_expression(self, col):
             return func.uncompress(col, type_=self)

     MyLargeBinary = LargeBinary().with_variant(CompressedLargeBinary(), "sqlite")

The above expression will render a function within SQL when used on
SQLite only:

     from sqlalchemy import select, column
     from sqlalchemy.dialects import sqlite
     print(select([column('x', CompressedLargeBinary)]).compile(dialect=sqlite.dialect()))

will render:

     SELECT uncompress(x) AS x

The change also includes that dialects can implement
TypeEngine.bind_expression() and
TypeEngine.column_expression() on dialect-level implementation
types where they will now be used; in particular this will be used for
MySQL’s new “binary prefix” requirement as well as for casting decimal
bind values for MySQL.

#3981(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3981

8.4.1.28 New last-in-first-out strategy for QueuePool
.....................................................

The connection pool usually used by create_engine() is known
as QueuePool.  This pool uses an object equivalent to
Python’s built-in ‘Queue’ class in order to store database connections
waiting to be used.  The ‘Queue’ features first-in-first-out behavior,
which is intended to provide a round-robin use of the database
connections that are persistently in the pool.  However, a potential
downside of this is that when the utilization of the pool is low, the
re-use of each connection in series means that a server-side timeout
strategy that attempts to reduce unused connections is prevented from
shutting down these connections.  To suit this use case, a new flag
create_engine.pool_use_lifo is added which reverses the
‘.get()’ method of the ‘Queue’ to pull the connection from the beginning
of the queue instead of the end, essentially turning the “queue” into a
“stack” (adding a whole new pool called ‘StackPool’ was considered,
however this was too much verbosity).

See also
........

See Using FIFO vs. LIFO.

8.4.1.29 Key Changes - Core
...........................

8.4.1.30 Coercion of string SQL fragments to text() fully removed
.................................................................

The warnings that were first added in version 1.0, described at
Warnings emitted when coercing full SQL fragments into text(), have
now been converted into exceptions.  Continued concerns have been raised
regarding the automatic coercion of string fragments passed to methods
like Query.filter() and Select.order_by() being
converted to text() constructs, even though this has emitted
a warning.  In the case of Select.order_by(),
Query.order_by(), Select.group_by(), and
Query.group_by(), a string label or column name is still resolved
into the corresponding expression construct, however if the resolution
fails, a CompileError is raised, thus preventing raw SQL
text from being rendered directly.

#4481(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4481

8.4.1.31 “threadlocal” engine strategy deprecated
.................................................

The “threadlocal engine strategy” was added around SQLAlchemy 0.2, as a
solution to the problem that the standard way of operating in SQLAlchemy
0.1, which can be summed up as “threadlocal everything”, was found to be
lacking.  In retrospect, it seems fairly absurd that by SQLAlchemy’s
first releases which were in every regard “alpha”, that there was
concern that too many users had already settled on the existing API to
simply change it.

The original usage model for SQLAlchemy looked like this:

     engine.begin()

     table.insert().execute(<params>)
     result = table.select().execute()

     table.update().execute(<params>)

     engine.commit()

After a few months of real world use, it was clear that trying to
pretend a “connection” or a “transaction” was a hidden implementation
detail was a bad idea, particularly the moment someone needed to deal
with more than one database connection at a time.  So the usage paradigm
we see today was introduced, minus the context managers since they
didn’t yet exist in Python:

     conn = engine.connect()
     try:
         trans = conn.begin()

         conn.execute(table.insert(), <params>)
         result = conn.execute(table.select())

         conn.execute(table.update(), <params>)

         trans.commit()
     except:
         trans.rollback()
         raise
     finally:
         conn.close()

The above paradigm was what people needed, but since it was still kind
of verbose (because no context managers), the old way of working was
kept around as well and it became the threadlocal engine strategy.

Today, working with Core is much more succinct, and even more succinct
than the original pattern, thanks to context managers:

     with engine.begin() as conn:
         conn.execute(table.insert(), <params>)
         result = conn.execute(table.select())

         conn.execute(table.update(), <params>)

At this point, any remaining code that is still relying upon the
“threadlocal” style will be encouraged via this deprecation to modernize
- the feature should be removed totally by the next major series of
SQLAlchemy, e.g.  1.4.  The connection pool parameter
Pool.use_threadlocal is also deprecated as it does not actually
have any effect in most cases, as is the ‘Engine.contextual_connect()’
method, which is normally synonymous with the Engine.connect()
method except in the case where the threadlocal engine is in use.

#4393(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4393

8.4.1.32 convert_unicode parameters deprecated
..............................................

The parameters String.convert_unicode and
create_engine.convert_unicode are deprecated.  The purpose of
these parameters was to instruct SQLAlchemy to ensure that incoming
Python Unicode objects under Python 2 were encoded to bytestrings before
passing to the database, and to expect bytestrings from the database to
be converted back to Python Unicode objects.  In the pre-Python 3 era,
this was an enormous ordeal to get right, as virtually all Python DBAPIs
had no Unicode support enabled by default, and most had major issues
with the Unicode extensions that they did provide.  Eventually,
SQLAlchemy added C extensions, one of the primary purposes of these
extensions was to speed up the Unicode decode process within result
sets.

Once Python 3 was introduced, DBAPIs began to start supporting Unicode
more fully, and more importantly, by default.  However, the conditions
under which a particular DBAPI would or would not return Unicode data
from a result, as well as accept Python Unicode values as parameters,
remained extremely complicated.  This was the beginning of the
obsolescence of the “convert_unicode” flags, because they were no longer
sufficient as a means of ensuring that encode/decode was occurring only
where needed and not where it wasn’t needed.  Instead, “convert_unicode”
started to be automatically detected by dialects.  Part of this can be
seen in the “SELECT ‘test plain returns’” and “SELECT
‘test_unicode_returns’” SQL emitted by an engine the first time it
connects; the dialect is testing that the current DBAPI with its current
settings and backend database connection is returning Unicode by default
or not.

The end result is that end-user use of the “convert_unicode” flags
should no longer be needed in any circumstances, and if they are, the
SQLAlchemy project needs to know what those cases are and why.
Currently, hundreds of Unicode round trip tests pass across all major
databases without the use of this flag so there is a fairly high level
of confidence that they are no longer needed except in arguable non use
cases such as accessing mis-encoded data from a legacy database, which
would be better suited using custom types.

#4393(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4393

8.4.1.33 Dialect Improvements and Changes - PostgreSQL
......................................................

8.4.1.34 Added basic reflection support for PostgreSQL partitioned tables
.........................................................................

SQLAlchemy can render the “PARTITION BY” sequence within a PostgreSQL
CREATE TABLE statement using the flag ‘postgresql_partition_by’, added
in version 1.2.6.  However, the ‘'p'’ type was not part of the
reflection queries used until now.

Given a schema such as:

     dv = Table(
         'data_values', metadata,
         Column('modulus', Integer, nullable=False),
         Column('data', String(30)),
         postgresql_partition_by='range(modulus)')

     sa.event.listen(
         dv,
         "after_create",
         sa.DDL(
             "CREATE TABLE data_values_4_10 PARTITION OF data_values "
             "FOR VALUES FROM (4) TO (10)")
     )

The two table names ‘'data_values'’ and ‘'data_values_4_10'’ will come
back from Inspector.get_table_names() and additionally the
columns will come back from ‘Inspector.get_columns('data_values')’ as
well as ‘Inspector.get_columns('data_values_4_10')’.  This also extends
to the use of ‘Table(..., autoload=True)’ with these tables.

#4237(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4237

8.4.1.35 Dialect Improvements and Changes - MySQL
.................................................

8.4.1.36 Protocol-level ping now used for pre-ping
..................................................

The MySQL dialects including mysqlclient, python-mysql, PyMySQL and
mysql-connector-python now use the ‘connection.ping()’ method for the
pool pre-ping feature, described at Disconnect Handling - Pessimistic.
This is a much more lightweight ping than the
previous method of emitting “SELECT 1” on the connection.

8.4.1.37 Control of parameter ordering within ON DUPLICATE KEY UPDATE
.....................................................................

The order of UPDATE parameters in the ‘ON DUPLICATE KEY UPDATE’ clause
can now be explicitly ordered by passing a list of 2-tuples:

     from sqlalchemy.dialects.mysql import insert

     insert_stmt = insert(my_table).values(
         id='some_existing_id',
         data='inserted value')

     on_duplicate_key_stmt = insert_stmt.on_duplicate_key_update(
         [
             ("data", "some data"),
             ("updated_at", func.current_timestamp()),
         ],
     )

See also
........

See INSERT…ON DUPLICATE KEY UPDATE (Upsert).

8.4.1.38 Dialect Improvements and Changes - SQLite
..................................................

8.4.1.39 Support for SQLite JSON Added
......................................

A new datatype JSON is added which implements SQLite’s json
member access functions on behalf of the JSON base datatype.
The SQLite ‘JSON_EXTRACT’ and ‘JSON_QUOTE’ functions are used by the
implementation to provide basic JSON support.

Note that the name of the datatype itself as rendered in the database is
the name “JSON”.  This will create a SQLite datatype with “numeric”
affinity, which normally should not be an issue except in the case of a
JSON value that consists of single integer value.  Nevertheless,
following an example in SQLite’s own documentation at
‘https://www.sqlite.org/json1.html’ the name JSON is being used for its
familiarity.

#3850(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3850

8.4.1.40 Support for SQLite ON CONFLICT in constraints added
............................................................

SQLite supports a non-standard ON CONFLICT clause that may be specified
for standalone constraints as well as some column-inline constraints
such as NOT NULL. Support has been added for these clauses via the
‘sqlite_on_conflict’ keyword added to objects like
UniqueConstraint as well as several Column. -specific
variants:

     some_table = Table(
         'some_table', metadata,
         Column('id', Integer, primary_key=True, sqlite_on_conflict_primary_key='FAIL'),
         Column('data', Integer),
         UniqueConstraint('id', 'data', sqlite_on_conflict='IGNORE')
     )

The above table would render in a CREATE TABLE statement as:

     CREATE TABLE some_table (
         id INTEGER NOT NULL,
         data INTEGER,
         PRIMARY KEY (id) ON CONFLICT FAIL,
         UNIQUE (id, data) ON CONFLICT IGNORE
     )

See also
........

See ON CONFLICT support for constraints.

#4360(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4360

8.4.1.41 Dialect Improvements and Changes - Oracle
..................................................

8.4.1.42 National char datatypes de-emphasized for generic unicode, re-enabled with option
..........................................................................................

The Unicode and UnicodeText datatypes by
default now correspond to the ‘VARCHAR2’ and ‘CLOB’ datatypes on Oracle,
rather than ‘NVARCHAR2’ and ‘NCLOB’ (otherwise known as “national”
character set types).  This will be seen in behaviors such as that of
how they render in ‘CREATE TABLE’ statements, as well as that no type
object will be passed to ‘setinputsizes()’ when bound parameters using
Unicode or UnicodeText are used; cx_Oracle
handles the string value natively.  This change is based on advice from
cx_Oracle’s maintainer that the “national” datatypes in Oracle are
largely obsolete and are not performant.  They also interfere in some
situations such as when applied to the format specifier for functions
like ‘trunc()’.

The one case where ‘NVARCHAR2’ and related types may be needed is for a
database that is not using a Unicode-compliant character set.  In this
case, the flag ‘use_nchar_for_unicode’ can be passed to
create_engine() to re-enable the old behavior.

As always, using the ‘NVARCHAR2’ and NCLOB datatypes
explicitly will continue to make use of ‘NVARCHAR2’ and ‘NCLOB’,
including within DDL as well as when handling bound parameters with
cx_Oracle’s ‘setinputsizes()’.

On the read side, automatic Unicode conversion under Python 2 has been
added to CHAR/VARCHAR/CLOB result rows, to match the behavior of
cx_Oracle under Python 3.  In order to mitigate the performance hit that
the cx_Oracle dialect had previously with this behavior under Python 2,
SQLAlchemy’s very performant (when C extensions are built) native
Unicode handlers are used under Python 2.  The automatic unicode
coercion can be disabled by setting the ‘coerce_to_unicode’ flag to
False.  This flag now defaults to True and applies to all string data
returned in a result set that isn’t explicitly under Unicode
or Oracle’s NVARCHAR2/NCHAR/NCLOB datatypes.

#4242(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4242

8.4.1.43 cx_Oracle connect arguments modernized, deprecated parameters removed
..............................................................................

A series of modernizations to the parameters accepted by the cx_oracle
dialect as well as the URL string:

   * The deprecated parameters ‘auto_setinputsizes’, ‘allow_twophase’,
     ‘exclude_setinputsizes’ are removed.

   * The value of the ‘threaded’ parameter, which has always been
     defaulted to True for the SQLAlchemy dialect, is no longer
     generated by default.  The SQLAlchemy Connection object
     is not considered to be thread-safe itself so there’s no need for
     this flag to be passed.

   * It’s deprecated to pass ‘threaded’ to create_engine().
     itself.  To set the value of ‘threaded’ to ‘True’, pass it to
     either the create_engine.connect_args dictionary or
     use the query string e.g.  ‘oracle+cx_oracle://...?threaded=true’.

   * All parameters passed on the URL query string that are not
     otherwise specially consumed are now passed to the
     cx_Oracle.connect() function.  A selection of these are also
     coerced either into cx_Oracle constants or booleans including
     ‘mode’, ‘purity’, ‘events’, and ‘threaded’.

   * As was the case earlier, all cx_Oracle ‘.connect()’ arguments are
     accepted via the create_engine.connect_args
     dictionary, the documentation was inaccurate regarding this.

#4369(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4369

8.4.1.44 Dialect Improvements and Changes - SQL Server
......................................................

8.4.1.45 Support for pyodbc fast_executemany
............................................

Pyodbc’s recently added “fast_executemany” mode, available when using
the Microsoft ODBC driver, is now an option for the pyodbc / mssql
dialect.  Pass it via create_engine():

     engine = create_engine(
         "mssql+pyodbc://scott:tiger@mssql2017:1433/test?driver=ODBC+Driver+13+for+SQL+Server",
         fast_executemany=True)

See also
........

See Fast Executemany Mode.

#4158(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4158

8.4.1.46 New parameters to affect IDENTITY start and increment, use of Sequence deprecated
..........................................................................................

SQL Server as of SQL Server 2012 now supports sequences with real
‘CREATE SEQUENCE’ syntax.  In #4235(1), SQLAlchemy will add support for
these using Sequence in the same way as for any other
dialect.  However, the current situation is that Sequence
has been repurposed on SQL Server specifically in order to affect the
“start” and “increment” parameters for the ‘IDENTITY’ specification on a
primary key column.  In order to make the transition towards normal
sequences being available as well, using Sequence will emit
a deprecation warning throughout the 1.3 series.  In order to affect
“start” and “increment”, use the new ‘mssql_identity_start’ and
‘mssql_identity_increment’ parameters on Column:

     test = Table(
         'test', metadata,
         Column(
             'id', Integer, primary_key=True, mssql_identity_start=100,
              mssql_identity_increment=10
         ),
         Column('name', String(20))
     )

In order to emit ‘IDENTITY’ on a non-primary key column, which is a
little-used but valid SQL Server use case, use the
Column.autoincrement flag, setting it to ‘True’ on the target
column, ‘False’ on any integer primary key column:

     test = Table(
         'test', metadata,
         Column('id', Integer, primary_key=True, autoincrement=False),
         Column('number', Integer, autoincrement=True)
     )

See also
........

See Auto Increment Behavior / IDENTITY Columns.

#4362(2)

#4235(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4235

   (2) http://www.sqlalchemy.org/trac/ticket/4362

   (3) http://www.sqlalchemy.org/trac/ticket/4235

8.4.1.47 Changed StatementError formatting (newlines and %s)
............................................................

Two changes are introduced to the string representation for
‘StatementError’.  The “detail” and “SQL” portions of the string
representation are now separated by newlines, and newlines that are
present in the original SQL statement are maintained.  The goal is to
improve readability while still keeping the original error message on
one line for logging purposes.

This means that an error message that previously looked like this:

     sqlalchemy.exc.StatementError: (sqlalchemy.exc.InvalidRequestError) A value is required for bind parameter 'id' [SQL: 'select * from reviews\nwhere id = ?'] (Background on this error at: http://sqlalche.me/e/cd3x)

Will now look like this:

     sqlalchemy.exc.StatementError: (sqlalchemy.exc.InvalidRequestError) A value is required for bind parameter 'id'
     [SQL: select * from reviews
     where id = ?]
     (Background on this error at: http://sqlalche.me/e/cd3x)

The primary impact of this change is that consumers can no longer assume
that a complete exception message is on a single line, however the
original “error” portion that is generated from the DBAPI driver or
SQLAlchemy internals will still be on the first line.

#4500(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4500

8.4.2 What’s New in SQLAlchemy 1.2?
-----------------------------------

     About this Document: This document describes changes between
     SQLAlchemy version 1.1 and SQLAlchemy version 1.2.

8.4.2.1 Introduction
....................

This guide introduces what’s new in SQLAlchemy version 1.2, and also
documents changes which affect users migrating their applications from
the 1.1 series of SQLAlchemy to 1.2.

Please carefully review the sections on behavioral changes for
potentially backwards-incompatible changes in behavior.

8.4.2.2 Platform Support
........................

8.4.2.3 Targeting Python 2.7 and Up
...................................

SQLAlchemy 1.2 now moves the minimum Python version to 2.7, no longer
supporting 2.6.  New language features are expected to be merged into
the 1.2 series that were not supported in Python 2.6.  For Python 3
support, SQLAlchemy is currently tested on versions 3.5 and 3.6.

8.4.2.4 New Features and Improvements - ORM
...........................................

8.4.2.5 “Baked” loading now the default for lazy loads
......................................................

The sqlalchemy.ext.baked extension, first introduced in the
1.0 series, allows for the construction of a so-called BakedQuery
object, which is an object that generates a Query
object in conjunction with a cache key representing the structure of the
query; this cache key is then linked to the resulting string SQL
statement so that subsequent use of another BakedQuery with
the same structure will bypass all the overhead of building the
Query object, building the core select() object within,
as well as the compilation of the select() into a string,
cutting out well the majority of function call overhead normally
associated with constructing and emitting an ORM Query
object.

The BakedQuery is now used by default by the ORM when it
generates a “lazy” query for the lazy load of a relationship()
construct, e.g.  that of the default ‘lazy="select"’ relationship
loader strategy.  This will allow for a significant reduction in
function calls within the scope of an application’s use of lazy load
queries to load collections and related objects.  Previously, this
feature was available in 1.0 and 1.1 through the use of a global API
method or by using the ‘baked_select’ strategy, it’s now the only
implementation for this behavior.  The feature has also been improved
such that the caching can still take place for objects that have
additional loader options in effect subsequent to the lazy load.

The caching behavior can be disabled on a per-relationship basis using
the relationship.bake_queries flag, which is available for
very unusual cases, such as a relationship that uses a custom
Query implementation that’s not compatible with caching.

#3954(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3954

8.4.2.6 New “selectin” eager loading, loads all collections at once using IN
............................................................................

A new eager loader called “selectin” loading is added, which in many
ways is similar to “subquery” loading, however produces a simpler SQL
statement that is cacheable as well as more efficient.

Given a query as below:

     q = session.query(User).\
         filter(User.name.like('%ed%')).\
         options(subqueryload(User.addresses))

The SQL produced would be the query against ‘User’ followed by the
subqueryload for ‘User.addresses’ (note the parameters are also listed):

     SELECT users.id AS users_id, users.name AS users_name
     FROM users
     WHERE users.name LIKE ?
     ('%ed%',)

     SELECT addresses.id AS addresses_id,
            addresses.user_id AS addresses_user_id,
            addresses.email_address AS addresses_email_address,
            anon_1.users_id AS anon_1_users_id
     FROM (SELECT users.id AS users_id
     FROM users
     WHERE users.name LIKE ?) AS anon_1
     JOIN addresses ON anon_1.users_id = addresses.user_id
     ORDER BY anon_1.users_id
     ('%ed%',)

With “selectin” loading, we instead get a SELECT that refers to the
actual primary key values loaded in the parent query:

     q = session.query(User).\
         filter(User.name.like('%ed%')).\
         options(selectinload(User.addresses))

Produces:

     SELECT users.id AS users_id, users.name AS users_name
     FROM users
     WHERE users.name LIKE ?
     ('%ed%',)

     SELECT users_1.id AS users_1_id,
            addresses.id AS addresses_id,
            addresses.user_id AS addresses_user_id,
            addresses.email_address AS addresses_email_address
     FROM users AS users_1
     JOIN addresses ON users_1.id = addresses.user_id
     WHERE users_1.id IN (?, ?)
     ORDER BY users_1.id
     (1, 3)

The above SELECT statement includes these advantages:

   * It doesn’t use a subquery, just an INNER JOIN, meaning it will
     perform much better on a database like MySQL that doesn’t like
     subqueries

   * Its structure is independent of the original query; in conjunction
     with the new expanding IN parameter system we can in
     most cases use the “baked” query to cache the string SQL, reducing
     per-query overhead significantly

   * Because the query only fetches for a given list of primary key
     identifiers, “selectin” loading is potentially compatible with
     Query.yield_per() to operate on chunks of a SELECT
     result at a time, provided that the database driver allows for
     multiple, simultaneous cursors (SQLite, PostgreSQL; `not' MySQL
     drivers or SQL Server ODBC drivers).  Neither joined eager loading
     nor subquery eager loading are compatible with
     Query.yield_per().

The disadvantages of selectin eager loading are potentially large SQL
queries, with large lists of IN parameters.  The list of IN parameters
themselves are chunked in groups of 500, so a result set of more than
500 lead objects will have more additional “SELECT IN” queries
following.  Also, support for composite primary keys depends on the
database’s ability to use tuples with IN, e.g.  ‘(table.column_one,
table_column_two) IN ((?, ?), (?, ?) (?, ?))’.  Currently, PostgreSQL
and MySQL are known to be compatible with this syntax, SQLite is not.

See also
........

See Select IN loading.

#3944(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3944

8.4.2.7 “selectin” polymorphic loading, loads subclasses using separate IN queries
..................................................................................

Along similar lines as the “selectin” relationship loading feature just
described at New “selectin” eager loading, loads all collections at once using IN
is “selectin” polymorphic loading.  This is a
polymorphic loading feature tailored primarily towards joined eager
loading that allows the loading of the base entity to proceed with a
simple SELECT statement, but then the attributes of the additional
subclasses are loaded with additional SELECT statements:

     from sqlalchemy.orm import selectin_polymorphic

     query = session.query(Employee).options(
         selectin_polymorphic(Employee, [Manager, Engineer])
     )

     {opensql}query.all()
     SELECT
         employee.id AS employee_id,
         employee.name AS employee_name,
         employee.type AS employee_type
     FROM employee
     ()

     SELECT
         engineer.id AS engineer_id,
         employee.id AS employee_id,
         employee.type AS employee_type,
         engineer.engineer_name AS engineer_engineer_name
     FROM employee JOIN engineer ON employee.id = engineer.id
     WHERE employee.id IN (?, ?) ORDER BY employee.id
     (1, 2)

     SELECT
         manager.id AS manager_id,
         employee.id AS employee_id,
         employee.type AS employee_type,
         manager.manager_name AS manager_manager_name
     FROM employee JOIN manager ON employee.id = manager.id
     WHERE employee.id IN (?) ORDER BY employee.id
     (3,)

See also
........

See Polymorphic Selectin Loading.

#3948(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3948

8.4.2.8 ORM attributes that can receive ad-hoc SQL expressions
..............................................................

A new ORM attribute type query_expression() is added which
is similar to deferred(), except its SQL expression is
determined at query time using a new option with_expression();
if not specified, the attribute defaults to ‘None’:

     from sqlalchemy.orm import query_expression
     from sqlalchemy.orm import with_expression

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)
         x = Column(Integer)
         y = Column(Integer)

         # will be None normally...
         expr = query_expression()

     # but let's give it x + y
     a1 = session.query(A).options(
         with_expression(A.expr, A.x + A.y)).first()
     print(a1.expr)

See also
........

See Query-time SQL expressions as mapped attributes.

#3058(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3058

8.4.2.9 ORM Support of multiple-table deletes
.............................................

The ORM Query.delete() method supports multiple-table
criteria for DELETE, as introduced in Multiple-table criteria support for DELETE.
The feature works in the same manner as
multiple-table criteria for UPDATE, first introduced in 0.8 and
described at Query.update() supports UPDATE..FROM.

Below, we emit a DELETE against ‘SomeEntity’, adding a FROM clause (or
equivalent, depending on backend) against ‘SomeOtherEntity’:

     query(SomeEntity).\
         filter(SomeEntity.id==SomeOtherEntity.id).\
         filter(SomeOtherEntity.foo=='bar').\
         delete()

See also
........

See Multiple-table criteria support for DELETE.

#959(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/959

8.4.2.10 Support for bulk updates of hybrids, composites
........................................................

Both hybrid attributes (e.g.  see sqlalchemy.ext.hybrid) as well
as composite attributes (see Composite Column Types) now support
being used in the SET clause of an UPDATE statement when using
Query.update().

For hybrids, simple expressions can be used directly, or the new
decorator hybrid_property.update_expression() can be used to
break a value into multiple columns/expressions:

     class Person(Base):
         # ...

         first_name = Column(String(10))
         last_name = Column(String(10))

         @hybrid.hybrid_property
         def name(self):
             return self.first_name + ' ' + self.last_name

         @name.expression
         def name(cls):
             return func.concat(cls.first_name, ' ', cls.last_name)

         @name.update_expression
         def name(cls, value):
             f, l = value.split(' ', 1)
             return [(cls.first_name, f), (cls.last_name, l)]

Above, an UPDATE can be rendered using:

     session.query(Person).filter(Person.id == 5).update(
         {Person.name: "Dr. No"})

Similar functionality is available for composites, where composite
values will be broken out into their individual columns for bulk UPDATE:

     session.query(Vertex).update({Edge.start: Point(3, 4)})

See also
........

See Allowing Bulk ORM Update.

8.4.2.11 Hybrid attributes support reuse among subclasses, redefinition of @getter
..................................................................................

The sqlalchemy.ext.hybrid.hybrid_property class now supports
calling mutators like ‘@setter’, ‘@expression’ etc.  multiple times
across subclasses, and now provides a ‘@getter’ mutator, so that a
particular hybrid can be repurposed across subclasses or other classes.
This now is similar to the behavior of ‘@property’ in standard Python:

     class FirstNameOnly(Base):
         # ...

         first_name = Column(String)

         @hybrid_property
         def name(self):
             return self.first_name

         @name.setter
         def name(self, value):
             self.first_name = value

     class FirstNameLastName(FirstNameOnly):
         # ...

         last_name = Column(String)

         @FirstNameOnly.name.getter
         def name(self):
             return self.first_name + ' ' + self.last_name

         @name.setter
         def name(self, value):
             self.first_name, self.last_name = value.split(' ', maxsplit=1)

         @name.expression
         def name(cls):
             return func.concat(cls.first_name, ' ', cls.last_name)

Above, the ‘FirstNameOnly.name’ hybrid is referenced by the
‘FirstNameLastName’ subclass in order to repurpose it specifically to
the new subclass.  This is achieved by copying the hybrid object to a
new one within each call to ‘@getter’, ‘@setter’, as well as in all
other mutator methods like ‘@expression’, leaving the previous hybrid’s
definition intact.  Previously, methods like ‘@setter’ would modify the
existing hybrid in-place, interfering with the definition on the
superclass.

     Note: Be sure to read the documentation at Reusing Hybrid Properties across Subclasses
     for important notes regarding
     how to override hybrid_property.expression() and
     hybrid_property.comparator(), as a special qualifier
     hybrid_property.overrides may be necessary to avoid name
     conflicts with QueryableAttribute in some cases.

     Note: This change in ‘@hybrid_property’ implies that when adding
     setters and other state to a ‘@hybrid_property’, the `methods must
     retain the name of the original hybrid', else the new hybrid with
     the additional state will be present on the class as the
     non-matching name.  This is the same behavior as that of the
     ‘@property’ construct that is part of standard Python:

          class FirstNameOnly(Base):
              @hybrid_property
              def name(self):
                  return self.first_name

              # WRONG - will raise AttributeError: can't set attribute when
              # assigning to .name
              @name.setter
              def _set_name(self, value):
                  self.first_name = value

          class FirstNameOnly(Base):
              @hybrid_property
              def name(self):
                  return self.first_name

              # CORRECT - note regular Python @property works the same way
              @name.setter
              def name(self, value):
                  self.first_name = value

#3911(1)

#3912(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3911

   (2) http://www.sqlalchemy.org/trac/ticket/3912

8.4.2.12 New bulk_replace event
...............................

To suit the validation use case described in A @validates method receives all values on bulk-collection set before comparison,
a
new AttributeEvents.bulk_replace() method is added, which is
called in conjunction with the AttributeEvents.append() and
AttributeEvents.remove() events.  “bulk_replace” is called
before “append” and “remove” so that the collection can be modified
ahead of comparison to the existing collection.  After that, individual
items are appended to a new target collection, firing off the “append”
event for items new to the collection, as was the previous behavior.
Below illustrates both “bulk_replace” and “append” at the same time,
including that “append” will receive an object already handled by
“bulk_replace” if collection assignment is used.  A new symbol
‘attributes.OP_BULK_REPLACE’ may be used to determine if this “append”
event is the second part of a bulk replace:

     from sqlalchemy.orm.attributes import OP_BULK_REPLACE

     @event.listens_for(SomeObject.collection, "bulk_replace")
     def process_collection(target, values, initiator):
         values[:] = [_make_value(value) for value in values]

     @event.listens_for(SomeObject.collection, "append", retval=True)
     def process_collection(target, value, initiator):
         # make sure bulk_replace didn't already do it
         if initiator is None or initiator.op is not OP_BULK_REPLACE:
             return _make_value(value)
         else:
             return value

#3896(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3896

8.4.2.13 New “modified” event handler for sqlalchemy.ext.mutable
................................................................

A new event handler AttributeEvents.modified() is added,
which is triggered corresponding to calls to the flag_modified()
method, which is normally called from the
sqlalchemy.ext.mutable extension:

     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.ext.mutable import MutableDict
     from sqlalchemy import event

     Base = declarative_base()

     class MyDataClass(Base):
         __tablename__ = 'my_data'
         id = Column(Integer, primary_key=True)
         data = Column(MutableDict.as_mutable(JSONEncodedDict))

     @event.listens_for(MyDataClass.data, "modified")
     def modified_json(instance):
         print("json value modified:", instance.data)

Above, the event handler will be triggered when an in-place change to
the ‘.data’ dictionary occurs.

#3303(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3303

8.4.2.14 Added “for update” arguments to Session.refresh
........................................................

Added new argument Session.refresh.with_for_update to the
Session.refresh() method.  When the ‘Query.with_lockmode()’
method were deprecated in favor of Query.with_for_update(),
the Session.refresh() method was never updated to reflect
the new option:

     session.refresh(some_object, with_for_update=True)

The Session.refresh.with_for_update argument accepts a
dictionary of options that will be passed as the same arguments which
are sent to Query.with_for_update():

     session.refresh(some_objects, with_for_update={"read": True})

The new parameter supersedes the Session.refresh.lockmode
parameter.

#3991(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3991

8.4.2.15 In-place mutation operators work for MutableSet, MutableList
.....................................................................

Implemented the in-place mutation operators ‘__ior__’, ‘__iand__’,
‘__ixor__’ and ‘__isub__’ for MutableSet and ‘__iadd__’ for
MutableList.  While these methods would successfully update
the collection previously, they would not correctly fire off change
events.  The operators mutate the collection as before but additionally
emit the correct change event so that the change becomes part of the
next flush process:

     model = session.query(MyModel).first()
     model.json_set &= {1, 3}

#3853(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3853

8.4.2.16 AssociationProxy any(), has(), contains() work with chained association proxies
........................................................................................

The ‘AssociationProxy.any()’, ‘AssociationProxy.has()’ and
‘AssociationProxy.contains()’ comparison methods now support linkage to
an attribute that is itself also an AssociationProxy,
recursively.  Below, ‘A.b_values’ is an association proxy that links to
‘AtoB.bvalue’, which is itself an association proxy onto ‘B’:

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)

         b_values = association_proxy("atob", "b_value")
         c_values = association_proxy("atob", "c_value")

     class B(Base):
         __tablename__ = 'b'
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey('a.id'))
         value = Column(String)

         c = relationship("C")

     class C(Base):
         __tablename__ = 'c'
         id = Column(Integer, primary_key=True)
         b_id = Column(ForeignKey('b.id'))
         value = Column(String)

     class AtoB(Base):
         __tablename__ = 'atob'

         a_id = Column(ForeignKey('a.id'), primary_key=True)
         b_id = Column(ForeignKey('b.id'), primary_key=True)

         a = relationship("A", backref="atob")
         b = relationship("B", backref="atob")

         b_value = association_proxy("b", "value")
         c_value = association_proxy("b", "c")

We can query on ‘A.b_values’ using ‘AssociationProxy.contains()’ to
query across the two proxies ‘A.b_values’, ‘AtoB.b_value’:

     >>> s.query(A).filter(A.b_values.contains('hi')).all()
     {opensql}SELECT a.id AS a_id
     FROM a
     WHERE EXISTS (SELECT 1
     FROM atob
     WHERE a.id = atob.a_id AND (EXISTS (SELECT 1
     FROM b
     WHERE b.id = atob.b_id AND b.value = :value_1)))

Similarly, we can query on ‘A.c_values’ using ‘AssociationProxy.any()’
to query across the two proxies ‘A.c_values’, ‘AtoB.c_value’:

     >>> s.query(A).filter(A.c_values.any(value='x')).all()
     {opensql}SELECT a.id AS a_id
     FROM a
     WHERE EXISTS (SELECT 1
     FROM atob
     WHERE a.id = atob.a_id AND (EXISTS (SELECT 1
     FROM b
     WHERE b.id = atob.b_id AND (EXISTS (SELECT 1
     FROM c
     WHERE b.id = c.b_id AND c.value = :value_1)))))

#3769(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3769

8.4.2.17 Identity key enhancements to support sharding
......................................................

The identity key structure used by the ORM now contains an additional
member, so that two identical primary keys that originate from different
contexts can co-exist within the same identity map.

The example at Horizontal Sharding has been updated to
illustrate this behavior.  The example shows a sharded class
‘WeatherLocation’ that refers to a dependent ‘WeatherReport’ object,
where the ‘WeatherReport’ class is mapped to a table that stores a
simple integer primary key.  Two ‘WeatherReport’ objects from different
databases may have the same primary key value.  The example now
illustrates that a new ‘identity_token’ field tracks this difference so
that the two objects can co-exist in the same identity map:

     tokyo = WeatherLocation('Asia', 'Tokyo')
     newyork = WeatherLocation('North America', 'New York')

     tokyo.reports.append(Report(80.0))
     newyork.reports.append(Report(75))

     sess = create_session()

     sess.add_all([tokyo, newyork, quito])

     sess.commit()

     # the Report class uses a simple integer primary key.  So across two
     # databases, a primary key will be repeated.  The "identity_token" tracks
     # in memory that these two identical primary keys are local to different
     # databases.

     newyork_report = newyork.reports[0]
     tokyo_report = tokyo.reports[0]

     assert inspect(newyork_report).identity_key == (Report, (1, ), "north_america")
     assert inspect(tokyo_report).identity_key == (Report, (1, ), "asia")

     # the token representing the originating shard is also available directly

     assert inspect(newyork_report).identity_token == "north_america"
     assert inspect(tokyo_report).identity_token == "asia"

#4137(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4137

8.4.2.18 New Features and Improvements - Core
.............................................

8.4.2.19 Boolean datatype now enforces strict True/False/None values
....................................................................

In version 1.1, the change described in Non-native boolean integer values coerced to zero/one/None in all cases
produced an
unintended side effect of altering the way Boolean behaves
when presented with a non-integer value, such as a string.  In
particular, the string value ‘"0"’, which would previously result in the
value ‘False’ being generated, would now produce ‘True’.  Making matters
worse, the change in behavior was only for some backends and not others,
meaning code that sends string ‘"0"’ values to Boolean would
break inconsistently across backends.

The ultimate solution to this problem is that `string values are not
supported with Boolean', so in 1.2 a hard ‘TypeError’ is raised if a
non-integer / True/False/None value is passed.  Additionally, only the
integer values 0 and 1 are accepted.

To accommodate for applications that wish to have more liberal
interpretation of boolean values, the TypeDecorator should
be used.  Below illustrates a recipe that will allow for the “liberal”
behavior of the pre-1.1 Boolean datatype:

     from sqlalchemy import Boolean
     from sqlalchemy import TypeDecorator

     class LiberalBoolean(TypeDecorator):
         impl = Boolean

         def process_bind_param(self, value, dialect):
             if value is not None:
                 value = bool(int(value))
             return value

#4102(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4102

8.4.2.20 Pessimistic disconnection detection added to the connection pool
.........................................................................

The connection pool documentation has long featured a recipe for using
the ConnectionEvents.engine_connect() engine event to emit
a simple statement on a checked-out connection to test it for liveness.
The functionality of this recipe has now been added into the connection
pool itself, when used in conjunction with an appropriate dialect.
Using the new parameter create_engine.pool_pre_ping, each
connection checked out will be tested for freshness before being
returned:

     engine = create_engine("mysql+pymysql://", pool_pre_ping=True)

While the “pre-ping” approach adds a small amount of latency to the
connection pool checkout, for a typical application that is
transactionally-oriented (which includes most ORM applications), this
overhead is minimal, and eliminates the problem of acquiring a stale
connection that will raise an error, requiring that the application
either abandon or retry the operation.

The feature does `not' accommodate for connections dropped within an
ongoing transaction or SQL operation.  If an application must recover
from these as well, it would need to employ its own operation retry
logic to anticipate these errors.

See also
........

See Disconnect Handling - Pessimistic.

#3919(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3919

8.4.2.21 The IN / NOT IN operator’s empty collection behavior is now configurable; default expression simplified
................................................................................................................

An expression such as ‘column.in_([])’, which is assumed to be false,
now produces the expression ‘1 != 1’ by default, instead of ‘column !=
column’.  This will `change the result' of a query that is comparing a
SQL expression or column that evaluates to NULL when compared to an
empty set, producing a boolean value false or true (for NOT IN) rather
than NULL. The warning that would emit under this condition is also
removed.  The old behavior is available using the
create_engine.empty_in_strategy parameter to
create_engine().

In SQL, the IN and NOT IN operators do not support comparison to a
collection of values that is explicitly empty; meaning, this syntax is
illegal:

     mycolumn IN ()

To work around this, SQLAlchemy and other database libraries detect this
condition and render an alternative expression that evaluates to false,
or in the case of NOT IN, to true, based on the theory that “col IN ()”
is always false since nothing is in “the empty set”.  Typically, in
order to produce a false/true constant that is portable across databases
and works in the context of the WHERE clause, a simple tautology such as
‘1 != 1’ is used to evaluate to false and ‘1 = 1’ to evaluate to true (a
simple constant “0” or “1” often does not work as the target of a WHERE
clause).

SQLAlchemy in its early days began with this approach as well, but soon
it was theorized that the SQL expression ‘column IN ()’ would not
evaluate to false if the “column” were NULL; instead, the expression
would produce NULL, since “NULL” means “unknown”, and comparisons to
NULL in SQL usually produce NULL.

To simulate this result, SQLAlchemy changed from using ‘1 != 1’ to
instead use th expression ‘expr != expr’ for empty “IN” and ‘expr =
expr’ for empty “NOT IN”; that is, instead of using a fixed value we use
the actual left-hand side of the expression.  If the left-hand side of
the expression passed evaluates to NULL, then the comparison overall
also gets the NULL result instead of false or true.

Unfortunately, users eventually complained that this expression had a
very severe performance impact on some query planners.  At that point, a
warning was added when an empty IN expression was encountered, favoring
that SQLAlchemy continues to be “correct” and urging users to avoid code
that generates empty IN predicates in general, since typically they can
be safely omitted.  However, this is of course burdensome in the case of
queries that are built up dynamically from input variables, where an
incoming set of values might be empty.

In recent months, the original assumptions of this decision have been
questioned.  The notion that the expression “NULL IN ()” should return
NULL was only theoretical, and could not be tested since databases don’t
support that syntax.  However, as it turns out, you can in fact ask a
relational database what value it would return for “NULL IN ()” by
simulating the empty set as follows:

     SELECT NULL IN (SELECT 1 WHERE 1 != 1)

With the above test, we see that the databases themselves can’t agree on
the answer.  PostgreSQL, considered by most to be the most “correct”
database, returns False; because even though “NULL” represents
“unknown”, the “empty set” means nothing is present, including all
unknown values.  On the other hand, MySQL and MariaDB return NULL for
the above expression, defaulting to the more common behavior of “all
comparisons to NULL return NULL”.

SQLAlchemy’s SQL architecture is more sophisticated than it was when
this design decision was first made, so we can now allow either behavior
to be invoked at SQL string compilation time.  Previously, the
conversion to a comparison expression were done at construction time,
that is, the moment the ColumnOperators.in_() or
ColumnOperators.notin_() operators were invoked.  With the
compilation-time behavior, the dialect itself can be instructed to
invoke either approach, that is, the “static” ‘1 != 1’ comparison or the
“dynamic” ‘expr != expr’ comparison.  The default has been `changed' to
be the “static” comparison, since this agrees with the behavior that
PostgreSQL would have in any case and this is also what the vast
majority of users prefer.  This will `change the result' of a query that
is comparing a null expression to the empty set, particularly one that
is querying for the negation ‘where(~null_expr.in_([]))’, since this now
evaluates to true and not NULL.

The behavior can now be controlled using the flag
create_engine.empty_in_strategy, which defaults to the ‘"static"’
setting, but may also be set to ‘"dynamic"’ or ‘"dynamic_warn"’, where
the ‘"dynamic_warn"’ setting is equivalent to the previous behavior of
emitting ‘expr != expr’ as well as a performance warning.  However, it
is anticipated that most users will appreciate the “static” default.

#3907(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3907

8.4.2.22 Late-expanded IN parameter sets allow IN expressions with cached statements
....................................................................................

Added a new kind of 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:

     stmt = select([table]).where(
         table.c.col.in_(bindparam('foo', expanding=True))
     conn.execute(stmt, {"foo": [1, 2, 3]})

The feature should be regarded as `experimental' within the 1.2 series.

#3953(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3953

8.4.2.23 Flattened operator precedence for comparison operators
...............................................................

The operator precedence for operators like IN, LIKE, equals, IS, MATCH,
and other comparison operators has been flattened into one level.  This
will have the effect of more parenthesization being generated when
comparison operators are combined together, such as:

     (column('q') == null()) != (column('y') == null())

Will now generate ‘(q IS NULL) != (y IS NULL)’ rather than ‘q IS NULL !=
y IS NULL’.

#3999(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3999

8.4.2.24 Support for SQL Comments on Table, Column, includes DDL, reflection
............................................................................

The Core receives support for string comments associated with tables and
columns.  These are specified via the Table.comment and
Column.comment arguments:

     Table(
         'my_table', metadata,
         Column('q', Integer, comment="the Q value"),
         comment="my Q table"
     )

Above, DDL will be rendered appropriately upon table create to associate
the above comments with the table/ column within the schema.  When the
above table is autoloaded or inspected with
Inspector.get_columns(), the comments are included.  The table
comment is also available independently using the
Inspector.get_table_comment() method.

Current backend support includes MySQL, PostgreSQL, and Oracle.

#1546(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1546

8.4.2.25 Multiple-table criteria support for DELETE
...................................................

The Delete construct now supports multiple-table criteria,
implemented for those backends which support it, currently these are
PostgreSQL, MySQL and Microsoft SQL Server (support is also added to the
currently non-working Sybase dialect).  The feature works in the same
was as that of multiple-table criteria for UPDATE, first introduced in
the 0.7 and 0.8 series.

Given a statement as:

     stmt = users.delete().\
             where(users.c.id == addresses.c.id).\
             where(addresses.c.email_address.startswith('ed%'))
     conn.execute(stmt)

The resulting SQL from the above statement on a PostgreSQL backend would
render as:

     DELETE FROM users USING addresses
     WHERE users.id = addresses.id
     AND (addresses.email_address LIKE %(email_address_1)s || '%%')

See also
........

See Multiple Table Deletes.

#959(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/959

8.4.2.26 New “autoescape” option for startswith(), endswith()
.............................................................

The “autoescape” parameter is added to
ColumnOperators.startswith(), ColumnOperators.endswith(),
see ColumnOperators.contains().  This parameter when set to
‘True’ will automatically escape all occurrences of ‘%’, ‘_’ with an
escape character, which defaults to a forwards slash ‘/’; occurrences of
the escape character itself are also escaped.  The forwards slash is
used to avoid conflicts with settings like PostgreSQL’s
‘standard_confirming_strings’, whose default value changed as of
PostgreSQL 9.1, and MySQL’s ‘NO_BACKSLASH_ESCAPES’ settings.  The
existing “escape” parameter can now be used to change the autoescape
character, if desired.

     Note: This feature has been changed as of 1.2.0 from its initial
     implementation in 1.2.0b2 such that autoescape is now passed as a
     boolean value, rather than a specific character to use as the
     escape character.

An expression such as:

     >>> column('x').startswith('total%score', autoescape=True)

Renders as:

     x LIKE :x_1 || '%' ESCAPE '/'

Where the value of the parameter “x_1” is ‘'total/%score'’.

Similarly, an expression that has backslashes:

     >>> column('x').startswith('total/score', autoescape=True)

Will render the same way, with the value of the parameter “x_1” as
‘'total//score'’.

#2694(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2694

8.4.2.27 Stronger typing added to “float” datatypes
...................................................

A series of changes allow for use of the Float datatype to
more strongly link itself to Python floating point values, instead of
the more generic Numeric.  The changes are mostly related to
ensuring that Python floating point values are not erroneously coerced
to ‘Decimal()’, and are coerced to ‘float’ if needed, on the result
side, if the application is working with plain floats.

   * A plain Python “float” value passed to a SQL expression will now be
     pulled into a literal parameter with the type Float;
     previously, the type was Numeric, with the default
     “asdecimal=True” flag, which meant the result type would coerce to
     ‘Decimal()’.  In particular, this would emit a confusing warning on
     SQLite:

          float_value = connection.scalar(
              select([literal(4.56)])   # the "BindParameter" will now be
                                        # Float, not Numeric(asdecimal=True)
          )

   * Math operations between Numeric, Float, and
     Integer will now preserve the Numeric or
     Float type in the resulting expression’s type,
     including the ‘asdecimal’ flag as well as if the type should be
     Float:

          # asdecimal flag is maintained
          expr = column('a', Integer) * column('b', Numeric(asdecimal=False))
          assert expr.type.asdecimal == False

          # Float subclass of Numeric is maintained
          expr = column('a', Integer) * column('b', Float())
          assert isinstance(expr.type, Float)

   * The Float datatype will apply the ‘float()’ processor
     to result values unconditionally if the DBAPI is known to support
     native ‘Decimal()’ mode.  Some backends do not always guarantee
     that a floating point number comes back as plain float and not
     precision numeric such as MySQL.

#4017(1)

#4018(2)

#4020(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4017

   (2) http://www.sqlalchemy.org/trac/ticket/4018

   (3) http://www.sqlalchemy.org/trac/ticket/4020

8.4.2.28 Support for GROUPING SETS, CUBE, ROLLUP
................................................

All three of GROUPING SETS, CUBE, ROLLUP are available via the ‘func’
namespace.  In the case of CUBE and ROLLUP, these functions already work
in previous versions, however for GROUPING SETS, a placeholder is added
to the compiler to allow for the space.  All three functions are named
in the documentation now:

     >>> from sqlalchemy import select, table, column, func, tuple_
     >>> t = table('t',
     ...           column('value'), column('x'),
     ...           column('y'), column('z'), column('q'))
     >>> stmt = select([func.sum(t.c.value)]).group_by(
     ...     func.grouping_sets(
     ...         tuple_(t.c.x, t.c.y),
     ...         tuple_(t.c.z, t.c.q),
     ...     )
     ... )
     >>> print(stmt)
     SELECT sum(t.value) AS sum_1
     FROM t GROUP BY GROUPING SETS((t.x, t.y), (t.z, t.q))

#3429(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3429

8.4.2.29 Parameter helper for multi-valued INSERT with contextual default generator
...................................................................................

A default generation function, e.g.  that described at
Context-Sensitive Default Functions, can look at the current
parameters relevant to the statement via the
DefaultExecutionContext.current_parameters attribute.  However,
in the case of a Insert construct that specifies multiple
VALUES clauses via the Insert.values() method, the
user-defined function is called multiple times, once for each parameter
set, however there was no way to know which subset of keys in
DefaultExecutionContext.current_parameters apply to that column.
A new function DefaultExecutionContext.get_current_parameters()
is added, which includes a keyword argument
DefaultExecutionContext.get_current_parameters.isolate_multiinsert_groups
defaulting to ‘True’, which performs the extra work of delivering
a sub-dictionary of DefaultExecutionContext.current_parameters
which has the names localized to the current VALUES clause being
processed:

     def mydefault(context):
         return context.get_current_parameters()['counter'] + 12

     mytable = Table('mytable', meta,
         Column('counter', Integer),
         Column('counter_plus_twelve',
                Integer, default=mydefault, onupdate=mydefault)
     )

     stmt = mytable.insert().values(
         [{"counter": 5}, {"counter": 18}, {"counter": 20}])

     conn.execute(stmt)

#4075(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4075

8.4.2.30 Key Behavioral Changes - ORM
.....................................

8.4.2.31 The after_rollback() Session event now emits before the expiration of objects
......................................................................................

The SessionEvents.after_rollback() event now has access to
the attribute state of objects before their state has been expired (e.g.
the “snapshot removal”).  This allows the event to be consistent with
the behavior of the SessionEvents.after_commit() event which
also emits before the “snapshot” has been removed:

     sess = Session()

     user = sess.query(User).filter_by(name='x').first()

     @event.listens_for(sess, "after_rollback")
     def after_rollback(session):
         # 'user.name' is now present, assuming it was already
         # loaded.  previously this would raise upon trying
         # to emit a lazy load.
         print("user name: %s" % user.name)

     @event.listens_for(sess, "after_commit")
     def after_commit(session):
         # 'user.name' is present, assuming it was already
         # loaded.  this is the existing behavior.
         print("user name: %s" % user.name)

     if should_rollback:
         sess.rollback()
     else:
         sess.commit()

Note that the Session will still disallow SQL from being
emitted within this event; meaning that unloaded attributes will still
not be able to load within the scope of the event.

#3934(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3934

8.4.2.32 Fixed issue involving single-table inheritance with ‘select_from()’
............................................................................

The Query.select_from() method now honors the single-table
inheritance column discriminator when generating SQL; previously, only
the expressions in the query column list would be taken into account.

Supposing ‘Manager’ is a subclass of ‘Employee’.  A query like the
following:

     sess.query(Manager.id)

Would generate SQL as:

     SELECT employee.id FROM employee WHERE employee.type IN ('manager')

However, if ‘Manager’ were only specified by Query.select_from()
and not in the columns list, the discriminator would not be added:

     sess.query(func.count(1)).select_from(Manager)

would generate:

     SELECT count(1) FROM employee

With the fix, see Query.select_from() now works correctly and we
get:

     SELECT count(1) FROM employee WHERE employee.type IN ('manager')

Applications that may have been working around this by supplying the
WHERE clause manually may need to be adjusted.

#3891(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3891

8.4.2.33 Previous collection is no longer mutated upon replacement
..................................................................

The ORM emits events whenever the members of a mapped collection change.
In the case of assigning a collection to an attribute that would replace
the previous collection, a side effect of this was that the collection
being replaced would also be mutated, which is misleading and
unnecessary:

     >>> a1, a2, a3 = Address('a1'), Address('a2'), Address('a3')
     >>> user.addresses = [a1, a2]

     >>> previous_collection = user.addresses

     # replace the collection with a new one
     >>> user.addresses = [a2, a3]

     >>> previous_collection
     [Address('a1'), Address('a2')]

Above, prior to the change, the ‘previous_collection’ would have had the
“a1” member removed, corresponding to the member that’s no longer in the
new collection.

#3913(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3913

8.4.2.34 A @validates method receives all values on bulk-collection set before comparison
.........................................................................................

A method that uses ‘@validates’ will now receive all members of a
collection during a “bulk set” operation, before comparison is applied
against the existing collection.

Given a mapping as:

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)
         bs = relationship("B")

         @validates('bs')
         def convert_dict_to_b(self, key, value):
             return B(data=value['data'])

     class B(Base):
         __tablename__ = 'b'
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey('a.id'))
         data = Column(String)

Above, we could use the validator as follows, to convert from an
incoming dictionary to an instance of ‘B’ upon collection append:

     a1 = A()
     a1.bs.append({"data": "b1"})

However, a collection assignment would fail, since the ORM would assume
incoming objects are already instances of ‘B’ as it attempts to compare
them to the existing members of the collection, before doing collection
appends which actually invoke the validator.  This would make it
impossible for bulk set operations to accommodate non-ORM objects like
dictionaries that needed up-front modification:

     a1 = A()
     a1.bs = [{"data": "b1"}]

The new logic uses the new AttributeEvents.bulk_replace()
event to ensure that all values are sent to the ‘@validates’ function up
front.

As part of this change, this means that validators will now receive
`all' members of a collection upon bulk set, not just the members that
are new.  Supposing a simple validator such as:

     class A(Base):
         # ...

         @validates('bs')
         def validate_b(self, key, value):
             assert value.data is not None
             return value

Above, if we began with a collection as:

     a1 = A()

     b1, b2 = B(data="one"), B(data="two")
     a1.bs = [b1, b2]

And then, replaced the collection with one that overlaps the first:

     b3 = B(data="three")
     a1.bs = [b2, b3]

Previously, the second assignment would trigger the ‘A.validate_b’
method only once, for the ‘b3’ object.  The ‘b2’ object would be seen as
being already present in the collection and not validated.  With the new
behavior, both ‘b2’ and ‘b3’ are passed to ‘A.validate_b’ before passing
onto the collection.  It is thus important that validation methods
employ idempotent behavior to suit such a case.

See also
........

See New bulk_replace event.

#3896(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3896

8.4.2.35 Use flag_dirty() to mark an object as “dirty” without any attribute changing
.....................................................................................

An exception is now raised if the flag_modified() function
is used to mark an attribute as modified that isn’t actually loaded:

     a1 = A(data='adf')
     s.add(a1)

     s.flush()

     # expire, similarly as though we said s.commit()
     s.expire(a1, 'data')

     # will raise InvalidRequestError
     attributes.flag_modified(a1, 'data')

This because the flush process will most likely fail in any case if the
attribute remains un-present by the time flush occurs.  To mark an
object as “modified” without referring to any attribute specifically, so
that it is considered within the flush process for the purpose of custom
event handlers such as SessionEvents.before_flush(), use the
new flag_dirty() function:

     from sqlalchemy.orm import attributes

     attributes.flag_dirty(a1)

#3753(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3753

8.4.2.36 “scope” keyword removed from scoped_session
....................................................

A very old and undocumented keyword argument ‘scope’ has been removed:

     from sqlalchemy.orm import scoped_session
     Session = scoped_session(sessionmaker())

     session = Session(scope=None)

The purpose of this keyword was an attempt to allow for variable
“scopes”, where ‘None’ indicated “no scope” and would therefore return a
new Session.  The keyword has never been documented and will
now raise ‘TypeError’ if encountered.  It is not anticipated that this
keyword is in use, however if users report issues related to this during
beta testing, it can be restored with a deprecation.

#3796(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3796

8.4.2.37 Refinements to post_update in conjunction with onupdate
................................................................

A relationship that uses the relationship.post_update
feature will now interact better with a column that has an
Column.onupdate value set.  If an object is inserted with an
explicit value for the column, it is re-stated during the UPDATE so that
the “onupdate” rule does not overwrite it:

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)
         favorite_b_id = Column(ForeignKey('b.id', name="favorite_b_fk"))
         bs = relationship("B", primaryjoin="A.id == B.a_id")
         favorite_b = relationship(
             "B", primaryjoin="A.favorite_b_id == B.id", post_update=True)
         updated = Column(Integer, onupdate=my_onupdate_function)

     class B(Base):
         __tablename__ = 'b'
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey('a.id', name="a_fk"))

     a1 = A()
     b1 = B()

     a1.bs.append(b1)
     a1.favorite_b = b1
     a1.updated = 5
     s.add(a1)
     s.flush()

Above, the previous behavior would be that an UPDATE would emit after
the INSERT, thus triggering the “onupdate” and overwriting the value
“5”.  The SQL now looks like:

     INSERT INTO a (favorite_b_id, updated) VALUES (?, ?)
     (None, 5)
     INSERT INTO b (a_id) VALUES (?)
     (1,)
     UPDATE a SET favorite_b_id=?, updated=? WHERE a.id = ?
     (1, 5, 1)

Additionally, if the value of “updated” is `not' set, then we correctly
get back the newly generated value on ‘a1.updated’; previously, the
logic that refreshes or expires the attribute to allow the generated
value to be present would not fire off for a post-update.  The
InstanceEvents.refresh_flush() event is also emitted when a
refresh within flush occurs in this case.

#3471(1)

#3472(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3471

   (2) http://www.sqlalchemy.org/trac/ticket/3472

8.4.2.38 post_update integrates with ORM versioning
...................................................

The post_update feature, documented at Rows that point to themselves / Mutually Dependent Rows,
involves that an UPDATE
statement is emitted in response to changes to a particular
relationship-bound foreign key, in addition to the INSERT/UPDATE/DELETE
that would normally be emitted for the target row.  This UPDATE
statement now participates in the versioning feature, documented at
Configuring a Version Counter.

Given a mapping:

     class Node(Base):
         __tablename__ = 'node'
         id = Column(Integer, primary_key=True)
         version_id = Column(Integer, default=0)
         parent_id = Column(ForeignKey('node.id'))
         favorite_node_id = Column(ForeignKey('node.id'))

         nodes = relationship("Node", primaryjoin=remote(parent_id) == id)
         favorite_node = relationship(
             "Node", primaryjoin=favorite_node_id == remote(id),
             post_update=True
         )

         __mapper_args__ = {
             'version_id_col': version_id
         }

An UPDATE of a node that associates another node as “favorite” will now
increment the version counter as well as match the current version:

     node = Node()
     session.add(node)
     session.commit()  # node is now version #1

     node = session.query(Node).get(node.id)
     node.favorite_node = Node()
     session.commit()  # node is now version #2

Note that this means an object that receives an UPDATE in response to
other attributes changing, and a second UPDATE due to a post_update
relationship change, will now receive `two version counter updates for
one flush'.  However, if the object is subject to an INSERT within the
current flush, the version counter `will not' be incremented an
additional time, unless a server-side versioning scheme is in place.

The reason post_update emits an UPDATE even for an UPDATE is now
discussed at Why does post_update emit UPDATE in addition to the first UPDATE?.

See also
........

See Rows that point to themselves / Mutually Dependent Rows.

See Why does post_update emit UPDATE in addition to the first UPDATE?.

#3496(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3496

8.4.2.39 Key Behavioral Changes - Core
......................................

8.4.2.40 The typing behavior of custom operators has been made consistent
.........................................................................

User defined operators can be made on the fly using the
Operators.op() function.  Previously, the typing behavior of an
expression against such an operator was inconsistent and also not
controllable.

Whereas in 1.1, an expression such as the following would produce a
result with no return type (assume ‘-%>’ is some special operator
supported by the database):

     >>> column('x', types.DateTime).op('-%>')(None).type
     NullType()

Other types would use the default behavior of using the left-hand type
as the return type:

     >>> column('x', types.String(50)).op('-%>')(None).type
     String(length=50)

These behaviors were mostly by accident, so the behavior has been made
consistent with the second form, that is the default return type is the
same as the left-hand expression:

     >>> column('x', types.DateTime).op('-%>')(None).type
     DateTime()

As most user-defined operators tend to be “comparison” operators, often
one of the many special operators defined by PostgreSQL, the
Operators.op.is_comparison flag has been repaired to follow its
documented behavior of allowing the return type to be Boolean
in all cases, including for ARRAY and JSON:

     >>> column('x', types.String(50)).op('-%>', is_comparison=True)(None).type
     Boolean()
     >>> column('x', types.ARRAY(types.Integer)).op('-%>', is_comparison=True)(None).type
     Boolean()
     >>> column('x', types.JSON()).op('-%>', is_comparison=True)(None).type
     Boolean()

To assist with boolean comparison operators, a new shorthand method
Operators.bool_op() has been added.  This method should be
preferred for on-the-fly boolean operators:

     >>> print(column('x', types.Integer).bool_op('-%>')(5))
     x -%> :x_1

8.4.2.41 Percent signs in literal_column() now conditionally escaped
....................................................................

The literal_column construct now escapes percent sign
characters conditionally, based on whether or not the DBAPI in use makes
use of a percent-sign-sensitive paramstyle or not (e.g.  ‘format’ or
‘pyformat’).

Previously, it was not possible to produce a literal_column
construct that stated a single percent sign:

     >>> from sqlalchemy import literal_column
     >>> print(literal_column('some%symbol'))
     some%%symbol

The percent sign is now unaffected for dialects that are not set to use
the ‘format’ or ‘pyformat’ paramstyles; dialects such most MySQL
dialects which do state one of these paramstyles will continue to escape
as is appropriate:

     >>> from sqlalchemy import literal_column
     >>> print(literal_column('some%symbol'))
     some%symbol
     >>> from sqlalchemy.dialects import mysql
     >>> print(literal_column('some%symbol').compile(dialect=mysql.dialect()))
     some%%symbol

As part of this change, the doubling that has been present when using
operators like ColumnOperators.contains(),
ColumnOperators.startswith() and ColumnOperators.endswith()
is also refined to only occur when appropriate.

#3740(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3740

8.4.2.42 The column-level COLLATE keyword now quotes the collation name
.......................................................................

A bug in the collate() and ColumnOperators.collate()
functions, used to supply ad-hoc column collations at the statement
level, is fixed, where a case sensitive name would not be quoted:

     stmt = select([mytable.c.x, mytable.c.y]).\
         order_by(mytable.c.somecolumn.collate("fr_FR"))

now renders:

     SELECT mytable.x, mytable.y,
     FROM mytable ORDER BY mytable.somecolumn COLLATE "fr_FR"

Previously, the case sensitive name ‘“fr_FR”’ would not be quoted.
Currently, manual quoting of the “fr_FR” name is `not' detected, so
applications that are manually quoting the identifier should be
adjusted.  Note that this change does not impact the use of collations
at the type level (e.g.  specified on the datatype like String
at the table level), where quoting is already applied.

#3785(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3785

8.4.2.43 Dialect Improvements and Changes - PostgreSQL
......................................................

8.4.2.44 Support for Batch Mode / Fast Execution Helpers
........................................................

The psycopg2 ‘cursor.executemany()’ method has been identified as
performing poorly, particularly with INSERT statements.  To alleviate
this, psycopg2 has added Fast Execution Helpers(1) which rework
statements into fewer server round trips by sending multiple DML
statements in batch.  SQLAlchemy 1.2 now includes support for these
helpers to be used transparently whenever the Engine makes
use of ‘cursor.executemany()’ to invoke a statement against multiple
parameter sets.  The feature is off by default and can be enabled using
the ‘use_batch_mode’ argument on create_engine():

     engine = create_engine(
         "postgresql+psycopg2://scott:tiger@host/dbname",
         use_batch_mode=True)

The feature is considered to be experimental for the moment but may
become on by default in a future release.

See also
........

See Psycopg2 Fast Execution Helpers.

#4109(2)

   ---------- Footnotes ----------

   (1) http://initd.org/psycopg/docs/extras.html#fast-execution-helpers

   (2) http://www.sqlalchemy.org/trac/ticket/4109

8.4.2.45 Support for fields specification in INTERVAL, including full reflection
................................................................................

The “fields” specifier in PostgreSQL’s INTERVAL datatype allows
specification of which fields of the interval to store, including such
values as “YEAR”, “MONTH”, “YEAR TO MONTH”, etc.  The INTERVAL
datatype now allows these values to be specified:

     from sqlalchemy.dialects.postgresql import INTERVAL

     Table(
         'my_table', metadata,
         Column("some_interval", INTERVAL(fields="DAY TO SECOND"))
     )

Additionally, all INTERVAL datatypes can now be reflected independently
of the “fields” specifier present; the “fields” parameter in the
datatype itself will also be present:

     >>> inspect(engine).get_columns("my_table")
     [{'comment': None,
       'name': u'some_interval', 'nullable': True,
       'default': None, 'autoincrement': False,
       'type': INTERVAL(fields=u'day to second')}]

#3959(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3959

8.4.2.46 Dialect Improvements and Changes - MySQL
.................................................

8.4.2.47 Support for INSERT..ON DUPLICATE KEY UPDATE
....................................................

The ‘ON DUPLICATE KEY UPDATE’ clause of ‘INSERT’ supported by MySQL is
now supported using a MySQL-specific version of the Insert
object, via ‘sqlalchemy.dialects.mysql.dml.insert()’.  This
Insert subclass adds a new method
‘Insert.on_duplicate_key_update()’ that implements MySQL’s syntax:

     from sqlalchemy.dialects.mysql import insert

     insert_stmt = insert(my_table). \
         values(id='some_id', data='some data to insert')

     on_conflict_stmt = insert_stmt.on_duplicate_key_update(
         data=insert_stmt.inserted.data,
         status='U'
     )

     conn.execute(on_conflict_stmt)

The above will render:

     INSERT INTO my_table (id, data)
     VALUES (:id, :data)
     ON DUPLICATE KEY UPDATE data=VALUES(data), status=:status_1

See also
........

See INSERT…ON DUPLICATE KEY UPDATE (Upsert).

#4009(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4009

8.4.2.48 Dialect Improvements and Changes - Oracle
..................................................

8.4.2.49 Major Refactor to cx_Oracle Dialect, Typing System
...........................................................

With the introduction of the 6.x series of the cx_Oracle DBAPI,
SQLAlchemy’s cx_Oracle dialect has been reworked and simplified to take
advantage of recent improvements in cx_Oracle as well as dropping
support for patterns that were more relevant before the 5.x series of
cx_Oracle.

   * The minimum cx_Oracle version supported is now 5.1.3; 5.3 or the
     most recent 6.x series are recommended.

   * The handling of datatypes has been refactored.  The
     ‘cursor.setinputsizes()’ method is no longer used for any datatype
     except LOB types, per advice from cx_Oracle’s developers.  As a
     result, the parameters ‘auto_setinputsizes’ and
     ‘exclude_setinputsizes’ are deprecated and no longer have any
     effect.

   * The ‘coerce_to_decimal’ flag, when set to False to indicate that
     coercion of numeric types with precision and scale to ‘Decimal’
     should not occur, only impacts untyped (e.g.  plain string with no
     TypeEngine objects) statements.  A Core expression that
     includes a Numeric type or subtype will now follow the
     decimal coercion rules of that type.

   * The “two phase” transaction support in the dialect, already dropped
     for the 6.x series of cx_Oracle, has now been removed entirely as
     this feature has never worked correctly and is unlikely to have
     been in production use.  As a result, the ‘allow_twophase’ dialect
     flag is deprecated and also has no effect.

   * Fixed a bug involving the column keys present with RETURNING. Given
     a statement as follows:

          result = conn.execute(table.insert().values(x=5).returning(table.c.a, table.c.b))

     Previously, the keys in each row of the result would be ‘ret_0’ and
     ‘ret_1’, which are identifiers internal to the cx_Oracle RETURNING
     implementation.  The keys will now be ‘a’ and ‘b’ as is expected
     for other dialects.

   * cx_Oracle’s LOB datatype represents return values as a
     ‘cx_Oracle.LOB’ object, which is a cursor-associated proxy that
     returns the ultimate data value via a ‘.read()’ method.
     Historically, if more rows were read before these LOB objects were
     consumed (specifically, more rows than the value of
     cursor.arraysize which causes a new batch of rows to be read),
     these LOB objects would raise the error “LOB variable no longer
     valid after subsequent fetch”.  SQLAlchemy worked around this by
     both automatically calling ‘.read()’ upon these LOBs within its
     typing system, as well as using a special ‘BufferedColumnResultSet’
     which would ensure this data was buffered in case a call like
     ‘cursor.fetchmany()’ or ‘cursor.fetchall()’ were used.

     The dialect now makes use of a cx_Oracle outputtypehandler to
     handle these ‘.read()’ calls, so that they are always called up
     front regardless of how many rows are being fetched, so that this
     error can no longer occur.  As a result, the use of the
     ‘BufferedColumnResultSet’, as well as some other internals to the
     Core ‘ResultSet’ that were specific to this use case, have been
     removed.  The type objects are also simplified as they no longer
     need to process a binary column result.

     Additionally, cx_Oracle 6.x has removed the conditions under which
     this error occurs in any case, so the error is no longer possible.
     The error can occur on SQLAlchemy in the case that the seldom (if
     ever) used ‘auto_convert_lobs=False’ option is in use, in
     conjunction with the previous 5.x series of cx_Oracle, and more
     rows are read before the LOB objects can be consumed.  Upgrading to
     cx_Oracle 6.x will resolve that issue.

8.4.2.50 Oracle Unique, Check constraints now reflected
.......................................................

UNIQUE and CHECK constraints now reflect via
Inspector.get_unique_constraints() and
Inspector.get_check_constraints().  A Table object
that’s reflected will now include CheckConstraint objects
as well.  See the notes at Constraint Reflection for
information on behavioral quirks here, including that most Table
objects will still not include any UniqueConstraint
objects as these usually represent via Index.

See also
........

See Constraint Reflection.

#4003(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4003

8.4.2.51 Oracle foreign key constraint names are now “name normalized”
......................................................................

The names of foreign key constraints as delivered to a
ForeignKeyConstraint object during table reflection as well as
within the Inspector.get_foreign_keys() method will now be
“name normalized”, that is, expressed as lower case for a case
insensitive name, rather than the raw UPPERCASE format that Oracle uses:

     >>> insp.get_indexes("addresses")
     [{'unique': False, 'column_names': [u'user_id'],
       'name': u'address_idx', 'dialect_options': {}}]

     >>> insp.get_pk_constraint("addresses")
     {'name': u'pk_cons', 'constrained_columns': [u'id']}

     >>> insp.get_foreign_keys("addresses")
     [{'referred_table': u'users', 'referred_columns': [u'id'],
       'referred_schema': None, 'name': u'user_id_fk',
       'constrained_columns': [u'user_id']}]

Previously, the foreign keys result would look like:

     [{'referred_table': u'users', 'referred_columns': [u'id'],
       'referred_schema': None, 'name': 'USER_ID_FK',
       'constrained_columns': [u'user_id']}]

Where the above could create problems particularly with Alembic
autogenerate.

#3276(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3276

8.4.2.52 Dialect Improvements and Changes - SQL Server
......................................................

8.4.2.53 SQL Server schema names with embedded dots supported
.............................................................

The SQL Server dialect has a behavior such that a schema name with a dot
inside of it is assumed to be a “database”.”owner” identifier pair,
which is necessarily split up into these separate components during
table and component reflection operations, as well as when rendering
quoting for the schema name so that the two symbols are quoted
separately.  The schema argument can now be passed using brackets to
manually specify where this split occurs, allowing database and/or owner
names that themselves contain one or more dots:

     Table(
         "some_table", metadata,
         Column("q", String(50)),
         schema="[MyDataBase.dbo]"
     )

The above table will consider the “owner” to be ‘MyDataBase.dbo’, which
will also be quoted upon render, and the “database” as None.  To
individually refer to database name and owner, use two pairs of
brackets:

     Table(
         "some_table", metadata,
         Column("q", String(50)),
         schema="[MyDataBase.SomeDB].[MyDB.owner]"
     )

Additionally, the quoted_name construct is now honored when
passed to “schema” by the SQL Server dialect; the given symbol will not
be split on the dot if the quote flag is True and will be interpreted as
the “owner”.

See also
........

See Multipart Schema Names.

#2626(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2626

8.4.2.54 AUTOCOMMIT isolation level support
...........................................

Both the PyODBC and pymssql dialects now support the “AUTOCOMMIT”
isolation level as set by Connection.execution_options()
which will establish the correct flags on the DBAPI connection object.

8.4.3 What’s New in SQLAlchemy 1.1?
-----------------------------------

     About this Document: This document describes changes between
     SQLAlchemy version 1.0 and SQLAlchemy version 1.1.

8.4.3.1 Introduction
....................

This guide introduces what’s new in SQLAlchemy version 1.1, and also
documents changes which affect users migrating their applications from
the 1.0 series of SQLAlchemy to 1.1.

Please carefully review the sections on behavioral changes for
potentially backwards-incompatible changes in behavior.

8.4.3.2 Platform / Installer Changes
....................................

8.4.3.3 Setuptools is now required for install
..............................................

SQLAlchemy’s ‘setup.py’ file has for many years supported operation both
with Setuptools installed and without; supporting a “fallback” mode that
uses straight Distutils.  As a Setuptools-less Python environment is now
unheard of, and in order to support the featureset of Setuptools more
fully, in particular to support py.test’s integration with it as well as
things like “extras”, ‘setup.py’ now depends on Setuptools fully.

See also
........

See Installation Guide.

#3489(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3489

8.4.3.4 Enabling / Disabling C Extension builds is only via environment variable
................................................................................

The C Extensions build by default during install as long as it is
possible.  To disable C extension builds, the ‘DISABLE_SQLALCHEMY_CEXT’
environment variable was made available as of SQLAlchemy 0.8.6 / 0.9.4.
The previous approach of using the ‘--without-cextensions’ argument has
been removed, as it relies on deprecated features of setuptools.

See also
........

See Installing the C Extensions.

#3500(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3500

8.4.3.5 New Features and Improvements - ORM
...........................................

8.4.3.6 New Session lifecycle events
....................................

The Session has long supported events that allow some degree
of tracking of state changes to objects, including
SessionEvents.before_attach(), SessionEvents.after_attach(),
and SessionEvents.before_flush().  The Session
documentation also documents major object states at Quickie Intro to Object States.
However, there has never been system of tracking
objects specifically as they pass through these transitions.
Additionally, the status of “deleted” objects has historically been
murky as the objects act somewhere between the “persistent” and
“detached” states.

To clean up this area and allow the realm of session state transition to
be fully transparent, a new series of events have been added that are
intended to cover every possible way that an object might transition
between states, and additionally the “deleted” status has been given its
own official state name within the realm of session object states.

8.4.3.7 New State Transition Events
...................................

Transitions between all states of an object such as persistent, pending
and others can now be intercepted in terms of a session-level event
intended to cover a specific transition.  Transitions as objects move
into a Session, move out of a Session, and even all
the transitions which occur when the transaction is rolled back using
Session.rollback() are explicitly present in the interface
of SessionEvents.

In total, there are `ten new events'.  A summary of these events is in a
newly written documentation section Object Lifecycle Events.

8.4.3.8 New Object State “deleted” is added, deleted objects no longer “persistent”
...................................................................................

The persistent state of an object in the Session has always
been documented as an object that has a valid database identity; however
in the case of objects that were deleted within a flush, they have
always been in a grey area where they are not really “detached” from the
Session yet, because they can still be restored within a
rollback, but are not really “persistent” because their database
identity has been deleted and they aren’t present in the identity map.

To resolve this grey area given the new events, a new object state
deleted is introduced.  This state exists between the “persistent” and
“detached” states.  An object that is marked for deletion via
Session.delete() remains in the “persistent” state until a flush
proceeds; at that point, it is removed from the identity map, moves to
the “deleted” state, and the
SessionEvents.persistent_to_deleted() hook is invoked.  If the
Session object’s transaction is rolled back, the object is
restored as persistent; the SessionEvents.deleted_to_persistent()
transition is called.  Otherwise if the Session object’s
transaction is committed, the SessionEvents.deleted_to_detached()
transition is invoked.

Additionally, the InstanceState.persistent accessor `no
longer returns True' for an object that is in the new “deleted” state;
instead, the InstanceState.deleted accessor has been
enhanced to reliably report on this new state.  When the object is
detached, the InstanceState.deleted returns False and the
InstanceState.detached accessor is True instead.  To
determine if an object was deleted either in the current transaction or
in a previous transaction, use the InstanceState.was_deleted
accessor.

8.4.3.9 Strong Identity Map is Deprecated
.........................................

One of the inspirations for the new series of transition events was to
enable leak-proof tracking of objects as they move in and out of the
identity map, so that a “strong reference” may be maintained mirroring
the object moving in and out of this map.  With this new capability,
there is no longer any need for the Session.weak_identity_map
parameter and the corresponding ‘StrongIdentityMap’ object.  This
option has remained in SQLAlchemy for many years as the
“strong-referencing” behavior used to be the only behavior available,
and many applications were written to assume this behavior.  It has long
been recommended that strong-reference tracking of objects not be an
intrinsic job of the Session and instead be an
application-level construct built as needed by the application; the new
event model allows even the exact behavior of the strong identity map to
be replicated.  See Session Referencing Behavior for a new
recipe illustrating how to replace the strong identity map.

#2677(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2677

8.4.3.10 New init_scalar() event intercepts default values at ORM level
.......................................................................

The ORM produces a value of ‘None’ when an attribute that has not been
set is first accessed, for a non-persistent object:

     >>> obj = MyObj()
     >>> obj.some_value
     None

There’s a use case for this in-Python value to correspond to that of a
Core-generated default value, even before the object is persisted.  To
suit this use case a new event AttributeEvents.init_scalar()
is added.  The new example ‘active_column_defaults.py’ at
Attribute Instrumentation illustrates a sample use, so the effect
can instead be:

     >>> obj = MyObj()
     >>> obj.some_value
     "my default"

#1311(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1311

8.4.3.11 Changes regarding “unhashable” types, impacts deduping of ORM rows
...........................................................................

The Query object has a well-known behavior of “deduping”
returned rows that contain at least one ORM-mapped entity (e.g., a full
mapped object, as opposed to individual column values).  The primary
purpose of this is so that the handling of entities works smoothly in
conjunction with the identity map, including to accommodate for the
duplicate entities normally represented within joined eager loading, as
well as when joins are used for the purposes of filtering on additional
columns.

This deduplication relies upon the hashability of the elements within
the row.  With the introduction of PostgreSQL’s special types like
ARRAY, HSTORE and JSON, the experience of
types within rows being unhashable and encountering problems here is
more prevalent than it was previously.

In fact, SQLAlchemy has since version 0.8 included a flag on datatypes
that are noted as “unhashable”, however this flag was not used
consistently on built in types.  As described in ARRAY and JSON types now correctly specify “unhashable”,
this flag is now set
consistently for all of PostgreSQL’s “structural” types.

The “unhashable” flag is also set on the NullType type, as
NullType is used to refer to any expression of unknown type.

Since NullType is applied to most usages of ‘func’, as
‘func’ doesn’t actually know anything about the function names given in
most cases, `using func() will often disable row deduping unless
explicit typing is applied'.  The following examples illustrate
‘func.substr()’ applied to a string expression, and ‘func.date()’
applied to a datetime expression; both examples will return duplicate
rows due to the joined eager load unless explicit typing is applied:

     result = session.query(
         func.substr(A.some_thing, 0, 4), A
     ).options(joinedload(A.bs)).all()

     users = session.query(
         func.date(
             User.date_created, 'start of month'
         ).label('month'),
         User,
     ).options(joinedload(User.orders)).all()

The above examples, in order to retain deduping, should be specified as:

     result = session.query(
         func.substr(A.some_thing, 0, 4, type_=String), A
     ).options(joinedload(A.bs)).all()

     users = session.query(
         func.date(
             User.date_created, 'start of month', type_=DateTime
         ).label('month'),
         User,
     ).options(joinedload(User.orders)).all()

Additionally, the treatment of a so-called “unhashable” type is slightly
different than its been in previous releases; internally we are using
the ‘id()’ function to get a “hash value” from these structures, just as
we would any ordinary mapped object.  This replaces the previous
approach which applied a counter to the object.

#3499(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3499

8.4.3.12 Specific checks added for passing mapped classes, instances as SQL literals
....................................................................................

The typing system now has specific checks for passing of SQLAlchemy
“inspectable” objects in contexts where they would otherwise be handled
as literal values.  Any SQLAlchemy built-in object that is legal to pass
as a SQL value (which is not already a ClauseElement
instance) includes a method ‘__clause_element__()’ which provides a
valid SQL expression for that object.  For SQLAlchemy objects that don’t
provide this, such as mapped classes, mappers, and mapped instances, a
more informative error message is emitted rather than allowing the DBAPI
to receive the object and fail later.  An example is illustrated below,
where a string-based attribute ‘User.name’ is compared to a full
instance of ‘User()’, rather than against a string value:

     >>> some_user = User()
     >>> q = s.query(User).filter(User.name == some_user)
     ...
     sqlalchemy.exc.ArgumentError: Object <__main__.User object at 0x103167e90> is not legal as a SQL literal value

The exception is now immediate when the comparison is made between
‘User.name == some_user’.  Previously, a comparison like the above would
produce a SQL expression that would only fail once resolved into a DBAPI
execution call; the mapped ‘User’ object would ultimately become a bound
parameter that would be rejected by the DBAPI.

Note that in the above example, the expression fails because ‘User.name’
is a string-based (e.g.  column oriented) attribute.  The change does
`not' impact the usual case of comparing a many-to-one relationship
attribute to an object, which is handled distinctly:

     >>> # Address.user refers to the User mapper, so
     >>> # this is of course still OK!
     >>> q = s.query(Address).filter(Address.user == some_user)

#3321(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3321

8.4.3.13 New Indexable ORM extension
....................................

The Indexable extension is an extension to the hybrid
attribute feature which allows the construction of attributes which
refer to specific elements of an “indexable” data type, such as an array
or JSON field:

     class Person(Base):
         __tablename__ = 'person'

         id = Column(Integer, primary_key=True)
         data = Column(JSON)

         name = index_property('data', 'name')

Above, the ‘name’ attribute will read/write the field ‘"name"’ from the
JSON column ‘data’, after initializing it to an empty dictionary:

     >>> person = Person(name='foobar')
     >>> person.name
     foobar

The extension also triggers a change event when the attribute is
modified, so that there’s no need to use MutableDict in
order to track this change.

See also
........

See Indexable.

8.4.3.14 New options allowing explicit persistence of NULL over a default
.........................................................................

Related to the new JSON-NULL support added to PostgreSQL as part of
JSON “null” is inserted as expected with ORM operations, omitted when not present,
the base TypeEngine class now
supports a method TypeEngine.evaluates_none() which allows a
positive set of the ‘None’ value on an attribute to be persisted as
NULL, rather than omitting the column from the INSERT statement, which
has the effect of using the column-level default.  This allows a
mapper-level configuration of the existing object-level technique of
assigning null() to the attribute.

See also
........

See Forcing NULL on a column with a default.

#3250(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3250

8.4.3.15 Further Fixes to single-table inheritance querying
...........................................................

Continuing from 1.0’s Change to single-table-inheritance criteria when using from_self(), count(),
the Query should no
longer inappropriately add the “single inheritance” criteria when the
query is against a subquery expression such as an exists:

     class Widget(Base):
         __tablename__ = 'widget'
         id = Column(Integer, primary_key=True)
         type = Column(String)
         data = Column(String)
         __mapper_args__ = {'polymorphic_on': type}

     class FooWidget(Widget):
         __mapper_args__ = {'polymorphic_identity': 'foo'}

     q = session.query(FooWidget).filter(FooWidget.data == 'bar').exists()

     session.query(q).all()

Produces:

     SELECT EXISTS (SELECT 1
     FROM widget
     WHERE widget.data = :data_1 AND widget.type IN (:type_1)) AS anon_1

The IN clause on the inside is appropriate, in order to limit to
FooWidget objects, however previously the IN clause would also be
generated a second time on the outside of the subquery.

#3582(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3582

8.4.3.16 Improved Session state when a SAVEPOINT is cancelled by the database
.............................................................................

A common case with MySQL is that a SAVEPOINT is cancelled when a
deadlock occurs within the transaction.  The Session has been
modified to deal with this failure mode slightly more gracefully, such
that the outer, non-savepoint transaction still remains usable:

     s = Session()
     s.begin_nested()

     s.add(SomeObject())

     try:
         # assume the flush fails, flush goes to rollback to the
         # savepoint and that also fails
         s.flush()
     except Exception as err:
         print("Something broke, and our SAVEPOINT vanished too")

     # this is the SAVEPOINT transaction, marked as
     # DEACTIVE so the rollback() call succeeds
     s.rollback()

     # this is the outermost transaction, remains ACTIVE
     # so rollback() or commit() can succeed
     s.rollback()

This issue is a continuation of #2696(1) where we emit a warning so that
the original error can be seen when running on Python 2, even though the
SAVEPOINT exception takes precedence.  On Python 3, exceptions are
chained so both failures are reported individually.

#3680(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2696

   (2) http://www.sqlalchemy.org/trac/ticket/3680

8.4.3.17 Erroneous “new instance X conflicts with persistent instance Y” flush errors fixed
...........................................................................................

The Session.rollback() method is responsible for removing
objects that were INSERTed into the database, e.g.  moved from pending
to persistent, within that now rolled-back transaction.  Objects that
make this state change are tracked in a weak-referencing collection, and
if an object is garbage collected from that collection, the
Session no longer worries about it (it would otherwise not scale
for operations that insert many new objects within a transaction).
However, an issue arises if the application re-loads that same
garbage-collected row within the transaction, before the rollback
occurs; if a strong reference to this object remains into the next
transaction, the fact that this object was not inserted and should be
removed would be lost, and the flush would incorrectly raise an error:

     from sqlalchemy import Column, create_engine
     from sqlalchemy.orm import Session
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)

     e = create_engine("sqlite://", echo=True)
     Base.metadata.create_all(e)

     s = Session(e)

     # persist an object
     s.add(A(id=1))
     s.flush()

     # rollback buffer loses reference to A

     # load it again, rollback buffer knows nothing
     # about it
     a1 = s.query(A).first()

     # roll back the transaction; all state is expired but the
     # "a1" reference remains
     s.rollback()

     # previous "a1" conflicts with the new one because we aren't
     # checking that it never got committed
     s.add(A(id=1))
     s.commit()

The above program would raise:

     FlushError: New instance <User at 0x7f0287eca4d0> with identity key
     (<class 'test.orm.test_transaction.User'>, ('u1',)) conflicts
     with persistent instance <User at 0x7f02889c70d0>

The bug is that when the above exception is raised, the unit of work is
operating upon the original object assuming it’s a live row, when in
fact the object is expired and upon testing reveals that it’s gone.  The
fix tests this condition now, so in the SQL log we see:

     BEGIN (implicit)

     INSERT INTO a (id) VALUES (?)
     (1,)

     SELECT a.id AS a_id FROM a LIMIT ? OFFSET ?
     (1, 0)

     ROLLBACK

     BEGIN (implicit)

     SELECT a.id AS a_id FROM a WHERE a.id = ?
     (1,)

     INSERT INTO a (id) VALUES (?)
     (1,)

     COMMIT

Above, the unit of work now does a SELECT for the row we’re about to
report as a conflict for, sees that it doesn’t exist, and proceeds
normally.  The expense of this SELECT is only incurred in the case when
we would have erroneously raised an exception in any case.

#3677(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3677

8.4.3.18 passive_deletes feature for joined-inheritance mappings
................................................................

A joined-table inheritance mapping may now allow a DELETE to proceed as
a result of Session.delete(), which only emits DELETE for the
base table, and not the subclass table, allowing configured ON DELETE
CASCADE to take place for the configured foreign keys.  This is
configured using the mapper.passive_deletes option:

     from sqlalchemy import Column, Integer, String, ForeignKey, create_engine
     from sqlalchemy.orm import Session
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class A(Base):
         __tablename__ = "a"
         id = Column('id', Integer, primary_key=True)
         type = Column(String)

         __mapper_args__ = {
             'polymorphic_on': type,
             'polymorphic_identity': 'a',
             'passive_deletes': True
         }

     class B(A):
         __tablename__ = 'b'
         b_table_id = Column('b_table_id', Integer, primary_key=True)
         bid = Column('bid', Integer, ForeignKey('a.id', ondelete="CASCADE"))
         data = Column('data', String)

         __mapper_args__ = {
             'polymorphic_identity': 'b'
         }

With the above mapping, the mapper.passive_deletes option is
configured on the base mapper; it takes effect for all non-base mappers
that are descendants of the mapper with the option set.  A DELETE for an
object of type ‘B’ no longer needs to retrieve the primary key value of
‘b_table_id’ if unloaded, nor does it need to emit a DELETE statement
for the table itself:

     session.delete(some_b)
     session.commit()

Will emit SQL as:

     DELETE FROM a WHERE a.id = %(id)s
     {'id': 1}
     COMMIT

As always, the target database must have foreign key support with ON
DELETE CASCADE enabled.

#2349(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2349

8.4.3.19 Same-named backrefs will not raise an error when applied to concrete inheritance subclasses
....................................................................................................

The following mapping has always been possible without issue:

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)
         b = relationship("B", foreign_keys="B.a_id", backref="a")

     class A1(A):
         __tablename__ = 'a1'
         id = Column(Integer, primary_key=True)
         b = relationship("B", foreign_keys="B.a1_id", backref="a1")
         __mapper_args__ = {'concrete': True}

     class B(Base):
         __tablename__ = 'b'
         id = Column(Integer, primary_key=True)

         a_id = Column(ForeignKey('a.id'))
         a1_id = Column(ForeignKey('a1.id'))

Above, even though class ‘A’ and class ‘A1’ have a relationship named
‘b’, no conflict warning or error occurs because class ‘A1’ is marked as
“concrete”.

However, if the relationships were configured the other way, an error
would occur:

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)

     class A1(A):
         __tablename__ = 'a1'
         id = Column(Integer, primary_key=True)
         __mapper_args__ = {'concrete': True}

     class B(Base):
         __tablename__ = 'b'
         id = Column(Integer, primary_key=True)

         a_id = Column(ForeignKey('a.id'))
         a1_id = Column(ForeignKey('a1.id'))

         a = relationship("A", backref="b")
         a1 = relationship("A1", backref="b")

The fix enhances the backref feature so that an error is not emitted, as
well as an additional check within the mapper logic to bypass warning
for an attribute being replaced.

#3630(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3630

8.4.3.20 Same-named relationships on inheriting mappers no longer warn
......................................................................

When creating two mappers in an inheritance scenario, placing a
relationship on both with the same name would emit the warning
“relationship ‘<name>’ on mapper <name> supersedes the same relationship
on inherited mapper ‘<name>’; this can cause dependency issues during
flush”.  An example is as follows:

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)
         bs = relationship("B")

     class ASub(A):
         __tablename__ = 'a_sub'
         id = Column(Integer, ForeignKey('a.id'), primary_key=True)
         bs = relationship("B")

     class B(Base):
         __tablename__ = 'b'
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey('a.id'))

This warning dates back to the 0.4 series in 2007 and is based on a
version of the unit of work code that has since been entirely rewritten.
Currently, there is no known issue with the same-named relationships
being placed on a base class and a descendant class, so the warning is
lifted.  However, note that this use case is likely not prevalent in
real world use due to the warning.  While rudimentary test support is
added for this use case, it is possible that some new issue with this
pattern may be identified.

New in version 1.1.0b3.

#3749(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3749

8.4.3.21 Hybrid properties and methods now propagate the docstring as well as .info
...................................................................................

A hybrid method or property will now reflect the ‘__doc__’ value present
in the original docstring:

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)

         name = Column(String)

         @hybrid_property
         def some_name(self):
             """The name field"""
             return self.name

The above value of ‘A.some_name.__doc__’ is now honored:

     >>> A.some_name.__doc__
     The name field

However, to accomplish this, the mechanics of hybrid properties
necessarily becomes more complex.  Previously, the class-level accessor
for a hybrid would be a simple pass-thru, that is, this test would
succeed:

     >>> assert A.name is A.some_name

With the change, the expression returned by ‘A.some_name’ is wrapped
inside of its own ‘QueryableAttribute’ wrapper:

     >>> A.some_name
     <sqlalchemy.orm.attributes.hybrid_propertyProxy object at 0x7fde03888230>

A lot of testing went into making sure this wrapper works correctly,
including for elaborate schemes like that of the Custom Value Object(1)
recipe, however we’ll be looking to see that no other regressions occur
for users.

As part of this change, the ‘hybrid_property.info’ collection is now
also propagated from the hybrid descriptor itself, rather than from the
underlying expression.  That is, accessing ‘A.some_name.info’ now
returns the same dictionary that you’d get from
‘inspect(A).all_orm_descriptors['some_name'].info’:

     >>> A.some_name.info['foo'] = 'bar'
     >>> from sqlalchemy import inspect
     >>> inspect(A).all_orm_descriptors['some_name'].info
     {'foo': 'bar'}

Note that this ‘.info’ dictionary is `separate' from that of a mapped
attribute which the hybrid descriptor may be proxying directly; this is
a behavioral change from 1.0.  The wrapper will still proxy other useful
attributes of a mirrored attribute such as
QueryableAttribute.property and ‘QueryableAttribute.class_’.

#3653(2)

   ---------- Footnotes ----------

   (1)
http://techspot.zzzeek.org/2011/10/21/hybrids-and-value-agnostic-types/

   (2) http://www.sqlalchemy.org/trac/ticket/3653

8.4.3.22 Session.merge resolves pending conflicts the same as persistent
........................................................................

The Session.merge() method will now track the identities of
objects given within a graph to maintain primary key uniqueness before
emitting an INSERT. When duplicate objects of the same identity are
encountered, non-primary-key attributes are `overwritten' as the objects
are encountered, which is essentially non-deterministic.  This behavior
matches that of how persistent objects, that is objects that are already
located in the database via primary key, are already treated, so this
behavior is more internally consistent.

Given:

     u1 = User(id=7, name='x')
     u1.orders = [
         Order(description='o1', address=Address(id=1, email_address='a')),
         Order(description='o2', address=Address(id=1, email_address='b')),
         Order(description='o3', address=Address(id=1, email_address='c'))
     ]

     sess = Session()
     sess.merge(u1)

Above, we merge a ‘User’ object with three new ‘Order’ objects, each
referring to a distinct ‘Address’ object, however each is given the same
primary key.  The current behavior of Session.merge() is to
look in the identity map for this ‘Address’ object, and use that as the
target.  If the object is present, meaning that the database already has
a row for ‘Address’ with primary key “1”, we can see that the
‘email_address’ field of the ‘Address’ will be overwritten three times,
in this case with the values a, b and finally c.

However, if the ‘Address’ row for primary key “1” were not present,
see Session.merge() would instead create three separate
‘Address’ instances, and we’d then get a primary key conflict upon
INSERT. The new behavior is that the proposed primary key for these
‘Address’ objects are tracked in a separate dictionary so that we merge
the state of the three proposed ‘Address’ objects onto one ‘Address’
object to be inserted.

It may have been preferable if the original case emitted some kind of
warning that conflicting data were present in a single merge-tree,
however the non-deterministic merging of values has been the behavior
for many years for the persistent case; it now matches for the pending
case.  A feature that warns for conflicting values could still be
feasible for both cases but would add considerable performance overhead
as each column value would have to be compared during the merge.

#3601(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3601

8.4.3.23 Fix involving many-to-one object moves with user-initiated foreign key manipulations
.............................................................................................

A bug has been fixed involving the mechanics of replacing a many-to-one
reference to an object with another object.  During the attribute
operation, the location of the object that was previously referred to
now makes use of the database-committed foreign key value, rather than
the current foreign key value.  The main effect of the fix is that a
backref event towards a collection will fire off more accurately when a
many-to-one change is made, even if the foreign key attribute was
manually moved to the new value beforehand.  Assume a mapping of the
classes ‘Parent’ and ‘SomeClass’, where ‘SomeClass.parent’ refers to
‘Parent’ and ‘Parent.items’ refers to the collection of ‘SomeClass’
objects:

     some_object = SomeClass()
     session.add(some_object)
     some_object.parent_id = some_parent.id
     some_object.parent = some_parent

Above, we’ve made a pending object ‘some_object’, manipulated its
foreign key towards ‘Parent’ to refer to it, `then' we actually set up
the relationship.  Before the bug fix, the backref would not have fired
off:

     # before the fix
     assert some_object not in some_parent.items

The fix now is that when we seek to locate the previous value of
‘some_object.parent’, we disregard the parent id that’s been manually
set, and we look for the database-committed value.  In this case, it’s
None because the object is pending, so the event system logs
‘some_object.parent’ as a net change:

     # after the fix, backref fired off for some_object.parent = some_parent
     assert some_object in some_parent.items

While it is discouraged to manipulate foreign key attributes that are
managed by relationships, there is limited support for this use case.
Applications that manipulate foreign keys in order to allow loads to
proceed will often make use of the
Session.enable_relationship_loading() and
‘RelationshipProperty.load_on_pending’ features, which cause
relationships to emit lazy loads based on in-memory foreign key values
that aren’t persisted.  Whether or not these features are in use, this
behavioral improvement will now be apparent.

#3708(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3708

8.4.3.24 Improvements to the Query.correlate method with polymorphic entities
.............................................................................

In recent SQLAlchemy versions, the SQL generated by many forms of
“polymorphic” queries has a more “flat” form than it used to, where a
JOIN of several tables is no longer bundled into a subquery
unconditionally.  To accommodate this, the Query.correlate()
method now extracts the individual tables from such a polymorphic
selectable and ensures that all are part of the “correlate” for the
subquery.  Assuming the ‘Person/Manager/Engineer->Company’ setup from
the mapping documentation, using with_polymorphic:

     sess.query(Person.name)
                 .filter(
                     sess.query(Company.name).
                     filter(Company.company_id == Person.company_id).
                     correlate(Person).as_scalar() == "Elbonia, Inc.")

The above query now produces:

     SELECT people.name AS people_name
     FROM people
     LEFT OUTER JOIN engineers ON people.person_id = engineers.person_id
     LEFT OUTER JOIN managers ON people.person_id = managers.person_id
     WHERE (SELECT companies.name
     FROM companies
     WHERE companies.company_id = people.company_id) = ?

Before the fix, the call to ‘correlate(Person)’ would inadvertently
attempt to correlate to the join of ‘Person’, ‘Engineer’ and ‘Manager’
as a single unit, so ‘Person’ wouldn’t be correlated:

     -- old, incorrect query
     SELECT people.name AS people_name
     FROM people
     LEFT OUTER JOIN engineers ON people.person_id = engineers.person_id
     LEFT OUTER JOIN managers ON people.person_id = managers.person_id
     WHERE (SELECT companies.name
     FROM companies, people
     WHERE companies.company_id = people.company_id) = ?

Using correlated subqueries against polymorphic mappings still has some
unpolished edges.  If for example ‘Person’ is polymorphically linked to
a so-called “concrete polymorphic union” query, the above subquery may
not correctly refer to this subquery.  In all cases, a way to refer to
the “polymorphic” entity fully is to create an aliased()
object from it first:

     # works with all SQLAlchemy versions and all types of polymorphic
     # aliasing.

     paliased = aliased(Person)
     sess.query(paliased.name)
                 .filter(
                     sess.query(Company.name).
                     filter(Company.company_id == paliased.company_id).
                     correlate(paliased).as_scalar() == "Elbonia, Inc.")

The aliased() construct guarantees that the “polymorphic
selectable” is wrapped in a subquery.  By referring to it explicitly in
the correlated subquery, the polymorphic form is correctly used.

#3662(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3662

8.4.3.25 Stringify of Query will consult the Session for the correct dialect
............................................................................

Calling ‘str()’ on a Query object will consult the
Session for the correct “bind” to use, in order to render the SQL
that would be passed to the database.  In particular this allows a
Query that refers to dialect-specific SQL constructs to be
renderable, assuming the Query is associated with an
appropriate Session.  Previously, this behavior would only
take effect if the MetaData to which the mappings were
associated were itself bound to the target Engine.

If neither the underlying MetaData nor the Session
are associated with any bound Engine, then the fallback to
the “default” dialect is used to generate the SQL string.

See also
........

See “Friendly” stringification of Core SQL constructs without a dialect.

#3081(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3081

8.4.3.26 Joined eager loading where the same entity is present multiple times in one row
........................................................................................

A fix has been made to the case has been made whereby an attribute will
be loaded via joined eager loading, even if the entity was already
loaded from the row on a different “path” that doesn’t include the
attribute.  This is a deep use case that’s hard to reproduce, but the
general idea is as follows:

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)
         b_id = Column(ForeignKey('b.id'))
         c_id = Column(ForeignKey('c.id'))

         b = relationship("B")
         c = relationship("C")

     class B(Base):
         __tablename__ = 'b'
         id = Column(Integer, primary_key=True)
         c_id = Column(ForeignKey('c.id'))

         c = relationship("C")

     class C(Base):
         __tablename__ = 'c'
         id = Column(Integer, primary_key=True)
         d_id = Column(ForeignKey('d.id'))
         d = relationship("D")

     class D(Base):
         __tablename__ = 'd'
         id = Column(Integer, primary_key=True)

     c_alias_1 = aliased(C)
     c_alias_2 = aliased(C)

     q = s.query(A)
     q = q.join(A.b).join(c_alias_1, B.c).join(c_alias_1.d)
     q = q.options(contains_eager(A.b).contains_eager(B.c, alias=c_alias_1).contains_eager(C.d))
     q = q.join(c_alias_2, A.c)
     q = q.options(contains_eager(A.c, alias=c_alias_2))

The above query emits SQL like this:

     SELECT
         d.id AS d_id,
         c_1.id AS c_1_id, c_1.d_id AS c_1_d_id,
         b.id AS b_id, b.c_id AS b_c_id,
         c_2.id AS c_2_id, c_2.d_id AS c_2_d_id,
         a.id AS a_id, a.b_id AS a_b_id, a.c_id AS a_c_id
     FROM
         a
         JOIN b ON b.id = a.b_id
         JOIN c AS c_1 ON c_1.id = b.c_id
         JOIN d ON d.id = c_1.d_id
         JOIN c AS c_2 ON c_2.id = a.c_id

We can see that the ‘c’ table is selected from twice; once in the
context of ‘A.b.c -> c_alias_1’ and another in the context of ‘A.c ->
c_alias_2’.  Also, we can see that it is quite possible that the ‘C’
identity for a single row is the `same' for both ‘c_alias_1’ and
‘c_alias_2’, meaning two sets of columns in one row result in only one
new object being added to the identity map.

The query options above only call for the attribute ‘C.d’ to be loaded
in the context of ‘c_alias_1’, and not ‘c_alias_2’.  So whether or not
the final ‘C’ object we get in the identity map has the ‘C.d’ attribute
loaded depends on how the mappings are traversed, which while not
completely random, is essentially non-deterministic.  The fix is that
even if the loader for ‘c_alias_1’ is processed after that of
‘c_alias_2’ for a single row where they both refer to the same identity,
the ‘C.d’ element will still be loaded.  Previously, the loader did not
seek to modify the load of an entity that was already loaded via a
different path.  The loader that reaches the entity first has always
been non-deterministic, so this fix may be detectable as a behavioral
change in some situations and not others.

The fix includes tests for two variants of the “multiple paths to one
entity” case, and the fix should hopefully cover all other scenarios of
this nature.

#3431(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3431

8.4.3.27 New MutableList and MutableSet helpers added to the mutation tracking extension
........................................................................................

New helper classes MutableList and MutableSet
have been added to the Mutation Tracking extension, to
complement the existing MutableDict helper.

#3297(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3297

8.4.3.28 New “raise” / “raise_on_sql” loader strategies
.......................................................

To assist with the use case of preventing unwanted lazy loads from
occurring after a series of objects are loaded, the new “lazy=’raise’”
and “lazy=’raise_on_sql’” strategies and corresponding loader option
raiseload() may be applied to a relationship attribute which
will cause it to raise ‘InvalidRequestError’ when a non-eagerly-loaded
attribute is accessed for read.  The two variants test for either a lazy
load of any variety, including those that would only return None or
retrieve from the identity map:

     >>> from sqlalchemy.orm import raiseload
     >>> a1 = s.query(A).options(raiseload(A.some_b)).first()
     >>> a1.some_b
     Traceback (most recent call last):
     ...
     sqlalchemy.exc.InvalidRequestError: 'A.some_b' is not available due to lazy='raise'

Or a lazy load only where SQL would be emitted:

     >>> from sqlalchemy.orm import raiseload
     >>> a1 = s.query(A).options(raiseload(A.some_b, sql_only=True)).first()
     >>> a1.some_b
     Traceback (most recent call last):
     ...
     sqlalchemy.exc.InvalidRequestError: 'A.bs' is not available due to lazy='raise_on_sql'

#3512(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3512

8.4.3.29 Mapper.order_by is deprecated
......................................

This old parameter from the very first versions of SQLAlchemy was part
of the original design of the ORM which featured the Mapper
object as a public-facing query structure.  This role has long since
been replaced by the Query object, where we use
Query.order_by() to indicate the ordering of results in a way that
works consistently for any combination of SELECT statements, entities
and SQL expressions.  There are many areas in which
Mapper.order_by doesn’t work as expected (or what would be
expected is not clear), such as when queries are combined into unions;
these cases are not supported.

#3394(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3394

8.4.3.30 New Features and Improvements - Core
.............................................

8.4.3.31 Engines now invalidate connections, run error handlers for BaseException
.................................................................................

New in version 1.1: this change is a late add to the 1.1 series just
prior to 1.1 final, and is not present in the 1.1 beta releases.

The Python ‘BaseException’ class is below that of ‘Exception’ but is the
identifiable base for system-level exceptions such as
‘KeyboardInterrupt’, ‘SystemExit’, and notably the ‘GreenletExit’
exception that’s used by eventlet and gevent.  This exception class is
now intercepted by the exception- handling routines of Connection,
and includes handling by the ConnectionEvents.handle_error()
event.  The Connection is now `invalidated' by default
in the case of a system level exception that is not a subclass of
‘Exception’, as it is assumed an operation was interrupted and the
connection may be in an unusable state.  The MySQL drivers are most
targeted by this change however the change is across all DBAPIs.

Note that upon invalidation, the immediate DBAPI connection used by
Connection is disposed, and the Connection, if
still being used subsequent to the exception raise, will use a new DBAPI
connection for subsequent operations upon next use; however, the state
of any transaction in progress is lost and the appropriate ‘.rollback()’
method must be called if applicable before this re-use can proceed.

In order to identify this change, it was straightforward to demonstrate
a pymysql or mysqlclient / MySQL-Python connection moving into a
corrupted state when these exceptions occur in the middle of the
connection doing its work; the connection would then be returned to the
connection pool where subsequent uses would fail, or even before
returning to the pool would cause secondary failures in context managers
that call ‘.rollback()’ upon the exception catch.  The behavior here is
expected to reduce the incidence of the MySQL error “commands out of
sync”, as well as the ‘ResourceClosedError’ which can occur when the
MySQL driver fails to report ‘cursor.description’ correctly, when
running under greenlet conditions where greenlets are killed, or where
‘KeyboardInterrupt’ exceptions are handled without exiting the program
entirely.

The behavior is distinct from the usual auto-invalidation feature, in
that it does not assume that the backend database itself has been shut
down or restarted; it does not recycle the entire connection pool as is
the case for usual DBAPI disconnect exceptions.

This change should be a net improvement for all users with the exception
of `any application that currently intercepts ‘‘KeyboardInterrupt‘‘ or
‘‘GreenletExit‘‘ and wishes to continue working within the same
transaction'.  Such an operation is theoretically possible with other
DBAPIs that do not appear to be impacted by ‘KeyboardInterrupt’ such as
psycopg2.  For these DBAPIs, the following workaround will disable the
connection from being recycled for specific exceptions:

     engine = create_engine("postgresql+psycopg2://")

     @event.listens_for(engine, "handle_error")
     def cancel_disconnect(ctx):
         if isinstance(ctx.original_exception, KeyboardInterrupt):
             ctx.is_disconnect = False

#3803(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3803

8.4.3.32 CTE Support for INSERT, UPDATE, DELETE
...............................................

One of the most widely requested features is support for common table
expressions (CTE) that work with INSERT, UPDATE, DELETE, and is now
implemented.  An INSERT/UPDATE/DELETE can both draw from a WITH clause
that’s stated at the top of the SQL, as well as can be used as a CTE
itself in the context of a larger statement.

As part of this change, an INSERT from SELECT that includes a CTE will
now render the CTE at the top of the entire statement, rather than
nested in the SELECT statement as was the case in 1.0.

Below is an example that renders UPDATE, INSERT and SELECT all in one
statement:

     >>> from sqlalchemy import table, column, select, literal, exists
     >>> orders = table(
     ...     'orders',
     ...     column('region'),
     ...     column('amount'),
     ...     column('product'),
     ...     column('quantity')
     ... )
     >>>
     >>> upsert = (
     ...     orders.update()
     ...     .where(orders.c.region == 'Region1')
     ...     .values(amount=1.0, product='Product1', quantity=1)
     ...     .returning(*(orders.c._all_columns)).cte('upsert'))
     >>>
     >>> insert = orders.insert().from_select(
     ...     orders.c.keys(),
     ...     select([
     ...         literal('Region1'), literal(1.0),
     ...         literal('Product1'), literal(1)
     ...     ]).where(~exists(upsert.select()))
     ... )
     >>>
     >>> print(insert)  # note formatting added for clarity
     WITH upsert AS
     (UPDATE orders SET amount=:amount, product=:product, quantity=:quantity
      WHERE orders.region = :region_1
      RETURNING orders.region, orders.amount, orders.product, orders.quantity
     )
     INSERT INTO orders (region, amount, product, quantity)
     SELECT
         :param_1 AS anon_1, :param_2 AS anon_2,
         :param_3 AS anon_3, :param_4 AS anon_4
     WHERE NOT (
         EXISTS (
             SELECT upsert.region, upsert.amount,
                    upsert.product, upsert.quantity
             FROM upsert))

#2551(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2551

8.4.3.33 Support for RANGE and ROWS specification within window functions
.........................................................................

New over.range_ and over.rows parameters allow
RANGE and ROWS expressions for window functions:

     >>> from sqlalchemy import func

     >>> print(func.row_number().over(order_by='x', range_=(-5, 10)))
     row_number() OVER (ORDER BY x RANGE BETWEEN :param_1 PRECEDING AND :param_2 FOLLOWING)

     >>> print(func.row_number().over(order_by='x', rows=(None, 0)))
     row_number() OVER (ORDER BY x ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)

     >>> print(func.row_number().over(order_by='x', range_=(-2, None)))
     row_number() OVER (ORDER BY x RANGE BETWEEN :param_1 PRECEDING AND UNBOUNDED FOLLOWING)

over.range_ and over.rows are specified as
2-tuples and indicate negative and positive values for specific ranges,
0 for “CURRENT ROW”, and None for UNBOUNDED.

See also
........

See Window Functions.

#3049(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3049

8.4.3.34 Support for the SQL LATERAL keyword
............................................

The LATERAL keyword is currently known to only be supported by
PostgreSQL 9.3 and greater, however as it is part of the SQL standard
support for this keyword is added to Core.  The implementation of
Select.lateral() employs special logic beyond just rendering the
LATERAL keyword to allow for correlation of tables that are derived from
the same FROM clause as the selectable, e.g.  lateral correlation:

     >>> from sqlalchemy import table, column, select, true
     >>> people = table('people', column('people_id'), column('age'), column('name'))
     >>> books = table('books', column('book_id'), column('owner_id'))
     >>> subq = select([books.c.book_id]).\
     ...      where(books.c.owner_id == people.c.people_id).lateral("book_subq")
     >>> print(select([people]).select_from(people.join(subq, true())))
     SELECT people.people_id, people.age, people.name
     FROM people JOIN LATERAL (SELECT books.book_id AS book_id
     FROM books WHERE books.owner_id = people.people_id)
     AS book_subq ON true

See also
........

See LATERAL correlation.

See Lateral.

See Select.lateral().

#2857(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2857

8.4.3.35 Support for TABLESAMPLE
................................

The SQL standard TABLESAMPLE can be rendered using the
FromClause.tablesample() method, which returns a
TableSample construct similar to an alias:

     from sqlalchemy import func

     selectable = people.tablesample(
                 func.bernoulli(1),
                 name='alias',
                 seed=func.random())
     stmt = select([selectable.c.people_id])

Assuming ‘people’ with a column ‘people_id’, the above statement would
render as:

     SELECT alias.people_id FROM
     people AS alias TABLESAMPLE bernoulli(:bernoulli_1)
     REPEATABLE (random())

#3718(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3718

8.4.3.36 The ‘.autoincrement’ directive is no longer implicitly enabled for a composite primary key column
..........................................................................................................

SQLAlchemy has always had the convenience feature of enabling the
backend database’s “autoincrement” feature for a single-column integer
primary key; by “autoincrement” we mean that the database column will
include whatever DDL directives the database provides in order to
indicate an auto-incrementing integer identifier, such as the SERIAL
keyword on PostgreSQL or AUTO_INCREMENT on MySQL, and additionally that
the dialect will receive these generated values from the execution of a
Table.insert() construct using techniques appropriate to
that backend.

What’s changed is that this feature no longer turns on automatically for
a `composite' primary key; previously, a table definition such as:

     Table(
         'some_table', metadata,
         Column('x', Integer, primary_key=True),
         Column('y', Integer, primary_key=True)
     )

Would have “autoincrement” semantics applied to the ‘'x'’ column, only
because it’s first in the list of primary key columns.  In order to
disable this, one would have to turn off ‘autoincrement’ on all columns:

     # old way
     Table(
         'some_table', metadata,
         Column('x', Integer, primary_key=True, autoincrement=False),
         Column('y', Integer, primary_key=True, autoincrement=False)
     )

With the new behavior, the composite primary key will not have
autoincrement semantics unless a column is marked explicitly with
‘autoincrement=True’:

     # column 'y' will be SERIAL/AUTO_INCREMENT/ auto-generating
     Table(
         'some_table', metadata,
         Column('x', Integer, primary_key=True),
         Column('y', Integer, primary_key=True, autoincrement=True)
     )

In order to anticipate some potential backwards-incompatible scenarios,
the Table.insert() construct will perform more thorough
checks for missing primary key values on composite primary key columns
that don’t have autoincrement set up; given a table such as:

     Table(
         'b', metadata,
         Column('x', Integer, primary_key=True),
         Column('y', Integer, primary_key=True)
     )

An INSERT emitted with no values for this table will produce this
warning:

     SAWarning: Column 'b.x' is marked as a member of the primary
     key for table 'b', but has no Python-side or server-side default
     generator indicated, nor does it indicate 'autoincrement=True',
     and no explicit value is passed.  Primary key columns may not
     store NULL. Note that as of SQLAlchemy 1.1, 'autoincrement=True'
     must be indicated explicitly for composite (e.g. multicolumn)
     primary keys if AUTO_INCREMENT/SERIAL/IDENTITY behavior is
     expected for one of the columns in the primary key. CREATE TABLE
     statements are impacted by this change as well on most backends.

For a column that is receiving primary key values from a server-side
default or something less common such as a trigger, the presence of a
value generator can be indicated using FetchedValue:

     Table(
         'b', metadata,
         Column('x', Integer, primary_key=True, server_default=FetchedValue()),
         Column('y', Integer, primary_key=True, server_default=FetchedValue())
     )

For the very unlikely case where a composite primary key is actually
intended to store NULL in one or more of its columns (only supported on
SQLite and MySQL), specify the column with ‘nullable=True’:

     Table(
         'b', metadata,
         Column('x', Integer, primary_key=True),
         Column('y', Integer, primary_key=True, nullable=True)
     )

In a related change, the ‘autoincrement’ flag may be set to True on a
column that has a client-side or server-side default.  This typically
will not have much impact on the behavior of the column during an
INSERT.

See also
........

See No more generation of an implicit KEY for composite primary key w/ AUTO_INCREMENT.

#3216(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3216

8.4.3.37 Support for IS DISTINCT FROM and IS NOT DISTINCT FROM
..............................................................

New operators ColumnOperators.is_distinct_from() and
ColumnOperators.isnot_distinct_from() allow the IS DISTINCT FROM
and IS NOT DISTINCT FROM sql operation:

     >>> print(column('x').is_distinct_from(None))
     x IS DISTINCT FROM NULL

Handling is provided for NULL, True and False:

     >>> print(column('x').isnot_distinct_from(False))
     x IS NOT DISTINCT FROM false

For SQLite, which doesn’t have this operator, “IS” / “IS NOT” is
rendered, which on SQLite works for NULL unlike other backends:

     >>> from sqlalchemy.dialects import sqlite
     >>> print(column('x').is_distinct_from(None).compile(dialect=sqlite.dialect()))
     x IS NOT NULL

8.4.3.38 Core and ORM support for FULL OUTER JOIN
.................................................

The new flag FromClause.outerjoin.full, available at the Core
and ORM level, instructs the compiler to render ‘FULL OUTER JOIN’ where
it would normally render ‘LEFT OUTER JOIN’:

     stmt = select([t1]).select_from(t1.outerjoin(t2, full=True))

The flag also works at the ORM level:

     q = session.query(MyClass).outerjoin(MyOtherClass, full=True)

#1957(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1957

8.4.3.39 ResultSet column matching enhancements; positional column setup for textual SQL
........................................................................................

A series of improvements were made to the ‘ResultProxy’ system in the
1.0 series as part of #918(1), which reorganizes the internals to match
cursor-bound result columns with table/ORM metadata positionally, rather
than by matching names, for compiled SQL constructs that contain full
information about the result rows to be returned.  This allows a
dramatic savings on Python overhead as well as much greater accuracy in
linking ORM and Core SQL expressions to result rows.  In 1.1, this
reorganization has been taken further internally, and also has been made
available to pure-text SQL constructs via the use of the recently added
TextClause.columns() method.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/918

8.4.3.40 TextAsFrom.columns() now works positionally
....................................................

The TextClause.columns() method, added in 0.9, accepts
column-based arguments positionally; in 1.1, when all columns are passed
positionally, the correlation of these columns to the ultimate result
set is also performed positionally.  The key advantage here is that
textual SQL can now be linked to an ORM- level result set without the
need to deal with ambiguous or duplicate column names, or with having to
match labeling schemes to ORM-level labeling schemes.  All that’s needed
now is the same ordering of columns within the textual SQL and the
column arguments passed to TextClause.columns():

     from sqlalchemy import text
     stmt = text("SELECT users.id, addresses.id, users.id, "
          "users.name, addresses.email_address AS email "
          "FROM users JOIN addresses ON users.id=addresses.user_id "
          "WHERE users.id = 1").columns(
             User.id,
             Address.id,
             Address.user_id,
             User.name,
             Address.email_address
          )

     query = session.query(User).from_statement(stmt).\
         options(contains_eager(User.addresses))
     result = query.all()

Above, the textual SQL contains the column “id” three times, which would
normally be ambiguous.  Using the new feature, we can apply the mapped
columns from the ‘User’ and ‘Address’ class directly, even linking the
‘Address.user_id’ column to the ‘users.id’ column in textual SQL for
fun, and the Query object will receive rows that are
correctly targetable as needed, including for an eager load.

This change is `backwards incompatible' with code that passes the
columns to the method with a different ordering than is present in the
textual statement.  It is hoped that this impact will be low due to the
fact that this method has always been documented illustrating the
columns being passed in the same order as that of the textual SQL
statement, as would seem intuitive, even though the internals weren’t
checking for this.  The method itself was only added as of 0.9 in any
case and may not yet have widespread use.  Notes on exactly how to
handle this behavioral change for applications using it are at
TextClause.columns() will match columns positionally, not by name, when passed positionally.

See also
........

See Specifying Result-Column Behaviors. - in the Core tutorial

See TextClause.columns() will match columns positionally, not by name, when passed positionally.
- backwards compatibility remarks

8.4.3.41 Positional matching is trusted over name-based matching for Core/ORM SQL constructs
............................................................................................

Another aspect of this change is that the rules for matching columns
have also been modified to rely upon “positional” matching more fully
for compiled SQL constructs as well.  Given a statement like the
following:

     ua = users.alias('ua')
     stmt = select([users.c.user_id, ua.c.user_id])

The above statement will compile to:

     SELECT users.user_id, ua.user_id FROM users, users AS ua

In 1.0, the above statement when executed would be matched to its
original compiled construct using positional matching, however because
the statement contains the ‘'user_id'’ label duplicated, the “ambiguous
column” rule would still get involved and prevent the columns from being
fetched from a row.  As of 1.1, the “ambiguous column” rule does not
affect an exact match from a column construct to the SQL column, which
is what the ORM uses to fetch columns:

     result = conn.execute(stmt)
     row = result.first()

     # these both match positionally, so no error
     user_id = row[users.c.user_id]
     ua_id = row[ua.c.user_id]

     # this still raises, however
     user_id = row['user_id']

8.4.3.42 Much less likely to get an “ambiguous column” error message
....................................................................

As part of this change, the wording of the error message ‘Ambiguous
column name '<name>' in result set! try 'use_labels' option on select
statement.’ has been dialed back; as this message should now be
extremely rare when using the ORM or Core compiled SQL constructs, it
merely states ‘Ambiguous column name '<name>' in result set column
descriptions’, and only when a result column is retrieved using the
string name that is actually ambiguous, e.g.  ‘row['user_id']’ in the
above example.  It also now refers to the actual ambiguous name from the
rendered SQL statement itself, rather than indicating the key or name
that was local to the construct being used for the fetch.

#3501(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3501

8.4.3.43 Support for Python’s native ‘enum’ type and compatible forms
.....................................................................

The Enum type can now be constructed using any PEP-435
compliant enumerated type.  When using this mode, input values and
return values are the actual enumerated objects, not the
string/integer/etc values:

     import enum
     from sqlalchemy import Table, MetaData, Column, Enum, create_engine

     class MyEnum(enum.Enum):
         one = 1
         two = 2
         three = 3

     t = Table(
         'data', MetaData(),
         Column('value', Enum(MyEnum))
     )

     e = create_engine("sqlite://")
     t.create(e)

     e.execute(t.insert(), {"value": MyEnum.two})
     assert e.scalar(t.select()) is MyEnum.two

8.4.3.44 The ‘Enum.enums’ collection is now a list instead of a tuple
.....................................................................

As part of the changes to Enum, the ‘Enum.enums’ collection
of elements is now a list instead of a tuple.  This because lists are
appropriate for variable length sequences of homogeneous items where the
position of the element is not semantically significant.

#3292(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3292

8.4.3.45 Negative integer indexes accommodated by Core result rows
..................................................................

The ‘RowProxy’ object now accommodates single negative integer indexes
like a regular Python sequence, both in the pure Python and C-extension
version.  Previously, negative values would only work in slices:

     >>> from sqlalchemy import create_engine
     >>> e = create_engine("sqlite://")
     >>> row = e.execute("select 1, 2, 3").first()
     >>> row[-1], row[-2], row[1], row[-2:2]
     3 2 2 (2,)

8.4.3.46 The ‘Enum’ type now does in-Python validation of values
................................................................

To accommodate for Python native enumerated objects, as well as for edge
cases such as that of where a non-native ENUM type is used within an
ARRAY and a CHECK constraint is infeasible, the Enum
datatype now adds in-Python validation of input values when the
Enum.validate_strings flag is used (1.1.0b2):

     >>> from sqlalchemy import Table, MetaData, Column, Enum, create_engine
     >>> t = Table(
     ...     'data', MetaData(),
     ...     Column('value', Enum("one", "two", "three", validate_strings=True))
     ... )
     >>> e = create_engine("sqlite://")
     >>> t.create(e)
     >>> e.execute(t.insert(), {"value": "four"})
     Traceback (most recent call last):
       ...
     sqlalchemy.exc.StatementError: (exceptions.LookupError)
     "four" is not among the defined enum values
     [SQL: u'INSERT INTO data (value) VALUES (?)']
     [parameters: [{'value': 'four'}]]

This validation is turned off by default as there are already use cases
identified where users don’t want such validation (such as string
comparisons).  For non-string types, it necessarily takes place in all
cases.  The check also occurs unconditionally on the result-handling
side as well, when values coming from the database are returned.

This validation is in addition to the existing behavior of creating a
CHECK constraint when a non-native enumerated type is used.  The
creation of this CHECK constraint can now be disabled using the new
Enum.create_constraint flag.

#3095(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3095

8.4.3.47 Non-native boolean integer values coerced to zero/one/None in all cases
................................................................................

The Boolean datatype coerces Python booleans to integer
values for backends that don’t have a native boolean type, such as
SQLite and MySQL. On these backends, a CHECK constraint is normally set
up which ensures the values in the database are in fact one of these two
values.  However, MySQL ignores CHECK constraints, the constraint is
optional, and an existing database might not have this constraint.  The
Boolean datatype has been repaired such that an incoming
Python-side value that is already an integer value is coerced to zero or
one, not just passed as-is; additionally, the C-extension version of the
int-to-boolean processor for results now uses the same Python boolean
interpretation of the value, rather than asserting an exact one or zero
value.  This is now consistent with the pure-Python int-to-boolean
processor and is more forgiving of existing data already within the
database.  Values of None/NULL are as before retained as None/NULL.

     Note: this change had an unintended side effect that the
     interpretation of non- integer values, such as strings, also
     changed in behavior such that the string value ‘"0"’ would be
     interpreted as “true”, but only on backends that don’t have a
     native boolean datatype - on “native boolean” backends like
     PostgreSQL, the string value ‘"0"’ is passed directly to the driver
     and is interpreted as “false”.  This is an inconsistency that did
     not occur with the previous implementation.  It should be noted
     that passing strings or any other value outside of ‘None’, ‘True’,
     ‘False’, ‘1’, ‘0’ to the Boolean datatype is `not
     supported' and version 1.2 will raise an error for this scenario
     (or possibly just emit a warning, TBD). See also #4102(1).

#3730(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/4102

   (2) http://www.sqlalchemy.org/trac/ticket/3730

8.4.3.48 Large parameter and row values are now truncated in logging and exception displays
...........................................................................................

A large value present as a bound parameter for a SQL statement, as well
as a large value present in a result row, will now be truncated during
display within logging, exception reporting, as well as ‘repr()’ of the
row itself:

     >>> from sqlalchemy import create_engine
     >>> import random
     >>> e = create_engine("sqlite://", echo='debug')
     >>> some_value = ''.join(chr(random.randint(52, 85)) for i in range(5000))
     >>> row = e.execute("select ?", [some_value]).first()
     ... (lines are wrapped for clarity) ...
     2016-02-17 13:23:03,027 INFO sqlalchemy.engine.base.Engine select ?
     2016-02-17 13:23:03,027 INFO sqlalchemy.engine.base.Engine
     ('E6@?>9HPOJB<<BHR:@=TS:5ILU=;JLM<4?B9<S48PTNG9>:=TSTLA;9K;9FPM4M8M@;NM6GU
     LUAEBT9QGHNHTHR5EP75@OER4?SKC;D:TFUMD:M>;C6U:JLM6R67GEK<A6@S@C@J7>4=4:P
     GJ7HQ6 ... (4702 characters truncated) ... J6IK546AJMB4N6S9L;;9AKI;=RJP
     HDSSOTNBUEEC9@Q:RCL:I@5?FO<9K>KJAGAO@E6@A7JI8O:J7B69T6<8;F:S;4BEIJS9HM
     K:;5OLPM@JR;R:J6<SOTTT=>Q>7T@I::OTDC:CC<=NGP6C>BC8N',)
     2016-02-17 13:23:03,027 DEBUG sqlalchemy.engine.base.Engine Col ('?',)
     2016-02-17 13:23:03,027 DEBUG sqlalchemy.engine.base.Engine
     Row (u'E6@?>9HPOJB<<BHR:@=TS:5ILU=;JLM<4?B9<S48PTNG9>:=TSTLA;9K;9FPM4M8M@;
     NM6GULUAEBT9QGHNHTHR5EP75@OER4?SKC;D:TFUMD:M>;C6U:JLM6R67GEK<A6@S@C@J7
     >4=4:PGJ7HQ ... (4703 characters truncated) ... J6IK546AJMB4N6S9L;;9AKI;=
     RJPHDSSOTNBUEEC9@Q:RCL:I@5?FO<9K>KJAGAO@E6@A7JI8O:J7B69T6<8;F:S;4BEIJS9HM
     K:;5OLPM@JR;R:J6<SOTTT=>Q>7T@I::OTDC:CC<=NGP6C>BC8N',)
     >>> print(row)
     (u'E6@?>9HPOJB<<BHR:@=TS:5ILU=;JLM<4?B9<S48PTNG9>:=TSTLA;9K;9FPM4M8M@;NM6
     GULUAEBT9QGHNHTHR5EP75@OER4?SKC;D:TFUMD:M>;C6U:JLM6R67GEK<A6@S@C@J7>4
     =4:PGJ7HQ ... (4703 characters truncated) ... J6IK546AJMB4N6S9L;;9AKI;
     =RJPHDSSOTNBUEEC9@Q:RCL:I@5?FO<9K>KJAGAO@E6@A7JI8O:J7B69T6<8;F:S;4BEIJS9H
     MK:;5OLPM@JR;R:J6<SOTTT=>Q>7T@I::OTDC:CC<=NGP6C>BC8N',)

#2837(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2837

8.4.3.49 JSON support added to Core
...................................

As MySQL now has a JSON datatype in addition to the PostgreSQL JSON
datatype, the core now gains a sqlalchemy.types.JSON
datatype that is the basis for both of these.  Using this type allows
access to the “getitem” operator as well as the “getpath” operator in a
way that is agnostic across PostgreSQL and MySQL.

The new datatype also has a series of improvements to the handling of
NULL values as well as expression handling.

See also
........

See MySQL JSON Support.

See JSON.

See JSON.

See JSON.

#3619(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3619

8.4.3.50 JSON “null” is inserted as expected with ORM operations, omitted when not present
..........................................................................................

The JSON type and its descendant types JSON and
JSON have a flag JSON.none_as_null which when
set to True indicates that the Python value ‘None’ should translate into
a SQL NULL rather than a JSON NULL value.  This flag defaults to False,
which means that the Python value ‘None’ should result in a JSON NULL
value.

This logic would fail, and is now corrected, in the following
circumstances:

1.  When the column also contained a default or server_default value, a
positive value of ‘None’ on the mapped attribute that expects to persist
JSON “null” would still result in the column-level default being
triggered, replacing the ‘None’ value:

     class MyObject(Base):
         # ...

         json_value = Column(JSON(none_as_null=False), default="some default")

     # would insert "some default" instead of "'null'",
     # now will insert "'null'"
     obj = MyObject(json_value=None)
     session.add(obj)
     session.commit()

2.  When the column `did not' contain a default or server_default value,
a missing value on a JSON column configured with none_as_null=False
would still render JSON NULL rather than falling back to not inserting
any value, behaving inconsistently vs.  all other datatypes:

     class MyObject(Base):
         # ...

         some_other_value = Column(String(50))
         json_value = Column(JSON(none_as_null=False))

     # would result in NULL for some_other_value,
     # but json "'null'" for json_value.  Now results in NULL for both
     # (the json_value is omitted from the INSERT)
     obj = MyObject()
     session.add(obj)
     session.commit()

This is a behavioral change that is backwards incompatible for an
application that was relying upon this to default a missing value as
JSON null.  This essentially establishes that a `missing value is
distinguished from a present value of None'.  See *note JSON Columns
will not insert JSON NULL if no value is supplied and no default is
established: 4920. for further detail.

3.  When the Session.bulk_insert_mappings() method were
used, ‘None’ would be ignored in all cases:

     # would insert SQL NULL and/or trigger defaults,
     # now inserts "'null'"
     session.bulk_insert_mappings(
         MyObject,
         [{"json_value": None}])

The JSON type now implements the
TypeEngine.should_evaluate_none flag, indicating that ‘None’
should not be ignored here; it is configured automatically based on the
value of JSON.none_as_null.  Thanks to #3061(1), we can
differentiate when the value ‘None’ is actively set by the user versus
when it was never set at all.

The feature applies as well to the new base JSON type and
its descendant types.

#3514(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3061

   (2) http://www.sqlalchemy.org/trac/ticket/3514

8.4.3.51 New JSON.NULL Constant Added
.....................................

To ensure that an application can always have full control at the value
level of whether a JSON, JSON, JSON,
or JSONB column should receive a SQL NULL or JSON ‘"null"’
value, the constant JSON.NULL has been added, which in
conjunction with null() can be used to determine fully
between SQL NULL and JSON ‘"null"’, regardless of what
JSON.none_as_null is set to:

     from sqlalchemy import null
     from sqlalchemy.dialects.postgresql import JSON

     obj1 = MyObject(json_value=null())  # will *always* insert SQL NULL
     obj2 = MyObject(json_value=JSON.NULL)  # will *always* insert JSON string "null"

     session.add_all([obj1, obj2])
     session.commit()

The feature applies as well to the new base JSON type and
its descendant types.

#3514(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3514

8.4.3.52 Array support added to Core; new ANY and ALL operators
...............................................................

Along with the enhancements made to the PostgreSQL ARRAY
type described in Correct SQL Types are Established from Indexed Access of ARRAY, JSON, HSTORE,
the base class of ARRAY
itself has been moved to Core in a new class ARRAY.

Arrays are part of the SQL standard, as are several array-oriented
functions such as ‘array_agg()’ and ‘unnest()’.  In support of these
constructs for not just PostgreSQL but also potentially for other
array-capable backends in the future such as DB2, the majority of array
logic for SQL expressions is now in Core.  The ARRAY type
still `only works on PostgreSQL', however it can be used directly,
supporting special array use cases such as indexed access, as well as
support for the ANY and ALL:

     mytable = Table("mytable", metadata,
             Column("data", ARRAY(Integer, dimensions=2))
         )

     expr = mytable.c.data[5][6]

     expr = mytable.c.data[5].any(12)

In support of ANY and ALL, the ARRAY type retains the same
Comparator.any() and Comparator.all() methods
from the PostgreSQL type, but also exports these operations to new
standalone operator functions any_() and all_().
These two functions work in more of the traditional SQL way, allowing a
right-side expression form such as:

     from sqlalchemy import any_, all_

     select([mytable]).where(12 == any_(mytable.c.data[5]))

For the PostgreSQL-specific operators “contains”, “contained_by”, and
“overlaps”, one should continue to use the ARRAY type
directly, which provides all functionality of the ARRAY type
as well.

The any_() and all_() operators are open-ended
at the Core level, however their interpretation by backend databases is
limited.  On the PostgreSQL backend, the two operators `only accept
array values'.  Whereas on the MySQL backend, they `only accept subquery
values'.  On MySQL, one can use an expression such as:

     from sqlalchemy import any_, all_

     subq = select([mytable.c.value])
     select([mytable]).where(12 > any_(subq))

#3516(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3516

8.4.3.53 New Function features, “WITHIN GROUP”, array_agg and set aggregate functions
.....................................................................................

With the new ARRAY type we can also implement a pre-typed
function for the ‘array_agg()’ SQL function that returns an array, which
is now available using array_agg:

     from sqlalchemy import func
     stmt = select([func.array_agg(table.c.value)])

A PostgreSQL element for an aggregate ORDER BY is also added via
aggregate_order_by:

     from sqlalchemy.dialects.postgresql import aggregate_order_by
     expr = func.array_agg(aggregate_order_by(table.c.a, table.c.b.desc()))
     stmt = select([expr])

Producing:

     SELECT array_agg(table1.a ORDER BY table1.b DESC) AS array_agg_1 FROM table1

The PG dialect itself also provides an array_agg() wrapper
to ensure the ARRAY type:

     from sqlalchemy.dialects.postgresql import array_agg
     stmt = select([array_agg(table.c.value).contains('foo')])

Additionally, functions like ‘percentile_cont()’, ‘percentile_disc()’,
‘rank()’, ‘dense_rank()’ and others that require an ordering via ‘WITHIN
GROUP (ORDER BY <expr>)’ are now available via the
FunctionElement.within_group() modifier:

     from sqlalchemy import func
     stmt = select([
         department.c.id,
         func.percentile_cont(0.5).within_group(
             department.c.salary.desc()
         )
     ])

The above statement would produce SQL similar to:

     SELECT department.id, percentile_cont(0.5)
     WITHIN GROUP (ORDER BY department.salary DESC)

Placeholders with correct return types are now provided for these
functions, and include percentile_cont,
percentile_disc, rank, dense_rank,
mode, percent_rank, and cume_dist.

#3132(1) #1370(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3132

   (2) http://www.sqlalchemy.org/trac/ticket/1370

8.4.3.54 TypeDecorator now works with Enum, Boolean, “schema” types automatically
.................................................................................

The SchemaType types include types such as Enum
and Boolean which, in addition to corresponding to a
database type, also generate either a CHECK constraint or in the case of
PostgreSQL ENUM a new CREATE TYPE statement, will now work automatically
with TypeDecorator recipes.  Previously, a
TypeDecorator for an ENUM had to look like this:

     # old way
     class MyEnum(TypeDecorator, SchemaType):
         impl = postgresql.ENUM('one', 'two', 'three', name='myenum')

         def _set_table(self, table):
             self.impl._set_table(table)

The TypeDecorator now propagates those additional events so
it can be done like any other type:

     # new way
     class MyEnum(TypeDecorator):
         impl = postgresql.ENUM('one', 'two', 'three', name='myenum')

#2919(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2919

8.4.3.55 Multi-Tenancy Schema Translation for Table objects
...........................................................

To support the use case of an application that uses the same set of
Table objects in many schemas, such as schema-per-user, a new
execution option
Connection.execution_options.schema_translate_map is added.
Using this mapping, a set of Table objects can be made on a
per-connection basis to refer to any set of schemas instead of the
Table.schema to which they were assigned.  The translation works
for DDL and SQL generation, as well as with the ORM.

For example, if the ‘User’ class were assigned the schema “per_user”:

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)

         __table_args__ = {'schema': 'per_user'}

On each request, the Session can be set up to refer to a
different schema each time:

     session = Session()
     session.connection(execution_options={
         "schema_translate_map": {"per_user": "account_one"}})

     # will query from the ``account_one.user`` table
     session.query(User).get(5)

See also
........

See Translation of Schema Names.

#2685(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2685

8.4.3.56 “Friendly” stringification of Core SQL constructs without a dialect
............................................................................

Calling ‘str()’ on a Core SQL construct will now produce a string in
more cases than before, supporting various SQL constructs not normally
present in default SQL such as RETURNING, array indexes, and
non-standard datatypes:

     >>> from sqlalchemy import table, column
     t>>> t = table('x', column('a'), column('b'))
     >>> print(t.insert().returning(t.c.a, t.c.b))
     INSERT INTO x (a, b) VALUES (:a, :b) RETURNING x.a, x.b

The ‘str()’ function now calls upon an entirely separate dialect /
compiler intended just for plain string printing without a specific
dialect set up, so as more “just show me a string!” cases come up, these
can be added to this dialect/compiler without impacting behaviors on
real dialects.

See also
........

See Stringify of Query will consult the Session for the correct dialect.

#3631(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3631

8.4.3.57 The type_coerce function is now a persistent SQL element
.................................................................

The type_coerce() function previously would return an object
either of type BindParameter or Label, depending
on the input.  An effect this would have was that in the case where
expression transformations were used, such as the conversion of an
element from a Column to a BindParameter that’s
critical to ORM-level lazy loading, the type coercion information would
not be used since it would have been lost already.

To improve this behavior, the function now returns a persistent
TypeCoerce container around the given expression, which itself
remains unaffected; this construct is evaluated explicitly by the SQL
compiler.  This allows for the coercion of the inner expression to be
maintained no matter how the statement is modified, including if the
contained element is replaced with a different one, as is common within
the ORM’s lazy loading feature.

The test case illustrating the effect makes use of a heterogeneous
primaryjoin condition in conjunction with custom types and lazy loading.
Given a custom type that applies a CAST as a “bind expression”:

     class StringAsInt(TypeDecorator):
         impl = String

         def column_expression(self, col):
             return cast(col, Integer)

         def bind_expression(self, value):
             return cast(value, String)

Then, a mapping where we are equating a string “id” column on one table
to an integer “id” column on the other:

     class Person(Base):
         __tablename__ = 'person'
         id = Column(StringAsInt, primary_key=True)

         pets = relationship(
             'Pets',
             primaryjoin=(
                 'foreign(Pets.person_id)'
                 '==cast(type_coerce(Person.id, Integer), Integer)'
             )
         )

     class Pets(Base):
         __tablename__ = 'pets'
         id = Column('id', Integer, primary_key=True)
         person_id = Column('person_id', Integer)

Above, in the relationship.primaryjoin expression, we are
using type_coerce() to handle bound parameters passed via
lazyloading as integers, since we already know these will come from our
‘StringAsInt’ type which maintains the value as an integer in Python.
We are then using cast() so that as a SQL expression, the
VARCHAR “id” column will be CAST to an integer for a regular non-
converted join as with Query.join() or joinedload().
That is, a joinedload of ‘.pets’ looks like:

     SELECT person.id AS person_id, pets_1.id AS pets_1_id,
            pets_1.person_id AS pets_1_person_id
     FROM person
     LEFT OUTER JOIN pets AS pets_1
     ON pets_1.person_id = CAST(person.id AS INTEGER)

Without the CAST in the ON clause of the join, strongly-typed databases
such as PostgreSQL will refuse to implicitly compare the integer and
fail.

The lazyload case of ‘.pets’ relies upon replacing the ‘Person.id’
column at load time with a bound parameter, which receives a
Python-loaded value.  This replacement is specifically where the intent
of our type_coerce() function would be lost.  Prior to the
change, this lazy load comes out as:

     SELECT pets.id AS pets_id, pets.person_id AS pets_person_id
     FROM pets
     WHERE pets.person_id = CAST(CAST(%(param_1)s AS VARCHAR) AS INTEGER)
     {'param_1': 5}

Where above, we see that our in-Python value of ‘5’ is CAST first to a
VARCHAR, then back to an INTEGER in SQL; a double CAST which works, but
is nevertheless not what we asked for.

With the change, the type_coerce() function maintains a
wrapper even after the column is swapped out for a bound parameter, and
the query now looks like:

     SELECT pets.id AS pets_id, pets.person_id AS pets_person_id
     FROM pets
     WHERE pets.person_id = CAST(%(param_1)s AS INTEGER)
     {'param_1': 5}

Where our outer CAST that’s in our primaryjoin still takes effect, but
the needless CAST that’s in part of the ‘StringAsInt’ custom type is
removed as intended by the type_coerce() function.

#3531(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3531

8.4.3.58 Key Behavioral Changes - ORM
.....................................

8.4.3.59 JSON Columns will not insert JSON NULL if no value is supplied and no default is established
.....................................................................................................

As detailed in JSON “null” is inserted as expected with ORM operations, omitted when not present,
see JSON will not
render a JSON “null” value if the value is missing entirely.  To prevent
SQL NULL, a default should be set up.  Given the following mapping:

     class MyObject(Base):
         # ...

         json_value = Column(JSON(none_as_null=False), nullable=False)

The following flush operation will fail with an integrity error:

     obj = MyObject()  # note no json_value
     session.add(obj)
     session.commit()  # will fail with integrity error

If the default for the column should be JSON NULL, set this on the
Column:

     class MyObject(Base):
         # ...

         json_value = Column(
             JSON(none_as_null=False), nullable=False, default=JSON.NULL)

Or, ensure the value is present on the object:

     obj = MyObject(json_value=None)
     session.add(obj)
     session.commit()  # will insert JSON NULL

Note that setting ‘None’ for the default is the same as omitting it
entirely; the JSON.none_as_null flag does not impact the
value of ‘None’ passed to Column.default or
Column.server_default:

     # default=None is the same as omitting it entirely, does not apply JSON NULL
     json_value = Column(JSON(none_as_null=False), nullable=False, default=None)

See also
........

See JSON “null” is inserted as expected with ORM operations, omitted when not present.

8.4.3.60 Columns no longer added redundantly with DISTINCT + ORDER BY
.....................................................................

A query such as the following will now augment only those columns that
are missing from the SELECT list, without duplicates:

     q = session.query(User.id, User.name.label('name')).\
         distinct().\
         order_by(User.id, User.name, User.fullname)

Produces:

     SELECT DISTINCT user.id AS a_id, user.name AS name,
      user.fullname AS a_fullname
     FROM a ORDER BY user.id, user.name, user.fullname

Previously, it would produce:

     SELECT DISTINCT user.id AS a_id, user.name AS name, user.name AS a_name,
       user.fullname AS a_fullname
     FROM a ORDER BY user.id, user.name, user.fullname

Where above, the ‘user.name’ column is added unnecessarily.  The results
would not be affected, as the additional columns are not included in the
result in any case, but the columns are unnecessary.

Additionally, when the PostgreSQL DISTINCT ON format is used by passing
expressions to Query.distinct(), the above “column adding”
logic is disabled entirely.

When the query is being bundled into a subquery for the purposes of
joined eager loading, the “augment column list” rules are necessarily
more aggressive so that the ORDER BY can still be satisfied, so this
case remains unchanged.

#3641(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3641

8.4.3.61 Same-named @validates decorators will now raise an exception
.....................................................................

The validates() decorator is only intended to be created
once per class for a particular attribute name.  Creating more than one
now raises an error, whereas previously it would silently pick only the
last defined validator:

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)

         data = Column(String)

         @validates("data")
         def _validate_data_one(self):
             assert "x" in data

         @validates("data")
         def _validate_data_two(self):
             assert "y" in data

     configure_mappers()

Will raise:

     sqlalchemy.exc.InvalidRequestError: A validation function for mapped attribute 'data' on mapper Mapper|A|a already exists.

#3776(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3776

8.4.3.62 Key Behavioral Changes - Core
......................................

8.4.3.63 TextClause.columns() will match columns positionally, not by name, when passed positionally
....................................................................................................

The new behavior of the TextClause.columns() method, which
itself was recently added as of the 0.9 series, is that when columns are
passed positionally without any additional keyword arguments, they are
linked to the ultimate result set columns positionally, and no longer on
name.  It is hoped that the impact of this change will be low due to the
fact that the method has always been documented illustrating the columns
being passed in the same order as that of the textual SQL statement, as
would seem intuitive, even though the internals weren’t checking for
this.

An application that is using this method by passing Column
objects to it positionally must ensure that the position of those
Column objects matches the position in which these columns are
stated in the textual SQL.

E.g., code like the following:

     stmt = text("SELECT id, name, description FROM table")

     # no longer matches by name
     stmt = stmt.columns(my_table.c.name, my_table.c.description, my_table.c.id)

Would no longer work as expected; the order of the columns given is now
significant:

     # correct version
     stmt = stmt.columns(my_table.c.id, my_table.c.name, my_table.c.description)

Possibly more likely, a statement that worked like this:

     stmt = text("SELECT * FROM table")
     stmt = stmt.columns(my_table.c.id, my_table.c.name, my_table.c.description)

is now slightly risky, as the “*” specification will generally deliver
columns in the order in which they are present in the table itself.  If
the structure of the table changes due to schema changes, this ordering
may no longer be the same.  Therefore when using
TextClause.columns(), it’s advised to list out the desired columns
explicitly in the textual SQL, though it’s no longer necessary to worry
about the names themselves in the textual SQL.

See also
........

See ResultSet column matching enhancements; positional column setup for textual SQL.

8.4.3.64 String server_default now literal quoted
.................................................

A server default passed to Column.server_default as a plain
Python string that has quotes embedded is now passed through the literal
quoting system:

     >>> from sqlalchemy.schema import MetaData, Table, Column, CreateTable
     >>> from sqlalchemy.types import String
     >>> t = Table('t', MetaData(), Column('x', String(), server_default="hi ' there"))
     >>> print(CreateTable(t))

     CREATE TABLE t (
         x VARCHAR DEFAULT 'hi '' there'
     )

Previously the quote would render directly.  This change may be
backwards incompatible for applications with such a use case who were
working around the issue.

#3809(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3809

8.4.3.65 A UNION or similar of SELECTs with LIMIT/OFFSET/ORDER BY now parenthesizes the embedded selects
........................................................................................................

An issue that, like others, was long driven by SQLite’s lack of
capabilities has now been enhanced to work on all supporting backends.
We refer to a query that is a UNION of SELECT statements that themselves
contain row-limiting or ordering features which include LIMIT, OFFSET,
and/or ORDER BY:

     (SELECT x FROM table1 ORDER BY y LIMIT 1) UNION
     (SELECT x FROM table2 ORDER BY y LIMIT 2)

The above query requires parenthesis within each sub-select in order to
group the sub-results correctly.  Production of the above statement in
SQLAlchemy Core looks like:

     stmt1 = select([table1.c.x]).order_by(table1.c.y).limit(1)
     stmt2 = select([table1.c.x]).order_by(table2.c.y).limit(2)

     stmt = union(stmt1, stmt2)

Previously, the above construct would not produce parenthesization for
the inner SELECT statements, producing a query that fails on all
backends.

The above formats will `continue to fail on SQLite'; additionally, the
format that includes ORDER BY but no LIMIT/SELECT will `continue to fail
on Oracle'.  This is not a backwards-incompatible change, because the
queries fail without the parentheses as well; with the fix, the queries
at least work on all other databases.

In all cases, in order to produce a UNION of limited SELECT statements
that also works on SQLite and in all cases on Oracle, the subqueries
must be a SELECT of an ALIAS:

     stmt1 = select([table1.c.x]).order_by(table1.c.y).limit(1).alias().select()
     stmt2 = select([table2.c.x]).order_by(table2.c.y).limit(2).alias().select()

     stmt = union(stmt1, stmt2)

This workaround works on all SQLAlchemy versions.  In the ORM, it looks
like:

     stmt1 = session.query(Model1).order_by(Model1.y).limit(1).subquery().select()
     stmt2 = session.query(Model2).order_by(Model2.y).limit(1).subquery().select()

     stmt = session.query(Model1).from_statement(stmt1.union(stmt2))

The behavior here has many parallels to the “join rewriting” behavior
introduced in SQLAlchemy 0.9 in Many JOIN and LEFT OUTER JOIN expressions will no longer be wrapped in (SELECT * FROM ..) AS ANON_1;
however in this case we have opted not to add new rewriting
behavior to accommodate this case for SQLite.  The existing rewriting
behavior is very complicated already, and the case of UNIONs with
parenthesized SELECT statements is much less common than the
“right-nested-join” use case of that feature.

#2528(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2528

8.4.3.66 Dialect Improvements and Changes - PostgreSQL
......................................................

8.4.3.67 Support for INSERT..ON CONFLICT (DO UPDATE | DO NOTHING)
.................................................................

The ‘ON CONFLICT’ clause of ‘INSERT’ added to PostgreSQL as of version
9.5 is now supported using a PostgreSQL-specific version of the
Insert object, via ‘sqlalchemy.dialects.postgresql.dml.insert()’.
This Insert subclass adds two new methods
‘Insert.on_conflict_do_update()’ and ‘Insert.on_conflict_do_nothing()’
which implement the full syntax supported by PostgreSQL 9.5 in this
area:

     from sqlalchemy.dialects.postgresql import insert

     insert_stmt = insert(my_table). \\
         values(id='some_id', data='some data to insert')

     do_update_stmt = insert_stmt.on_conflict_do_update(
         index_elements=[my_table.c.id],
         set_=dict(data='some data to update')
     )

     conn.execute(do_update_stmt)

The above will render:

     INSERT INTO my_table (id, data)
     VALUES (:id, :data)
     ON CONFLICT id DO UPDATE SET data=:data_2

See also
........

See INSERT…ON CONFLICT (Upsert).

#3529(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3529

8.4.3.68 ARRAY and JSON types now correctly specify “unhashable”
................................................................

As described in Changes regarding “unhashable” types, impacts deduping of ORM rows,
the ORM relies upon being able to produce a
hash function for column values when a query’s selected entities mixes
full ORM entities with column expressions.  The ‘hashable=False’ flag is
now correctly set on all of PG’s “data structure” types, including
ARRAY and JSON.  The JSONB and
HSTORE types already included this flag.  For ARRAY,
this is conditional based on the ARRAY.as_tuple flag,
however it should no longer be necessary to set this flag in order to
have an array value present in a composed ORM row.

See also
........

See Changes regarding “unhashable” types, impacts deduping of ORM rows.

See Correct SQL Types are Established from Indexed Access of ARRAY, JSON, HSTORE.

#3499(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3499

8.4.3.69 Correct SQL Types are Established from Indexed Access of ARRAY, JSON, HSTORE
.....................................................................................

For all three of ARRAY, JSON and HSTORE,
the SQL type assigned to the expression returned by indexed access,
e.g.  ‘col[someindex]’, should be correct in all cases.

This includes:

   * The SQL type assigned to indexed access of an ARRAY.
     takes into account the number of dimensions configured.  An
     ARRAY with three dimensions will return a SQL expression with
     a type of ARRAY of one less dimension.  Given a column
     with type ‘ARRAY(Integer, dimensions=3)’, we can now perform this
     expression:

          int_expr = col[5][6][7]   # returns an Integer expression object

     Previously, the indexed access to ‘col[5]’ would return an
     expression of type Integer where we could no longer
     perform indexed access for the remaining dimensions, unless we used
     cast() or type_coerce().

   * The JSON and JSONB types now mirror what
     PostgreSQL itself does for indexed access.  This means that all
     indexed access for a JSON or JSONB type
     returns an expression that itself is `always' JSON or
     JSONB itself, unless the Comparator.astext
     modifier is used.  This means that whether the indexed access
     of the JSON structure ultimately refers to a string, list, number,
     or other JSON structure, PostgreSQL always considers it to be JSON
     itself unless it is explicitly cast differently.  Like the
     ARRAY type, this means that it is now straightforward to
     produce JSON expressions with multiple levels of indexed access:

          json_expr = json_col['key1']['attr1'][5]

   * The “textual” type that is returned by indexed access of
     HSTORE as well as the “textual” type that is returned by
     indexed access of JSON and JSONB in
     conjunction with the Comparator.astext modifier is now
     configurable; it defaults to TextClause in both cases
     but can be set to a user-defined type using the
     JSON.astext_type or HSTORE.text_type
     parameters.

See also
........

See The JSON cast() operation now requires .astext is called explicitly.

#3499(1) #3487(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3499

   (2) http://www.sqlalchemy.org/trac/ticket/3487

8.4.3.70 The JSON cast() operation now requires ‘.astext’ is called explicitly
..............................................................................

As part of the changes in Correct SQL Types are Established from Indexed Access of ARRAY, JSON, HSTORE,
the workings of the
ColumnElement.cast() operator on JSON and JSONB
no longer implicitly invoke the Comparator.astext
modifier; PostgreSQL’s JSON/JSONB types support CAST operations to each
other without the “astext” aspect.

This means that in most cases, an application that was doing this:

     expr = json_col['somekey'].cast(Integer)

Will now need to change to this:

     expr = json_col['somekey'].astext.cast(Integer)

8.4.3.71 ARRAY with ENUM will now emit CREATE TYPE for the ENUM
...............................................................

A table definition like the following will now emit CREATE TYPE as
expected:

     enum = Enum(
         'manager', 'place_admin', 'carwash_admin',
         'parking_admin', 'service_admin', 'tire_admin',
         'mechanic', 'carwasher', 'tire_mechanic', name="work_place_roles")

     class WorkPlacement(Base):
         __tablename__ = 'work_placement'
         id = Column(Integer, primary_key=True)
         roles = Column(ARRAY(enum))

     e = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
     Base.metadata.create_all(e)

emits:

     CREATE TYPE work_place_roles AS ENUM (
         'manager', 'place_admin', 'carwash_admin', 'parking_admin',
         'service_admin', 'tire_admin', 'mechanic', 'carwasher',
         'tire_mechanic')

     CREATE TABLE work_placement (
         id SERIAL NOT NULL,
         roles work_place_roles[],
         PRIMARY KEY (id)
     )

#2729(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2729

8.4.3.72 Check constraints now reflect
......................................

The PostgreSQL dialect now supports reflection of CHECK constraints both
within the method Inspector.get_check_constraints() as well
as within Table reflection within the
Table.constraints collection.

8.4.3.73 “Plain” and “Materialized” views can be inspected separately
.....................................................................

The new argument PGInspector.get_view_names.include allows
specification of which sub-types of views should be returned:

     from sqlalchemy import inspect
     insp = inspect(engine)

     plain_views = insp.get_view_names(include='plain')
     all_views = insp.get_view_names(include=('plain', 'materialized'))

#3588(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3588

8.4.3.74 Added tablespace option to Index
.........................................

The Index object now accepts the argument
‘postgresql_tablespace’ in order to specify TABLESPACE, the same way as
accepted by the Table object.

See also
........

See Index Storage Parameters.

#3720(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3720

8.4.3.75 Support for PyGreSQL
.............................

The PyGreSQL(1) DBAPI is now supported.

See also
........

See pygresql.

   ---------- Footnotes ----------

   (1) https://pypi.python.org/pypi/PyGreSQL

8.4.3.76 The “postgres” module is removed
.........................................

The ‘sqlalchemy.dialects.postgres’ module, long deprecated, is removed;
this has emitted a warning for many years and projects should be calling
upon ‘sqlalchemy.dialects.postgresql’.  Engine URLs of the form
‘postgres://’ will still continue to function, however.

8.4.3.77 Support for FOR UPDATE SKIP LOCKED / FOR NO KEY UPDATE / FOR KEY SHARE
...............................................................................

The new parameters GenerativeSelect.with_for_update.skip_locked
and GenerativeSelect.with_for_update.key_share in both
Core and ORM apply a modification to a “SELECT…FOR UPDATE” or
“SELECT…FOR SHARE” query on the PostgreSQL backend:

   * SELECT FOR NO KEY UPDATE:

          stmt = select([table]).with_for_update(key_share=True)

   * SELECT FOR UPDATE SKIP LOCKED:

          stmt = select([table]).with_for_update(skip_locked=True)

   * SELECT FOR KEY SHARE:

          stmt = select([table]).with_for_update(read=True, key_share=True)

8.4.3.78 Dialect Improvements and Changes - MySQL
.................................................

8.4.3.79 MySQL JSON Support
...........................

A new type JSON is added to the MySQL dialect supporting
the JSON type newly added to MySQL 5.7.  This type provides both
persistence of JSON as well as rudimentary indexed-access using the
‘JSON_EXTRACT’ function internally.  An indexable JSON column that works
across MySQL and PostgreSQL can be achieved by using the JSON
datatype common to both MySQL and PostgreSQL.

See also
........

See JSON support added to Core.

#3547(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3547

8.4.3.80 Added support for AUTOCOMMIT “isolation level”
.......................................................

The MySQL dialect now accepts the value “AUTOCOMMIT” for the
create_engine.isolation_level and
Connection.execution_options.isolation_level parameters:

     connection = engine.connect()
     connection = connection.execution_options(
         isolation_level="AUTOCOMMIT"
     )

The isolation level makes use of the various “autocommit” attributes
provided by most MySQL DBAPIs.

#3332(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3332

8.4.3.81 No more generation of an implicit KEY for composite primary key w/ AUTO_INCREMENT
..........................................................................................

The MySQL dialect had the behavior such that if a composite primary key
on an InnoDB table featured AUTO_INCREMENT on one of its columns which
was not the first column, e.g.:

     t = Table(
         'some_table', metadata,
         Column('x', Integer, primary_key=True, autoincrement=False),
         Column('y', Integer, primary_key=True, autoincrement=True),
         mysql_engine='InnoDB'
     )

DDL such as the following would be generated:

     CREATE TABLE some_table (
         x INTEGER NOT NULL,
         y INTEGER NOT NULL AUTO_INCREMENT,
         PRIMARY KEY (x, y),
         KEY idx_autoinc_y (y)
     )ENGINE=InnoDB

Note the above “KEY” with an auto-generated name; this is a change that
found its way into the dialect many years ago in response to the issue
that the AUTO_INCREMENT would otherwise fail on InnoDB without this
additional KEY.

This workaround has been removed and replaced with the much better
system of just stating the AUTO_INCREMENT column `first' within the
primary key:

     CREATE TABLE some_table (
         x INTEGER NOT NULL,
         y INTEGER NOT NULL AUTO_INCREMENT,
         PRIMARY KEY (y, x)
     )ENGINE=InnoDB

To maintain explicit control of the ordering of primary key columns, use
the PrimaryKeyConstraint construct explicitly (1.1.0b2)
(along with a KEY for the autoincrement column as required by MySQL),
e.g.:

     t = Table(
         'some_table', metadata,
         Column('x', Integer, primary_key=True),
         Column('y', Integer, primary_key=True, autoincrement=True),
         PrimaryKeyConstraint('x', 'y'),
         UniqueConstraint('y'),
         mysql_engine='InnoDB'
     )

Along with the change The .autoincrement directive is no longer implicitly enabled for a composite primary key column,
composite
primary keys with or without auto increment are now easier to specify;
see Column.autoincrement now defaults to the value ‘"auto"’ and
the ‘autoincrement=False’ directives are no longer needed:

     t = Table(
         'some_table', metadata,
         Column('x', Integer, primary_key=True),
         Column('y', Integer, primary_key=True, autoincrement=True),
         mysql_engine='InnoDB'
     )

8.4.3.82 Dialect Improvements and Changes - SQLite
..................................................

8.4.3.83 Right-nested join workaround lifted for SQLite version 3.7.16
......................................................................

In version 0.9, the feature introduced by *note Many JOIN and LEFT OUTER
JOIN expressions will no longer be wrapped in (SELECT * FROM ..)  AS
ANON_1: 1b5d. went through lots of effort to support rewriting of joins
on SQLite to always use subqueries in order to achieve a
“right-nested-join” effect, as SQLite has not supported this syntax for
many years.  Ironically, the version of SQLite noted in that migration
note, 3.7.15.2, was the `last' version of SQLite to actually have this
limitation!  The next release was 3.7.16 and support for right nested
joins was quietly added.  In 1.1, the work to identify the specific
SQLite version and source commit where this change was made was done
(SQLite’s changelog refers to it with the cryptic phrase “Enhance the
query optimizer to exploit transitive join constraints” without linking
to any issue number, change number, or further explanation), and the
workarounds present in this change are now lifted for SQLite when the
DBAPI reports that version 3.7.16 or greater is in effect.

#3634(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3634

8.4.3.84 Dotted column names workaround lifted for SQLite version 3.10.0
........................................................................

The SQLite dialect has long had a workaround for an issue where the
database driver does not report the correct column names for some SQL
result sets, in particular when UNION is used.  The workaround is
detailed at Dotted Column Names, and requires that
SQLAlchemy assume that any column name with a dot in it is actually a
‘tablename.columnname’ combination delivered via this buggy behavior,
with an option to turn it off via the ‘sqlite_raw_colnames’ execution
option.

As of SQLite version 3.10.0, the bug in UNION and other queries has been
fixed; like the change described in Right-nested join workaround lifted for SQLite version 3.7.16,
SQLite’s changelog only
identifies it cryptically as “Added the colUsed field to
sqlite3_index_info for use by the sqlite3_module.xBestIndex method”,
however SQLAlchemy’s translation of these dotted column names is no
longer required with this version, so is turned off when version 3.10.0
or greater is detected.

Overall, the SQLAlchemy ‘ResultProxy’ as of the 1.0 series relies much
less on column names in result sets when delivering results for Core and
ORM SQL constructs, so the importance of this issue was already lessened
in any case.

#3633(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3633

8.4.3.85 Improved Support for Remote Schemas
............................................

The SQLite dialect now implements Inspector.get_schema_names()
and additionally has improved support for tables and indexes that
are created and reflected from a remote schema, which in SQLite is a
database that is assigned a name via the ‘ATTACH’ statement; previously,
the‘‘CREATE INDEX‘‘ DDL didn’t work correctly for a schema-bound table
and the Inspector.get_foreign_keys() method will now
indicate the given schema in the results.  Cross-schema foreign keys
aren’t supported.

8.4.3.86 Reflection of the name of PRIMARY KEY constraints
..........................................................

The SQLite backend now takes advantage of the “sqlite_master” view of
SQLite in order to extract the name of the primary key constraint of a
table from the original DDL, in the same way that is achieved for
foreign key constraints in recent SQLAlchemy versions.

#3629(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3629

8.4.3.87 Check constraints now reflect
......................................

The SQLite dialect now supports reflection of CHECK constraints both
within the method Inspector.get_check_constraints() as well
as within Table reflection within the
Table.constraints collection.

8.4.3.88 ON DELETE and ON UPDATE foreign key phrases now reflect
................................................................

The Inspector will now include ON DELETE and ON UPDATE
phrases from foreign key constraints on the SQLite dialect, and the
ForeignKeyConstraint object as reflected as part of a
Table will also indicate these phrases.

8.4.3.89 Dialect Improvements and Changes - SQL Server
......................................................

8.4.3.90 Added transaction isolation level support for SQL Server
.................................................................

All SQL Server dialects support transaction isolation level settings via
the create_engine.isolation_level and
Connection.execution_options.isolation_level parameters.  The
four standard levels are supported as well as ‘SNAPSHOT’:

     engine = create_engine(
         "mssql+pyodbc://scott:tiger@ms_2008",
         isolation_level="REPEATABLE READ"
     )

See also
........

See Transaction Isolation Level.

#3534(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3534

8.4.3.91 String / varlength types no longer represent “max” explicitly on reflection
....................................................................................

When reflecting a type such as String, TextClause,
etc.  which includes a length, an “un-lengthed” type under SQL Server
would copy the “length” parameter as the value ‘"max"’:

     >>> from sqlalchemy import create_engine, inspect
     >>> engine = create_engine('mssql+pyodbc://scott:tiger@ms_2008', echo=True)
     >>> engine.execute("create table s (x varchar(max), y varbinary(max))")
     >>> insp = inspect(engine)
     >>> for col in insp.get_columns("s"):
     ...     print(col['type'].__class__, col['type'].length)
     ...
     <class 'sqlalchemy.sql.sqltypes.VARCHAR'> max
     <class 'sqlalchemy.dialects.mssql.base.VARBINARY'> max

The “length” parameter in the base types is expected to be an integer
value or None only; None indicates unbounded length which the SQL Server
dialect interprets as “max”.  The fix then is so that these lengths come
out as None, so that the type objects work in non-SQL Server contexts:

     >>> for col in insp.get_columns("s"):
     ...     print(col['type'].__class__, col['type'].length)
     ...
     <class 'sqlalchemy.sql.sqltypes.VARCHAR'> None
     <class 'sqlalchemy.dialects.mssql.base.VARBINARY'> None

Applications which may have been relying on a direct comparison of the
“length” value to the string “max” should consider the value of ‘None’
to mean the same thing.

#3504(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3504

8.4.3.92 Support for “non clustered” on primary key to allow clustered elsewhere
................................................................................

The ‘mssql_clustered’ flag available on UniqueConstraint,
PrimaryKeyConstraint, Index now defaults to
‘None’, and can be set to False which will render the NONCLUSTERED
keyword in particular for a primary key, allowing a different index to
be used as “clustered”.

See also
........

See Clustered Index Support.

8.4.3.93 The legacy_schema_aliasing flag is now set to False
............................................................

SQLAlchemy 1.0.5 introduced the ‘legacy_schema_aliasing’ flag to the
MSSQL dialect, allowing so-called “legacy mode” aliasing to be turned
off.  This aliasing attempts to turn schema-qualified tables into
aliases; given a table such as:

     account_table = Table(
         'account', metadata,
         Column('id', Integer, primary_key=True),
         Column('info', String(100)),
         schema="customer_schema"
     )

The legacy mode of behavior will attempt to turn a schema-qualified
table name into an alias:

     >>> eng = create_engine("mssql+pymssql://mydsn", legacy_schema_aliasing=True)
     >>> print(account_table.select().compile(eng))
     SELECT account_1.id, account_1.info
     FROM customer_schema.account AS account_1

However, this aliasing has been shown to be unnecessary and in many
cases produces incorrect SQL.

In SQLAlchemy 1.1, the ‘legacy_schema_aliasing’ flag now defaults to
False, disabling this mode of behavior and allowing the MSSQL dialect to
behave normally with schema-qualified tables.  For applications which
may rely on this behavior, set the flag back to True.

#3434(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3434

8.4.3.94 Dialect Improvements and Changes - Oracle
..................................................

8.4.3.95 Support for SKIP LOCKED
................................

The new parameter GenerativeSelect.with_for_update.skip_locked
in both Core and ORM will generate the “SKIP LOCKED” suffix for a
“SELECT…FOR UPDATE” or “SELECT.. FOR SHARE” query.

8.4.4 What’s New in SQLAlchemy 1.0?
-----------------------------------

     About this Document: This document describes changes between
     SQLAlchemy version 0.9, undergoing maintenance releases as of May,
     2014, and SQLAlchemy version 1.0, released in April, 2015.

     Document last updated: June 9, 2015

8.4.4.1 Introduction
....................

This guide introduces what’s new in SQLAlchemy version 1.0, and also
documents changes which affect users migrating their applications from
the 0.9 series of SQLAlchemy to 1.0.

Please carefully review the sections on behavioral changes for
potentially backwards-incompatible changes in behavior.

8.4.4.2 New Features and Improvements - ORM
...........................................

8.4.4.3 New Session Bulk INSERT/UPDATE API
..........................................

A new series of Session methods which provide hooks directly
into the unit of work’s facility for emitting INSERT and UPDATE
statements has been created.  When used correctly, this expert-oriented
system can allow ORM-mappings to be used to generate bulk insert and
update statements batched into executemany groups, allowing the
statements to proceed at speeds that rival direct use of the Core.

See also
........

See Bulk Operations. - introduction and full documentation

#3100(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3100

8.4.4.4 New Performance Example Suite
.....................................

Inspired by the benchmarking done for the Bulk Operations
feature as well as for the How can I profile a SQLAlchemy powered application?
section of the FAQ, a new example section has been
added which features several scripts designed to illustrate the relative
performance profile of various Core and ORM techniques.  The scripts are
organized into use cases, and are packaged under a single console
interface such that any combination of demonstrations can be run,
dumping out timings, Python profile results and/or RunSnake profile
displays.

See also
........

See Performance.

8.4.4.5 “Baked” Queries
.......................

The “baked” query feature is an unusual new approach which allows for
straightforward construction an invocation of Query objects
using caching, which upon successive calls features vastly reduced
Python function call overhead (over 75%).  By specifying a Query
object as a series of lambdas which are only invoked once, a query
as a pre-compiled unit begins to be feasible:

     from sqlalchemy.ext import baked
     from sqlalchemy import bindparam

     bakery = baked.bakery()

     def search_for_user(session, username, email=None):

         baked_query = bakery(lambda session: session.query(User))
         baked_query += lambda q: q.filter(User.name == bindparam('username'))

         baked_query += lambda q: q.order_by(User.id)

         if email:
             baked_query += lambda q: q.filter(User.email == bindparam('email'))

         result = baked_query(session).params(username=username, email=email).all()

         return result

See also
........

See Baked Queries.

#3054(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3054

8.4.4.6 Improvements to declarative mixins, ‘@declared_attr’ and related features
.................................................................................

The declarative system in conjunction with declared_attr has
been overhauled to support new capabilities.

A function decorated with declared_attr is now called only
`after' any mixin-based column copies are generated.  This means the
function can call upon mixin-established columns and will receive a
reference to the correct Column object:

     class HasFooBar(object):
         foobar = Column(Integer)

         @declared_attr
         def foobar_prop(cls):
             return column_property('foobar: ' + cls.foobar)

     class SomeClass(HasFooBar, Base):
         __tablename__ = 'some_table'
         id = Column(Integer, primary_key=True)

Above, ‘SomeClass.foobar_prop’ will be invoked against ‘SomeClass’, and
‘SomeClass.foobar’ will be the final Column object that is to
be mapped to ‘SomeClass’, as opposed to the non-copied object present
directly on ‘HasFooBar’, even though the columns aren’t mapped yet.

The declared_attr function now `memoizes' the value that’s
returned on a per-class basis, so that repeated calls to the same
attribute will return the same value.  We can alter the example to
illustrate this:

     class HasFooBar(object):
         @declared_attr
         def foobar(cls):
             return Column(Integer)

         @declared_attr
         def foobar_prop(cls):
             return column_property('foobar: ' + cls.foobar)

     class SomeClass(HasFooBar, Base):
         __tablename__ = 'some_table'
         id = Column(Integer, primary_key=True)

Previously, ‘SomeClass’ would be mapped with one particular copy of the
‘foobar’ column, but the ‘foobar_prop’ by calling upon ‘foobar’ a second
time would produce a different column.  The value of ‘SomeClass.foobar’
is now memoized during declarative setup time, so that even before the
attribute is mapped by the mapper, the interim column value will remain
consistent no matter how many times the declared_attr is
called upon.

The two behaviors above should help considerably with declarative
definition of many types of mapper properties that derive from other
attributes, where the declared_attr function is called upon
from other declared_attr functions locally present before
the class is actually mapped.

For a pretty slim edge case where one wishes to build a declarative
mixin that establishes distinct columns per subclass, a new modifier
declared_attr.cascading is added.  With this modifier, the
decorated function will be invoked individually for each class in the
mapped inheritance hierarchy.  While this is already the behavior for
special attributes such as ‘__table_args__’ and ‘__mapper_args__’, for
columns and other properties the behavior by default assumes that
attribute is affixed to the base class only, and just inherited from
subclasses.  With declared_attr.cascading, individual
behaviors can be applied:

     class HasIdMixin(object):
         @declared_attr.cascading
         def id(cls):
             if has_inherited_table(cls):
                 return Column(ForeignKey('myclass.id'), primary_key=True)
             else:
                 return Column(Integer, primary_key=True)

     class MyClass(HasIdMixin, Base):
         __tablename__ = 'myclass'
         # ...

     class MySubClass(MyClass):
         ""
         # ...

See also
........

See Mixing in Columns in Inheritance Scenarios.

Finally, the AbstractConcreteBase class has been reworked so
that a relationship or other mapper property can be set up inline on the
abstract base:

     from sqlalchemy import Column, Integer, ForeignKey
     from sqlalchemy.orm import relationship
     from sqlalchemy.ext.declarative import (declarative_base, declared_attr,
         AbstractConcreteBase)

     Base = declarative_base()

     class Something(Base):
         __tablename__ = u'something'
         id = Column(Integer, primary_key=True)

     class Abstract(AbstractConcreteBase, Base):
         id = Column(Integer, primary_key=True)

         @declared_attr
         def something_id(cls):
             return Column(ForeignKey(Something.id))

         @declared_attr
         def something(cls):
             return relationship(Something)

     class Concrete(Abstract):
         __tablename__ = u'cca'
         __mapper_args__ = {'polymorphic_identity': 'cca', 'concrete': True}

The above mapping will set up a table ‘cca’ with both an ‘id’ and a
‘something_id’ column, and ‘Concrete’ will also have a relationship
‘something’.  The new feature is that ‘Abstract’ will also have an
independently configured relationship ‘something’ that builds against
the polymorphic union of the base.

#3150(1) #2670(2) #3149(3) #2952(4) #3050(5)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3150

   (2) http://www.sqlalchemy.org/trac/ticket/2670

   (3) http://www.sqlalchemy.org/trac/ticket/3149

   (4) http://www.sqlalchemy.org/trac/ticket/2952

   (5) http://www.sqlalchemy.org/trac/ticket/3050

8.4.4.7 ORM full object fetches 25% faster
..........................................

The mechanics of the ‘loading.py’ module as well as the identity map
have undergone several passes of inlining, refactoring, and pruning, so
that a raw load of rows now populates ORM-based objects around 25%
faster.  Assuming a 1M row table, a script like the following
illustrates the type of load that’s improved the most:

     import time
     from sqlalchemy import Integer, Column, create_engine, Table
     from sqlalchemy.orm import Session
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class Foo(Base):
         __table__ = Table(
             'foo', Base.metadata,
             Column('id', Integer, primary_key=True),
             Column('a', Integer(), nullable=False),
             Column('b', Integer(), nullable=False),
             Column('c', Integer(), nullable=False),
         )

     engine = create_engine(
         'mysql+mysqldb://scott:tiger@localhost/test', echo=True)

     sess = Session(engine)

     now = time.time()

     # avoid using all() so that we don't have the overhead of building
     # a large list of full objects in memory
     for obj in sess.query(Foo).yield_per(100).limit(1000000):
         pass

     print("Total time: %d" % (time.time() - now))

Local MacBookPro results bench from 19 seconds for 0.9 down to 14
seconds for 1.0.  The Query.yield_per() call is always a
good idea when batching huge numbers of rows, as it prevents the Python
interpreter from having to allocate a huge amount of memory for all
objects and their instrumentation at once.  Without the
Query.yield_per(), the above script on the MacBookPro is 31 seconds
on 0.9 and 26 seconds on 1.0, the extra time spent setting up very large
memory buffers.

8.4.4.8 New KeyedTuple implementation dramatically faster
.........................................................

We took a look into the ‘KeyedTuple’ implementation in the hopes of
improving queries like this:

     rows = sess.query(Foo.a, Foo.b, Foo.c).all()

The ‘KeyedTuple’ class is used rather than Python’s
‘collections.namedtuple()’, because the latter has a very complex
type-creation routine that benchmarks much slower than ‘KeyedTuple’.
However, when fetching hundreds of thousands of rows,
‘collections.namedtuple()’ quickly overtakes ‘KeyedTuple’ which becomes
dramatically slower as instance invocation goes up.  What to do?  A new
type that hedges between the approaches of both.  Benching all three
types for “size” (number of rows returned) and “num” (number of distinct
queries), the new “lightweight keyed tuple” either outperforms both, or
lags very slightly behind the faster object, based on which scenario.
In the “sweet spot”, where we are both creating a good number of new
types as well as fetching a good number of rows, the lightweight object
totally smokes both namedtuple and KeyedTuple:

     -----------------
     size=10 num=10000                 # few rows, lots of queries
     namedtuple: 3.60302400589         # namedtuple falls over
     keyedtuple: 0.255059957504        # KeyedTuple very fast
     lw keyed tuple: 0.582715034485    # lw keyed trails right on KeyedTuple
     -----------------
     size=100 num=1000                 # <--- sweet spot
     namedtuple: 0.365247011185
     keyedtuple: 0.24896979332
     lw keyed tuple: 0.0889317989349   # lw keyed blows both away!
     -----------------
     size=10000 num=100
     namedtuple: 0.572599887848
     keyedtuple: 2.54251694679
     lw keyed tuple: 0.613876104355
     -----------------
     size=1000000 num=10               # few queries, lots of rows
     namedtuple: 5.79669594765         # namedtuple very fast
     keyedtuple: 28.856498003          # KeyedTuple falls over
     lw keyed tuple: 6.74346804619     # lw keyed trails right on namedtuple

#3176(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3176

8.4.4.9 Significant Improvements in Structural Memory Use
.........................................................

Structural memory use has been improved via much more significant use of
‘__slots__’ for many internal objects.  This optimization is
particularly geared towards the base memory size of large applications
that have lots of tables and columns, and reduces memory size for a
variety of high-volume objects including event listening internals,
comparator objects and parts of the ORM attribute and loader strategy
system.

A bench that makes use of heapy measure the startup size of Nova
illustrates a difference of about 3.7 fewer megs, or 46%, taken up by
SQLAlchemy’s objects, associated dictionaries, as well as weakrefs,
within a basic import of “nova.db.sqlalchemy.models”:

     # reported by heapy, summation of SQLAlchemy objects +
     # associated dicts + weakref-related objects with core of Nova imported:

         Before: total count 26477 total bytes 7975712
         After: total count 18181 total bytes 4236456

     # reported for the Python module space overall with the
     # core of Nova imported:

         Before: Partition of a set of 355558 objects. Total size = 61661760 bytes.
         After: Partition of a set of 346034 objects. Total size = 57808016 bytes.

8.4.4.10 UPDATE statements are now batched with executemany() in a flush
........................................................................

UPDATE statements can now be batched within an ORM flush into more
performant executemany() call, similarly to how INSERT statements can be
batched; this will be invoked within flush based on the following
criteria:

   * two or more UPDATE statements in sequence involve the identical set
     of columns to be modified.

   * The statement has no embedded SQL expressions in the SET clause.

   * The mapping does not use a mapper.version_id_col, or the
     backend dialect supports a “sane” rowcount for an executemany()
     operation; most DBAPIs support this correctly now.

8.4.4.11 Session.get_bind() handles a wider variety of inheritance scenarios
............................................................................

The Session.get_bind() method is invoked whenever a query or
unit of work flush process seeks to locate the database engine that
corresponds to a particular class.  The method has been improved to
handle a variety of inheritance-oriented scenarios, including:

   * Binding to a Mixin or Abstract Class:

          class MyClass(SomeMixin, Base):
              __tablename__ = 'my_table'
              # ...

          session = Session(binds={SomeMixin: some_engine})

   * Binding to inherited concrete subclasses individually based on
     table:

          class BaseClass(Base):
              __tablename__ = 'base'

              # ...

          class ConcreteSubClass(BaseClass):
              __tablename__ = 'concrete'

              # ...

              __mapper_args__ = {'concrete': True}

          session = Session(binds={
              base_table: some_engine,
              concrete_table: some_other_engine
          })

#3035(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3035

8.4.4.12 Session.get_bind() will receive the Mapper in all relevant Query cases
...............................................................................

A series of issues were repaired where the Session.get_bind()
would not receive the primary Mapper of the
Query, even though this mapper was readily available (the primary
mapper is the single mapper, or alternatively the first mapper, that is
associated with a Query object).

The Mapper object, when passed to Session.get_bind(),
is typically used by sessions that make use of the
Session.binds parameter to associate mappers with a series of
engines (although in this use case, things frequently “worked” in most
cases anyway as the bind would be located via the mapped table object),
or more specifically implement a user-defined Session.get_bind()
method that provies some pattern of selecting engines based on
mappers, such as horizontal sharding or a so-called “routing” session
that routes queries to different backends.

These scenarios include:

   * Query.count():

          session.query(User).count()

   * Query.update() and Query.delete(), both for
     the UPDATE/DELETE statement as well as for the SELECT used by the
     “fetch” strategy:

          session.query(User).filter(User.id == 15).update(
                  {"name": "foob"}, synchronize_session='fetch')

          session.query(User).filter(User.id == 15).delete(
                  synchronize_session='fetch')

   * Queries against individual columns:

          session.query(User.id, User.name).all()

   * SQL functions and other expressions against indirect mappings such
     as column_property:

          class User(Base):
              # ...

              score = column_property(func.coalesce(self.tables.users.c.name, None)))

          session.query(func.max(User.score)).scalar()

#3227(1) #3242(2) #1326(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3227

   (2) http://www.sqlalchemy.org/trac/ticket/3242

   (3) http://www.sqlalchemy.org/trac/ticket/1326

8.4.4.13 .info dictionary improvements
......................................

The ‘InspectionAttr.info’ collection is now available on every kind of
object that one would retrieve from the
Mapper.all_orm_descriptors collection.  This includes
hybrid_property and association_proxy().  However, as
these objects are class-bound descriptors, they must be accessed
`separately' from the class to which they are attached in order to get
at the attribute.  Below this is illustrated using the
Mapper.all_orm_descriptors namespace:

     class SomeObject(Base):
         # ...

         @hybrid_property
         def some_prop(self):
             return self.value + 5

     inspect(SomeObject).all_orm_descriptors.some_prop.info['foo'] = 'bar'

It is also available as a constructor argument for all SchemaItem
objects (e.g.  see ForeignKey, UniqueConstraint
etc.)  as well as remaining ORM constructs such as synonym().

#2971(1)

#2963(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2971

   (2) http://www.sqlalchemy.org/trac/ticket/2963

8.4.4.14 ColumnProperty constructs work a lot better with aliases, order_by
...........................................................................

A variety of issues regarding column_property() have been
fixed, most specifically with regards to the aliased()
construct as well as the “order by label” logic introduced in 0.9 (see
Label constructs can now render as their name alone in an ORDER BY).

Given a mapping like the following:

     class A(Base):
         __tablename__ = 'a'

         id = Column(Integer, primary_key=True)

     class B(Base):
         __tablename__ = 'b'

         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey('a.id'))

     A.b = column_property(
             select([func.max(B.id)]).where(B.a_id == A.id).correlate(A)
         )

A simple scenario that included “A.b” twice would fail to render
correctly:

     print(sess.query(A, a1).order_by(a1.b))

This would order by the wrong column:

     SELECT a.id AS a_id, (SELECT max(b.id) AS max_1 FROM b
     WHERE b.a_id = a.id) AS anon_1, a_1.id AS a_1_id,
     (SELECT max(b.id) AS max_2
     FROM b WHERE b.a_id = a_1.id) AS anon_2
     FROM a, a AS a_1 ORDER BY anon_1

New output:

     SELECT a.id AS a_id, (SELECT max(b.id) AS max_1
     FROM b WHERE b.a_id = a.id) AS anon_1, a_1.id AS a_1_id,
     (SELECT max(b.id) AS max_2
     FROM b WHERE b.a_id = a_1.id) AS anon_2
     FROM a, a AS a_1 ORDER BY anon_2

There were also many scenarios where the “order by” logic would fail to
order by label, for example if the mapping were “polymorphic”:

     class A(Base):
         __tablename__ = 'a'

         id = Column(Integer, primary_key=True)
         type = Column(String)

         __mapper_args__ = {'polymorphic_on': type, 'with_polymorphic': '*'}

The order_by would fail to use the label, as it would be anonymized due
to the polymorphic loading:

     SELECT a.id AS a_id, a.type AS a_type, (SELECT max(b.id) AS max_1
     FROM b WHERE b.a_id = a.id) AS anon_1
     FROM a ORDER BY (SELECT max(b.id) AS max_2
     FROM b WHERE b.a_id = a.id)

Now that the order by label tracks the anonymized label, this now works:

     SELECT a.id AS a_id, a.type AS a_type, (SELECT max(b.id) AS max_1
     FROM b WHERE b.a_id = a.id) AS anon_1
     FROM a ORDER BY anon_1

Included in these fixes are a variety of heisenbugs that could corrupt
the state of an ‘aliased()’ construct such that the labeling logic would
again fail; these have also been fixed.

#3148(1) #3188(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3148

   (2) http://www.sqlalchemy.org/trac/ticket/3188

8.4.4.15 New Features and Improvements - Core
.............................................

8.4.4.16 Select/Query LIMIT / OFFSET may be specified as an arbitrary SQL expression
....................................................................................

The Select.limit() and Select.offset() methods
now accept any SQL expression, in addition to integer values, as
arguments.  The ORM Query object also passes through any
expression to the underlying Select object.  Typically this
is used to allow a bound parameter to be passed, which can be
substituted with a value later:

     sel = select([table]).limit(bindparam('mylimit')).offset(bindparam('myoffset'))

Dialects which don’t support non-integer LIMIT or OFFSET expressions may
continue to not support this behavior; third party dialects may also
need modification in order to take advantage of the new behavior.  A
dialect which currently uses the ‘._limit’ or ‘._offset’ attributes will
continue to function for those cases where the limit/offset was
specified as a simple integer value.  However, when a SQL expression is
specified, these two attributes will instead raise a CompileError
on access.  A third-party dialect which wishes to support the new
feature should now call upon the ‘._limit_clause’ and ‘._offset_clause’
attributes to receive the full SQL expression, rather than the integer
value.

8.4.4.17 The ‘use_alter’ flag on ‘ForeignKeyConstraint’ is (usually) no longer needed
.....................................................................................

The MetaData.create_all() and MetaData.drop_all()
methods will now make use of a system that automatically renders an
ALTER statement for foreign key constraints that are involved in
mutually-dependent cycles between tables, without the need to specify
ForeignKeyConstraint.use_alter.  Additionally, the foreign
key constraints no longer need to have a name in order to be created via
ALTER; only the DROP operation requires a name.  In the case of a DROP,
the feature will ensure that only constraints which have explicit names
are actually included as ALTER statements.  In the case of an
unresolvable cycle within a DROP, the system emits a succinct and clear
error message now if the DROP cannot proceed.

The ForeignKeyConstraint.use_alter and
ForeignKey.use_alter flags remain in place, and continue to have
the same effect of establishing those constraints for which ALTER is
required during a CREATE/DROP scenario.

As of version 1.0.1, special logic takes over in the case of SQLite,
which does not support ALTER, in the case that during a DROP, the given
tables have an unresolvable cycle; in this case a warning is emitted,
and the tables are dropped with `no' ordering, which is usually fine on
SQLite unless constraints are enabled.  To resolve the warning and
proceed with at least a partial ordering on a SQLite database,
particularly one where constraints are enabled, re-apply “use_alter”
flags to those ForeignKey and ForeignKeyConstraint
objects which should be explicitly omitted from the sort.

See also
........

See Creating/Dropping Foreign Key Constraints via ALTER. - full
description of the new behavior.

#3282(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3282

8.4.4.18 ResultProxy “auto close” is now a “soft” close
.......................................................

For many releases, the ‘ResultProxy’ object has always been
automatically closed out at the point at which all result rows have been
fetched.  This was to allow usage of the object without the need to call
upon ‘ResultProxy.close()’ explicitly; as all DBAPI resources had been
freed, the object was safe to discard.  However, the object maintained a
strict “closed” behavior, which meant that any subsequent calls to
‘ResultProxy.fetchone()’, ‘ResultProxy.fetchmany()’ or
‘ResultProxy.fetchall()’ would now raise a ResourceClosedError:

     >>> result = connection.execute(stmt)
     >>> result.fetchone()
     (1, 'x')
     >>> result.fetchone()
     None  # indicates no more rows
     >>> result.fetchone()
     exception: ResourceClosedError

This behavior is inconsistent vs.  what pep-249 states, which is that
you can call upon the fetch methods repeatedly even after results are
exhausted.  It also interferes with behavior for some implementations of
result proxy, such as the ‘BufferedColumnResultProxy’ used by the
cx_oracle dialect for certain datatypes.

To solve this, the “closed” state of the ‘ResultProxy’ has been broken
into two states; a “soft close” which does the majority of what “close”
does, in that it releases the DBAPI cursor and in the case of a “close
with result” object will also release the connection, and a “closed”
state which is everything included by “soft close” as well as
establishing the fetch methods as “closed”.  The ‘ResultProxy.close()’
method is now never called implicitly, only the
‘ResultProxy._soft_close()’ method which is non-public:

     >>> result = connection.execute(stmt)
     >>> result.fetchone()
     (1, 'x')
     >>> result.fetchone()
     None  # indicates no more rows
     >>> result.fetchone()
     None  # still None
     >>> result.fetchall()
     []
     >>> result.close()
     >>> result.fetchone()
     exception: ResourceClosedError  # *now* it raises

#3330(1) #3329(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3330

   (2) http://www.sqlalchemy.org/trac/ticket/3329

8.4.4.19 CHECK Constraints now support the ‘%(column_0_name)s’ token in naming conventions
..........................................................................................

The ‘%(column_0_name)s’ will derive from the first column found in the
expression of a CheckConstraint:

     metadata = MetaData(
         naming_convention={"ck": "ck_%(table_name)s_%(column_0_name)s"}
     )

     foo = Table('foo', metadata,
         Column('value', Integer),
     )

     CheckConstraint(foo.c.value > 5)

Will render:

     CREATE TABLE foo (
         value INTEGER,
         CONSTRAINT ck_foo_value CHECK (value > 5)
     )

The combination of naming conventions with the constraint produced by a
SchemaType such as Boolean or Enum
will also now make use of all CHECK constraint conventions.

See also
........

See Naming CHECK Constraints.

See Configuring Naming for Boolean, Enum, and other schema types.

#3299(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3299

8.4.4.20 Constraints referring to unattached Columns can auto-attach to the Table when their referred columns are attached
..........................................................................................................................

Since at least version 0.8, a Constraint has had the ability
to “auto-attach” itself to a Table based on being passed
table-attached columns:

     from sqlalchemy import Table, Column, MetaData, Integer, UniqueConstraint

     m = MetaData()

     t = Table('t', m,
         Column('a', Integer),
         Column('b', Integer)
     )

     uq = UniqueConstraint(t.c.a, t.c.b)  # will auto-attach to Table

     assert uq in t.constraints

In order to assist with some cases that tend to come up with
declarative, this same auto-attachment logic can now function even if
the Column objects are not yet associated with the
Table; additional events are established such that when those
Column objects are associated, the Constraint is also
added:

     from sqlalchemy import Table, Column, MetaData, Integer, UniqueConstraint

     m = MetaData()

     a = Column('a', Integer)
     b = Column('b', Integer)

     uq = UniqueConstraint(a, b)

     t = Table('t', m, a, b)

     assert uq in t.constraints  # constraint auto-attached

The above feature was a late add as of version 1.0.0b3.  A fix as of
version 1.0.4 for #3411(1) ensures that this logic does not occur if the
Constraint refers to a mixture of Column objects
and string column names; as we do not yet have tracking for the addition
of names to a Table:

     from sqlalchemy import Table, Column, MetaData, Integer, UniqueConstraint

     m = MetaData()

     a = Column('a', Integer)
     b = Column('b', Integer)

     uq = UniqueConstraint(a, 'b')

     t = Table('t', m, a, b)

     # constraint *not* auto-attached, as we do not have tracking
     # to locate when a name 'b' becomes available on the table
     assert uq not in t.constraints

Above, the attachment event for column “a” to table “t” will fire off
before column “b” is attached (as “a” is stated in the Table
constructor before “b”), and the constraint will fail to locate “b” if
it were to attempt an attachment.  For consistency, if the constraint
refers to any string names, the autoattach-on-column-attach logic is
skipped.

The original auto-attach logic of course remains in place, if the
Table already contains all the target Column objects at
the time the Constraint is constructed:

     from sqlalchemy import Table, Column, MetaData, Integer, UniqueConstraint

     m = MetaData()

     a = Column('a', Integer)
     b = Column('b', Integer)

     t = Table('t', m, a, b)

     uq = UniqueConstraint(a, 'b')

     # constraint auto-attached normally as in older versions
     assert uq in t.constraints

#3341(2) #3411(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3411

   (2) http://www.sqlalchemy.org/trac/ticket/3341

   (3) http://www.sqlalchemy.org/trac/ticket/3411

8.4.4.21 INSERT FROM SELECT now includes Python and SQL-expression defaults
...........................................................................

Insert.from_select() now includes Python and SQL-expression
defaults if otherwise unspecified; the limitation where non-server
column defaults aren’t included in an INSERT FROM SELECT is now lifted
and these expressions are rendered as constants into the SELECT
statement:

     from sqlalchemy import Table, Column, MetaData, Integer, select, func

     m = MetaData()

     t = Table(
         't', m,
         Column('x', Integer),
         Column('y', Integer, default=func.somefunction()))

     stmt = select([t.c.x])
     print(t.insert().from_select(['x'], stmt))

Will render:

     INSERT INTO t (x, y) SELECT t.x, somefunction() AS somefunction_1
     FROM t

The feature can be disabled using
Insert.from_select.include_defaults.

8.4.4.22 Column server defaults now render literal values
.........................................................

The “literal binds” compiler flag is switched on when a
DefaultClause, set up by Column.server_default is
present as a SQL expression to be compiled.  This allows literals
embedded in SQL to render correctly, such as:

     from sqlalchemy import Table, Column, MetaData, Text
     from sqlalchemy.schema import CreateTable
     from sqlalchemy.dialects.postgresql import ARRAY, array
     from sqlalchemy.dialects import postgresql

     metadata = MetaData()

     tbl = Table("derp", metadata,
         Column("arr", ARRAY(Text),
                     server_default=array(["foo", "bar", "baz"])),
     )

     print(CreateTable(tbl).compile(dialect=postgresql.dialect()))

Now renders:

     CREATE TABLE derp (
         arr TEXT[] DEFAULT ARRAY['foo', 'bar', 'baz']
     )

Previously, the literal values ‘"foo", "bar", "baz"’ would render as
bound parameters, which are useless in DDL.

#3087(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3087

8.4.4.23 UniqueConstraint is now part of the Table reflection process
.....................................................................

A Table object populated using ‘autoload=True’ will now
include UniqueConstraint constructs as well as Index
constructs.  This logic has a few caveats for PostgreSQL and MySQL:

8.4.4.24 PostgreSQL
...................

PostgreSQL has the behavior such that when a UNIQUE constraint is
created, it implicitly creates a UNIQUE INDEX corresponding to that
constraint as well.  The Inspector.get_indexes() and the
Inspector.get_unique_constraints() methods will continue to
`both' return these entries distinctly, where
Inspector.get_indexes() now features a token
‘duplicates_constraint’ within the index entry indicating the
corresponding constraint when detected.  However, when performing full
table reflection using ‘Table(..., autoload=True)’, the Index
construct is detected as being linked to the
UniqueConstraint, and is `not' present within the
Table.indexes collection; only the UniqueConstraint
will be present in the Table.constraints collection.  This
deduplication logic works by joining to the ‘pg_constraint’ table when
querying ‘pg_index’ to see if the two constructs are linked.

8.4.4.25 MySQL
..............

MySQL does not have separate concepts for a UNIQUE INDEX and a UNIQUE
constraint.  While it supports both syntaxes when creating tables and
indexes, it does not store them any differently.  The
Inspector.get_indexes() and the
Inspector.get_unique_constraints() methods will continue to
`both' return an entry for a UNIQUE index in MySQL, where
Inspector.get_unique_constraints() features a new token
‘duplicates_index’ within the constraint entry indicating that this is a
dupe entry corresponding to that index.  However, when performing full
table reflection using ‘Table(..., autoload=True)’, the
UniqueConstraint construct is `not' part of the fully reflected
Table construct under any circumstances; this construct is
always represented by a Index with the ‘unique=True’ setting
present in the Table.indexes collection.

See also
........

See PostgreSQL Index Reflection.

See MySQL / MariaDB Unique Constraints and Reflection.

#3184(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3184

8.4.4.26 New systems to safely emit parameterized warnings
..........................................................

For a long time, there has been a restriction that warning messages
could not refer to data elements, such that a particular function might
emit an infinite number of unique warnings.  The key place this occurs
is in the ‘Unicode type received non-unicode bind param value’ warning.
Placing the data value in this message would mean that the Python
‘__warningregistry__’ for that module, or in some cases the
Python-global ‘warnings.onceregistry’, would grow unbounded, as in most
warning scenarios, one of these two collections is populated with every
distinct warning message.

The change here is that by using a special ‘string’ type that purposely
changes how the string is hashed, we can control that a large number of
parameterized messages are hashed only on a small set of possible hash
values, such that a warning such as ‘Unicode type received non-unicode
bind param value’ can be tailored to be emitted only a specific number
of times; beyond that, the Python warnings registry will begin recording
them as duplicates.

To illustrate, the following test script will show only ten warnings
being emitted for ten of the parameter sets, out of a total of 1000:

     from sqlalchemy import create_engine, Unicode, select, cast
     import random
     import warnings

     e = create_engine("sqlite://")

     # Use the "once" filter (which is also the default for Python
     # warnings).  Exactly ten of these warnings will
     # be emitted; beyond that, the Python warnings registry will accumulate
     # new values as dupes of one of the ten existing.
     warnings.filterwarnings("once")

     for i in range(1000):
         e.execute(select([cast(
             ('foo_%d' % random.randint(0, 1000000)).encode('ascii'), Unicode)]))

The format of the warning here is:

     /path/lib/sqlalchemy/sql/sqltypes.py:186: SAWarning: Unicode type received
       non-unicode bind param value 'foo_4852'. (this warning may be
       suppressed after 10 occurrences)

#3178(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3178

8.4.4.27 Key Behavioral Changes - ORM
.....................................

8.4.4.28 query.update() now resolves string names into mapped attribute names
.............................................................................

The documentation for Query.update() states that the given
‘values’ dictionary is “a dictionary with attributes names as keys”,
implying that these are mapped attribute names.  Unfortunately, the
function was designed more in mind to receive attributes and SQL
expressions and not as much strings; when strings were passed, these
strings would be passed through straight to the core update statement
without any resolution as far as how these names are represented on the
mapped class, meaning the name would have to match that of a table
column exactly, not how an attribute of that name was mapped onto the
class.

The string names are now resolved as attribute names in earnest:

     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         name = Column('user_name', String(50))

Above, the column ‘user_name’ is mapped as ‘name’.  Previously, a call
to Query.update() that was passed strings would have to have
been called as follows:

     session.query(User).update({'user_name': 'moonbeam'})

The given string is now resolved against the entity:

     session.query(User).update({'name': 'moonbeam'})

It is typically preferable to use the attribute directly, to avoid any
ambiguity:

     session.query(User).update({User.name: 'moonbeam'})

The change also indicates that synonyms and hybrid attributes can be
referred to by string name as well:

     class User(Base):
         __tablename__ = 'user'

         id = Column(Integer, primary_key=True)
         name = Column('user_name', String(50))

         @hybrid_property
         def fullname(self):
             return self.name

     session.query(User).update({'fullname': 'moonbeam'})

#3228(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3228

8.4.4.29 Warnings emitted when comparing objects with None values to relationships
..................................................................................

This change is new as of 1.0.1.  Some users are performing queries that
are essentially of this form:

     session.query(Address).filter(Address.user == User(id=None))

This pattern is not currently supported in SQLAlchemy.  For all
versions, it emits SQL resembling:

     SELECT address.id AS address_id, address.user_id AS address_user_id,
     address.email_address AS address_email_address
     FROM address WHERE ? = address.user_id
     (None,)

Note above, there is a comparison ‘WHERE ? = address.user_id’ where the
bound value ‘?’ is receiving ‘None’, or ‘NULL’ in SQL. `This will always
return False in SQL'. The comparison here would in theory generate SQL
as follows:

     SELECT address.id AS address_id, address.user_id AS address_user_id,
     address.email_address AS address_email_address
     FROM address WHERE address.user_id IS NULL

But right now, `it does not'.  Applications which are relying upon the
fact that “NULL = NULL” produces False in all cases run the risk that
someday, SQLAlchemy might fix this issue to generate “IS NULL”, and the
queries will then produce different results.  Therefore with this kind
of operation, you will see a warning:

     SAWarning: Got None for value of column user.id; this is unsupported
     for a relationship comparison and will not currently produce an
     IS comparison (but may in a future release)

Note that this pattern was broken in most cases for release 1.0.0
including all of the betas; a value like ‘SYMBOL('NEVER_SET')’ would be
generated.  This issue has been fixed, but as a result of identifying
this pattern, the warning is now there so that we can more safely repair
this broken behavior (now captured in #3373(1)) in a future release.

#3371(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3373

   (2) http://www.sqlalchemy.org/trac/ticket/3371

8.4.4.30 A “negated contains or equals” relationship comparison will use the current value of attributes, not the database value
................................................................................................................................

This change is new as of 1.0.1; while we would have preferred for this
to be in 1.0.0, it only became apparent as a result of #3371(1).

Given a mapping:

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)

     class B(Base):
         __tablename__ = 'b'
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey('a.id'))
         a = relationship("A")

Given ‘A’, with primary key of 7, but which we changed to be 10 without
flushing:

     s = Session(autoflush=False)
     a1 = A(id=7)
     s.add(a1)
     s.commit()

     a1.id = 10

A query against a many-to-one relationship with this object as the
target will use the value 10 in the bound parameters:

     s.query(B).filter(B.a == a1)

Produces:

     SELECT b.id AS b_id, b.a_id AS b_a_id
     FROM b
     WHERE ? = b.a_id
     (10,)

However, before this change, the negation of this criteria would `not'
use 10, it would use 7, unless the object were flushed first:

     s.query(B).filter(B.a != a1)

Produces (in 0.9 and all versions prior to 1.0.1):

     SELECT b.id AS b_id, b.a_id AS b_a_id
     FROM b
     WHERE b.a_id != ? OR b.a_id IS NULL
     (7,)

For a transient object, it would produce a broken query:

     SELECT b.id, b.a_id
     FROM b
     WHERE b.a_id != :a_id_1 OR b.a_id IS NULL
     {u'a_id_1': symbol('NEVER_SET')}

This inconsistency has been repaired, and in all queries the current
attribute value, in this example ‘10’, will now be used.

#3374(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3371

   (2) http://www.sqlalchemy.org/trac/ticket/3374

8.4.4.31 Changes to attribute events and other operations regarding attributes that have no pre-existing value
..............................................................................................................

In this change, the default return value of ‘None’ when accessing an
object is now returned dynamically on each access, rather than
implicitly setting the attribute’s state with a special “set” operation
when it is first accessed.  The visible result of this change is that
‘obj.__dict__’ is not implicitly modified on get, and there are also
some minor behavioral changes for get_history() and related
functions.

Given an object with no state:

     >>> obj = Foo()

It has always been SQLAlchemy’s behavior such that if we access a scalar
or many-to-one attribute that was never set, it is returned as ‘None’:

     >>> obj.someattr
     None

This value of ‘None’ is in fact now part of the state of ‘obj’, and is
not unlike as though we had set the attribute explicitly, e.g.
‘obj.someattr = None’.  However, the “set on get” here would behave
differently as far as history and events.  It would not emit any
attribute event, and additionally if we view history, we see this:

     >>> inspect(obj).attrs.someattr.history
     History(added=(), unchanged=[None], deleted=())   # 0.9 and below

That is, it’s as though the attribute were always ‘None’ and were never
changed.  This is explicitly different from if we had set the attribute
first instead:

     >>> obj = Foo()
     >>> obj.someattr = None
     >>> inspect(obj).attrs.someattr.history
     History(added=[None], unchanged=(), deleted=())  # all versions

The above means that the behavior of our “set” operation can be
corrupted by the fact that the value was accessed via “get” earlier.  In
1.0, this inconsistency has been resolved, by no longer actually setting
anything when the default “getter” is used.

     >>> obj = Foo()
     >>> obj.someattr
     None
     >>> inspect(obj).attrs.someattr.history
     History(added=(), unchanged=(), deleted=())  # 1.0
     >>> obj.someattr = None
     >>> inspect(obj).attrs.someattr.history
     History(added=[None], unchanged=(), deleted=())

The reason the above behavior hasn’t had much impact is because the
INSERT statement in relational databases considers a missing value to be
the same as NULL in most cases.  Whether SQLAlchemy received a history
event for a particular attribute set to None or not would usually not
matter; as the difference between sending None/NULL or not wouldn’t have
an impact.  However, as #3060(1) (described here in *note Priority of
attribute changes on relationship-bound attributes vs.  FK-bound may
appear to change: 4970.) illustrates, there are some seldom edge cases
where we do in fact want to positively have ‘None’ set.  Also, allowing
the attribute event here means it’s now possible to create “default
value” functions for ORM mapped attributes.

As part of this change, the generation of the implicit “None” is now
disabled for other situations where this used to occur; this includes
when an attribute set operation on a many-to-one is received;
previously, the “old” value would be “None” if it had been not set
otherwise; it now will send the value ‘NEVER_SET’, which is a value that
may be sent to an attribute listener now.  This symbol may also be
received when calling on mapper utility functions such as
Mapper.primary_key_from_instance(); if the primary key attributes
have no setting at all, whereas the value would be ‘None’ before, it
will now be the ‘NEVER_SET’ symbol, and no change to the object’s state
occurs.

#3061(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3060

   (2) http://www.sqlalchemy.org/trac/ticket/3061

8.4.4.32 Priority of attribute changes on relationship-bound attributes vs. FK-bound may appear to change
.........................................................................................................

As a side effect of #3060(1), setting a relationship-bound attribute to
‘None’ is now a tracked history event which refers to the intention of
persisting ‘None’ to that attribute.  As it has always been the case
that setting a relationship-bound attribute will trump direct assignment
to the foreign key attributes, a change in behavior can be seen here
when assigning None.  Given a mapping:

     class A(Base):
         __tablename__ = 'table_a'

         id = Column(Integer, primary_key=True)

     class B(Base):
         __tablename__ = 'table_b'

         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey('table_a.id'))
         a = relationship(A)

In 1.0, the relationship-bound attribute takes precedence over the
FK-bound attribute in all cases, whether or not the value we assign is a
reference to an ‘A’ object or is ‘None’.  In 0.9, the behavior is
inconsistent and only takes effect if a value is assigned; the None is
not considered:

     a1 = A(id=1)
     a2 = A(id=2)
     session.add_all([a1, a2])
     session.flush()

     b1 = B()
     b1.a = a1   # we expect a_id to be '1'; takes precedence in 0.9 and 1.0

     b2 = B()
     b2.a = None  # we expect a_id to be None; takes precedence only in 1.0

     b1.a_id = 2
     b2.a_id = 2

     session.add_all([b1, b2])
     session.commit()

     assert b1.a is a1  # passes in both 0.9 and 1.0
     assert b2.a is None  # passes in 1.0, in 0.9 it's a2

#3060(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3060

   (2) http://www.sqlalchemy.org/trac/ticket/3060

8.4.4.33 session.expunge() will fully detach an object that’s been deleted
..........................................................................

The behavior of Session.expunge() had a bug that caused an
inconsistency in behavior regarding deleted objects.  The
object_session() function as well as the
InstanceState.session attribute would still report object as
belonging to the Session subsequent to the expunge:

     u1 = sess.query(User).first()
     sess.delete(u1)

     sess.flush()

     assert u1 not in sess
     assert inspect(u1).session is sess  # this is normal before commit

     sess.expunge(u1)

     assert u1 not in sess
     assert inspect(u1).session is None  # would fail

Note that it is normal for ‘u1 not in sess’ to be True while
‘inspect(u1).session’ still refers to the session, while the transaction
is ongoing subsequent to the delete operation and
Session.expunge() has not been called; the full detachment
normally completes once the transaction is committed.  This issue would
also impact functions that rely on Session.expunge() such as
make_transient().

#3139(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3139

8.4.4.34 Joined/Subquery eager loading explicitly disallowed with yield_per
...........................................................................

In order to make the Query.yield_per() method easier to use,
an exception is raised if any subquery eager loaders, or joined eager
loaders that would use collections, are to take effect when yield_per is
used, as these are currently not compatible with yield-per (subquery
loading could be in theory, however).  When this error is raised, the
lazyload() option can be sent with an asterisk:

     q = sess.query(Object).options(lazyload('*')).yield_per(100)

or use Query.enable_eagerloads():

     q = sess.query(Object).enable_eagerloads(False).yield_per(100)

The lazyload() option has the advantage that additional
many-to-one joined loader options can still be used:

     q = sess.query(Object).options(
         lazyload('*'), joinedload("some_manytoone")).yield_per(100)

8.4.4.35 Changes and fixes in handling of duplicate join targets
................................................................

Changes here encompass bugs where an unexpected and inconsistent
behavior would occur in some scenarios when joining to an entity twice,
or to multiple single-table entities against the same table, without
using a relationship-based ON clause, as well as when joining multiple
times to the same target relationship.

Starting with a mapping as:

     from sqlalchemy import Integer, Column, String, ForeignKey
     from sqlalchemy.orm import Session, relationship
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)
         bs = relationship("B")

     class B(Base):
         __tablename__ = 'b'
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey('a.id'))

A query that joins to ‘A.bs’ twice:

     print(s.query(A).join(A.bs).join(A.bs))

Will render:

     SELECT a.id AS a_id
     FROM a JOIN b ON a.id = b.a_id

The query deduplicates the redundant ‘A.bs’ because it is attempting to
support a case like the following:

     s.query(A).join(A.bs).\
         filter(B.foo == 'bar').\
         reset_joinpoint().join(A.bs, B.cs).filter(C.bar == 'bat')

That is, the ‘A.bs’ is part of a “path”.  As part of #3367(1), arriving
at the same endpoint twice without it being part of a larger path will
now emit a warning:

     SAWarning: Pathed join target A.bs has already been joined to; skipping

The bigger change involves when joining to an entity without using a
relationship-bound path.  If we join to ‘B’ twice:

     print(s.query(A).join(B, B.a_id == A.id).join(B, B.a_id == A.id))

In 0.9, this would render as follows:

     SELECT a.id AS a_id
     FROM a JOIN b ON b.a_id = a.id JOIN b AS b_1 ON b_1.a_id = a.id

This is problematic since the aliasing is implicit and in the case of
different ON clauses can lead to unpredictable results.

In 1.0, no automatic aliasing is applied and we get:

     SELECT a.id AS a_id
     FROM a JOIN b ON b.a_id = a.id JOIN b ON b.a_id = a.id

This will raise an error from the database.  While it might be nice if
the “duplicate join target” acted identically if we joined both from
redundant relationships vs.  redundant non-relationship based targets,
for now we are only changing the behavior in the more serious case where
implicit aliasing would have occurred previously, and only emitting a
warning in the relationship case.  Ultimately, joining to the same thing
twice without any aliasing to disambiguate should raise an error in all
cases.

The change also has an impact on single-table inheritance targets.
Using a mapping as follows:

     from sqlalchemy import Integer, Column, String, ForeignKey
     from sqlalchemy.orm import Session, relationship
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class A(Base):
         __tablename__ = "a"

         id = Column(Integer, primary_key=True)
         type = Column(String)

         __mapper_args__ = {'polymorphic_on': type, 'polymorphic_identity': 'a'}

     class ASub1(A):
         __mapper_args__ = {'polymorphic_identity': 'asub1'}

     class ASub2(A):
         __mapper_args__ = {'polymorphic_identity': 'asub2'}

     class B(Base):
         __tablename__ = 'b'

         id = Column(Integer, primary_key=True)

         a_id = Column(Integer, ForeignKey("a.id"))

         a = relationship("A", primaryjoin="B.a_id == A.id", backref='b')

     s = Session()

     print(s.query(ASub1).join(B, ASub1.b).join(ASub2, B.a))

     print(s.query(ASub1).join(B, ASub1.b).join(ASub2, ASub2.id == B.a_id))

The two queries at the bottom are equivalent, and should both render the
identical SQL:

     SELECT a.id AS a_id, a.type AS a_type
     FROM a JOIN b ON b.a_id = a.id JOIN a ON b.a_id = a.id AND a.type IN (:type_1)
     WHERE a.type IN (:type_2)

The above SQL is invalid, as it renders “a” within the FROM list twice.
However, the implicit aliasing bug would occur with the second query
only and render this instead:

     SELECT a.id AS a_id, a.type AS a_type
     FROM a JOIN b ON b.a_id = a.id JOIN a AS a_1
     ON a_1.id = b.a_id AND a_1.type IN (:type_1)
     WHERE a_1.type IN (:type_2)

Where above, the second join to “a” is aliased.  While this seems
convenient, it’s not how single-inheritance queries work in general and
is misleading and inconsistent.

The net effect is that applications which were relying on this bug will
now have an error raised by the database.  The solution is to use the
expected form.  When referring to multiple subclasses of a
single-inheritance entity in a query, you must manually use aliases to
disambiguate the table, as all the subclasses normally refer to the same
table:

     asub2_alias = aliased(ASub2)

     print(s.query(ASub1).join(B, ASub1.b).join(asub2_alias, B.a.of_type(asub2_alias)))

#3233(2) #3367(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3367

   (2) http://www.sqlalchemy.org/trac/ticket/3233

   (3) http://www.sqlalchemy.org/trac/ticket/3367

8.4.4.36 Deferred Columns No Longer Implicitly Undefer
......................................................

Mapped attributes marked as deferred without explicit undeferral will
now remain “deferred” even if their column is otherwise present in the
result set in some way.  This is a performance enhancement in that an
ORM load no longer spends time searching for each deferred column when
the result set is obtained.  However, for an application that has been
relying upon this, an explicit undefer() or similar option
should now be used, in order to prevent a SELECT from being emitted when
the attribute is accessed.

8.4.4.37 Deprecated ORM Event Hooks Removed
...........................................

The following ORM event hooks, some of which have been deprecated since
0.5, have been removed: ‘translate_row’, ‘populate_instance’,
‘append_result’, ‘create_instance’.  The use cases for these hooks
originated in the very early 0.1 / 0.2 series of SQLAlchemy and have
long since been unnecessary.  In particular, the hooks were largely
unusable as the behavioral contracts within these events was strongly
linked to the surrounding internals, such as how an instance needs to be
created and initialized as well as how columns are located within an
ORM-generated row.  The removal of these hooks greatly simplifies the
mechanics of ORM object loading.

8.4.4.38 API Change for new Bundle feature when custom row loaders are used
...........................................................................

The new Bundle object of 0.9 has a small change in API, when
the ‘create_row_processor()’ method is overridden on a custom class.
Previously, the sample code looked like:

     from sqlalchemy.orm import Bundle

     class DictBundle(Bundle):
         def create_row_processor(self, query, procs, labels):
             """Override create_row_processor to return values as dictionaries"""
             def proc(row, result):
                 return dict(
                             zip(labels, (proc(row, result) for proc in procs))
                         )
             return proc

The unused ‘result’ member is now removed:

     from sqlalchemy.orm import Bundle

     class DictBundle(Bundle):
         def create_row_processor(self, query, procs, labels):
             """Override create_row_processor to return values as dictionaries"""
             def proc(row):
                 return dict(
                             zip(labels, (proc(row) for proc in procs))
                         )
             return proc

See also
........

See Column Bundles.

8.4.4.39 Right inner join nesting now the default for joinedload with innerjoin=True
....................................................................................

The behavior of joinedload.innerjoin as well as
relationship.innerjoin is now to use “nested” inner joins, that
is, right-nested, as the default behavior when an inner join joined
eager load is chained to an outer join eager load.  In order to get the
old behavior of chaining all joined eager loads as outer join when an
outer join is present, use ‘innerjoin="unnested"’.

As introduced in Right-nested inner joins available in joined eager loads
from version 0.9, the behavior of
‘innerjoin="nested"’ is that an inner join eager load chained to an
outer join eager load will use a right-nested join.  ‘"nested"’ is now
implied when using ‘innerjoin=True’:

     query(User).options(
         joinedload("orders", innerjoin=False).joinedload("items", innerjoin=True))

With the new default, this will render the FROM clause in the form:

     FROM users LEFT OUTER JOIN (orders JOIN items ON <onclause>) ON <onclause>

That is, using a right-nested join for the INNER join so that the full
result of ‘users’ can be returned.  The use of an INNER join is more
efficient than using an OUTER join, and allows the
joinedload.innerjoin optimization parameter to take effect in all
cases.

To get the older behavior, use ‘innerjoin="unnested"’:

     query(User).options(
         joinedload("orders", innerjoin=False).joinedload("items", innerjoin="unnested"))

This will avoid right-nested joins and chain the joins together using
all OUTER joins despite the innerjoin directive:

     FROM users LEFT OUTER JOIN orders ON <onclause> LEFT OUTER JOIN items ON <onclause>

As noted in the 0.9 notes, the only database backend that has difficulty
with right-nested joins is SQLite; SQLAlchemy as of 0.9 converts a
right-nested join into a subquery as a join target on SQLite.

See also
........

See Right-nested inner joins available in joined eager loads. -
description of the feature as introduced in 0.9.4.

#3008(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3008

8.4.4.40 Subqueries no longer applied to uselist=False joined eager loads
.........................................................................

Given a joined eager load like the following:

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)
         b = relationship("B", uselist=False)

     class B(Base):
         __tablename__ = 'b'
         id = Column(Integer, primary_key=True)
         a_id = Column(ForeignKey('a.id'))

     s = Session()
     print(s.query(A).options(joinedload(A.b)).limit(5))

SQLAlchemy considers the relationship ‘A.b’ to be a “one to many, loaded
as a single value”, which is essentially a “one to one” relationship.
However, joined eager loading has always treated the above as a
situation where the main query needs to be inside a subquery, as would
normally be needed for a collection of B objects where the main query
has a LIMIT applied:

     SELECT anon_1.a_id AS anon_1_a_id, b_1.id AS b_1_id, b_1.a_id AS b_1_a_id
     FROM (SELECT a.id AS a_id
     FROM a LIMIT :param_1) AS anon_1
     LEFT OUTER JOIN b AS b_1 ON anon_1.a_id = b_1.a_id

However, since the relationship of the inner query to the outer one is
that at most only one row is shared in the case of ‘uselist=False’ (in
the same way as a many-to-one), the “subquery” used with LIMIT + joined
eager loading is now dropped in this case:

     SELECT a.id AS a_id, b_1.id AS b_1_id, b_1.a_id AS b_1_a_id
     FROM a LEFT OUTER JOIN b AS b_1 ON a.id = b_1.a_id
     LIMIT :param_1

In the case that the LEFT OUTER JOIN returns more than one row, the ORM
has always emitted a warning here and ignored additional results for
‘uselist=False’, so the results in that error situation should not
change.

#3249(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3249

8.4.4.41 query.update() / query.delete() raises if used with join(), select_from(), from_self()
...............................................................................................

A warning is emitted in SQLAlchemy 0.9.10 (not yet released as of June
9, 2015) when the Query.update() or Query.delete()
methods are invoked against a query which has also called upon
Query.join(), Query.outerjoin(),
Query.select_from() or Query.from_self().  These are
unsupported use cases which silently fail in the 0.9 series up until
0.9.10 where it emits a warning.  In 1.0, these cases raise an
exception.

#3349(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3349

8.4.4.42 query.update() with ‘synchronize_session='evaluate'’ raises on multi-table update
..........................................................................................

The “evaluator” for Query.update() won’t work with
multi-table updates, and needs to be set to ‘synchronize_session=False’
or ‘synchronize_session='fetch'’ when multiple tables are present.  The
new behavior is that an explicit exception is now raised, with a message
to change the synchronize setting.  This is upgraded from a warning
emitted as of 0.9.7.

#3117(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3117

8.4.4.43 Resurrect Event has been Removed
.........................................

The “resurrect” ORM event has been removed entirely.  This event ceased
to have any function since version 0.8 removed the older “mutable”
system from the unit of work.

8.4.4.44 Change to single-table-inheritance criteria when using from_self(), count()
....................................................................................

Given a single-table inheritance mapping, such as:

     class Widget(Base):
         __table__ = 'widget_table'

     class FooWidget(Widget):
         pass

Using Query.from_self() or Query.count() against
a subclass would produce a subquery, but then add the “WHERE” criteria
for subtypes to the outside:

     sess.query(FooWidget).from_self().all()

rendering:

     SELECT
         anon_1.widgets_id AS anon_1_widgets_id,
         anon_1.widgets_type AS anon_1_widgets_type
     FROM (SELECT widgets.id AS widgets_id, widgets.type AS widgets_type,
     FROM widgets) AS anon_1
     WHERE anon_1.widgets_type IN (?)

The issue with this is that if the inner query does not specify all
columns, then we can’t add the WHERE clause on the outside (it actually
tries, and produces a bad query).  This decision apparently goes way
back to 0.6.5 with the note “may need to make more adjustments to this”.
Well, those adjustments have arrived!  So now the above query will
render:

     SELECT
         anon_1.widgets_id AS anon_1_widgets_id,
         anon_1.widgets_type AS anon_1_widgets_type
     FROM (SELECT widgets.id AS widgets_id, widgets.type AS widgets_type,
     FROM widgets
     WHERE widgets.type IN (?)) AS anon_1

So that queries that don’t include “type” will still work!:

     sess.query(FooWidget.id).count()

Renders:

     SELECT count(*) AS count_1
     FROM (SELECT widgets.id AS widgets_id
     FROM widgets
     WHERE widgets.type IN (?)) AS anon_1

#3177(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3177

8.4.4.45 single-table-inheritance criteria added to all ON clauses unconditionally
..................................................................................

When joining to a single-table inheritance subclass target, the ORM
always adds the “single table criteria” when joining on a relationship.
Given a mapping as:

     class Widget(Base):
         __tablename__ = 'widget'
         id = Column(Integer, primary_key=True)
         type = Column(String)
         related_id = Column(ForeignKey('related.id'))
         related = relationship("Related", backref="widget")
         __mapper_args__ = {'polymorphic_on': type}

     class FooWidget(Widget):
         __mapper_args__ = {'polymorphic_identity': 'foo'}

     class Related(Base):
         __tablename__ = 'related'
         id = Column(Integer, primary_key=True)

It’s been the behavior for quite some time that a JOIN on the
relationship will render a “single inheritance” clause for the type:

     s.query(Related).join(FooWidget, Related.widget).all()

SQL output:

     SELECT related.id AS related_id
     FROM related JOIN widget ON related.id = widget.related_id AND widget.type IN (:type_1)

Above, because we joined to a subclass ‘FooWidget’, see Query.join()
knew to add the ‘AND widget.type IN ('foo')’ criteria to the ON
clause.

The change here is that the ‘AND widget.type IN()’ criteria is now
appended to `any' ON clause, not just those generated from a
relationship, including one that is explicitly stated:

     # ON clause will now render as
     # related.id = widget.related_id AND widget.type IN (:type_1)
     s.query(Related).join(FooWidget, FooWidget.related_id == Related.id).all()

As well as the “implicit” join when no ON clause of any kind is stated:

     # ON clause will now render as
     # related.id = widget.related_id AND widget.type IN (:type_1)
     s.query(Related).join(FooWidget).all()

Previously, the ON clause for these would not include the
single-inheritance criteria.  Applications that are already adding this
criteria to work around this will want to remove its explicit use,
though it should continue to work fine if the criteria happens to be
rendered twice in the meantime.

See also
........

See Changes and fixes in handling of duplicate join targets.

#3222(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3222

8.4.4.46 Key Behavioral Changes - Core
......................................

8.4.4.47 Warnings emitted when coercing full SQL fragments into text()
......................................................................

Since SQLAlchemy’s inception, there has always been an emphasis on not
getting in the way of the usage of plain text.  The Core and ORM
expression systems were intended to allow any number of points at which
the user can just use plain text SQL expressions, not just in the sense
that you can send a full SQL string to Connection.execute(),
but that you can send strings with SQL expressions into many functions,
such as Select.where(), Query.filter(), and
Select.order_by().

Note that by “SQL expressions” we mean a `full fragment of a SQL
string', such as:

     # the argument sent to where() is a full SQL expression
     stmt = select([sometable]).where("somecolumn = 'value'")

and we are `not talking about string arguments', that is, the normal
behavior of passing string values that become parameterized:

     # This is a normal Core expression with a string argument -
     # we aren't talking about this!!
     stmt = select([sometable]).where(sometable.c.somecolumn == 'value')

The Core tutorial has long featured an example of the use of this
technique, using a select() construct where virtually all
components of it are specified as straight strings.  However, despite
this long-standing behavior and example, users are apparently surprised
that this behavior exists, and when asking around the community, I was
unable to find any user that was in fact `not' surprised that you can
send a full string into a method like Query.filter().

So the change here is to encourage the user to qualify textual strings
when composing SQL that is partially or fully composed from textual
fragments.  When composing a select as below:

     stmt = select(["a", "b"]).where("a = b").select_from("sometable")

The statement is built up normally, with all the same coercions as
before.  However, one will see the following warnings emitted:

     SAWarning: Textual column expression 'a' should be explicitly declared
     with text('a'), or use column('a') for more specificity
     (this warning may be suppressed after 10 occurrences)

     SAWarning: Textual column expression 'b' should be explicitly declared
     with text('b'), or use column('b') for more specificity
     (this warning may be suppressed after 10 occurrences)

     SAWarning: Textual SQL expression 'a = b' should be explicitly declared
     as text('a = b') (this warning may be suppressed after 10 occurrences)

     SAWarning: Textual SQL FROM expression 'sometable' should be explicitly
     declared as text('sometable'), or use table('sometable') for more
     specificity (this warning may be suppressed after 10 occurrences)

These warnings attempt to show exactly where the issue is by displaying
the parameters as well as where the string was received.  The warnings
make use of the Session.get_bind() handles a wider variety of inheritance scenarios
so that parameterized warnings can be
emitted safely without running out of memory, and as always, if one
wishes the warnings to be exceptions, the Python Warnings Filter(1)
should be used:

     import warnings
     warnings.simplefilter("error")   # all warnings raise an exception

Given the above warnings, our statement works just fine, but to get rid
of the warnings we would rewrite our statement as follows:

     from sqlalchemy import select, text
     stmt = select([
             text("a"),
             text("b")
         ]).where(text("a = b")).select_from(text("sometable"))

and as the warnings suggest, we can give our statement more specificity
about the text if we use column() and table():

     from sqlalchemy import select, text, column, table

     stmt = select([column("a"), column("b")]).\
         where(text("a = b")).select_from(table("sometable"))

Where note also that table() and column() can
now be imported from “sqlalchemy” without the “sql” part.

The behavior here applies to select() as well as to key
methods on Query, including Query.filter(),
Query.from_statement() and Query.having().

   ---------- Footnotes ----------

   (1) https://docs.python.org/2/library/warnings.html

8.4.4.48 ORDER BY and GROUP BY are special cases
................................................

There is one case where usage of a string has special meaning, and as
part of this change we have enhanced its functionality.  When we have a
select() or Query that refers to some column name
or named label, we might want to GROUP BY and/or ORDER BY known columns
or labels:

     stmt = select([
         user.c.name,
         func.count(user.c.id).label("id_count")
     ]).group_by("name").order_by("id_count")

In the above statement we expect to see “ORDER BY id_count”, as opposed
to a re-statement of the function.  The string argument given is
actively matched to an entry in the columns clause during compilation,
so the above statement would produce as we expect, without warnings
(though note that the ‘"name"’ expression has been resolved to
‘users.name’!):

     SELECT users.name, count(users.id) AS id_count
     FROM users GROUP BY users.name ORDER BY id_count

However, if we refer to a name that cannot be located, then we get the
warning again, as below:

     stmt = select([
             user.c.name,
             func.count(user.c.id).label("id_count")
         ]).order_by("some_label")

The output does what we say, but again it warns us:

     SAWarning: Can't resolve label reference 'some_label'; converting to
     text() (this warning may be suppressed after 10 occurrences)

     SELECT users.name, count(users.id) AS id_count
     FROM users ORDER BY some_label

The above behavior applies to all those places where we might want to
refer to a so-called “label reference”; ORDER BY and GROUP BY, but also
within an OVER clause as well as a DISTINCT ON clause that refers to
columns (e.g.  the PostgreSQL syntax).

We can still specify any arbitrary expression for ORDER BY or others
using text():

     stmt = select([users]).order_by(text("some special expression"))

The upshot of the whole change is that SQLAlchemy now would like us to
tell it when a string is sent that this string is explicitly a
text() construct, or a column, table, etc., and if we use it as a
label name in an order by, group by, or other expression, SQLAlchemy
expects that the string resolves to something known, else it should
again be qualified with text() or similar.

#2992(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2992

8.4.4.49 Python-side defaults invoked for each row individually when using a multivalued insert
...............................................................................................

Support for Python-side column defaults when using the multi-valued
version of Insert.values() were essentially not implemented,
and would only work “by accident” in specific situations, when the
dialect in use was using a non-positional (e.g.  named) style of bound
parameter, and when it was not necessary that a Python-side callable be
invoked for each row.

The feature has been overhauled so that it works more similarly to that
of an “executemany” style of invocation:

     import itertools

     counter = itertools.count(1)
     t = Table(
         'my_table', metadata,
         Column('id', Integer, default=lambda: next(counter)),
         Column('data', String)
     )

     conn.execute(t.insert().values([
         {"data": "d1"},
         {"data": "d2"},
         {"data": "d3"},
     ]))

The above example will invoke ‘next(counter)’ for each row individually
as would be expected:

     INSERT INTO my_table (id, data) VALUES (?, ?), (?, ?), (?, ?)
     (1, 'd1', 2, 'd2', 3, 'd3')

Previously, a positional dialect would fail as a bind would not be
generated for additional positions:

     Incorrect number of bindings supplied. The current statement uses 6,
     and there are 4 supplied.
     [SQL: u'INSERT INTO my_table (id, data) VALUES (?, ?), (?, ?), (?, ?)']
     [parameters: (1, 'd1', 'd2', 'd3')]

And with a “named” dialect, the same value for “id” would be re-used in
each row (hence this change is backwards-incompatible with a system that
relied on this):

     INSERT INTO my_table (id, data) VALUES (:id, :data_0), (:id, :data_1), (:id, :data_2)
     {u'data_2': 'd3', u'data_1': 'd2', u'data_0': 'd1', 'id': 1}

The system will also refuse to invoke a “server side” default as
inline-rendered SQL, since it cannot be guaranteed that a server side
default is compatible with this.  If the VALUES clause renders for a
specific column, then a Python-side value is required; if an omitted
value only refers to a server-side default, an exception is raised:

     t = Table(
         'my_table', metadata,
         Column('id', Integer, primary_key=True),
         Column('data', String, server_default='some default')
     )

     conn.execute(t.insert().values([
         {"data": "d1"},
         {"data": "d2"},
         {},
     ]))

will raise:

     sqlalchemy.exc.CompileError: INSERT value for column my_table.data is
     explicitly rendered as a boundparameter in the VALUES clause; a
     Python-side value or SQL expression is required

Previously, the value “d1” would be copied into that of the third row
(but again, only with named format!):

     INSERT INTO my_table (data) VALUES (:data_0), (:data_1), (:data_0)
     {u'data_1': 'd2', u'data_0': 'd1'}

#3288(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3288

8.4.4.50 Event listeners can not be added or removed from within that event’s runner
....................................................................................

Removal of an event listener from inside that same event itself would
modify the elements of a list during iteration, which would cause
still-attached event listeners to silently fail to fire.  To prevent
this while still maintaining performance, the lists have been replaced
with ‘collections.deque()’, which does not allow any additions or
removals during iteration, and instead raises ‘RuntimeError’.

#3163(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3163

8.4.4.51 The INSERT…FROM SELECT construct now implies ‘inline=True’
...................................................................

Using Insert.from_select() now implies ‘inline=True’ on
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 variable numbers of rows, the
‘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 Insert.returning() should be used to return variable
numbers of result rows if inserted data is needed.

#3169(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3169

8.4.4.52 ‘autoload_with’ now implies ‘autoload=True’
....................................................

A Table can be set up for reflection by passing
Table.autoload_with alone:

     my_table = Table('my_table', metadata, autoload_with=some_engine)

#3027(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3027

8.4.4.53 DBAPI exception wrapping and handle_error() event improvements
.......................................................................

SQLAlchemy’s wrapping of DBAPI exceptions was not taking place in the
case where a Connection object was invalidated, and then
tried to reconnect and encountered an error; this has been resolved.

Additionally, the recently added ConnectionEvents.handle_error()
event is now invoked for errors that occur upon initial connect,
upon reconnect, and when create_engine() is used given a
custom connection function via create_engine.creator.

The ExceptionContext object has a new datamember
ExceptionContext.engine that will always refer to the
Engine in use, in those cases when the Connection
object is not available (e.g.  on initial connect).

#3266(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3266

8.4.4.54 ForeignKeyConstraint.columns is now a ColumnCollection
...............................................................

ForeignKeyConstraint.columns was previously a plain list
containing either strings or Column objects, depending on how
the ForeignKeyConstraint was constructed and whether it was
associated with a table.  The collection is now a
ColumnCollection, and is only initialized after the
ForeignKeyConstraint is associated with a Table.  A new
accessor ForeignKeyConstraint.column_keys is added to
unconditionally return string keys for the local set of columns
regardless of how the object was constructed or its current state.

8.4.4.55 MetaData.sorted_tables accessor is “deterministic”
...........................................................

The sorting of tables resulting from the MetaData.sorted_tables
accessor is “deterministic”; the ordering should be the same in
all cases regardless of Python hashing.  This is done by first sorting
the tables by name before passing them to the topological algorithm,
which maintains that ordering as it iterates.

Note that this change does `not' yet apply to the ordering applied when
emitting MetaData.create_all() or MetaData.drop_all().

#3084(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3084

8.4.4.56 null(), false() and true() constants are no longer singletons
......................................................................

These three constants were changed to return a “singleton” value in 0.9;
unfortunately, that would lead to a query like the following to not
render as expected:

     select([null(), null()])

rendering only ‘SELECT NULL AS anon_1’, because the two null()
constructs would come out as the same ‘NULL’ object, and
SQLAlchemy’s Core model is based on object identity in order to
determine lexical significance.  The change in 0.9 had no importance
other than the desire to save on object overhead; in general, an unnamed
construct needs to stay lexically unique so that it gets labeled
uniquely.

#3170(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3170

8.4.4.57 SQLite/Oracle have distinct methods for temporary table/view name reporting
....................................................................................

The Inspector.get_table_names() and
Inspector.get_view_names() methods in the case of SQLite/Oracle
would also return the names of temporary tables and views, which is not
provided by any other dialect (in the case of MySQL at least it is not
even possible).  This logic has been moved out to two new methods
Inspector.get_temp_table_names() and
Inspector.get_temp_view_names().

Note that reflection of a specific named temporary table or temporary
view, either by ‘Table('name', autoload=True)’ or via methods like
Inspector.get_columns() continues to function for most if not all
dialects.  For SQLite specifically, there is a bug fix for UNIQUE
constraint reflection from temp tables as well, which is #3203(1).

#3204(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3203

   (2) http://www.sqlalchemy.org/trac/ticket/3204

8.4.4.58 Dialect Improvements and Changes - PostgreSQL
......................................................

8.4.4.59 Overhaul of ENUM type create/drop rules
................................................

The rules for PostgreSQL ENUM have been made more strict
with regards to creating and dropping of the TYPE.

An ENUM that is created `without' being explicitly
associated with a MetaData object will be created `and'
dropped corresponding to Table.create() and
Table.drop():

     table = Table('sometable', metadata,
         Column('some_enum', ENUM('a', 'b', 'c', name='myenum'))
     )

     table.create(engine)  # will emit CREATE TYPE and CREATE TABLE
     table.drop(engine)  # will emit DROP TABLE and DROP TYPE - new for 1.0

This means that if a second table also has an enum named ‘myenum’, the
above DROP operation will now fail.  In order to accommodate the use
case of a common shared enumerated type, the behavior of a
metadata-associated enumeration has been enhanced.

An ENUM that is created `with' being explicitly associated
with a MetaData object will `not' be created `or' dropped
corresponding to Table.create() and Table.drop(),
with the exception of Table.create() called with the
‘checkfirst=True’ flag:

     my_enum = ENUM('a', 'b', 'c', name='myenum', metadata=metadata)

     table = Table('sometable', metadata,
         Column('some_enum', my_enum)
     )

     # will fail: ENUM 'my_enum' does not exist
     table.create(engine)

     # will check for enum and emit CREATE TYPE
     table.create(engine, checkfirst=True)

     table.drop(engine)  # will emit DROP TABLE, *not* DROP TYPE

     metadata.drop_all(engine) # will emit DROP TYPE

     metadata.create_all(engine) # will emit CREATE TYPE

#3319(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3319

8.4.4.60 New PostgreSQL Table options
.....................................

Added support for PG table options TABLESPACE, ON COMMIT, WITH(OUT)
OIDS, and INHERITS, when rendering DDL via the Table
construct.

See also
........

See PostgreSQL Table Options.

#2051(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2051

8.4.4.61 New get_enums() method with PostgreSQL Dialect
.......................................................

The inspect() method returns a PGInspector
object in the case of PostgreSQL, which includes a new
PGInspector.get_enums() method that returns information on all
available ‘ENUM’ types:

     from sqlalchemy import inspect, create_engine

     engine = create_engine("postgresql+psycopg2://host/dbname")
     insp = inspect(engine)
     print(insp.get_enums())

See also
........

See PGInspector.get_enums().

8.4.4.62 PostgreSQL Dialect reflects Materialized Views, Foreign Tables
.......................................................................

Changes are as follows:

   * the ‘Table’ construct with ‘autoload=True’ will now match a name
     that exists in the database as a materialized view or foreign
     table.

   * Inspector.get_view_names() will return plain and
     materialized view names.

   * Inspector.get_table_names() does `not' change for
     PostgreSQL, it continues to return only the names of plain tables.

   * A new method PGInspector.get_foreign_table_names() is
     added which will return the names of tables that are specifically
     marked as “foreign” in the PostgreSQL schema tables.

The change to reflection involves adding ‘'m'’ and ‘'f'’ to the list of
qualifiers we use when querying ‘pg_class.relkind’, but this change is
new in 1.0.0 to avoid any backwards-incompatible surprises for those
running 0.9 in production.

#2891(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2891

8.4.4.63 PostgreSQL ‘has_table()’ now works for temporary tables
................................................................

This is a simple fix such that “has table” for temporary tables now
works, so that code like the following may proceed:

     from sqlalchemy import *

     metadata = MetaData()
     user_tmp = Table(
         "user_tmp", metadata,
         Column("id", INT, primary_key=True),
         Column('name', VARCHAR(50)),
         prefixes=['TEMPORARY']
     )

     e = create_engine("postgresql://scott:tiger@localhost/test", echo='debug')
     with e.begin() as conn:
         user_tmp.create(conn, checkfirst=True)

         # checkfirst will succeed
         user_tmp.create(conn, checkfirst=True)

The very unlikely case that this behavior will cause a non-failing
application to behave differently, is because PostgreSQL allows a
non-temporary table to silently overwrite a temporary table.  So code
like the following will now act completely differently, no longer
creating the real table following the temporary table:

     from sqlalchemy import *

     metadata = MetaData()
     user_tmp = Table(
         "user_tmp", metadata,
         Column("id", INT, primary_key=True),
         Column('name', VARCHAR(50)),
         prefixes=['TEMPORARY']
     )

     e = create_engine("postgresql://scott:tiger@localhost/test", echo='debug')
     with e.begin() as conn:
         user_tmp.create(conn, checkfirst=True)

         m2 = MetaData()
         user = Table(
             "user_tmp", m2,
             Column("id", INT, primary_key=True),
             Column('name', VARCHAR(50)),
         )

         # in 0.9, *will create* the new table, overwriting the old one.
         # in 1.0, *will not create* the new table
         user.create(conn, checkfirst=True)

#3264(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3264

8.4.4.64 PostgreSQL FILTER keyword
..................................

The SQL standard FILTER keyword for aggregate functions is now supported
by PostgreSQL as of 9.4.  SQLAlchemy allows this using
FunctionElement.filter():

     func.count(1).filter(True)

See also
........

See FunctionElement.filter().

See FunctionFilter.

8.4.4.65 PG8000 dialect supports client side encoding
.....................................................

The create_engine.encoding parameter is now honored by the
pg8000 dialect, using on connect handler which emits ‘SET
CLIENT_ENCODING’ matching the selected encoding.

8.4.4.66 PG8000 native JSONB support
....................................

Support for PG8000 versions greater than 1.10.1 has been added, where
JSONB is supported natively.

8.4.4.67 Support for psycopg2cffi Dialect on PyPy
.................................................

Support for the pypy psycopg2cffi dialect is added.

See also
........

See sqlalchemy.dialects.postgresql.psycopg2cffi.

8.4.4.68 Dialect Improvements and Changes - MySQL
.................................................

8.4.4.69 MySQL TIMESTAMP Type now renders NULL / NOT NULL in all cases
......................................................................

The MySQL dialect has always worked around MySQL’s implicit NOT NULL
default associated with TIMESTAMP columns by emitting NULL for such a
type, if the column is set up with ‘nullable=True’.  However, MySQL
5.6.6 and above features a new flag explicit_defaults_for_timestamp(1)
which repairs MySQL’s non-standard behavior to make it behave like any
other type; to accommodate this, SQLAlchemy now emits NULL/NOT NULL
unconditionally for all TIMESTAMP columns.

See also
........

See TIMESTAMP Columns and NULL.

#3155(2)

   ---------- Footnotes ----------

   (1)
http://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html#sysvar_explicit_defaults_for_timestamp

   (2) http://www.sqlalchemy.org/trac/ticket/3155

8.4.4.70 MySQL SET Type Overhauled to support empty sets, unicode, blank value handling
.......................................................................................

The SET type historically not included a system of handling
blank sets and empty values separately; as different drivers had
different behaviors for treatment of empty strings and empty-string-set
representations, the SET type tried only to hedge between these
behaviors, opting to treat the empty set as ‘set([''])’ as is still the
current behavior for the MySQL-Connector-Python DBAPI. Part of the
rationale here was that it was otherwise impossible to actually store a
blank string within a MySQL SET, as the driver gives us back strings
with no way to discern between ‘set([''])’ and ‘set()’.  It was left to
the user to determine if ‘set([''])’ actually meant “empty set” or not.

The new behavior moves the use case for the blank string, which is an
unusual case that isn’t even documented in MySQL’s documentation, into a
special case, and the default behavior of SET is now:

   * to treat the empty string ‘''’ as returned by MySQL-python into the
     empty set ‘set()’;

   * to convert the single-blank value set ‘set([''])’ returned by
     MySQL-Connector-Python into the empty set ‘set()’;

   * To handle the case of a set type that actually wishes includes the
     blank value ‘''’ in its list of possible values, a new feature
     (required in this use case) is implemented whereby the set value is
     persisted and loaded as a bitwise integer value; the flag
     SET.retrieve_as_bitwise is added in order to enable this.

Using the SET.retrieve_as_bitwise flag allows the set to be
persisted and retrieved with no ambiguity of values.  Theoretically this
flag can be turned on in all cases, as long as the given list of values
to the type matches the ordering exactly as declared in the database; it
only makes the SQL echo output a bit more unusual.

The default behavior of SET otherwise remains the same,
roundtripping values using strings.  The string-based behavior now
supports unicode fully including MySQL-python with use_unicode=0.

#3283(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3283

8.4.4.71 MySQL internal “no such table” exceptions not passed to event handlers
...............................................................................

The MySQL dialect will now disable
ConnectionEvents.handle_error() events from firing for those
statements which it uses internally to detect if a table exists or not.
This is achieved using an execution option ‘skip_user_error_events’ that
disables the handle error event for the scope of that execution.  In
this way, user code that rewrites exceptions doesn’t need to worry about
the MySQL dialect or other dialects that occasionally need to catch
SQLAlchemy specific exceptions.

8.4.4.72 Changed the default value of ‘raise_on_warnings’ for MySQL-Connector
.............................................................................

Changed the default value of “raise_on_warnings” to False for
MySQL-Connector.  This was set at True for some reason.  The “buffered”
flag unfortunately must stay at True as MySQLconnector does not allow a
cursor to be closed unless all results are fully fetched.

#2515(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2515

8.4.4.73 MySQL boolean symbols “true”, “false” work again
.........................................................

0.9’s overhaul of the IS/IS NOT operators as well as boolean types in
#2682(1) disallowed the MySQL dialect from making use of the “true” and
“false” symbols in the context of “IS” / “IS NOT”.  Apparently, even
though MySQL has no “boolean” type, it supports IS / IS NOT when the
special “true” and “false” symbols are used, even though these are
otherwise synonymous with “1” and “0” (and IS/IS NOT don’t work with the
numerics).

So the change here is that the MySQL dialect remains “non native
boolean”, but the true() and false() symbols
again produce the keywords “true” and “false”, so that an expression
like ‘column.is_(true())’ again works on MySQL.

#3186(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2682

   (2) http://www.sqlalchemy.org/trac/ticket/3186

8.4.4.74 The match() operator now returns an agnostic MatchType compatible with MySQL’s floating point return value
...................................................................................................................

The return type of a ColumnOperators.match() expression is
now a new type called MatchType.  This is a subclass of
Boolean, that can be intercepted by the dialect in order to
produce a different result type at SQL execution time.

Code like the following will now function correctly and return floating
points on MySQL:

     >>> connection.execute(
     ...    select([
     ...        matchtable.c.title.match('Agile Ruby Programming').label('ruby'),
     ...        matchtable.c.title.match('Dive Python').label('python'),
     ...        matchtable.c.title
     ...    ]).order_by(matchtable.c.id)
     ... )
     [
         (2.0, 0.0, 'Agile Web Development with Ruby On Rails'),
         (0.0, 2.0, 'Dive Into Python'),
         (2.0, 0.0, "Programming Matz's Ruby"),
         (0.0, 0.0, 'The Definitive Guide to Django'),
         (0.0, 1.0, 'Python in a Nutshell')
     ]

#3263(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3263

8.4.4.75 Drizzle Dialect is now an External Dialect
...................................................

The dialect for Drizzle(1) is now an external dialect, available at
‘https://bitbucket.org/zzzeek/sqlalchemy-drizzle’.  This dialect was
added to SQLAlchemy right before SQLAlchemy was able to accommodate
third party dialects well; going forward, all databases that aren’t
within the “ubiquitous use” category are third party dialects.  The
dialect’s implementation hasn’t changed and is still based on the MySQL
+ MySQLdb dialects within SQLAlchemy.  The dialect is as of yet
unreleased and in “attic” status; however it passes the majority of
tests and is generally in decent working order, if someone wants to pick
up on polishing it.

   ---------- Footnotes ----------

   (1) http://www.drizzle.org/

8.4.4.76 Dialect Improvements and Changes - SQLite
..................................................

8.4.4.77 SQLite named and unnamed UNIQUE and FOREIGN KEY constraints will inspect and reflect
.............................................................................................

UNIQUE and FOREIGN KEY constraints are now fully reflected on SQLite
both with and without names.  Previously, foreign key names were ignored
and unnamed unique constraints were skipped.  In particular this will
help with Alembic’s new SQLite migration features.

To achieve this, for both foreign keys and unique constraints, the
result of PRAGMA foreign_keys, index_list, and index_info is combined
with regular expression parsing of the CREATE TABLE statement overall to
form a complete picture of the names of constraints, as well as
differentiating UNIQUE constraints that were created as UNIQUE vs.
unnamed INDEXes.

#3244(1)

#3261(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3244

   (2) http://www.sqlalchemy.org/trac/ticket/3261

8.4.4.78 Dialect Improvements and Changes - SQL Server
......................................................

8.4.4.79 PyODBC driver name is required with hostname-based SQL Server connections
..................................................................................

Connecting to SQL Server with PyODBC using a DSN-less connection, e.g.
with an explicit hostname, now requires a driver name - SQLAlchemy will
no longer attempt to guess a default:

     engine = create_engine("mssql+pyodbc://scott:tiger@myhost:port/databasename?driver=SQL+Server+Native+Client+10.0")

SQLAlchemy’s previously hardcoded default of “SQL Server” is obsolete on
Windows, and SQLAlchemy cannot be tasked with guessing the best driver
based on operation system/driver detection.  Using a DSN is always
preferred when using ODBC to avoid this issue entirely.

#3182(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3182

8.4.4.80 SQL Server 2012 large text / binary types render as VARCHAR, NVARCHAR, VARBINARY
.........................................................................................

The rendering of the TextClause, UnicodeText, and
LargeBinary types has been changed for SQL Server 2012 and
greater, with options to control the behavior completely, based on
deprecation guidelines from Microsoft.  See Large Text/Binary Type Deprecation
for details.

8.4.4.81 Dialect Improvements and Changes - Oracle
..................................................

8.4.4.82 Improved support for CTEs in Oracle
............................................

CTE support has been fixed up for Oracle, and there is also a new
feature ‘CTE.with_suffixes()’ that can assist with Oracle’s special
directives:

     included_parts = select([
         part.c.sub_part, part.c.part, part.c.quantity
     ]).where(part.c.part == "p1").\
         cte(name="included_parts", recursive=True).\
         suffix_with(
             "search depth first by part set ord1",
             "cycle part set y_cycle to 1 default 0", dialect='oracle')

#3220(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/3220

8.4.4.83 New Oracle Keywords for DDL
....................................

Keywords such as COMPRESS, ON COMMIT, BITMAP:

Oracle Table Options.

See Oracle Specific Index Options.

8.4.5 What’s New in SQLAlchemy 0.9?
-----------------------------------

     About this Document: This document describes changes between
     SQLAlchemy version 0.8, undergoing maintenance releases as of May,
     2013, and SQLAlchemy version 0.9, which had its first production
     release on December 30, 2013.

     Document last updated: June 10, 2015

8.4.5.1 Introduction
....................

This guide introduces what’s new in SQLAlchemy version 0.9, and also
documents changes which affect users migrating their applications from
the 0.8 series of SQLAlchemy to 0.9.

Please carefully review Behavioral Changes - ORM and
Behavioral Changes - Core for potentially backwards-incompatible
changes.

8.4.5.2 Platform Support
........................

8.4.5.3 Targeting Python 2.6 and Up Now, Python 3 without 2to3
..............................................................

The first achievement of the 0.9 release is to remove the dependency on
the 2to3 tool for Python 3 compatibility.  To make this more
straightforward, the lowest Python release targeted now is 2.6, which
features a wide degree of cross-compatibility with Python 3.  All
SQLAlchemy modules and unit tests are now interpreted equally well with
any Python interpreter from 2.6 forward, including the 3.1 and 3.2
interpreters.

#2671(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2671

8.4.5.4 C Extensions Supported on Python 3
..........................................

The C extensions have been ported to support Python 3 and now build in
both Python 2 and Python 3 environments.

#2161(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2161

8.4.5.5 Behavioral Changes - ORM
................................

8.4.5.6 Composite attributes are now returned as their object form when queried on a per-attribute basis
........................................................................................................

Using a Query in conjunction with a composite attribute now
returns the object type maintained by that composite, rather than being
broken out into individual columns.  Using the mapping setup at
Composite Column Types:

     >>> session.query(Vertex.start, Vertex.end).\
     ...     filter(Vertex.start == Point(3, 4)).all()
     [(Point(x=3, y=4), Point(x=5, y=6))]

This change is backwards-incompatible with code that expects the
individual attribute to be expanded into individual columns.  To get
that behavior, use the ‘.clauses’ accessor:

     >>> session.query(Vertex.start.clauses, Vertex.end.clauses).\
     ...     filter(Vertex.start == Point(3, 4)).all()
     [(3, 4, 5, 6)]

See also
........

See Column Bundles for ORM queries.

#2824(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2824

8.4.5.7 ‘Query.select_from()’ no longer applies the clause to corresponding entities
....................................................................................

The Query.select_from() method has been popularized in
recent versions as a means of controlling the first thing that a
Query object “selects from”, typically for the purposes of
controlling how a JOIN will render.

Consider the following example against the usual ‘User’ mapping:

     select_stmt = select([User]).where(User.id == 7).alias()

     q = session.query(User).\
                join(select_stmt, User.id == select_stmt.c.id).\
                filter(User.name == 'ed')

The above statement predictably renders SQL like the following:

     SELECT "user".id AS user_id, "user".name AS user_name
     FROM "user" JOIN (SELECT "user".id AS id, "user".name AS name
     FROM "user"
     WHERE "user".id = :id_1) AS anon_1 ON "user".id = anon_1.id
     WHERE "user".name = :name_1

If we wanted to reverse the order of the left and right elements of the
JOIN, the documentation would lead us to believe we could use
Query.select_from() to do so:

     q = session.query(User).\
             select_from(select_stmt).\
             join(User, User.id == select_stmt.c.id).\
             filter(User.name == 'ed')

However, in version 0.8 and earlier, the above use of
Query.select_from() would apply the ‘select_stmt’ to `replace' the
‘User’ entity, as it selects from the ‘user’ table which is compatible
with ‘User’:

     -- SQLAlchemy 0.8 and earlier...
     SELECT anon_1.id AS anon_1_id, anon_1.name AS anon_1_name
     FROM (SELECT "user".id AS id, "user".name AS name
     FROM "user"
     WHERE "user".id = :id_1) AS anon_1 JOIN "user" ON anon_1.id = anon_1.id
     WHERE anon_1.name = :name_1

The above statement is a mess, the ON clause refers ‘anon_1.id =
anon_1.id’, our WHERE clause has been replaced with ‘anon_1’ as well.

This behavior is quite intentional, but has a different use case from
that which has become popular for Query.select_from().  The
above behavior is now available by a new method known as
Query.select_entity_from().  This is a lesser used behavior that in
modern SQLAlchemy is roughly equivalent to selecting from a customized
aliased() construct:

     select_stmt = select([User]).where(User.id == 7)
     user_from_stmt = aliased(User, select_stmt.alias())

     q = session.query(user_from_stmt).filter(user_from_stmt.name == 'ed')

So with SQLAlchemy 0.9, our query that selects from ‘select_stmt’
produces the SQL we expect:

     -- SQLAlchemy 0.9
     SELECT "user".id AS user_id, "user".name AS user_name
     FROM (SELECT "user".id AS id, "user".name AS name
     FROM "user"
     WHERE "user".id = :id_1) AS anon_1 JOIN "user" ON "user".id = id
     WHERE "user".name = :name_1

The Query.select_entity_from() method will be available in
SQLAlchemy `0.8.2', so applications which rely on the old behavior can
transition to this method first, ensure all tests continue to function,
then upgrade to 0.9 without issue.

#2736(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2736

8.4.5.8 ‘viewonly=True’ on ‘relationship()’ prevents history from taking effect
...............................................................................

The ‘viewonly’ flag on relationship() is applied to prevent
changes to the target attribute from having any effect within the flush
process.  This is achieved by eliminating the attribute from being
considered during the flush.  However, up until now, changes to the
attribute would still register the parent object as “dirty” and trigger
a potential flush.  The change is that the ‘viewonly’ flag now prevents
history from being set for the target attribute as well.  Attribute
events like backrefs and user-defined events still continue to function
normally.

The change is illustrated as follows:

     from sqlalchemy import Column, Integer, ForeignKey, create_engine
     from sqlalchemy.orm import backref, relationship, Session
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy import inspect

     Base = declarative_base()

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)

     class B(Base):
         __tablename__ = 'b'

         id = Column(Integer, primary_key=True)
         a_id = Column(Integer, ForeignKey('a.id'))
         a = relationship("A", backref=backref("bs", viewonly=True))

     e = create_engine("sqlite://")
     Base.metadata.create_all(e)

     a = A()
     b = B()

     sess = Session(e)
     sess.add_all([a, b])
     sess.commit()

     b.a = a

     assert b in sess.dirty

     # before 0.9.0
     # assert a in sess.dirty
     # assert inspect(a).attrs.bs.history.has_changes()

     # after 0.9.0
     assert a not in sess.dirty
     assert not inspect(a).attrs.bs.history.has_changes()

#2833(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2833

8.4.5.9 Association Proxy SQL Expression Improvements and Fixes
...............................................................

The ‘==’ and ‘!=’ operators as implemented by an association proxy that
refers to a scalar value on a scalar relationship now produces a more
complete SQL expression, intended to take into account the “association”
row being present or not when the comparison is against ‘None’.

Consider this mapping:

     class A(Base):
         __tablename__ = 'a'

         id = Column(Integer, primary_key=True)

         b_id = Column(Integer, ForeignKey('b.id'), primary_key=True)
         b = relationship("B")
         b_value = association_proxy("b", "value")

     class B(Base):
         __tablename__ = 'b'
         id = Column(Integer, primary_key=True)
         value = Column(String)

Up through 0.8, a query like the following:

     s.query(A).filter(A.b_value == None).all()

would produce:

     SELECT a.id AS a_id, a.b_id AS a_b_id
     FROM a
     WHERE EXISTS (SELECT 1
     FROM b
     WHERE b.id = a.b_id AND b.value IS NULL)

In 0.9, it now produces:

     SELECT a.id AS a_id, a.b_id AS a_b_id
     FROM a
     WHERE (EXISTS (SELECT 1
     FROM b
     WHERE b.id = a.b_id AND b.value IS NULL)) OR a.b_id IS NULL

The difference being, it not only checks ‘b.value’, it also checks if
‘a’ refers to no ‘b’ row at all.  This will return different results
versus prior versions, for a system that uses this type of comparison
where some parent rows have no association row.

More critically, a correct expression is emitted for ‘A.b_value !=
None’.  In 0.8, this would return ‘True’ for ‘A’ rows that had no ‘b’:

     SELECT a.id AS a_id, a.b_id AS a_b_id
     FROM a
     WHERE NOT (EXISTS (SELECT 1
     FROM b
     WHERE b.id = a.b_id AND b.value IS NULL))

Now in 0.9, the check has been reworked so that it ensures the A.b_id
row is present, in addition to ‘B.value’ being non-NULL:

     SELECT a.id AS a_id, a.b_id AS a_b_id
     FROM a
     WHERE EXISTS (SELECT 1
     FROM b
     WHERE b.id = a.b_id AND b.value IS NOT NULL)

In addition, the ‘has()’ operator is enhanced such that you can call it
against a scalar column value with no criterion only, and it will
produce criteria that checks for the association row being present or
not:

     s.query(A).filter(A.b_value.has()).all()

output:

     SELECT a.id AS a_id, a.b_id AS a_b_id
     FROM a
     WHERE EXISTS (SELECT 1
     FROM b
     WHERE b.id = a.b_id)

This is equivalent to ‘A.b.has()’, but allows one to query against
‘b_value’ directly.

#2751(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2751

8.4.5.10 Association Proxy Missing Scalar returns None
......................................................

An association proxy from a scalar attribute to a scalar will now return
‘None’ if the proxied object isn’t present.  This is consistent with the
fact that missing many-to-ones return None in SQLAlchemy, so should the
proxied value.  E.g.:

     from sqlalchemy import *
     from sqlalchemy.orm import *
     from sqlalchemy.ext.declarative import declarative_base
     from sqlalchemy.ext.associationproxy import association_proxy

     Base = declarative_base()

     class A(Base):
         __tablename__ = 'a'

         id = Column(Integer, primary_key=True)
         b = relationship("B", uselist=False)

         bname = association_proxy("b", "name")

     class B(Base):
         __tablename__ = 'b'

         id = Column(Integer, primary_key=True)
         a_id = Column(Integer, ForeignKey('a.id'))
         name = Column(String)

     a1 = A()

     # this is how m2o's always have worked
     assert a1.b is None

     # but prior to 0.9, this would raise AttributeError,
     # now returns None just like the proxied value.
     assert a1.bname is None

#2810(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2810

8.4.5.11 attributes.get_history() will query from the DB by default if value not present
........................................................................................

A bugfix regarding get_history() allows a column-based
attribute to query out to the database for an unloaded value, assuming
the ‘passive’ flag is left at its default of ‘PASSIVE_OFF’.  Previously,
this flag would not be honored.  Additionally, a new method
AttributeState.load_history() is added to complement the
AttributeState.history attribute, which will emit loader callables
for an unloaded attribute.

This is a small change demonstrated as follows:

     from sqlalchemy import Column, Integer, String, create_engine, inspect
     from sqlalchemy.orm import Session, attributes
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class A(Base):
         __tablename__ = 'a'
         id = Column(Integer, primary_key=True)
         data = Column(String)

     e = create_engine("sqlite://", echo=True)
     Base.metadata.create_all(e)

     sess = Session(e)

     a1 = A(data='a1')
     sess.add(a1)
     sess.commit()  # a1 is now expired

     # history doesn't emit loader callables
     assert inspect(a1).attrs.data.history == (None, None, None)

     # in 0.8, this would fail to load the unloaded state.
     assert attributes.get_history(a1, 'data') == ((), ['a1',], ())

     # load_history() is now equivalent to get_history() with
     # passive=PASSIVE_OFF ^ INIT_OK
     assert inspect(a1).attrs.data.load_history() == ((), ['a1',], ())

#2787(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2787

8.4.5.12 Behavioral Changes - Core
..................................

8.4.5.13 Type objects no longer accept ignored keyword arguments
................................................................

Up through the 0.8 series, most type objects accepted arbitrary keyword
arguments which were silently ignored:

     from sqlalchemy import Date, Integer

     # storage_format argument here has no effect on any backend;
     # it needs to be on the SQLite-specific type
     d = Date(storage_format="%(day)02d.%(month)02d.%(year)04d")

     # display_width argument here has no effect on any backend;
     # it needs to be on the MySQL-specific type
     i = Integer(display_width=5)

This was a very old bug for which a deprecation warning was added to the
0.8 series, but because nobody ever runs Python with the “-W” flag, it
was mostly never seen:

     $ python -W always::DeprecationWarning ~/dev/sqlalchemy/test.py
     /Users/classic/dev/sqlalchemy/test.py:5: SADeprecationWarning: Passing arguments to
     type object constructor <class 'sqlalchemy.types.Date'> is deprecated
       d = Date(storage_format="%(day)02d.%(month)02d.%(year)04d")
     /Users/classic/dev/sqlalchemy/test.py:9: SADeprecationWarning: Passing arguments to
     type object constructor <class 'sqlalchemy.types.Integer'> is deprecated
       i = Integer(display_width=5)

As of the 0.9 series the “catch all” constructor is removed from
TypeEngine, and these meaningless arguments are no longer accepted.

The correct way to make use of dialect-specific arguments such as
‘storage_format’ and ‘display_width’ is to use the appropriate
dialect-specific types:

     from sqlalchemy.dialects.sqlite import DATE
     from sqlalchemy.dialects.mysql import INTEGER

     d = DATE(storage_format="%(day)02d.%(month)02d.%(year)04d")

     i = INTEGER(display_width=5)

What about the case where we want the dialect-agnostic type also?  We
use the TypeEngine.with_variant() method:

     from sqlalchemy import Date, Integer
     from sqlalchemy.dialects.sqlite import DATE
     from sqlalchemy.dialects.mysql import INTEGER

     d = Date().with_variant(
             DATE(storage_format="%(day)02d.%(month)02d.%(year)04d"),
             "sqlite"
         )

     i = Integer().with_variant(
             INTEGER(display_width=5),
             "mysql"
         )

TypeEngine.with_variant() isn’t new, it was added in
SQLAlchemy 0.7.2.  So code that is running on the 0.8 series can be
corrected to use this approach and tested before upgrading to 0.9.

8.4.5.14 ‘None’ can no longer be used as a “partial AND” constructor
....................................................................

‘None’ can no longer be used as the “backstop” to form an AND condition
piecemeal.  This pattern was not a documented pattern even though some
SQLAlchemy internals made use of it:

     condition = None

     for cond in conditions:
         condition = condition & cond

     if condition is not None:
         stmt = stmt.where(condition)

The above sequence, when ‘conditions’ is non-empty, will on 0.9 produce
‘SELECT .. WHERE <condition> AND NULL’.  The ‘None’ is no longer
implicitly ignored, and is instead consistent with when ‘None’ is
interpreted in other contexts besides that of a conjunction.

The correct code for both 0.8 and 0.9 should read:

     from sqlalchemy.sql import and_

     if conditions:
         stmt = stmt.where(and_(*conditions))

Another variant that works on all backends on 0.9, but on 0.8 only works
on backends that support boolean constants:

     from sqlalchemy.sql import true

     condition = true()

     for cond in conditions:
         condition = cond & condition

     stmt = stmt.where(condition)

On 0.8, this will produce a SELECT statement that always has ‘AND true’
in the WHERE clause, which is not accepted by backends that don’t
support boolean constants (MySQL, MSSQL). On 0.9, the ‘true’ constant
will be dropped within an ‘and_()’ conjunction.

See also
........

See Improved rendering of Boolean constants, NULL constants, conjunctions.

8.4.5.15 The “password” portion of a ‘create_engine()’ no longer considers the ‘+’ sign as an encoded space
...........................................................................................................

For whatever reason, the Python function ‘unquote_plus()’ was applied to
the “password” field of a URL, which is an incorrect application of the
encoding rules described in RFC 1738(1) in that it escaped spaces as
plus signs.  The stringification of a URL now only encodes “:”, “@”, or
“/” and nothing else, and is now applied to both the ‘username’ and
‘password’ fields (previously it only applied to the password).  On
parsing, encoded characters are converted, but plus signs and spaces are
passed through as is:

     # password: "pass word + other:words"
     dbtype://user:pass word + other%3Awords@host/dbname

     # password: "apples/oranges"
     dbtype://username:apples%2Foranges@hostspec/database

     # password: "apples@oranges@@"
     dbtype://username:apples%40oranges%40%40@hostspec/database

     # password: '', username is "username@"
     dbtype://username%40:@hostspec/database

#2873(2)

   ---------- Footnotes ----------

   (1) http://www.ietf.org/rfc/rfc1738.txt

   (2) http://www.sqlalchemy.org/trac/ticket/2873

8.4.5.16 The precedence rules for COLLATE have been changed
...........................................................

Previously, an expression like the following:

     print((column('x') == 'somevalue').collate("en_EN"))

would produce an expression like this:

     -- 0.8 behavior
     (x = :x_1) COLLATE en_EN

The above is misunderstood by MSSQL and is generally not the syntax
suggested for any database.  The expression will now produce the syntax
illustrated by that of most database documentation:

     -- 0.9 behavior
     x = :x_1 COLLATE en_EN

The potentially backwards incompatible change arises if the
ColumnOperators.collate() operator is being applied to the
right-hand column, as follows:

     print(column('x') == literal('somevalue').collate("en_EN"))

In 0.8, this produces:

     x = :param_1 COLLATE en_EN

However in 0.9, will now produce the more accurate, but probably not
what you want, form of:

     x = (:param_1 COLLATE en_EN)

The ColumnOperators.collate() operator now works more
appropriately within an ‘ORDER BY’ expression as well, as a specific
precedence has been given to the ‘ASC’ and ‘DESC’ operators which will
again ensure no parentheses are generated:

     >>> # 0.8
     >>> print(column('x').collate('en_EN').desc())
     (x COLLATE en_EN) DESC

     >>> # 0.9
     >>> print(column('x').collate('en_EN').desc())
     x COLLATE en_EN DESC

#2879(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2879

8.4.5.17 PostgreSQL CREATE TYPE <x> AS ENUM now applies quoting to values
.........................................................................

The ENUM type will now apply escaping to single quote signs
within the enumerated values:

     >>> from sqlalchemy.dialects import postgresql
     >>> type = postgresql.ENUM('one', 'two', "three's", name="myenum")
     >>> from sqlalchemy.dialects.postgresql import base
     >>> print(base.CreateEnumType(type).compile(dialect=postgresql.dialect()))
     CREATE TYPE myenum AS ENUM ('one','two','three''s')

Existing workarounds which already escape single quote signs will need
to be modified, else they will now double-escape.

#2878(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2878

8.4.5.18 New Features
.....................

8.4.5.19 Event Removal API
..........................

Events established using listen() or listens_for()
can now be removed using the new remove() function.
The ‘target’, ‘identifier’ and ‘fn’ arguments sent to remove()
need to match exactly those which were sent for listening, and the
event will be removed from all locations in which it had been
established:

     @event.listens_for(MyClass, "before_insert", propagate=True)
     def my_before_insert(mapper, connection, target):
         """listen for before_insert"""
         # ...

     event.remove(MyClass, "before_insert", my_before_insert)

In the example above, the ‘propagate=True’ flag is set.  This means
‘my_before_insert()’ is established as a listener for ‘MyClass’ as well
as all subclasses of ‘MyClass’.  The system tracks everywhere that the
‘my_before_insert()’ listener function had been placed as a result of
this call and removes it as a result of calling remove().

The removal system uses a registry to associate arguments passed to
listen() with collections of event listeners, which are in
many cases wrapped versions of the original user-supplied function.
This registry makes heavy use of weak references in order to allow all
the contained contents, such as listener targets, to be garbage
collected when they go out of scope.

#2268(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2268

8.4.5.20 New Query Options API; ‘load_only()’ option
....................................................

The system of loader options such as joinedload(),
subqueryload(), lazyload(), defer(), etc.
all build upon a new system known as Load.  Load
provides a “method chained” (a.k.a.  generative) approach to loader
options, so that instead of joining together long paths using dots or
multiple attribute names, an explicit loader style is given for each
path.

While the new way is slightly more verbose, it is simpler to understand
in that there is no ambiguity in what options are being applied to which
paths; it simplifies the method signatures of the options and provides
greater flexibility particularly for column-based options.  The old
systems are to remain functional indefinitely as well and all styles can
be mixed.

`Old Way'

To set a certain style of loading along every link in a multi-element
path, the ‘_all()’ option has to be used:

     query(User).options(joinedload_all("orders.items.keywords"))

`New Way'

Loader options are now chainable, so the same ‘joinedload(x)’ method is
applied equally to each link, without the need to keep straight between
joinedload() and ‘joinedload_all()’:

     query(User).options(joinedload("orders").joinedload("items").joinedload("keywords"))

`Old Way'

Setting an option on path that is based on a subclass requires that all
links in the path be spelled out as class bound attributes, since the
PropComparator.of_type() method needs to be called:

     session.query(Company).\
         options(
             subqueryload_all(
                 Company.employees.of_type(Engineer),
                 Engineer.machines
             )
         )

`New Way'

Only those elements in the path that actually need
PropComparator.of_type() need to be set as a class-bound
attribute, string-based names can be resumed afterwards:

     session.query(Company).\
         options(
             subqueryload(Company.employees.of_type(Engineer)).
             subqueryload("machines")
             )
         )

`Old Way'

Setting the loader option on the last link in a long path uses a syntax
that looks a lot like it should be setting the option for all links in
the path, causing confusion:

     query(User).options(subqueryload("orders.items.keywords"))

`New Way'

A path can now be spelled out using defaultload() for
entries in the path where the existing loader style should be unchanged.
More verbose but the intent is clearer:

     query(User).options(defaultload("orders").defaultload("items").subqueryload("keywords"))

The dotted style can still be taken advantage of, particularly in the
case of skipping over several path elements:

     query(User).options(defaultload("orders.items").subqueryload("keywords"))

`Old Way'

The defer() option on a path needed to be spelled out with
the full path for each column:

     query(User).options(defer("orders.description"), defer("orders.isopen"))

`New Way'

A single Load object that arrives at the target path can
have Load.defer() called upon it repeatedly:

     query(User).options(defaultload("orders").defer("description").defer("isopen"))

8.4.5.21 The Load Class
.......................

The Load class can be used directly to provide a “bound”
target, especially when multiple parent entities are present:

     from sqlalchemy.orm import Load

     query(User, Address).options(Load(Address).joinedload("entries"))

8.4.5.22 Load Only
..................

A new option load_only() achieves a “defer everything but”
style of load, loading only the given columns and deferring the rest:

     from sqlalchemy.orm import load_only

     query(User).options(load_only("name", "fullname"))

     # specify explicit parent entity
     query(User, Address).options(Load(User).load_only("name", "fullname"))

     # specify path
     query(User).options(joinedload(User.addresses).load_only("email_address"))

8.4.5.23 Class-specific Wildcards
.................................

Using Load, a wildcard may be used to set the loading for all
relationships (or perhaps columns) on a given entity, without affecting
any others:

     # lazyload all User relationships
     query(User).options(Load(User).lazyload("*"))

     # undefer all User columns
     query(User).options(Load(User).undefer("*"))

     # lazyload all Address relationships
     query(User).options(defaultload(User.addresses).lazyload("*"))

     # undefer all Address columns
     query(User).options(defaultload(User.addresses).undefer("*"))

#1418(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1418

8.4.5.24 New ‘text()’ Capabilities
..................................

The text() construct gains new methods:

   * TextClause.bindparams() allows bound parameter types and
     values to be set flexibly:

          # setup values
          stmt = text("SELECT id, name FROM user "
                "WHERE name=:name AND timestamp=:timestamp").\
                bindparams(name="ed", timestamp=datetime(2012, 11, 10, 15, 12, 35))

          # setup types and/or values
          stmt = text("SELECT id, name FROM user "
                "WHERE name=:name AND timestamp=:timestamp").\
                bindparams(
                    bindparam("name", value="ed"),
                    bindparam("timestamp", type_=DateTime()
                ).bindparam(timestamp=datetime(2012, 11, 10, 15, 12, 35))

   * TextClause.columns() supersedes the ‘typemap’ option of
     text(), returning a new construct ‘TextAsFrom’:

          # turn a text() into an alias(), with a .c. collection:
          stmt = text("SELECT id, name FROM user").columns(id=Integer, name=String)
          stmt = stmt.alias()

          stmt = select([addresses]).select_from(
                        addresses.join(stmt), addresses.c.user_id == stmt.c.id)

          # or into a cte():
          stmt = text("SELECT id, name FROM user").columns(id=Integer, name=String)
          stmt = stmt.cte("x")

          stmt = select([addresses]).select_from(
                        addresses.join(stmt), addresses.c.user_id == stmt.c.id)

#2877(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2877

8.4.5.25 INSERT from SELECT
...........................

After literally years of pointless procrastination this relatively minor
syntactical feature has been added, and is also backported to 0.8.3, so
technically isn’t “new” in 0.9.  A select() construct or
other compatible construct can be passed to the new method
Insert.from_select() where it will be used to render an ‘INSERT ..
SELECT’ construct:

     >>> from sqlalchemy.sql import table, column
     >>> t1 = table('t1', column('a'), column('b'))
     >>> t2 = table('t2', column('x'), column('y'))
     >>> print(t1.insert().from_select(['a', 'b'], t2.select().where(t2.c.y == 5)))
     INSERT INTO t1 (a, b) SELECT t2.x, t2.y
     FROM t2
     WHERE t2.y = :y_1

The construct is smart enough to also accommodate ORM objects such as
classes and Query objects:

     s = Session()
     q = s.query(User.id, User.name).filter_by(name='ed')
     ins = insert(Address).from_select((Address.id, Address.email_address), q)

rendering:

     INSERT INTO addresses (id, email_address)
     SELECT users.id AS users_id, users.name AS users_name
     FROM users WHERE users.name = :name_1

#722(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/722

8.4.5.26 New FOR UPDATE support on ‘select()’, ‘Query()’
........................................................

An attempt is made to simplify the specification of the ‘FOR UPDATE’
clause on ‘SELECT’ statements made within Core and ORM, and support is
added for the ‘FOR UPDATE OF’ SQL supported by PostgreSQL and Oracle.

Using the core GenerativeSelect.with_for_update(), options
like ‘FOR SHARE’ and ‘NOWAIT’ can be specified individually, rather than
linking to arbitrary string codes:

     stmt = select([table]).with_for_update(read=True, nowait=True, of=table)

On Posgtresql the above statement might render like:

     SELECT table.a, table.b FROM table FOR SHARE OF table NOWAIT

The Query object gains a similar method
Query.with_for_update() which behaves in the same way.  This
method supersedes the existing ‘Query.with_lockmode()’ method, which
translated ‘FOR UPDATE’ clauses using a different system.  At the
moment, the “lockmode” string argument is still accepted by the
Session.refresh() method.

8.4.5.27 Floating Point String-Conversion Precision Configurable for Native Floating Point Types
................................................................................................

The conversion which SQLAlchemy does whenever a DBAPI returns a Python
floating point type which is to be converted into a Python ‘Decimal()’
necessarily involves an intermediary step which converts the floating
point value to a string.  The scale used for this string conversion was
previously hardcoded to 10, and is now configurable.  The setting is
available on both the Numeric as well as the Float
type, as well as all SQL- and dialect-specific descendant types,
using the parameter ‘decimal_return_scale’.  If the type supports a
‘.scale’ parameter, as is the case with Numeric and some
float types such as DOUBLE, the value of ‘.scale’ is used as
the default for ‘.decimal_return_scale’ if it is not otherwise
specified.  If both ‘.scale’ and ‘.decimal_return_scale’ are absent,
then the default of 10 takes place.  E.g.:

     from sqlalchemy.dialects.mysql import DOUBLE
     import decimal

     data = Table('data', metadata,
         Column('double_value',
                     mysql.DOUBLE(decimal_return_scale=12, asdecimal=True))
     )

     conn.execute(
         data.insert(),
         double_value=45.768392065789,
     )
     result = conn.scalar(select([data.c.double_value]))

     # previously, this would typically be Decimal("45.7683920658"),
     # e.g. trimmed to 10 decimal places

     # now we get 12, as requested, as MySQL can support this
     # much precision for DOUBLE
     assert result == decimal.Decimal("45.768392065789")

#2867(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2867

8.4.5.28 Column Bundles for ORM queries
.......................................

The Bundle allows for querying of sets of columns, which are
then grouped into one name under the tuple returned by the query.  The
initial purposes of Bundle are 1.  to allow “composite” ORM
columns to be returned as a single value in a column-based result set,
rather than expanding them out into individual columns and 2.  to allow
the creation of custom result-set constructs within the ORM, using
ad-hoc columns and return types, without involving the more heavyweight
mechanics of mapped classes.

See also
........

See Composite attributes are now returned as their object form when queried on a per-attribute basis.

See Column Bundles.

#2824(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2824

8.4.5.29 Server Side Version Counting
.....................................

The versioning feature of the ORM (now also documented at
Configuring a Version Counter) can now make use of server-side
version counting schemes, such as those produced by triggers or database
system columns, as well as conditional programmatic schemes outside of
the version_id_counter function itself.  By providing the value ‘False’
to the ‘version_id_generator’ parameter, the ORM will use the
already-set version identifier, or alternatively fetch the version
identifier from each row at the same time the INSERT or UPDATE is
emitted.  When using a server-generated version identifier, it is
strongly recommended that this feature be used only on a backend with
strong RETURNING support (PostgreSQL, SQL Server; Oracle also supports
RETURNING but the cx_oracle driver has only limited support), else the
additional SELECT statements will add significant performance overhead.
The example provided at Server Side Version Counters
illustrates the usage of the PostgreSQL ‘xmin’ system column in order to
integrate it with the ORM’s versioning feature.

See also
........

See Server Side Version Counters.

#2793(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2793

8.4.5.30 ‘include_backrefs=False’ option for ‘@validates’
.........................................................

The validates() function now accepts an option
‘include_backrefs=True’, which will bypass firing the validator for the
case where the event initiated from a backref:

     from sqlalchemy import Column, Integer, ForeignKey
     from sqlalchemy.orm import relationship, validates
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class A(Base):
         __tablename__ = 'a'

         id = Column(Integer, primary_key=True)
         bs = relationship("B", backref="a")

         @validates("bs")
         def validate_bs(self, key, item):
             print("A.bs validator")
             return item

     class B(Base):
         __tablename__ = 'b'

         id = Column(Integer, primary_key=True)
         a_id = Column(Integer, ForeignKey('a.id'))

         @validates("a", include_backrefs=False)
         def validate_a(self, key, item):
             print("B.a validator")
             return item

     a1 = A()
     a1.bs.append(B())  # prints only "A.bs validator"

#1535(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1535

8.4.5.31 PostgreSQL JSON Type
.............................

The PostgreSQL dialect now features a JSON type to
complement the HSTORE type.

See also
........

See JSON.

#2581(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2581

8.4.5.32 Automap Extension
..........................

A new extension is added in `0.9.1' known as
sqlalchemy.ext.automap.  This is an `experimental' extension which
expands upon the functionality of Declarative as well as the
DeferredReflection class.  Essentially, the extension provides a
base class AutomapBase which automatically generates mapped
classes and relationships between them based on given table metadata.

The MetaData in use normally might be produced via
reflection, but there is no requirement that reflection is used.  The
most basic usage illustrates how sqlalchemy.ext.automap is
able to deliver mapped classes, including relationships, based on a
reflected schema:

     from sqlalchemy.ext.automap import automap_base
     from sqlalchemy.orm import Session
     from sqlalchemy import create_engine

     Base = automap_base()

     # engine, suppose it has two tables 'user' and 'address' set up
     engine = create_engine("sqlite:///mydatabase.db")

     # reflect the tables
     Base.prepare(engine, reflect=True)

     # mapped classes are now created with names matching that of the table
     # name.
     User = Base.classes.user
     Address = Base.classes.address

     session = Session(engine)

     # rudimentary relationships are produced
     session.add(Address(email_address="foo@bar.com", user=User(name="foo")))
     session.commit()

     # collection-based relationships are by default named "<classname>_collection"
     print(u1.address_collection)

Beyond that, the AutomapBase class is a declarative base,
and supports all the features that declarative does.  The “automapping”
feature can be used with an existing, explicitly declared schema to
generate relationships and missing classes only.  Naming schemes and
relationship-production routines can be dropped in using callable
functions.

It is hoped that the AutomapBase system provides a quick and
modernized solution to the problem that the very famous SQLSoup(1) also
tries to solve, that of generating a quick and rudimentary object model
from an existing database on the fly.  By addressing the issue strictly
at the mapper configuration level, and integrating fully with existing
Declarative class techniques, see AutomapBase seeks to provide a
well-integrated approach to the issue of expediently auto-generating
ad-hoc mappings.

See also
........

See Automap.

   ---------- Footnotes ----------

   (1) https://sqlsoup.readthedocs.io/en/latest/

8.4.5.33 Behavioral Improvements
................................

Improvements that should produce no compatibility issues except in
exceedingly rare and unusual hypothetical cases, but are good to be
aware of in case there are unexpected issues.

8.4.5.34 Many JOIN and LEFT OUTER JOIN expressions will no longer be wrapped in (SELECT * FROM ..) AS ANON_1
............................................................................................................

For many years, the SQLAlchemy ORM has been held back from being able to
nest a JOIN inside the right side of an existing JOIN (typically a LEFT
OUTER JOIN, as INNER JOINs could always be flattened):

     SELECT a.*, b.*, c.* FROM a LEFT OUTER JOIN (b JOIN c ON b.id = c.id) ON a.id

This was due to the fact that SQLite up until version `3.7.16' cannot
parse a statement of the above format:

     SQLite version 3.7.15.2 2013-01-09 11:53:05
     Enter ".help" for instructions
     Enter SQL statements terminated with a ";"
     sqlite> create table a(id integer);
     sqlite> create table b(id integer);
     sqlite> create table c(id integer);
     sqlite> select a.id, b.id, c.id from a left outer join (b join c on b.id=c.id) on b.id=a.id;
     Error: no such column: b.id

Right-outer-joins are of course another way to work around right-side
parenthesization; this would be significantly complicated and visually
unpleasant to implement, but fortunately SQLite doesn’t support RIGHT
OUTER JOIN either :):

     sqlite> select a.id, b.id, c.id from b join c on b.id=c.id
        ...> right outer join a on b.id=a.id;
     Error: RIGHT and FULL OUTER JOINs are not currently supported

Back in 2005, it wasn’t clear if other databases had trouble with this
form, but today it seems clear every database tested except SQLite now
supports it (Oracle 8, a very old database, doesn’t support the JOIN
keyword at all, but SQLAlchemy has always had a simple rewriting scheme
in place for Oracle’s syntax).  To make matters worse, SQLAlchemy’s
usual workaround of applying a SELECT often degrades performance on
platforms like PostgreSQL and MySQL:

     SELECT a.*, anon_1.* FROM a LEFT OUTER JOIN (
                     SELECT b.id AS b_id, c.id AS c_id
                     FROM b JOIN c ON b.id = c.id
                 ) AS anon_1 ON a.id=anon_1.b_id

A JOIN like the above form is commonplace when working with joined-table
inheritance structures; any time Query.join() is used to
join from some parent to a joined-table subclass, or when
joinedload() is used similarly, SQLAlchemy’s ORM would always make
sure a nested JOIN was never rendered, lest the query wouldn’t be able
to run on SQLite.  Even though the Core has always supported a JOIN of
the more compact form, the ORM had to avoid it.

An additional issue would arise when producing joins across many-to-many
relationships where special criteria is present in the ON clause.
Consider an eager load join like the following:

     session.query(Order).outerjoin(Order.items)

Assuming a many-to-many from ‘Order’ to ‘Item’ which actually refers to
a subclass like ‘Subitem’, the SQL for the above would look like:

     SELECT order.id, order.name
     FROM order LEFT OUTER JOIN order_item ON order.id = order_item.order_id
     LEFT OUTER JOIN item ON order_item.item_id = item.id AND item.type = 'subitem'

What’s wrong with the above query?  Basically, that it will load many
‘order’ / ‘order_item’ rows where the criteria of ‘item.type ==
'subitem'’ is not true.

As of SQLAlchemy 0.9, an entirely new approach has been taken.  The ORM
no longer worries about nesting JOINs in the right side of an enclosing
JOIN, and it now will render these as often as possible while still
returning the correct results.  When the SQL statement is passed to be
compiled, the `dialect compiler' will `rewrite the join' to suit the
target backend, if that backend is known to not support a right-nested
JOIN (which currently is only SQLite - if other backends have this issue
please let us know!).

So a regular ‘query(Parent).join(Subclass)’ will now usually produce a
simpler expression:

     SELECT parent.id AS parent_id
     FROM parent JOIN (
             base_table JOIN subclass_table
             ON base_table.id = subclass_table.id) ON parent.id = base_table.parent_id

Joined eager loads like
‘query(Parent).options(joinedload(Parent.subclasses))’ will alias the
individual tables instead of wrapping in an ‘ANON_1’:

     SELECT parent.*, base_table_1.*, subclass_table_1.* FROM parent
         LEFT OUTER JOIN (
             base_table AS base_table_1 JOIN subclass_table AS subclass_table_1
             ON base_table_1.id = subclass_table_1.id)
             ON parent.id = base_table_1.parent_id

Many-to-many joins and eagerloads will right nest the “secondary” and
“right” tables:

     SELECT order.id, order.name
     FROM order LEFT OUTER JOIN
     (order_item JOIN item ON order_item.item_id = item.id AND item.type = 'subitem')
     ON order_item.order_id = order.id

All of these joins, when rendered with a Select statement
that specifically specifies ‘use_labels=True’, which is true for all the
queries the ORM emits, are candidates for “join rewriting”, which is the
process of rewriting all those right-nested joins into nested SELECT
statements, while maintaining the identical labeling used by the
Select.  So SQLite, the one database that won’t support this very
common SQL syntax even in 2013, shoulders the extra complexity itself,
with the above queries rewritten as:

     -- sqlite only!
     SELECT parent.id AS parent_id
         FROM parent JOIN (
             SELECT base_table.id AS base_table_id,
                     base_table.parent_id AS base_table_parent_id,
                     subclass_table.id AS subclass_table_id
             FROM base_table JOIN subclass_table ON base_table.id = subclass_table.id
         ) AS anon_1 ON parent.id = anon_1.base_table_parent_id

     -- sqlite only!
     SELECT parent.id AS parent_id, anon_1.subclass_table_1_id AS subclass_table_1_id,
             anon_1.base_table_1_id AS base_table_1_id,
             anon_1.base_table_1_parent_id AS base_table_1_parent_id
     FROM parent LEFT OUTER JOIN (
         SELECT base_table_1.id AS base_table_1_id,
             base_table_1.parent_id AS base_table_1_parent_id,
             subclass_table_1.id AS subclass_table_1_id
         FROM base_table AS base_table_1
         JOIN subclass_table AS subclass_table_1 ON base_table_1.id = subclass_table_1.id
     ) AS anon_1 ON parent.id = anon_1.base_table_1_parent_id

     -- sqlite only!
     SELECT "order".id AS order_id
     FROM "order" LEFT OUTER JOIN (
             SELECT order_item_1.order_id AS order_item_1_order_id,
                 order_item_1.item_id AS order_item_1_item_id,
                 item.id AS item_id, item.type AS item_type
     FROM order_item AS order_item_1
         JOIN item ON item.id = order_item_1.item_id AND item.type IN (?)
     ) AS anon_1 ON "order".id = anon_1.order_item_1_order_id

     Note: As of SQLAlchemy 1.1, the workarounds present in this feature
     for SQLite will automatically disable themselves when SQLite
     version `3.7.16' or greater is detected, as SQLite has repaired
     support for right-nested joins.

The Join.alias(), aliased() and
with_polymorphic() functions now support a new argument,
‘flat=True’, which is used to construct aliases of joined-table entities
without embedding into a SELECT. This flag is not on by default, to help
with backwards compatibility - but now a “polymorphic” selectable can be
joined as a target without any subqueries generated:

     employee_alias = with_polymorphic(Person, [Engineer, Manager], flat=True)

     session.query(Company).join(
                         Company.employees.of_type(employee_alias)
                     ).filter(
                         or_(
                             Engineer.primary_language == 'python',
                             Manager.manager_name == 'dilbert'
                         )
                     )

Generates (everywhere except SQLite):

     SELECT companies.company_id AS companies_company_id, companies.name AS companies_name
     FROM companies JOIN (
         people AS people_1
         LEFT OUTER JOIN engineers AS engineers_1 ON people_1.person_id = engineers_1.person_id
         LEFT OUTER JOIN managers AS managers_1 ON people_1.person_id = managers_1.person_id
     ) ON companies.company_id = people_1.company_id
     WHERE engineers.primary_language = %(primary_language_1)s
         OR managers.manager_name = %(manager_name_1)s

#2369(1) #2587(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2369

   (2) http://www.sqlalchemy.org/trac/ticket/2587

8.4.5.35 Right-nested inner joins available in joined eager loads
.................................................................

As of version 0.9.4, the above mentioned right-nested joining can be
enabled in the case of a joined eager load where an “outer” join is
linked to an “inner” on the right side.

Normally, a joined eager load chain like the following:

     query(User).options(joinedload("orders", innerjoin=False).joinedload("items", innerjoin=True))

Would not produce an inner join; because of the LEFT OUTER JOIN from
user->order, joined eager loading could not use an INNER join from
order->items without changing the user rows that are returned, and would
instead ignore the “chained” ‘innerjoin=True’ directive.  How 0.9.0
should have delivered this would be that instead of:

     FROM users LEFT OUTER JOIN orders ON <onclause> LEFT OUTER JOIN items ON <onclause>

the new “right-nested joins are OK” logic would kick in, and we’d get:

     FROM users LEFT OUTER JOIN (orders JOIN items ON <onclause>) ON <onclause>

Since we missed the boat on that, to avoid further regressions we’ve
added the above functionality by specifying the string ‘"nested"’ to
joinedload.innerjoin:

     query(User).options(joinedload("orders", innerjoin=False).joinedload("items", innerjoin="nested"))

This feature is new in 0.9.4.

#2976(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2976

8.4.5.36 ORM can efficiently fetch just-generated INSERT/UPDATE defaults using RETURNING
........................................................................................

The Mapper has long supported an undocumented flag known as
‘eager_defaults=True’.  The effect of this flag is that when an INSERT
or UPDATE proceeds, and the row is known to have server-generated
default values, a SELECT would immediately follow it in order to
“eagerly” load those new values.  Normally, the server-generated columns
are marked as “expired” on the object, so that no overhead is incurred
unless the application actually accesses these columns soon after the
flush.  The ‘eager_defaults’ flag was therefore not of much use as it
could only decrease performance, and was present only to support exotic
event schemes where users needed default values to be available
immediately within the flush process.

In 0.9, as a result of the version id enhancements, ‘eager_defaults’ can
now emit a RETURNING clause for these values, so on a backend with
strong RETURNING support in particular PostgreSQL, the ORM can fetch
newly generated default and SQL expression values inline with the INSERT
or UPDATE. ‘eager_defaults’, when enabled, makes use of RETURNING
automatically when the target backend and Table supports
“implicit returning”.

8.4.5.37 Subquery Eager Loading will apply DISTINCT to the innermost SELECT for some queries
............................................................................................

In an effort to reduce the number of duplicate rows that can be
generated by subquery eager loading when a many-to-one relationship is
involved, a DISTINCT keyword will be applied to the innermost SELECT
when the join is targeting columns that do not comprise the primary key,
as in when loading along a many to one.

That is, when subquery loading on a many-to-one from A->B:

     SELECT b.id AS b_id, b.name AS b_name, anon_1.b_id AS a_b_id
     FROM (SELECT DISTINCT a_b_id FROM a) AS anon_1
     JOIN b ON b.id = anon_1.a_b_id

Since ‘a.b_id’ is a non-distinct foreign key, DISTINCT is applied so
that redundant ‘a.b_id’ are eliminated.  The behavior can be turned on
or off unconditionally for a particular relationship() using
the flag ‘distinct_target_key’, setting the value to ‘True’ for
unconditionally on, ‘False’ for unconditionally off, and ‘None’ for the
feature to take effect when the target SELECT is against columns that do
not comprise a full primary key.  In 0.9, ‘None’ is the default.

The option is also backported to 0.8 where the ‘distinct_target_key’
option defaults to ‘False’.

While the feature here is designed to help performance by eliminating
duplicate rows, the ‘DISTINCT’ keyword in SQL itself can have a negative
performance impact.  If columns in the SELECT are not indexed,
‘DISTINCT’ will likely perform an ‘ORDER BY’ on the rowset which can be
expensive.  By keeping the feature limited just to foreign keys which
are hopefully indexed in any case, it’s expected that the new defaults
are reasonable.

The feature also does not eliminate every possible dupe-row scenario; if
a many-to-one is present elsewhere in the chain of joins, dupe rows may
still be present.

#2836(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2836

8.4.5.38 Backref handlers can now propagate more than one level deep
....................................................................

The mechanism by which attribute events pass along their “initiator”,
that is the object associated with the start of the event, has been
changed; instead of a ‘AttributeImpl’ being passed, a new object ‘Event’
is passed instead; this object refers to the ‘AttributeImpl’ as well as
to an “operation token”, representing if the operation is an append,
remove, or replace operation.

The attribute event system no longer looks at this “initiator” object in
order to halt a recursive series of attribute events.  Instead, the
system of preventing endless recursion due to mutually-dependent backref
handlers has been moved to the ORM backref event handlers specifically,
which now take over the role of ensuring that a chain of
mutually-dependent events (such as append to collection A.bs, set
many-to-one attribute B.a in response) doesn’t go into an endless
recursion stream.  The rationale here is that the backref system, given
more detail and control over event propagation, can finally allow
operations more than one level deep to occur; the typical scenario is
when a collection append results in a many-to-one replacement operation,
which in turn should cause the item to be removed from a previous
collection:

     class Parent(Base):
         __tablename__ = 'parent'

         id = Column(Integer, primary_key=True)
         children = relationship("Child", backref="parent")

     class Child(Base):
         __tablename__ = 'child'

         id = Column(Integer, primary_key=True)
         parent_id = Column(ForeignKey('parent.id'))

     p1 = Parent()
     p2 = Parent()
     c1 = Child()

     p1.children.append(c1)

     assert c1.parent is p1  # backref event establishes c1.parent as p1

     p2.children.append(c1)

     assert c1.parent is p2  # backref event establishes c1.parent as p2
     assert c1 not in p1.children  # second backref event removes c1 from p1.children

Above, prior to this change, the ‘c1’ object would still have been
present in ‘p1.children’, even though it is also present in
‘p2.children’ at the same time; the backref handlers would have stopped
at replacing ‘c1.parent’ with ‘p2’ instead of ‘p1’.  In 0.9, using the
more detailed ‘Event’ object as well as letting the backref handlers
make more detailed decisions about these objects, the propagation can
continue onto removing ‘c1’ from ‘p1.children’ while maintaining a check
against the propagation from going into an endless recursive loop.

End-user code which a.  makes use of the AttributeEvents.set(),
see AttributeEvents.append(), or
AttributeEvents.remove() events, and b.  initiates further
attribute modification operations as a result of these events may need
to be modified to prevent recursive loops, as the attribute system no
longer stops a chain of events from propagating endlessly in the absence
of the backref event handlers.  Additionally, code which depends upon
the value of the ‘initiator’ will need to be adjusted to the new API,
and furthermore must be ready for the value of ‘initiator’ to change
from its original value within a string of backref-initiated events, as
the backref handlers may now swap in a new ‘initiator’ value for some
operations.

#2789(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2789

8.4.5.39 The typing system now handles the task of rendering “literal bind” values
..................................................................................

A new method is added to TypeEngine.
TypeEngine.literal_processor() as well as
TypeDecorator.process_literal_param() for TypeDecorator
which take on the task of rendering so-called “inline literal
parameters” - parameters that normally render as “bound” values, but are
instead being rendered inline into the SQL statement due to the compiler
configuration.  This feature is used when generating DDL for constructs
such as CheckConstraint, as well as by Alembic when using
constructs such as ‘op.inline_literal()’.  Previously, a simple
“isinstance” check checked for a few basic types, and the “bind
processor” was used unconditionally, leading to such issues as strings
being encoded into utf-8 prematurely.

Custom types written with TypeDecorator should continue to
work in “inline literal” scenarios, as the
TypeDecorator.process_literal_param() falls back to
TypeDecorator.process_bind_param() by default, as these methods
usually handle a data manipulation, not as much how the data is
presented to the database.  TypeDecorator.process_literal_param()
can be specified to specifically produce a string representing how
a value should be rendered into an inline DDL statement.

#2838(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2838

8.4.5.40 Schema identifiers now carry along their own quoting information
.........................................................................

This change simplifies the Core’s usage of so-called “quote” flags, such
as the ‘quote’ flag passed to Table and Column.
The flag is now internalized within the string name itself, which is now
represented as an instance of quoted_name, a string subclass.
The IdentifierPreparer now relies solely on the quoting
preferences reported by the quoted_name object rather than
checking for any explicit ‘quote’ flags in most cases.  The issue
resolved here includes that various case-sensitive methods such as
Engine.has_table() as well as similar methods within dialects now
function with explicitly quoted names, without the need to complicate or
introduce backwards-incompatible changes to those APIs (many of which
are 3rd party) with the details of quoting flags - in particular, a
wider range of identifiers now function correctly with the so-called
“uppercase” backends like Oracle, Firebird, and DB2 (backends that store
and report upon table and column names using all uppercase for case
insensitive names).

The quoted_name object is used internally as needed; however
if other keywords require fixed quoting preferences, the class is
available publicly.

#2812(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2812

8.4.5.41 Improved rendering of Boolean constants, NULL constants, conjunctions
..............................................................................

New capabilities have been added to the true() and
false() constants, in particular in conjunction with and_()
and or_() functions as well as the behavior of the
WHERE/HAVING clauses in conjunction with these types, boolean types
overall, and the null() constant.

Starting with a table such as this:

     from sqlalchemy import Table, Boolean, Integer, Column, MetaData

     t1 = Table('t', MetaData(), Column('x', Boolean()), Column('y', Integer))

A select construct will now render the boolean column as a binary
expression on backends that don’t feature ‘true’/‘false’ constant
behavior:

     >>> from sqlalchemy import select, and_, false, true
     >>> from sqlalchemy.dialects import mysql, postgresql

     >>> print(select([t1]).where(t1.c.x).compile(dialect=mysql.dialect()))
     SELECT t.x, t.y  FROM t WHERE t.x = 1

The and_() and or_() constructs will now exhibit
quasi “short circuit” behavior, that is truncating a rendered
expression, when a true() or false() constant is
present:

     >>> print(select([t1]).where(and_(t1.c.y > 5, false())).compile(
     ...     dialect=postgresql.dialect()))
     SELECT t.x, t.y FROM t WHERE false

true() can be used as the base to build up an expression:

     >>> expr = true()
     >>> expr = expr & (t1.c.y > 5)
     >>> print(select([t1]).where(expr))
     SELECT t.x, t.y FROM t WHERE t.y > :y_1

The boolean constants true() and false()
themselves render as ‘0 = 1’ and ‘1 = 1’ for a backend with no boolean
constants:

     >>> print(select([t1]).where(and_(t1.c.y > 5, false())).compile(
     ...     dialect=mysql.dialect()))
     SELECT t.x, t.y FROM t WHERE 0 = 1

Interpretation of ‘None’, while not particularly valid SQL, is at least
now consistent:

     >>> print(select([t1.c.x]).where(None))
     SELECT t.x FROM t WHERE NULL

     >>> print(select([t1.c.x]).where(None).where(None))
     SELECT t.x FROM t WHERE NULL AND NULL

     >>> print(select([t1.c.x]).where(and_(None, None)))
     SELECT t.x FROM t WHERE NULL AND NULL

#2804(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2804

8.4.5.42 Label constructs can now render as their name alone in an ORDER BY
...........................................................................

For the case where a Label is used in both the columns
clause as well as the ORDER BY clause of a SELECT, the label will render
as just its name in the ORDER BY clause, assuming the underlying dialect
reports support of this feature.

E.g.  an example like:

     from sqlalchemy.sql import table, column, select, func

     t = table('t', column('c1'), column('c2'))
     expr = (func.foo(t.c.c1) + t.c.c2).label("expr")

     stmt = select([expr]).order_by(expr)

     print(stmt)

Prior to 0.9 would render as:

     SELECT foo(t.c1) + t.c2 AS expr
     FROM t ORDER BY foo(t.c1) + t.c2

And now renders as:

     SELECT foo(t.c1) + t.c2 AS expr
     FROM t ORDER BY expr

The ORDER BY only renders the label if the label isn’t further embedded
into an expression within the ORDER BY, other than a simple ‘ASC’ or
‘DESC’.

The above format works on all databases tested, but might have
compatibility issues with older database versions (MySQL 4?  Oracle 8?
etc.).  Based on user reports we can add rules that will disable the
feature based on database version detection.

#1068(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1068

8.4.5.43 ‘RowProxy’ now has tuple-sorting behavior
..................................................

The ‘RowProxy’ object acts much like a tuple, but up until now would not
sort as a tuple if a list of them were sorted using ‘sorted()’.  The
‘__eq__()’ method now compares both sides as a tuple and also an
‘__lt__()’ method has been added:

     users.insert().execute(
             dict(user_id=1, user_name='foo'),
             dict(user_id=2, user_name='bar'),
             dict(user_id=3, user_name='def'),
         )

     rows = users.select().order_by(users.c.user_name).execute().fetchall()

     eq_(rows, [(2, 'bar'), (3, 'def'), (1, 'foo')])

     eq_(sorted(rows), [(1, 'foo'), (2, 'bar'), (3, 'def')])

#2848(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2848

8.4.5.44 A bindparam() construct with no type gets upgraded via copy when a type is available
.............................................................................................

The logic which “upgrades” a bindparam() construct to take on
the type of the enclosing expression has been improved in two ways.
First, the bindparam() object is `copied' before the new type
is assigned, so that the given bindparam() is not mutated in
place.  Secondly, this same operation occurs when an Insert
or Update construct is compiled, regarding the “values” that
were set in the statement via the ValuesBase.values()
method.

If given an untyped bindparam():

     bp = bindparam("some_col")

If we use this parameter as follows:

     expr = mytable.c.col == bp

The type for ‘bp’ remains as ‘NullType’, however if ‘mytable.c.col’ is
of type ‘String’, then ‘expr.right’, that is the right side of the
binary expression, will take on the ‘String’ type.  Previously, ‘bp’
itself would have been changed in place to have ‘String’ as its type.

Similarly, this operation occurs in an Insert or
Update:

     stmt = mytable.update().values(col=bp)

Above, ‘bp’ remains unchanged, but the ‘String’ type will be used when
the statement is executed, which we can see by examining the ‘binds’
dictionary:

     >>> compiled = stmt.compile()
     >>> compiled.binds['some_col'].type
     String

The feature allows custom types to take their expected effect within
INSERT/UPDATE statements without needing to explicitly specify those
types within every bindparam() expression.

The potentially backwards-compatible changes involve two unlikely
scenarios.  Since the bound parameter is `cloned', users should not be
relying upon making in-place changes to a bindparam()
construct once created.  Additionally, code which uses
bindparam() within an Insert or Update
statement which is relying on the fact that the bindparam()
is not typed according to the column being assigned towards will no
longer function in that way.

#2850(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2850

8.4.5.45 Columns can reliably get their type from a column referred to via ForeignKey
.....................................................................................

There’s a long standing behavior which says that a Column can
be declared without a type, as long as that Column is
referred to by a ForeignKeyConstraint, and the type from the
referenced column will be copied into this one.  The problem has been
that this feature never worked very well and wasn’t maintained.  The
core issue was that the ForeignKey object doesn’t know what
target Column it refers to until it is asked, typically the
first time the foreign key is used to construct a Join.  So
until that time, the parent Column would not have a type, or
more specifically, it would have a default type of NullType.

While it’s taken a long time, the work to reorganize the initialization
of ForeignKey objects has been completed such that this
feature can finally work acceptably.  At the core of the change is that
the ForeignKey.column attribute no longer lazily
initializes the location of the target Column; the issue with
this system was that the owning Column would be stuck with
NullType as its type until the ForeignKey
happened to be used.

In the new version, the ForeignKey coordinates with the
eventual Column it will refer to using internal attachment
events, so that the moment the referencing Column is
associated with the MetaData, all ForeignKey
objects that refer to it will be sent a message that they need to
initialize their parent column.  This system is more complicated but
works more solidly; as a bonus, there are now tests in place for a wide
variety of Column. / see ForeignKey configuration
scenarios and error messages have been improved to be very specific to
no less than seven different error conditions.

Scenarios which now work correctly include:

  1. The type on a Column is immediately present as soon as
     the target Column becomes associated with the same
     MetaData; this works no matter which side is configured first:

          >>> from sqlalchemy import Table, MetaData, Column, Integer, ForeignKey
          >>> metadata = MetaData()
          >>> t2 = Table('t2', metadata, Column('t1id', ForeignKey('t1.id')))
          >>> t2.c.t1id.type
          NullType()
          >>> t1 = Table('t1', metadata, Column('id', Integer, primary_key=True))
          >>> t2.c.t1id.type
          Integer()

  2. The system now works with ForeignKeyConstraint as well:

          >>> from sqlalchemy import Table, MetaData, Column, Integer, ForeignKeyConstraint
          >>> metadata = MetaData()
          >>> t2 = Table('t2', metadata,
          ...     Column('t1a'), Column('t1b'),
          ...     ForeignKeyConstraint(['t1a', 't1b'], ['t1.a', 't1.b']))
          >>> t2.c.t1a.type
          NullType()
          >>> t2.c.t1b.type
          NullType()
          >>> t1 = Table('t1', metadata,
          ...     Column('a', Integer, primary_key=True),
          ...     Column('b', Integer, primary_key=True))
          >>> t2.c.t1a.type
          Integer()
          >>> t2.c.t1b.type
          Integer()

  3. It even works for “multiple hops” - that is, a ForeignKey
     that refers to a Column that refers to another
     Column:

          >>> from sqlalchemy import Table, MetaData, Column, Integer, ForeignKey
          >>> metadata = MetaData()
          >>> t2 = Table('t2', metadata, Column('t1id', ForeignKey('t1.id')))
          >>> t3 = Table('t3', metadata, Column('t2t1id', ForeignKey('t2.t1id')))
          >>> t2.c.t1id.type
          NullType()
          >>> t3.c.t2t1id.type
          NullType()
          >>> t1 = Table('t1', metadata, Column('id', Integer, primary_key=True))
          >>> t2.c.t1id.type
          Integer()
          >>> t3.c.t2t1id.type
          Integer()

#1765(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1765

8.4.5.46 Dialect Changes
........................

8.4.5.47 Firebird ‘fdb’ is now the default Firebird dialect.
............................................................

The ‘fdb’ dialect is now used if an engine is created without a dialect
specifier, i.e.  ‘firebird://’.  ‘fdb’ is a ‘kinterbasdb’ compatible
DBAPI which per the Firebird project is now their official Python
driver.

#2504(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2504

8.4.5.48 Firebird ‘fdb’ and ‘kinterbasdb’ set ‘retaining=False’ by default
..........................................................................

Both the ‘fdb’ and ‘kinterbasdb’ DBAPIs support a flag ‘retaining=True’
which can be passed to the ‘commit()’ and ‘rollback()’ methods of its
connection.  The documented rationale for this flag is so that the DBAPI
can re-use internal transaction state for subsequent transactions, for
the purposes of improving performance.  However, newer documentation
refers to analyses of Firebird’s “garbage collection” which expresses
that this flag can have a negative effect on the database’s ability to
process cleanup tasks, and has been reported as `lowering' performance
as a result.

It’s not clear how this flag is actually usable given this information,
and as it appears to be only a performance enhancing feature, it now
defaults to ‘False’.  The value can be controlled by passing the flag
‘retaining=True’ to the create_engine() call.  This is a new
flag which is added as of 0.8.2, so applications on 0.8.2 can begin
setting this to ‘True’ or ‘False’ as desired.

See also
........

See sqlalchemy.dialects.firebird.fdb.

See sqlalchemy.dialects.firebird.kinterbasdb.

‘http://pythonhosted.org/fdb/usage-guide.html#retaining-transactions’ -
information on the “retaining” flag.

#2763(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2763

8.4.6 What’s New in SQLAlchemy 0.8?
-----------------------------------

     About this Document: This document describes changes between
     SQLAlchemy version 0.7, undergoing maintenance releases as of
     October, 2012, and SQLAlchemy version 0.8, which is expected for
     release in early 2013.

     Document date: October 25, 2012 Updated: March 9, 2013

8.4.6.1 Introduction
....................

This guide introduces what’s new in SQLAlchemy version 0.8, and also
documents changes which affect users migrating their applications from
the 0.7 series of SQLAlchemy to 0.8.

SQLAlchemy releases are closing in on 1.0, and each new version since
0.5 features fewer major usage changes.  Most applications that are
settled into modern 0.7 patterns should be movable to 0.8 with no
changes.  Applications that use 0.6 and even 0.5 patterns should be
directly migratable to 0.8 as well, though larger applications may want
to test with each interim version.

8.4.6.2 Platform Support
........................

8.4.6.3 Targeting Python 2.5 and Up Now
.......................................

SQLAlchemy 0.8 will target Python 2.5 and forward; compatibility for
Python 2.4 is being dropped.

The internals will be able to make usage of Python ternaries (that is,
‘x if y else z’) which will improve things versus the usage of ‘y and x
or z’, which naturally has been the source of some bugs, as well as
context managers (that is, ‘with:’) and perhaps in some cases
‘try:/except:/else:’ blocks which will help with code readability.

SQLAlchemy will eventually drop 2.5 support as well - when 2.6 is
reached as the baseline, SQLAlchemy will move to use 2.6/3.3 in-place
compatibility, removing the usage of the ‘2to3’ tool and maintaining a
source base that works with Python 2 and 3 at the same time.

8.4.6.4 New ORM Features
........................

8.4.6.5 Rewritten ‘relationship()’ mechanics
............................................

0.8 features a much improved and capable system regarding how
relationship() determines how to join between two entities.  The
new system includes these features:

   * The ‘primaryjoin’ argument is `no longer needed' when constructing
     a relationship() against a class that has multiple
     foreign key paths to the target.  Only the ‘foreign_keys’ argument
     is needed to specify those columns which should be included:

          class Parent(Base):
              __tablename__ = 'parent'
              id = Column(Integer, primary_key=True)
              child_id_one = Column(Integer, ForeignKey('child.id'))
              child_id_two = Column(Integer, ForeignKey('child.id'))

              child_one = relationship("Child", foreign_keys=child_id_one)
              child_two = relationship("Child", foreign_keys=child_id_two)

          class Child(Base):
              __tablename__ = 'child'
              id = Column(Integer, primary_key=True)

   * relationships against self-referential, composite foreign keys
     where `a column points to itself' are now supported.  The canonical
     case is as follows:

          class Folder(Base):
              __tablename__ = 'folder'
              __table_args__ = (
                ForeignKeyConstraint(
                    ['account_id', 'parent_id'],
                    ['folder.account_id', 'folder.folder_id']),
              )

              account_id = Column(Integer, primary_key=True)
              folder_id = Column(Integer, primary_key=True)
              parent_id = Column(Integer)
              name = Column(String)

              parent_folder = relationship("Folder",
                                  backref="child_folders",
                                  remote_side=[account_id, folder_id]
                            )

     Above, the ‘Folder’ refers to its parent ‘Folder’ joining from
     ‘account_id’ to itself, and ‘parent_id’ to ‘folder_id’.  When
     SQLAlchemy constructs an auto- join, no longer can it assume all
     columns on the “remote” side are aliased, and all columns on the
     “local” side are not - the ‘account_id’ column is `on both sides'.
     So the internal relationship mechanics were totally rewritten to
     support an entirely different system whereby two copies of
     ‘account_id’ are generated, each containing different `annotations'
     to determine their role within the statement.  Note the join
     condition within a basic eager load:

          SELECT
              folder.account_id AS folder_account_id,
              folder.folder_id AS folder_folder_id,
              folder.parent_id AS folder_parent_id,
              folder.name AS folder_name,
              folder_1.account_id AS folder_1_account_id,
              folder_1.folder_id AS folder_1_folder_id,
              folder_1.parent_id AS folder_1_parent_id,
              folder_1.name AS folder_1_name
          FROM folder
              LEFT OUTER JOIN folder AS folder_1
              ON
                  folder_1.account_id = folder.account_id
                  AND folder.folder_id = folder_1.parent_id

          WHERE folder.folder_id = ? AND folder.account_id = ?

   * Previously difficult custom join conditions, like those involving
     functions and/or CASTing of types, will now function as expected in
     most cases:

          class HostEntry(Base):
              __tablename__ = 'host_entry'

              id = Column(Integer, primary_key=True)
              ip_address = Column(INET)
              content = Column(String(50))

              # relationship() using explicit foreign_keys, remote_side
              parent_host = relationship("HostEntry",
                                  primaryjoin=ip_address == cast(content, INET),
                                  foreign_keys=content,
                                  remote_side=ip_address
                              )

     The new relationship() mechanics make use of a
     SQLAlchemy concept known as annotations.  These annotations are
     also available to application code explicitly via the
     foreign() and remote() functions, either as a
     means to improve readability for advanced configurations or to
     directly inject an exact configuration, bypassing the usual
     join-inspection heuristics:

          from sqlalchemy.orm import foreign, remote

          class HostEntry(Base):
              __tablename__ = 'host_entry'

              id = Column(Integer, primary_key=True)
              ip_address = Column(INET)
              content = Column(String(50))

              # relationship() using explicit foreign() and remote() annotations
              # in lieu of separate arguments
              parent_host = relationship("HostEntry",
                                  primaryjoin=remote(ip_address) == \
                                          cast(foreign(content), INET),
                              )

See also
........

See Configuring how Relationship Joins. - a newly revised section
on relationship() detailing the latest techniques for
customizing related attributes and collection access.

#1401(1) #610(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1401

   (2) http://www.sqlalchemy.org/trac/ticket/610

8.4.6.6 New Class/Object Inspection System
..........................................

Lots of SQLAlchemy users are writing systems that require the ability to
inspect the attributes of a mapped class, including being able to get at
the primary key columns, object relationships, plain attributes, and so
forth, typically for the purpose of building data-marshalling systems,
like JSON/XML conversion schemes and of course form libraries galore.

Originally, the Table and Column model were the
original inspection points, which have a well-documented system.  While
SQLAlchemy ORM models are also fully introspectable, this has never been
a fully stable and supported feature, and users tended to not have a
clear idea how to get at this information.

0.8 now provides a consistent, stable and fully documented API for this
purpose, including an inspection system which works on mapped classes,
instances, attributes, and other Core and ORM constructs.  The
entrypoint to this system is the core-level inspect()
function.  In most cases, the object being inspected is one already part
of SQLAlchemy’s system, such as Mapper, InstanceState,
see Inspector.  In some cases, new objects have been added
with the job of providing the inspection API in certain contexts, such
as AliasedInsp and AttributeState.

A walkthrough of some key capabilities follows:

     >>> class User(Base):
     ...     __tablename__ = 'user'
     ...     id = Column(Integer, primary_key=True)
     ...     name = Column(String)
     ...     name_syn = synonym(name)
     ...     addresses = relationship("Address")
     ...

     >>> # universal entry point is inspect()
     >>> b = inspect(User)

     >>> # b in this case is the Mapper
     >>> b
     <Mapper at 0x101521950; User>

     >>> # Column namespace
     >>> b.columns.id
     Column('id', Integer(), table=<user>, primary_key=True, nullable=False)

     >>> # mapper's perspective of the primary key
     >>> b.primary_key
     (Column('id', Integer(), table=<user>, primary_key=True, nullable=False),)

     >>> # MapperProperties available from .attrs
     >>> b.attrs.keys()
     ['name_syn', 'addresses', 'id', 'name']

     >>> # .column_attrs, .relationships, etc. filter this collection
     >>> b.column_attrs.keys()
     ['id', 'name']

     >>> list(b.relationships)
     [<sqlalchemy.orm.properties.RelationshipProperty object at 0x1015212d0>]

     >>> # they are also namespaces
     >>> b.column_attrs.id
     <sqlalchemy.orm.properties.ColumnProperty object at 0x101525090>

     >>> b.relationships.addresses
     <sqlalchemy.orm.properties.RelationshipProperty object at 0x1015212d0>

     >>> # point inspect() at a mapped, class level attribute,
     >>> # returns the attribute itself
     >>> b = inspect(User.addresses)
     >>> b
     <sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x101521fd0>

     >>> # From here we can get the mapper:
     >>> b.mapper
     <Mapper at 0x101525810; Address>

     >>> # the parent inspector, in this case a mapper
     >>> b.parent
     <Mapper at 0x101521950; User>

     >>> # an expression
     >>> print(b.expression)
     "user".id = address.user_id

     >>> # inspect works on instances
     >>> u1 = User(id=3, name='x')
     >>> b = inspect(u1)

     >>> # it returns the InstanceState
     >>> b
     <sqlalchemy.orm.state.InstanceState object at 0x10152bed0>

     >>> # similar attrs accessor refers to the
     >>> b.attrs.keys()
     ['id', 'name_syn', 'addresses', 'name']

     >>> # attribute interface - from attrs, you get a state object
     >>> b.attrs.id
     <sqlalchemy.orm.state.AttributeState object at 0x10152bf90>

     >>> # this object can give you, current value...
     >>> b.attrs.id.value
     3

     >>> # ... current history
     >>> b.attrs.id.history
     History(added=[3], unchanged=(), deleted=())

     >>> # InstanceState can also provide session state information
     >>> # lets assume the object is persistent
     >>> s = Session()
     >>> s.add(u1)
     >>> s.commit()

     >>> # now we can get primary key identity, always
     >>> # works in query.get()
     >>> b.identity
     (3,)

     >>> # the mapper level key
     >>> b.identity_key
     (<class '__main__.User'>, (3,))

     >>> # state within the session
     >>> b.persistent, b.transient, b.deleted, b.detached
     (True, False, False, False)

     >>> # owning session
     >>> b.session
     <sqlalchemy.orm.session.Session object at 0x101701150>

See also
........

See Runtime Inspection API.

#2208(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2208

8.4.6.7 New with_polymorphic() feature, can be used anywhere
............................................................

The Query.with_polymorphic() method allows the user to
specify which tables should be present when querying against a
joined-table entity.  Unfortunately the method is awkward and only
applies to the first entity in the list, and otherwise has awkward
behaviors both in usage as well as within the internals.  A new
enhancement to the aliased() construct has been added called
with_polymorphic() which allows any entity to be “aliased”
into a “polymorphic” version of itself, freely usable anywhere:

     from sqlalchemy.orm import with_polymorphic
     palias = with_polymorphic(Person, [Engineer, Manager])
     session.query(Company).\
                 join(palias, Company.employees).\
                 filter(or_(Engineer.language=='java', Manager.hair=='pointy'))

See also
........

See Using with_polymorphic. - newly updated documentation for
polymorphic loading control.

#2333(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2333

8.4.6.8 of_type() works with alias(), with_polymorphic(), any(), has(), joinedload(), subqueryload(), contains_eager()
......................................................................................................................

The PropComparator.of_type() method is used to specify a
specific subtype to use when constructing SQL expressions along a
relationship() that has a polymorphic mapping as its target.  This
method can now be used to target `any number' of target subtypes, by
combining it with the new with_polymorphic() function:

     # use eager loading in conjunction with with_polymorphic targets
     Job_P = with_polymorphic(Job, [SubJob, ExtraJob], aliased=True)
     q = s.query(DataContainer).\
                 join(DataContainer.jobs.of_type(Job_P)).\
                     options(contains_eager(DataContainer.jobs.of_type(Job_P)))

The method now works equally well in most places a regular relationship
attribute is accepted, including with loader functions like
joinedload(), subqueryload(), contains_eager(),
and comparison methods like PropComparator.any() and
PropComparator.has():

     # use eager loading in conjunction with with_polymorphic targets
     Job_P = with_polymorphic(Job, [SubJob, ExtraJob], aliased=True)
     q = s.query(DataContainer).\
                 join(DataContainer.jobs.of_type(Job_P)).\
                     options(contains_eager(DataContainer.jobs.of_type(Job_P)))

     # pass subclasses to eager loads (implicitly applies with_polymorphic)
     q = s.query(ParentThing).\
                     options(
                         joinedload_all(
                             ParentThing.container,
                             DataContainer.jobs.of_type(SubJob)
                     ))

     # control self-referential aliasing with any()/has()
     Job_A = aliased(Job)
     q = s.query(Job).join(DataContainer.jobs).\
                     filter(
                         DataContainer.jobs.of_type(Job_A).\
                             any(and_(Job_A.id < Job.id, Job_A.type=='fred')
                         )
                     )

See also
........

See Referring to specific subtypes on relationships.

#2438(1) #1106(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2438

   (2) http://www.sqlalchemy.org/trac/ticket/1106

8.4.6.9 Events Can Be Applied to Unmapped Superclasses
......................................................

Mapper and instance events can now be associated with an unmapped
superclass, where those events will be propagated to subclasses as those
subclasses are mapped.  The ‘propagate=True’ flag should be used.  This
feature allows events to be associated with a declarative base class:

     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     @event.listens_for("load", Base, propagate=True)
     def on_load(target, context):
         print("New instance loaded:", target)

     # on_load() will be applied to SomeClass
     class SomeClass(Base):
         __tablename__ = 'sometable'

         # ...

#2585(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2585

8.4.6.10 Declarative Distinguishes Between Modules/Packages
...........................................................

A key feature of Declarative is the ability to refer to other mapped
classes using their string name.  The registry of class names is now
sensitive to the owning module and package of a given class.  The
classes can be referred to via dotted name in expressions:

     class Snack(Base):
         # ...

         peanuts = relationship("nuts.Peanut",
                 primaryjoin="nuts.Peanut.snack_id == Snack.id")

The resolution allows that any full or partial disambiguating package
name can be used.  If the path to a particular class is still ambiguous,
an error is raised.

#2338(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2338

8.4.6.11 New DeferredReflection Feature in Declarative
......................................................

The “deferred reflection” example has been moved to a supported feature
within Declarative.  This feature allows the construction of declarative
mapped classes with only placeholder ‘Table’ metadata, until a
‘prepare()’ step is called, given an ‘Engine’ with which to reflect
fully all tables and establish actual mappings.  The system supports
overriding of columns, single and joined inheritance, as well as
distinct bases-per-engine.  A full declarative configuration can now be
created against an existing table that is assembled upon engine creation
time in one step:

     class ReflectedOne(DeferredReflection, Base):
         __abstract__ = True

     class ReflectedTwo(DeferredReflection, Base):
         __abstract__ = True

     class MyClass(ReflectedOne):
         __tablename__ = 'mytable'

     class MyOtherClass(ReflectedOne):
         __tablename__ = 'myothertable'

     class YetAnotherClass(ReflectedTwo):
         __tablename__ = 'yetanothertable'

     ReflectedOne.prepare(engine_one)
     ReflectedTwo.prepare(engine_two)

See also
........

See DeferredReflection.

#2485(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2485

8.4.6.12 ORM Classes Now Accepted by Core Constructs
....................................................

While the SQL expressions used with Query.filter(), such as
‘User.id == 5’, have always been compatible for use with core constructs
such as select(), the mapped class itself would not be
recognized when passed to select(),
Select.select_from(), or Select.correlate().  A new SQL
registration system allows a mapped class to be accepted as a FROM
clause within the core:

     from sqlalchemy import select

     stmt = select([User]).where(User.id == 5)

Above, the mapped ‘User’ class will expand into the Table to
which ‘User’ is mapped.

#2245(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2245

8.4.6.13 Query.update() supports UPDATE..FROM
.............................................

The new UPDATE..FROM mechanics work in query.update().  Below, we emit
an UPDATE against ‘SomeEntity’, adding a FROM clause (or equivalent,
depending on backend) against ‘SomeOtherEntity’:

     query(SomeEntity).\
         filter(SomeEntity.id==SomeOtherEntity.id).\
         filter(SomeOtherEntity.foo=='bar').\
         update({"data":"x"})

In particular, updates to joined-inheritance entities are supported,
provided the target of the UPDATE is local to the table being filtered
on, or if the parent and child tables are mixed, they are joined
explicitly in the query.  Below, given ‘Engineer’ as a joined subclass
of ‘Person’:

     query(Engineer).\
             filter(Person.id==Engineer.id).\
             filter(Person.name=='dilbert').\
             update({"engineer_data":"java"})

would produce:

     UPDATE engineer SET engineer_data='java' FROM person
     WHERE person.id=engineer.id AND person.name='dilbert'

#2365(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2365

8.4.6.14 rollback() will only roll back “dirty” objects from a begin_nested()
.............................................................................

A behavioral change that should improve efficiency for those users using
SAVEPOINT via ‘Session.begin_nested()’ - upon ‘rollback()’, only those
objects that were made dirty since the last flush will be expired, the
rest of the ‘Session’ remains intact.  This because a ROLLBACK to a
SAVEPOINT does not terminate the containing transaction’s isolation, so
no expiry is needed except for those changes that were not flushed in
the current transaction.

#2452(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2452

8.4.6.15 Caching Example now uses dogpile.cache
...............................................

The caching example now uses dogpile.cache(1).  Dogpile.cache is a
rewrite of the caching portion of Beaker, featuring vastly simpler and
faster operation, as well as support for distributed locking.

Note that the SQLAlchemy APIs used by the Dogpile example as well as the
previous Beaker example have changed slightly, in particular this change
is needed as illustrated in the Beaker example:

     --- examples/beaker_caching/caching_query.py
     +++ examples/beaker_caching/caching_query.py
     @@ -222,7 +222,8 @@

              """
              if query._current_path:
     -            mapper, key = query._current_path[-2:]
     +            mapper, prop = query._current_path[-2:]
     +            key = prop.key

                  for cls in mapper.class_.__mro__:
                      if (cls, key) in self._relationship_options:

See also
........

‘dogpile_caching’

#2589(2)

   ---------- Footnotes ----------

   (1) https://dogpilecache.readthedocs.io/

   (2) http://www.sqlalchemy.org/trac/ticket/2589

8.4.6.16 New Core Features
..........................

8.4.6.17 Fully extensible, type-level operator support in Core
..............................................................

The Core has to date never had any system of adding support for new SQL
operators to Column and other expression constructs, other than the
ColumnOperators.op() method which is “just enough” to make
things work.  There has also never been any system in place for Core
which allows the behavior of existing operators to be overridden.  Up
until now, the only way operators could be flexibly redefined was in the
ORM layer, using column_property() given a
‘comparator_factory’ argument.  Third party libraries like GeoAlchemy
therefore were forced to be ORM-centric and rely upon an array of hacks
to apply new operations as well as to get them to propagate correctly.

The new operator system in Core adds the one hook that’s been missing
all along, which is to associate new and overridden operators with
`types'.  Since after all, it’s not really a column, CAST operator, or
SQL function that really drives what kinds of operations are present,
it’s the `type' of the expression.  The implementation details are
minimal - only a few extra methods are added to the core
ColumnElement type so that it consults its TypeEngine
object for an optional set of operators.  New or revised operations can
be associated with any type, either via subclassing of an existing type,
by using TypeDecorator, or “globally across-the-board” by
attaching a new Comparator object to an existing type
class.

For example, to add logarithm support to Numeric types:

     from sqlalchemy.types import Numeric
     from sqlalchemy.sql import func

     class CustomNumeric(Numeric):
         class comparator_factory(Numeric.Comparator):
             def log(self, other):
                 return func.log(self.expr, other)

The new type is usable like any other type:

     data = Table('data', metadata,
               Column('id', Integer, primary_key=True),
               Column('x', CustomNumeric(10, 5)),
               Column('y', CustomNumeric(10, 5))
          )

     stmt = select([data.c.x.log(data.c.y)]).where(data.c.x.log(2) < value)
     print(conn.execute(stmt).fetchall())

New features which have come from this immediately include support for
PostgreSQL’s HSTORE type, as well as new operations associated with
PostgreSQL’s ARRAY type.  It also paves the way for existing types to
acquire lots more operators that are specific to those types, such as
more string, integer and date operators.

See also
........

See Redefining and Creating New Operators.

See HSTORE.

#2547(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2547

8.4.6.18 Multiple-VALUES support for Insert
...........................................

The Insert.values() method now supports a list of
dictionaries, which will render a multi-VALUES statement such as ‘VALUES
(<row1>), (<row2>), ...’.  This is only relevant to backends which
support this syntax, including PostgreSQL, SQLite, and MySQL. It is not
the same thing as the usual ‘executemany()’ style of INSERT which
remains unchanged:

     users.insert().values([
                         {"name": "some name"},
                         {"name": "some other name"},
                         {"name": "yet another name"},
                     ])

See also
........

See Insert.values().

#2623(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2623

8.4.6.19 Type Expressions
.........................

SQL expressions can now be associated with types.  Historically, see
TypeEngine has always allowed Python-side functions which receive
both bound parameters as well as result row values, passing them through
a Python side conversion function on the way to/back from the database.
The new feature allows similar functionality, except on the database
side:

     from sqlalchemy.types import String
     from sqlalchemy import func, Table, Column, MetaData

     class LowerString(String):
         def bind_expression(self, bindvalue):
             return func.lower(bindvalue)

         def column_expression(self, col):
             return func.lower(col)

     metadata = MetaData()
     test_table = Table(
             'test_table',
             metadata,
             Column('data', LowerString)
     )

Above, the ‘LowerString’ type defines a SQL expression that will be
emitted whenever the ‘test_table.c.data’ column is rendered in the
columns clause of a SELECT statement:

     >>> print(select([test_table]).where(test_table.c.data == 'HI'))
     SELECT lower(test_table.data) AS data
     FROM test_table
     WHERE test_table.data = lower(:data_1)

This feature is also used heavily by the new release of GeoAlchemy, to
embed PostGIS expressions inline in SQL based on type rules.

See also
........

See Applying SQL-level Bind/Result Processing.

#1534(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1534

8.4.6.20 Core Inspection System
...............................

The inspect() function introduced in New Class/Object Inspection System
also applies to the core.  Applied to an
Engine it produces an Inspector object:

     from sqlalchemy import inspect
     from sqlalchemy import create_engine

     engine = create_engine("postgresql://scott:tiger@localhost/test")
     insp = inspect(engine)
     print(insp.get_table_names())

It can also be applied to any ClauseElement, which returns
the ClauseElement itself, such as Table,
Column, Select, etc.  This allows it to work fluently
between Core and ORM constructs.

8.4.6.21 New Method ‘Select.correlate_except()’
...............................................

select() now has a method Select.correlate_except()
which specifies “correlate on all FROM clauses except those
specified”.  It can be used for mapping scenarios where a related
subquery should correlate normally, except against a particular target
selectable:

     class SnortEvent(Base):
         __tablename__ = "event"

         id = Column(Integer, primary_key=True)
         signature = Column(Integer, ForeignKey("signature.id"))

         signatures = relationship("Signature", lazy=False)

     class Signature(Base):
         __tablename__ = "signature"

         id = Column(Integer, primary_key=True)

         sig_count = column_property(
                         select([func.count('*')]).\
                             where(SnortEvent.signature == id).
                             correlate_except(SnortEvent)
                     )

See also
........

See Select.correlate_except().

8.4.6.22 PostgreSQL HSTORE type
...............................

Support for PostgreSQL’s ‘HSTORE’ type is now available as HSTORE.
This type makes great usage of the new operator system to provide
a full range of operators for HSTORE types, including index access,
concatenation, and containment methods such as
‘comparator_factory.has_key()’, ‘comparator_factory.has_any()’, and
‘comparator_factory.matrix()’:

     from sqlalchemy.dialects.postgresql import HSTORE

     data = Table('data_table', metadata,
             Column('id', Integer, primary_key=True),
             Column('hstore_data', HSTORE)
         )

     engine.execute(
         select([data.c.hstore_data['some_key']])
     ).scalar()

     engine.execute(
         select([data.c.hstore_data.matrix()])
     ).scalar()

See also
........

See HSTORE.

See hstore.

#2606(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2606

8.4.6.23 Enhanced PostgreSQL ARRAY type
.......................................

The ARRAY type will accept an optional “dimension” argument,
pinning it to a fixed number of dimensions and greatly improving
efficiency when retrieving results:

     # old way, still works since PG supports N-dimensions per row:
     Column("my_array", postgresql.ARRAY(Integer))

     # new way, will render ARRAY with correct number of [] in DDL,
     # will process binds and results more efficiently as we don't need
     # to guess how many levels deep to go
     Column("my_array", postgresql.ARRAY(Integer, dimensions=2))

The type also introduces new operators, using the new type-specific
operator framework.  New operations include indexed access:

     result = conn.execute(
         select([mytable.c.arraycol[2]])
     )

slice access in SELECT:

     result = conn.execute(
         select([mytable.c.arraycol[2:4]])
     )

slice updates in UPDATE:

     conn.execute(
         mytable.update().values({mytable.c.arraycol[2:3]: [7, 8]})
     )

freestanding array literals:

     >>> from sqlalchemy.dialects import postgresql
     >>> conn.scalar(
     ...    select([
     ...        postgresql.array([1, 2]) + postgresql.array([3, 4, 5])
     ...    ])
     ...  )
     [1, 2, 3, 4, 5]

array concatenation, where below, the right side ‘[4, 5, 6]’ is coerced
into an array literal:

     select([mytable.c.arraycol + [4, 5, 6]])

See also
........

See ARRAY.

See array.

#2441(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2441

8.4.6.24 New, configurable DATE, TIME types for SQLite
......................................................

SQLite has no built-in DATE, TIME, or DATETIME types, and instead
provides some support for storage of date and time values either as
strings or integers.  The date and time types for SQLite are enhanced in
0.8 to be much more configurable as to the specific format, including
that the “microseconds” portion is optional, as well as pretty much
everything else.

     Column('sometimestamp', sqlite.DATETIME(truncate_microseconds=True))
     Column('sometimestamp', sqlite.DATETIME(
                         storage_format=(
                                     "%(year)04d%(month)02d%(day)02d"
                                     "%(hour)02d%(minute)02d%(second)02d%(microsecond)06d"
                         ),
                         regexp="(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{6})"
                         )
                 )
     Column('somedate', sqlite.DATE(
                         storage_format="%(month)02d/%(day)02d/%(year)04d",
                         regexp="(?P<month>\d+)/(?P<day>\d+)/(?P<year>\d+)",
                     )
                 )

Huge thanks to Nate Dub for the sprinting on this at Pycon 2012.

See also
........

See DATETIME.

See DATE.

See TIME.

#2363(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2363

8.4.6.25 “COLLATE” supported across all dialects; in particular MySQL, PostgreSQL, SQLite
.........................................................................................

The “collate” keyword, long accepted by the MySQL dialect, is now
established on all String types and will render on any
backend, including when features such as MetaData.create_all()
and cast() is used:

     >>> stmt = select([cast(sometable.c.somechar, String(20, collation='utf8'))])
     >>> print(stmt)
     SELECT CAST(sometable.somechar AS VARCHAR(20) COLLATE "utf8") AS anon_1
     FROM sometable

See also
........

See String.

#2276(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2276

8.4.6.26 “Prefixes” now supported for ‘update()’, ‘delete()’
............................................................

Geared towards MySQL, a “prefix” can be rendered within any of these
constructs.  E.g.:

     stmt = table.delete().prefix_with("LOW_PRIORITY", dialect="mysql")

     stmt = table.update().prefix_with("LOW_PRIORITY", dialect="mysql")

The method is new in addition to those which already existed on
insert(), select() and Query.

See also
........

‘Update.prefix_with()’

‘Delete.prefix_with()’

‘Insert.prefix_with()’

See Select.prefix_with().

See Query.prefix_with().

#2431(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2431

8.4.6.27 Behavioral Changes
...........................

8.4.6.28 The consideration of a “pending” object as an “orphan” has been made more aggressive
.............................................................................................

This is a late add to the 0.8 series, however it is hoped that the new
behavior is generally more consistent and intuitive in a wider variety
of situations.  The ORM has since at least version 0.4 included behavior
such that an object that’s “pending”, meaning that it’s associated with
a Session but hasn’t been inserted into the database yet, is
automatically expunged from the Session when it becomes an
“orphan”, which means it has been de-associated with a parent object
that refers to it with ‘delete-orphan’ cascade on the configured
relationship().  This behavior is intended to approximately mirror
the behavior of a persistent (that is, already inserted) object, where
the ORM will emit a DELETE for such objects that become orphans based on
the interception of detachment events.

The behavioral change comes into play for objects that are referred to
by multiple kinds of parents that each specify ‘delete-orphan’; the
typical example is an association object that bridges two
other kinds of objects in a many-to-many pattern.  Previously, the
behavior was such that the pending object would be expunged only when
de-associated with `all' of its parents.  With the behavioral change,
the pending object is expunged as soon as it is de-associated from `any'
of the parents that it was previously associated with.  This behavior is
intended to more closely match that of persistent objects, which are
deleted as soon as they are de-associated from any parent.

The rationale for the older behavior dates back at least to version 0.4,
and was basically a defensive decision to try to alleviate confusion
when an object was still being constructed for INSERT. But the reality
is that the object is re-associated with the Session as soon
as it is attached to any new parent in any case.

It’s still possible to flush an object that is not associated with all
of its required parents, if the object was either not associated with
those parents in the first place, or if it was expunged, but then
re-associated with a Session via a subsequent attachment
event but still not fully associated.  In this situation, it is expected
that the database would emit an integrity error, as there are likely NOT
NULL foreign key columns that are unpopulated.  The ORM makes the
decision to let these INSERT attempts occur, based on the judgment that
an object that is only partially associated with its required parents
but has been actively associated with some of them, is more often than
not a user error, rather than an intentional omission which should be
silently skipped - silently skipping the INSERT here would make user
errors of this nature very hard to debug.

The old behavior, for applications that might have been relying upon it,
can be re-enabled for any Mapper by specifying the flag
‘legacy_is_orphan’ as a mapper option.

The new behavior allows the following test case to work:

     from sqlalchemy import Column, Integer, String, ForeignKey
     from sqlalchemy.orm import relationship, backref
     from sqlalchemy.ext.declarative import declarative_base

     Base = declarative_base()

     class User(Base):
         __tablename__ = 'user'
         id = Column(Integer, primary_key=True)
         name = Column(String(64))

     class UserKeyword(Base):
         __tablename__ = 'user_keyword'
         user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
         keyword_id = Column(Integer, ForeignKey('keyword.id'), primary_key=True)

         user = relationship(User,
                     backref=backref("user_keywords",
                                     cascade="all, delete-orphan")
                 )

         keyword = relationship("Keyword",
                     backref=backref("user_keywords",
                                     cascade="all, delete-orphan")
                 )

         # uncomment this to enable the old behavior
         # __mapper_args__ = {"legacy_is_orphan": True}

     class Keyword(Base):
         __tablename__ = 'keyword'
         id = Column(Integer, primary_key=True)
         keyword = Column('keyword', String(64))

     from sqlalchemy import create_engine
     from sqlalchemy.orm import Session

     # note we're using PostgreSQL to ensure that referential integrity
     # is enforced, for demonstration purposes.
     e = create_engine("postgresql://scott:tiger@localhost/test", echo=True)

     Base.metadata.drop_all(e)
     Base.metadata.create_all(e)

     session = Session(e)

     u1 = User(name="u1")
     k1 = Keyword(keyword="k1")

     session.add_all([u1, k1])

     uk1 = UserKeyword(keyword=k1, user=u1)

     # previously, if session.flush() were called here,
     # this operation would succeed, but if session.flush()
     # were not called here, the operation fails with an
     # integrity error.
     # session.flush()
     del u1.user_keywords[0]

     session.commit()

#2655(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2655

8.4.6.29 The after_attach event fires after the item is associated with the Session instead of before; before_attach added
..........................................................................................................................

Event handlers which use after_attach can now assume the given instance
is associated with the given session:

     @event.listens_for(Session, "after_attach")
     def after_attach(session, instance):
         assert instance in session

Some use cases require that it work this way.  However, other use cases
require that the item is `not' yet part of the session, such as when a
query, intended to load some state required for an instance, emits
autoflush first and would otherwise prematurely flush the target object.
Those use cases should use the new “before_attach” event:

     @event.listens_for(Session, "before_attach")
     def before_attach(session, instance):
         instance.some_necessary_attribute = session.query(Widget).\
                                                 filter_by(instance.widget_name).\
                                                 first()

#2464(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2464

8.4.6.30 Query now auto-correlates like a select() does
.......................................................

Previously it was necessary to call Query.correlate() in
order to have a column- or WHERE-subquery correlate to the parent:

     subq = session.query(Entity.value).\
                     filter(Entity.id==Parent.entity_id).\
                     correlate(Parent).\
                     as_scalar()
     session.query(Parent).filter(subq=="some value")

This was the opposite behavior of a plain ‘select()’ construct which
would assume auto-correlation by default.  The above statement in 0.8
will correlate automatically:

     subq = session.query(Entity.value).\
                     filter(Entity.id==Parent.entity_id).\
                     as_scalar()
     session.query(Parent).filter(subq=="some value")

like in ‘select()’, correlation can be disabled by calling
‘query.correlate(None)’ or manually set by passing an entity,
‘query.correlate(someentity)’.

#2179(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2179

8.4.6.31 Correlation is now always context-specific
...................................................

To allow a wider variety of correlation scenarios, the behavior of
Select.correlate() and Query.correlate() has changed
slightly such that the SELECT statement will omit the “correlated”
target from the FROM clause only if the statement is actually used in
that context.  Additionally, it’s no longer possible for a SELECT
statement that’s placed as a FROM in an enclosing SELECT statement to
“correlate” (i.e.  omit) a FROM clause.

This change only makes things better as far as rendering SQL, in that
it’s no longer possible to render illegal SQL where there are
insufficient FROM objects relative to what’s being selected:

     from sqlalchemy.sql import table, column, select

     t1 = table('t1', column('x'))
     t2 = table('t2', column('y'))
     s = select([t1, t2]).correlate(t1)

     print(s)

Prior to this change, the above would return:

     SELECT t1.x, t2.y FROM t2

which is invalid SQL as “t1” is not referred to in any FROM clause.

Now, in the absence of an enclosing SELECT, it returns:

     SELECT t1.x, t2.y FROM t1, t2

Within a SELECT, the correlation takes effect as expected:

     s2 = select([t1, t2]).where(t1.c.x == t2.c.y).where(t1.c.x == s)

     print(s2)

     SELECT t1.x, t2.y FROM t1, t2
     WHERE t1.x = t2.y AND t1.x =
         (SELECT t1.x, t2.y FROM t2)

This change is not expected to impact any existing applications, as the
correlation behavior remains identical for properly constructed
expressions.  Only an application that relies, most likely within a
testing scenario, on the invalid string output of a correlated SELECT
used in a non-correlating context would see any change.

#2668(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2668

8.4.6.32 create_all() and drop_all() will now honor an empty list as such
.........................................................................

The methods MetaData.create_all() and
MetaData.drop_all() will now accept a list of Table
objects that is empty, and will not emit any CREATE or DROP statements.
Previously, an empty list was interpreted the same as passing ‘None’ for
a collection, and CREATE/DROP would be emitted for all items
unconditionally.

This is a bug fix but some applications may have been relying upon the
previous behavior.

#2664(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2664

8.4.6.33 Repaired the Event Targeting of ‘InstrumentationEvents’
................................................................

The InstrumentationEvents series of event targets have
documented that the events will only be fired off according to the
actual class passed as a target.  Through 0.7, this wasn’t the case, and
any event listener applied to InstrumentationEvents would be
invoked for all classes mapped.  In 0.8, additional logic has been added
so that the events will only invoke for those classes sent in.  The
‘propagate’ flag here is set to ‘True’ by default as class
instrumentation events are typically used to intercept classes that
aren’t yet created.

#2590(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2590

8.4.6.34 No more magic coercion of “=” to IN when comparing to subquery in MS-SQL
.................................................................................

We found a very old behavior in the MSSQL dialect which would attempt to
rescue users from themselves when doing something like this:

     scalar_subq = select([someothertable.c.id]).where(someothertable.c.data=='foo')
     select([sometable]).where(sometable.c.id==scalar_subq)

SQL Server doesn’t allow an equality comparison to a scalar SELECT, that
is, “x = (SELECT something)”.  The MSSQL dialect would convert this to
an IN. The same thing would happen however upon a comparison like
“(SELECT something) = x”, and overall this level of guessing is outside
of SQLAlchemy’s usual scope so the behavior is removed.

#2277(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2277

8.4.6.35 Fixed the behavior of ‘Session.is_modified()’
......................................................

The Session.is_modified() method accepts an argument
‘passive’ which basically should not be necessary, the argument in all
cases should be the value ‘True’ - when left at its default of ‘False’
it would have the effect of hitting the database, and often triggering
autoflush which would itself change the results.  In 0.8 the ‘passive’
argument will have no effect, and unloaded attributes will never be
checked for history since by definition there can be no pending state
change on an unloaded attribute.

See also
........

See Session.is_modified().

#2320(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2320

8.4.6.36 ‘Column.key’ is honored in the ‘Select.c’ attribute of ‘select()’ with ‘Select.apply_labels()’
.......................................................................................................

Users of the expression system know that Select.apply_labels()
prepends the table name to each column name, affecting the names
that are available from Select.c:

     s = select([table1]).apply_labels()
     s.c.table1_col1
     s.c.table1_col2

Before 0.8, if the Column had a different ‘Column.key’, this
key would be ignored, inconsistently versus when
Select.apply_labels() were not used:

     # before 0.8
     table1 = Table('t1', metadata,
         Column('col1', Integer, key='column_one')
     )
     s = select([table1])
     s.c.column_one # would be accessible like this
     s.c.col1 # would raise AttributeError

     s = select([table1]).apply_labels()
     s.c.table1_column_one # would raise AttributeError
     s.c.table1_col1 # would be accessible like this

In 0.8, ‘Column.key’ is honored in both cases:

     # with 0.8
     table1 = Table('t1', metadata,
         Column('col1', Integer, key='column_one')
     )
     s = select([table1])
     s.c.column_one # works
     s.c.col1 # AttributeError

     s = select([table1]).apply_labels()
     s.c.table1_column_one # works
     s.c.table1_col1 # AttributeError

All other behavior regarding “name” and “key” are the same, including
that the rendered SQL will still use the form ‘<tablename>_<colname>’ -
the emphasis here was on preventing the ‘Column.key’ contents from being
rendered into the ‘SELECT’ statement so that there are no issues with
special/ non-ascii characters used in the ‘Column.key’.

#2397(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2397

8.4.6.37 single_parent warning is now an error
..............................................

A relationship() that is many-to-one or many-to-many and
specifies “cascade=’all, delete-orphan’”, which is an awkward but
nonetheless supported use case (with restrictions) will now raise an
error if the relationship does not specify the ‘single_parent=True’
option.  Previously it would only emit a warning, but a failure would
follow almost immediately within the attribute system in any case.

#2405(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2405

8.4.6.38 Adding the ‘inspector’ argument to the ‘column_reflect’ event
......................................................................

0.7 added a new event called ‘column_reflect’, provided so that the
reflection of columns could be augmented as each one were reflected.  We
got this event slightly wrong in that the event gave no way to get at
the current ‘Inspector’ and ‘Connection’ being used for the reflection,
in the case that additional information from the database is needed.  As
this is a new event not widely used yet, we’ll be adding the ‘inspector’
argument into it directly:

     @event.listens_for(Table, "column_reflect")
     def listen_for_col(inspector, table, column_info):
         # ...

#2418(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2418

8.4.6.39 Disabling auto-detect of collations, casing for MySQL
..............................................................

The MySQL dialect does two calls, one very expensive, to load all
possible collations from the database as well as information on casing,
the first time an ‘Engine’ connects.  Neither of these collections are
used for any SQLAlchemy functions, so these calls will be changed to no
longer be emitted automatically.  Applications that might have relied on
these collections being present on ‘engine.dialect’ will need to call
upon ‘_detect_collations()’ and ‘_detect_casing()’ directly.

#2404(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2404

8.4.6.40 “Unconsumed column names” warning becomes an exception
...............................................................

Referring to a non-existent column in an ‘insert()’ or ‘update()’
construct will raise an error instead of a warning:

     t1 = table('t1', column('x'))
     t1.insert().values(x=5, z=5) # raises "Unconsumed column names: z"

#2415(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2415

8.4.6.41 Inspector.get_primary_keys() is deprecated, use Inspector.get_pk_constraint
....................................................................................

These two methods on ‘Inspector’ were redundant, where
‘get_primary_keys()’ would return the same information as
‘get_pk_constraint()’ minus the name of the constraint:

     >>> insp.get_primary_keys()
     ["a", "b"]

     >>> insp.get_pk_constraint()
     {"name":"pk_constraint", "constrained_columns":["a", "b"]}

#2422(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2422

8.4.6.42 Case-insensitive result row names will be disabled in most cases
.........................................................................

A very old behavior, the column names in ‘RowProxy’ were always compared
case-insensitively:

     >>> row = result.fetchone()
     >>> row['foo'] == row['FOO'] == row['Foo']
     True

This was for the benefit of a few dialects which in the early days
needed this, like Oracle and Firebird, but in modern usage we have more
accurate ways of dealing with the case-insensitive behavior of these two
platforms.

Going forward, this behavior will be available only optionally, by
passing the flag ‘`case_sensitive=False`’ to ‘`create_engine()`’, but
otherwise column names requested from the row must match as far as
casing.

#2423(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2423

8.4.6.43 ‘InstrumentationManager’ and alternate class instrumentation is now an extension
.........................................................................................

The ‘sqlalchemy.orm.interfaces.InstrumentationManager’ class is moved to
‘sqlalchemy.ext.instrumentation.InstrumentationManager’.  The “alternate
instrumentation” system was built for the benefit of a very small number
of installations that needed to work with existing or unusual class
instrumentation systems, and generally is very seldom used.  The
complexity of this system has been exported to an ‘ext.’ module.  It
remains unused until once imported, typically when a third party library
imports ‘InstrumentationManager’, at which point it is injected back
into ‘sqlalchemy.orm’ by replacing the default ‘InstrumentationFactory’
with ‘ExtendedInstrumentationRegistry’.

8.4.6.44 Removed
................

8.4.6.45 SQLSoup
................

SQLSoup is a handy package that presents an alternative interface on top
of the SQLAlchemy ORM. SQLSoup is now moved into its own project and
documented/released separately; see
‘https://bitbucket.org/zzzeek/sqlsoup’.

SQLSoup is a very simple tool that could also benefit from contributors
who are interested in its style of usage.

#2262(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2262

8.4.6.46 MutableType
....................

The older “mutable” system within the SQLAlchemy ORM has been removed.
This refers to the ‘MutableType’ interface which was applied to types
such as ‘PickleType’ and conditionally to ‘TypeDecorator’, and since
very early SQLAlchemy versions has provided a way for the ORM to detect
changes in so-called “mutable” data structures such as JSON structures
and pickled objects.  However, the implementation was never reasonable
and forced a very inefficient mode of usage on the unit-of-work which
caused an expensive scan of all objects to take place during flush.  In
0.7, the sqlalchemy.ext.mutable(1) extension was introduced so that
user-defined datatypes can appropriately send events to the unit of work
as changes occur.

Today, usage of ‘MutableType’ is expected to be low, as warnings have
been in place for some years now regarding its inefficiency.

#2442(2)

   ---------- Footnotes ----------

   (1) http://docs.sqlalchemy.org/en/latest/orm/extensions/mutable.html

   (2) http://www.sqlalchemy.org/trac/ticket/2442

8.4.6.47 sqlalchemy.exceptions (has been sqlalchemy.exc for years)
..................................................................

We had left in an alias ‘sqlalchemy.exceptions’ to attempt to make it
slightly easier for some very old libraries that hadn’t yet been
upgraded to use ‘sqlalchemy.exc’.  Some users are still being confused
by it however so in 0.8 we’re taking it out entirely to eliminate any of
that confusion.

#2433(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2433

8.4.7 What’s New in SQLAlchemy 0.7?
-----------------------------------

     About this Document: This document describes changes between
     SQLAlchemy version 0.6, last released May 5, 2012, and SQLAlchemy
     version 0.7, undergoing maintenance releases as of October, 2012.

     Document date: July 27, 2011

8.4.7.1 Introduction
....................

This guide introduces what’s new in SQLAlchemy version 0.7, and also
documents changes which affect users migrating their applications from
the 0.6 series of SQLAlchemy to 0.7.

To as great a degree as possible, changes are made in such a way as to
not break compatibility with applications built for 0.6.  The changes
that are necessarily not backwards compatible are very few, and all but
one, the change to mutable attribute defaults, should affect an
exceedingly small portion of applications - many of the changes regard
non-public APIs and undocumented hacks some users may have been
attempting to use.

A second, even smaller class of non-backwards-compatible changes is also
documented.  This class of change regards those features and behaviors
that have been deprecated at least since version 0.5 and have been
raising warnings since their deprecation.  These changes would only
affect applications that are still using 0.4- or early 0.5-style APIs.
As the project matures, we have fewer and fewer of these kinds of
changes with 0.x level releases, which is a product of our API having
ever fewer features that are less than ideal for the use cases they were
meant to solve.

An array of existing functionalities have been superseded in SQLAlchemy
0.7.  There’s not much difference between the terms “superseded” and
“deprecated”, except that the former has a much weaker suggestion of the
old feature would ever be removed.  In 0.7, features like ‘synonym’ and
‘comparable_property’, as well as all the ‘Extension’ and other event
classes, have been superseded.  But these “superseded” features have
been re-implemented such that their implementations live mostly outside
of core ORM code, so their continued “hanging around” doesn’t impact
SQLAlchemy’s ability to further streamline and refine its internals, and
we expect them to remain within the API for the foreseeable future.

8.4.7.2 New Features
....................

8.4.7.3 New Event System
........................

SQLAlchemy started early with the ‘MapperExtension’ class, which
provided hooks into the persistence cycle of mappers.  As SQLAlchemy
quickly became more componentized, pushing mappers into a more focused
configurational role, many more “extension”, “listener”, and “proxy”
classes popped up to solve various activity-interception use cases in an
ad-hoc fashion.  Part of this was driven by the divergence of
activities; ‘ConnectionProxy’ objects wanted to provide a system of
rewriting statements and parameters; ‘AttributeExtension’ provided a
system of replacing incoming values, and ‘DDL’ objects had events that
could be switched off of dialect-sensitive callables.

0.7 re-implements virtually all of these plugin points with a new,
unified approach, which retains all the functionalities of the different
systems, provides more flexibility and less boilerplate, performs
better, and eliminates the need to learn radically different APIs for
each event subsystem.  The pre-existing classes ‘MapperExtension’,
‘SessionExtension’, ‘AttributeExtension’, ‘ConnectionProxy’,
‘PoolListener’ as well as the ‘DDLElement.execute_at’ method are
deprecated and now implemented in terms of the new system - these APIs
remain fully functional and are expected to remain in place for the
foreseeable future.

The new approach uses named events and user-defined callables to
associate activities with events.  The API’s look and feel was driven by
such diverse sources as JQuery, Blinker, and Hibernate, and was also
modified further on several occasions during conferences with dozens of
users on Twitter, which appears to have a much higher response rate than
the mailing list for such questions.

It also features an open-ended system of target specification that
allows events to be associated with API classes, such as for all
‘Session’ or ‘Engine’ objects, with specific instances of API classes,
such as for a specific ‘Pool’ or ‘Mapper’, as well as for related
objects like a user- defined class that’s mapped, or something as
specific as a certain attribute on instances of a particular subclass of
a mapped parent class.  Individual listener subsystems can apply
wrappers to incoming user- defined listener functions which modify how
they are called - an mapper event can receive either the instance of the
object being operated upon, or its underlying ‘InstanceState’ object.
An attribute event can opt whether or not to have the responsibility of
returning a new value.

Several systems now build upon the new event API, including the new
“mutable attributes” API as well as composite attributes.  The greater
emphasis on events has also led to the introduction of a handful of new
events, including attribute expiration and refresh operations, pickle
loads/dumps operations, completed mapper construction operations.

See also
........

See Events.

#1902(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1902

8.4.7.4 Hybrid Attributes, implements/supersedes synonym(), comparable_property()
.................................................................................

The “derived attributes” example has now been turned into an official
extension.  The typical use case for ‘synonym()’ is to provide
descriptor access to a mapped column; the use case for
‘comparable_property()’ is to be able to return a ‘PropComparator’ from
any descriptor.  In practice, the approach of “derived” is easier to
use, more extensible, is implemented in a few dozen lines of pure Python
with almost no imports, and doesn’t require the ORM core to even be
aware of it.  The feature is now known as the “Hybrid Attributes”
extension.

‘synonym()’ and ‘comparable_property()’ are still part of the ORM,
though their implementations have been moved outwards, building on an
approach that is similar to that of the hybrid extension, so that the
core ORM mapper/query/property modules aren’t really aware of them
otherwise.

See also
........

See Hybrid Attributes.

#1903(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1903

8.4.7.5 Speed Enhancements
..........................

As is customary with all major SQLA releases, a wide pass through the
internals to reduce overhead and callcounts has been made which further
reduces the work needed in common scenarios.  Highlights of this release
include:

   * The flush process will now bundle INSERT statements into batches
     fed to ‘cursor.executemany()’, for rows where the primary key is
     already present.  In particular this usually applies to the “child”
     table on a joined table inheritance configuration, meaning the
     number of calls to ‘cursor.execute’ for a large bulk insert of
     joined- table objects can be cut in half, allowing native DBAPI
     optimizations to take place for those statements passed to
     ‘cursor.executemany()’ (such as re-using a prepared statement).

   * The codepath invoked when accessing a many-to-one reference to a
     related object that’s already loaded has been greatly simplified.
     The identity map is checked directly without the need to generate a
     new ‘Query’ object first, which is expensive in the context of
     thousands of in-memory many-to-ones being accessed.  The usage of
     constructed-per-call “loader” objects is also no longer used for
     the majority of lazy attribute loads.

   * The rewrite of composites allows a shorter codepath when mapper
     internals access mapped attributes within a flush.

   * New inlined attribute access functions replace the previous usage
     of “history” when the “save-update” and other cascade operations
     need to cascade among the full scope of datamembers associated with
     an attribute.  This reduces the overhead of generating a new
     ‘History’ object for this speed-critical operation.

   * The internals of the ‘ExecutionContext’, the object corresponding
     to a statement execution, have been inlined and simplified.

   * The ‘bind_processor()’ and ‘result_processor()’ callables generated
     by types for each statement execution are now cached (carefully, so
     as to avoid memory leaks for ad-hoc types and dialects) for the
     lifespan of that type, further reducing per-statement call
     overhead.

   * The collection of “bind processors” for a particular ‘Compiled’
     instance of a statement is also cached on the ‘Compiled’ object,
     taking further advantage of the “compiled cache” used by the flush
     process to re-use the same compiled form of INSERT, UPDATE, DELETE
     statements.

A demonstration of callcount reduction including a sample benchmark
script is at ‘http://techspot.zzzeek.org/2010/12/12/a-tale-of-three’-
profiles/

8.4.7.6 Composites Rewritten
............................

The “composite” feature has been rewritten, like ‘synonym()’ and
‘comparable_property()’, to use a lighter weight implementation based on
descriptors and events, rather than building into the ORM internals.
This allowed the removal of some latency from the mapper/unit of work
internals, and simplifies the workings of composite.  The composite
attribute now no longer conceals the underlying columns it builds upon,
which now remain as regular attributes.  Composites can also act as a
proxy for ‘relationship()’ as well as ‘Column()’ attributes.

The major backwards-incompatible change of composites is that they no
longer use the ‘mutable=True’ system to detect in-place mutations.
Please use the Mutation Tracking(1) extension to establish in-place
change events to existing composite usage.

See also
........

See Composite Column Types.

See Mutation Tracking.

#2008(2) #2024(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/docs/07/orm/extensions/mutable.html

   (2) http://www.sqlalchemy.org/trac/ticket/2008

   (3) http://www.sqlalchemy.org/trac/ticket/2024

8.4.7.7 More succinct form of query.join(target, onclause)
..........................................................

The default method of issuing ‘query.join()’ to a target with an
explicit onclause is now:

     query.join(SomeClass, SomeClass.id==ParentClass.some_id)

In 0.6, this usage was considered to be an error, because ‘join()’
accepts multiple arguments corresponding to multiple JOIN clauses - the
two-argument form needed to be in a tuple to disambiguate between
single-argument and two- argument join targets.  In the middle of 0.6 we
added detection and an error message for this specific calling style,
since it was so common.  In 0.7, since we are detecting the exact
pattern anyway, and since having to type out a tuple for no reason is
extremely annoying, the non- tuple method now becomes the “normal” way
to do it.  The “multiple JOIN” use case is exceedingly rare compared to
the single join case, and multiple joins these days are more clearly
represented by multiple calls to ‘join()’.

The tuple form will remain for backwards compatibility.

Note that all the other forms of ‘query.join()’ remain unchanged:

     query.join(MyClass.somerelation)
     query.join("somerelation")
     query.join(MyTarget)
     # ... etc

Querying with Joins(1)

#1923(2)

   ---------- Footnotes ----------

   (1)
http://www.sqlalchemy.org/docs/07/orm/tutorial.html#querying-with-joins

   (2) http://www.sqlalchemy.org/trac/ticket/1923

8.4.7.8 Mutation event extension, supersedes “mutable=True”
...........................................................

A new extension, see Mutation Tracking, provides a mechanism by
which user-defined datatypes can provide change events back to the
owning parent or parents.  The extension includes an approach for scalar
database values, such as those managed by PickleType,
‘postgresql.ARRAY’, or other custom ‘MutableType’ classes, as well as an
approach for ORM “composites”, those configured using composite().

See also
........

See Mutation Tracking.

8.4.7.9 NULLS FIRST / NULLS LAST operators
..........................................

These are implemented as an extension to the ‘asc()’ and ‘desc()’
operators, called ‘nullsfirst()’ and ‘nullslast()’.

See also
........

‘nullsfirst()’

‘nullslast()’

#723(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/723

8.4.7.10 select.distinct(), query.distinct() accepts *args for PostgreSQL DISTINCT ON
.....................................................................................

This was already available by passing a list of expressions to the
‘distinct’ keyword argument of ‘select()’, the ‘distinct()’ method of
‘select()’ and ‘Query’ now accept positional arguments which are
rendered as DISTINCT ON when a PostgreSQL backend is used.

distinct()(1)

Query.distinct()(2)

#1069(3)

   ---------- Footnotes ----------

   (1)
http://www.sqlalchemy.org/docs/07/core/expression_api.html#sqlalchemy.sql.expression.Select.distinct

   (2)
http://www.sqlalchemy.org/docs/07/orm/query.html#sqlalchemy.orm.query.Query.distinct

   (3) http://www.sqlalchemy.org/trac/ticket/1069

8.4.7.11 ‘Index()’ can be placed inline inside of ‘Table’, ‘__table_args__’
...........................................................................

The Index() construct can be created inline with a Table definition,
using strings as column names, as an alternative to the creation of the
index outside of the Table.  That is:

     Table('mytable', metadata,
             Column('id',Integer, primary_key=True),
             Column('name', String(50), nullable=False),
             Index('idx_name', 'name')
     )

The primary rationale here is for the benefit of declarative
‘__table_args__’, particularly when used with mixins:

     class HasNameMixin(object):
         name = Column('name', String(50), nullable=False)
         @declared_attr
         def __table_args__(cls):
             return (Index('name'), {})

     class User(HasNameMixin, Base):
         __tablename__ = 'user'
         id = Column('id', Integer, primary_key=True)

Indexes(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/docs/07/core/schema.html#indexes

8.4.7.12 Window Function SQL Construct
......................................

A “window function” provides to a statement information about the result
set as it’s produced.  This allows criteria against various things like
“row number”, “rank” and so forth.  They are known to be supported at
least by PostgreSQL, SQL Server and Oracle, possibly others.

The best introduction to window functions is on PostgreSQL’s site, where
window functions have been supported since version 8.4:

‘http://www.postgresql.org/docs/9.0/static/tutorial’- window.html

SQLAlchemy provides a simple construct typically invoked via an existing
function clause, using the ‘over()’ method, which accepts ‘order_by’ and
‘partition_by’ keyword arguments.  Below we replicate the first example
in PG’s tutorial:

     from sqlalchemy.sql import table, column, select, func

     empsalary = table('empsalary',
                     column('depname'),
                     column('empno'),
                     column('salary'))

     s = select([
             empsalary,
             func.avg(empsalary.c.salary).
                   over(partition_by=empsalary.c.depname).
                   label('avg')
         ])

     print(s)

SQL:

     SELECT empsalary.depname, empsalary.empno, empsalary.salary,
     avg(empsalary.salary) OVER (PARTITION BY empsalary.depname) AS avg
     FROM empsalary

sqlalchemy.sql.expression.over(1)

#1844(2)

   ---------- Footnotes ----------

   (1)
http://www.sqlalchemy.org/docs/07/core/expression_api.html#sqlalchemy.sql.expression.over

   (2) http://www.sqlalchemy.org/trac/ticket/1844

8.4.7.13 execution_options() on Connection accepts “isolation_level” argument
.............................................................................

This sets the transaction isolation level for a single ‘Connection’,
until that ‘Connection’ is closed and its underlying DBAPI resource
returned to the connection pool, upon which the isolation level is reset
back to the default.  The default isolation level is set using the
‘isolation_level’ argument to ‘create_engine()’.

Transaction isolation support is currently only supported by the
PostgreSQL and SQLite backends.

execution_options()(1)

#2001(2)

   ---------- Footnotes ----------

   (1)
http://www.sqlalchemy.org/docs/07/core/connections.html#sqlalchemy.engine.base.Connection.execution_options

   (2) http://www.sqlalchemy.org/trac/ticket/2001

8.4.7.14 ‘TypeDecorator’ works with integer primary key columns
...............................................................

A ‘TypeDecorator’ which extends the behavior of ‘Integer’ can be used
with a primary key column.  The “autoincrement” feature of ‘Column’ will
now recognize that the underlying database column is still an integer so
that lastrowid mechanisms continue to function.  The ‘TypeDecorator’
itself will have its result value processor applied to newly generated
primary keys, including those received by the DBAPI ‘cursor.lastrowid’
accessor.

#2005(1) #2006(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2005

   (2) http://www.sqlalchemy.org/trac/ticket/2006

8.4.7.15 ‘TypeDecorator’ is present in the “sqlalchemy” import space
....................................................................

No longer need to import this from ‘sqlalchemy.types’, it’s now mirrored
in ‘sqlalchemy’.

8.4.7.16 New Dialects
.....................

Dialects have been added:

   * a MySQLdb driver for the Drizzle database:

     Drizzle(1)

   * support for the pymysql DBAPI:

     pymsql Notes(2)

   * psycopg2 now works with Python 3

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/docs/07/dialects/drizzle.html

   (2)
http://www.sqlalchemy.org/docs/07/dialects/mysql.html#module-sqlalchemy.dialects.mysql.pymysql

8.4.7.17 Behavioral Changes (Backwards Compatible)
..................................................

8.4.7.18 C Extensions Build by Default
......................................

This is as of 0.7b4.  The exts will build if cPython 2.xx is detected.
If the build fails, such as on a windows install, that condition is
caught and the non-C install proceeds.  The C exts won’t build if Python
3 or PyPy is used.

8.4.7.19 Query.count() simplified, should work virtually always
...............................................................

The very old guesswork which occurred within ‘Query.count()’ has been
modernized to use ‘.from_self()’.  That is, ‘query.count()’ is now
equivalent to:

     query.from_self(func.count(literal_column('1'))).scalar()

Previously, internal logic attempted to rewrite the columns clause of
the query itself, and upon detection of a “subquery” condition, such as
a column-based query that might have aggregates in it, or a query with
DISTINCT, would go through a convoluted process of rewriting the columns
clause.  This logic failed in complex conditions, particularly those
involving joined table inheritance, and was long obsolete by the more
comprehensive ‘.from_self()’ call.

The SQL emitted by ‘query.count()’ is now always of the form:

     SELECT count(1) AS count_1 FROM (
         SELECT user.id AS user_id, user.name AS user_name from user
     ) AS anon_1

that is, the original query is preserved entirely inside of a subquery,
with no more guessing as to how count should be applied.

#2093(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2093

8.4.7.20 To emit a non-subquery form of count()
...............................................

MySQL users have already reported that the MyISAM engine not
surprisingly falls over completely with this simple change.  Note that
for a simple ‘count()’ that optimizes for DBs that can’t handle simple
subqueries, ‘func.count()’ should be used:

     from sqlalchemy import func
     session.query(func.count(MyClass.id)).scalar()

or for ‘count(*)’:

     from sqlalchemy import func, literal_column
     session.query(func.count(literal_column('*'))).select_from(MyClass).scalar()

8.4.7.21 LIMIT/OFFSET clauses now use bind parameters
.....................................................

The LIMIT and OFFSET clauses, or their backend equivalents (i.e.  TOP,
ROW NUMBER OVER, etc.), use bind parameters for the actual values, for
all backends which support it (most except for Sybase).  This allows
better query optimizer performance as the textual string for multiple
statements with differing LIMIT/OFFSET are now identical.

#805(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/805

8.4.7.22 Logging enhancements
.............................

Vinay Sajip has provided a patch to our logging system such that the
“hex string” embedded in logging statements for engines and pools is no
longer needed to allow the ‘echo’ flag to work correctly.  A new system
that uses filtered logging objects allows us to maintain our current
behavior of ‘echo’ being local to individual engines without the need
for additional identifying strings local to those engines.

#1926(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1926

8.4.7.23 Simplified polymorphic_on assignment
.............................................

The population of the ‘polymorphic_on’ column-mapped attribute, when
used in an inheritance scenario, now occurs when the object is
constructed, i.e.  its ‘__init__’ method is called, using the init
event.  The attribute then behaves the same as any other column-mapped
attribute.  Previously, special logic would fire off during flush to
populate this column, which prevented any user code from modifying its
behavior.  The new approach improves upon this in three ways: 1.  the
polymorphic identity is now present on the object as soon as its
constructed; 2.  the polymorphic identity can be changed by user code
without any difference in behavior from any other column-mapped
attribute; 3.  the internals of the mapper during flush are simplified
and no longer need to make special checks for this column.

#1895(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1895

8.4.7.24 contains_eager() chains across multiple paths (i.e. “all()”)
.....................................................................

The ‘`contains_eager()``’ modifier now will chain itself for a longer
path without the need to emit individual ‘``contains_eager()`’ calls.
Instead of:

     session.query(A).options(contains_eager(A.b), contains_eager(A.b, B.c))

you can say:

     session.query(A).options(contains_eager(A.b, B.c))

#2032(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2032

8.4.7.25 Flushing of orphans that have no parent is allowed
...........................................................

We’ve had a long standing behavior that checks for a so- called “orphan”
during flush, that is, an object which is associated with a
‘relationship()’ that specifies “delete- orphan” cascade, has been newly
added to the session for an INSERT, and no parent relationship has been
established.  This check was added years ago to accommodate some test
cases which tested the orphan behavior for consistency.  In modern SQLA,
this check is no longer needed on the Python side.  The equivalent
behavior of the “orphan check” is accomplished by making the foreign key
reference to the object’s parent row NOT NULL, where the database does
its job of establishing data consistency in the same way SQLA allows
most other operations to do.  If the object’s parent foreign key is
nullable, then the row can be inserted.  The “orphan” behavior runs when
the object was persisted with a particular parent, and is then
disassociated with that parent, leading to a DELETE statement emitted
for it.

#1912(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1912

8.4.7.26 Warnings generated when collection members, scalar referents not part of the flush
...........................................................................................

Warnings are now emitted when related objects referenced via a loaded
‘relationship()’ on a parent object marked as “dirty” are not present in
the current ‘Session’.

The ‘save-update’ cascade takes effect when objects are added to the
‘Session’, or when objects are first associated with a parent, so that
an object and everything related to it are usually all present in the
same ‘Session’.  However, if ‘save-update’ cascade is disabled for a
particular ‘relationship()’, then this behavior does not occur, and the
flush process does not try to correct for it, instead staying consistent
to the configured cascade behavior.  Previously, when such objects were
detected during the flush, they were silently skipped.  The new behavior
is that a warning is emitted, for the purposes of alerting to a
situation that more often than not is the source of unexpected behavior.

#1973(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1973

8.4.7.27 Setup no longer installs a Nose plugin
...............................................

Since we moved to nose we’ve used a plugin that installs via setuptools,
so that the ‘nosetests’ script would automatically run SQLA’s plugin
code, necessary for our tests to have a full environment.  In the middle
of 0.6, we realized that the import pattern here meant that Nose’s
“coverage” plugin would break, since “coverage” requires that it be
started before any modules to be covered are imported; so in the middle
of 0.6 we made the situation worse by adding a separate
‘sqlalchemy-nose’ package to the build to overcome this.

In 0.7 we’ve done away with trying to get ‘nosetests’ to work
automatically, since the SQLAlchemy module would produce a large number
of nose configuration options for all usages of ‘nosetests’, not just
the SQLAlchemy unit tests themselves, and the additional
‘sqlalchemy-nose’ install was an even worse idea, producing an extra
package in Python environments.  The ‘sqla_nose.py’ script in 0.7 is now
the only way to run the tests with nose.

#1949(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1949

8.4.7.28 Non-‘Table’-derived constructs can be mapped
.....................................................

A construct that isn’t against any ‘Table’ at all, like a function, can
be mapped.

     from sqlalchemy import select, func
     from sqlalchemy.orm import mapper

     class Subset(object):
         pass
     selectable = select(["x", "y", "z"]).select_from(func.some_db_function()).alias()
     mapper(Subset, selectable, primary_key=[selectable.c.x])

#1876(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1876

8.4.7.29 aliased() accepts ‘FromClause’ elements
................................................

This is a convenience helper such that in the case a plain ‘FromClause’,
such as a ‘select’, ‘Table’ or ‘join’ is passed to the ‘orm.aliased()’
construct, it passes through to the ‘.alias()’ method of that from
construct rather than constructing an ORM level ‘AliasedClass’.

#2018(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2018

8.4.7.30 Session.connection(), Session.execute() accept ‘bind’
..............................................................

This is to allow execute/connection operations to participate in the
open transaction of an engine explicitly.  It also allows custom
subclasses of ‘Session’ that implement their own ‘get_bind()’ method and
arguments to use those custom arguments with both the ‘execute()’ and
‘connection()’ methods equally.

Session.connection(1) Session.execute(2)

#1996(3)

   ---------- Footnotes ----------

   (1)
http://www.sqlalchemy.org/docs/07/orm/session.html#sqlalchemy.orm.session.Session.connection

   (2)
http://www.sqlalchemy.org/docs/07/orm/session.html#sqlalchemy.orm.session.Session.execute

   (3) http://www.sqlalchemy.org/trac/ticket/1996

8.4.7.31 Standalone bind parameters in columns clause auto-labeled.
...................................................................

Bind parameters present in the “columns clause” of a select are now
auto-labeled like other “anonymous” clauses, which among other things
allows their “type” to be meaningful when the row is fetched, as in
result row processors.

8.4.7.32 SQLite - relative file paths are normalized through os.path.abspath()
..............................................................................

This so that a script that changes the current directory will continue
to target the same location as subsequent SQLite connections are
established.

#2036(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2036

8.4.7.33 MS-SQL - ‘String’/‘Unicode’/‘VARCHAR’/‘NVARCHAR’/‘VARBINARY’ emit “max” for no length
..............................................................................................

On the MS-SQL backend, the String/Unicode types, and their counterparts
VARCHAR/ NVARCHAR, as well as VARBINARY (#1833(1)) emit “max” as the
length when no length is specified.  This makes it more compatible with
PostgreSQL’s VARCHAR type which is similarly unbounded when no length
specified.  SQL Server defaults the length on these types to ‘1’ when no
length is specified.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1833

8.4.7.34 Behavioral Changes (Backwards Incompatible)
....................................................

Note again, aside from the default mutability change, most of these
changes are *extremely minor* and will not affect most users.

8.4.7.35 ‘PickleType’ and ARRAY mutability turned off by default
................................................................

This change refers to the default behavior of the ORM when mapping
columns that have either the ‘PickleType’ or ‘postgresql.ARRAY’
datatypes.  The ‘mutable’ flag is now set to ‘False’ by default.  If an
existing application uses these types and depends upon detection of
in-place mutations, the type object must be constructed with
‘mutable=True’ to restore the 0.6 behavior:

     Table('mytable', metadata,
         # ....

         Column('pickled_data', PickleType(mutable=True))
     )

The ‘mutable=True’ flag is being phased out, in favor of the new
Mutation Tracking(1) extension.  This extension provides a mechanism by
which user-defined datatypes can provide change events back to the
owning parent or parents.

The previous approach of using ‘mutable=True’ does not provide for
change events - instead, the ORM must scan through all mutable values
present in a session and compare them against their original value for
changes every time ‘flush()’ is called, which is a very time consuming
event.  This is a holdover from the very early days of SQLAlchemy when
‘flush()’ was not automatic and the history tracking system was not
nearly as sophisticated as it is now.

Existing applications which use ‘PickleType’, ‘postgresql.ARRAY’ or
other ‘MutableType’ subclasses, and require in-place mutation detection,
should migrate to the new mutation tracking system, as ‘mutable=True’ is
likely to be deprecated in the future.

#1980(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/docs/07/orm/extensions/mutable.html

   (2) http://www.sqlalchemy.org/trac/ticket/1980

8.4.7.36 Mutability detection of ‘composite()’ requires the Mutation Tracking Extension
.......................................................................................

So-called “composite” mapped attributes, those configured using the
technique described at Composite Column Types(1), have been
re-implemented such that the ORM internals are no longer aware of them
(leading to shorter and more efficient codepaths in critical sections).
While composite types are generally intended to be treated as immutable
value objects, this was never enforced.  For applications that use
composites with mutability, the Mutation Tracking(2) extension offers a
base class which establishes a mechanism for user-defined composite
types to send change event messages back to the owning parent or parents
of each object.

Applications which use composite types and rely upon in- place mutation
detection of these objects should either migrate to the “mutation
tracking” extension, or change the usage of the composite types such
that in-place changes are no longer needed (i.e., treat them as
immutable value objects).

   ---------- Footnotes ----------

   (1)
http://www.sqlalchemy.org/docs/07/orm/mapper_config.html#composite-column-types

   (2) http://www.sqlalchemy.org/docs/07/orm/extensions/mutable.html

8.4.7.37 SQLite - the SQLite dialect now uses ‘NullPool’ for file-based databases
.................................................................................

This change is `99.999% backwards compatible', unless you are using
temporary tables across connection pool connections.

A file-based SQLite connection is blazingly fast, and using ‘NullPool’
means that each call to ‘Engine.connect’ creates a new pysqlite
connection.

Previously, the ‘SingletonThreadPool’ was used, which meant that all
connections to a certain engine in a thread would be the same
connection.  It’s intended that the new approach is more intuitive,
particularly when multiple connections are used.

‘SingletonThreadPool’ is still the default engine when a ‘:memory:’
database is used.

Note that this change `breaks temporary tables used across Session
commits', due to the way SQLite handles temp tables.  See the note at
‘http://www.sqlalchemy.org/docs/dialects/sqlite.html#using’-
temporary-tables-with-sqlite if temporary tables beyond the scope of one
pool connection are desired.

#1921(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1921

8.4.7.38 ‘Session.merge()’ checks version ids for versioned mappers
...................................................................

Session.merge() will check the version id of the incoming state against
that of the database, assuming the mapping uses version ids and incoming
state has a version_id assigned, and raise StaleDataError if they don’t
match.  This is the correct behavior, in that if incoming state contains
a stale version id, it should be assumed the state is stale.

If merging data into a versioned state, the version id attribute can be
left undefined, and no version check will take place.

This check was confirmed by examining what Hibernate does - both the
‘merge()’ and the versioning features were originally adapted from
Hibernate.

#2027(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2027

8.4.7.39 Tuple label names in Query Improved
............................................

This improvement is potentially slightly backwards incompatible for an
application that relied upon the old behavior.

Given two mapped classes ‘Foo’ and ‘Bar’ each with a column ‘spam’:

     qa = session.query(Foo.spam)
     qb = session.query(Bar.spam)

     qu = qa.union(qb)

The name given to the single column yielded by ‘qu’ will be ‘spam’.
Previously it would be something like ‘foo_spam’ due to the way the
‘union’ would combine things, which is inconsistent with the name ‘spam’
in the case of a non-unioned query.

#1942(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1942

8.4.7.40 Mapped column attributes reference the most specific column first
..........................................................................

This is a change to the behavior involved when a mapped column attribute
references multiple columns, specifically when dealing with an attribute
on a joined-table subclass that has the same name as that of an
attribute on the superclass.

Using declarative, the scenario is this:

     class Parent(Base):
         __tablename__ = 'parent'
         id = Column(Integer, primary_key=True)

     class Child(Parent):
        __tablename__ = 'child'
         id = Column(Integer, ForeignKey('parent.id'), primary_key=True)

Above, the attribute ‘Child.id’ refers to both the ‘child.id’ column as
well as ‘parent.id’ - this due to the name of the attribute.  If it were
named differently on the class, such as ‘Child.child_id’, it then maps
distinctly to ‘child.id’, with ‘Child.id’ being the same attribute as
‘Parent.id’.

When the ‘id’ attribute is made to reference both ‘parent.id’ and
‘child.id’, it stores them in an ordered list.  An expression such as
‘Child.id’ then refers to just `one' of those columns when rendered.  Up
until 0.6, this column would be ‘parent.id’.  In 0.7, it is the less
surprising ‘child.id’.

The legacy of this behavior deals with behaviors and restrictions of the
ORM that don’t really apply anymore; all that was needed was to reverse
the order.

A primary advantage of this approach is that it’s now easier to
construct ‘primaryjoin’ expressions that refer to the local column:

     class Child(Parent):
        __tablename__ = 'child'
         id = Column(Integer, ForeignKey('parent.id'), primary_key=True)
         some_related = relationship("SomeRelated",
                         primaryjoin="Child.id==SomeRelated.child_id")

     class SomeRelated(Base):
        __tablename__ = 'some_related'
         id = Column(Integer, primary_key=True)
         child_id = Column(Integer, ForeignKey('child.id'))

Prior to 0.7 the ‘Child.id’ expression would reference ‘Parent.id’, and
it would be necessary to map ‘child.id’ to a distinct attribute.

It also means that a query like this one changes its behavior:

     session.query(Parent).filter(Child.id > 7)

In 0.6, this would render:

     SELECT parent.id AS parent_id
     FROM parent
     WHERE parent.id > :id_1

in 0.7, you get:

     SELECT parent.id AS parent_id
     FROM parent, child
     WHERE child.id > :id_1

which you’ll note is a cartesian product - this behavior is now
equivalent to that of any other attribute that is local to ‘Child’.  The
‘with_polymorphic()’ method, or a similar strategy of explicitly joining
the underlying ‘Table’ objects, is used to render a query against all
‘Parent’ objects with criteria against ‘Child’, in the same manner as
that of 0.5 and 0.6:

     print(s.query(Parent).with_polymorphic([Child]).filter(Child.id > 7))

Which on both 0.6 and 0.7 renders:

     SELECT parent.id AS parent_id, child.id AS child_id
     FROM parent LEFT OUTER JOIN child ON parent.id = child.id
     WHERE child.id > :id_1

Another effect of this change is that a joined-inheritance load across
two tables will populate from the child table’s value, not that of the
parent table.  An unusual case is that a query against “Parent” using
‘with_polymorphic="*"’ issues a query against “parent”, with a LEFT
OUTER JOIN to “child”.  The row is located in “Parent”, sees the
polymorphic identity corresponds to “Child”, but suppose the actual row
in “child” has been `deleted'.  Due to this corruption, the row comes in
with all the columns corresponding to “child” set to NULL - this is now
the value that gets populated, not the one in the parent table.

#1892(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1892

8.4.7.41 Mapping to joins with two or more same-named columns requires explicit declaration
...........................................................................................

This is somewhat related to the previous change in #1892(1).  When
mapping to a join, same-named columns must be explicitly linked to
mapped attributes, i.e.  as described in Mapping a Class Against
Multiple Tables(2).

Given two tables ‘foo’ and ‘bar’, each with a primary key column ‘id’,
the following now produces an error:

     foobar = foo.join(bar, foo.c.id==bar.c.foo_id)
     mapper(FooBar, foobar)

This because the ‘mapper()’ refuses to guess what column is the primary
representation of ‘FooBar.id’ - is it ‘foo.c.id’ or is it ‘bar.c.id’ ?
The attribute must be explicit:

     foobar = foo.join(bar, foo.c.id==bar.c.foo_id)
     mapper(FooBar, foobar, properties={
         'id':[foo.c.id, bar.c.id]
     })

#1896(3)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1892

   (2)
http://www.sqlalchemy.org/docs/07/orm/mapper_config.html#mapping-a-class-against-multiple-tables

   (3) http://www.sqlalchemy.org/trac/ticket/1896

8.4.7.42 Mapper requires that polymorphic_on column be present in the mapped selectable
.......................................................................................

This is a warning in 0.6, now an error in 0.7.  The column given for
‘polymorphic_on’ must be in the mapped selectable.  This to prevent some
occasional user errors such as:

     mapper(SomeClass, sometable, polymorphic_on=some_lookup_table.c.id)

where above the polymorphic_on needs to be on a ‘sometable’ column, in
this case perhaps ‘sometable.c.some_lookup_id’.  There are also some
“polymorphic union” scenarios where similar mistakes sometimes occur.

Such a configuration error has always been “wrong”, and the above
mapping doesn’t work as specified - the column would be ignored.  It is
however potentially backwards incompatible in the rare case that an
application has been unknowingly relying upon this behavior.

#1875(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1875

8.4.7.43 ‘DDL()’ constructs now escape percent signs
....................................................

Previously, percent signs in ‘DDL()’ strings would have to be escaped,
i.e.  ‘%%’ depending on DBAPI, for those DBAPIs that accept ‘pyformat’
or ‘format’ binds (i.e.  psycopg2, mysql-python), which was inconsistent
versus ‘text()’ constructs which did this automatically.  The same
escaping now occurs for ‘DDL()’ as for ‘text()’.

#1897(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1897

8.4.7.44 ‘Table.c’ / ‘MetaData.tables’ refined a bit, don’t allow direct mutation
.................................................................................

Another area where some users were tinkering around in such a way that
doesn’t actually work as expected, but still left an exceedingly small
chance that some application was relying upon this behavior, the
construct returned by the ‘.c’ attribute on ‘Table’ and the ‘.tables’
attribute on ‘MetaData’ is explicitly non-mutable.  The “mutable”
version of the construct is now private.  Adding columns to ‘.c’
involves using the ‘append_column()’ method of ‘Table’, which ensures
things are associated with the parent ‘Table’ in the appropriate way;
similarly, ‘MetaData.tables’ has a contract with the ‘Table’ objects
stored in this dictionary, as well as a little bit of new bookkeeping in
that a ‘set()’ of all schema names is tracked, which is satisfied only
by using the public ‘Table’ constructor as well as ‘Table.tometadata()’.

It is of course possible that the ‘ColumnCollection’ and ‘dict’
collections consulted by these attributes could someday implement events
on all of their mutational methods such that the appropriate bookkeeping
occurred upon direct mutation of the collections, but until someone has
the motivation to implement all that along with dozens of new unit
tests, narrowing the paths to mutation of these collections will ensure
no application is attempting to rely upon usages that are currently not
supported.

#1893(1) #1917(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1893

   (2) http://www.sqlalchemy.org/trac/ticket/1917

8.4.7.45 server_default consistently returns None for all inserted_primary_key values
.....................................................................................

Established consistency when server_default is present on an Integer PK
column.  SQLA doesn’t pre-fetch these, nor do they come back in
cursor.lastrowid (DBAPI). Ensured all backends consistently return None
in result.inserted_primary_key for these - some backends may have
returned a value previously.  Using a server_default on a primary key
column is extremely unusual.  If a special function or SQL expression is
used to generate primary key defaults, this should be established as a
Python-side “default” instead of server_default.

Regarding reflection for this case, reflection of an int PK col with a
server_default sets the “autoincrement” flag to False, except in the
case of a PG SERIAL col where we detected a sequence default.

#2020(1) #2021(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/2020

   (2) http://www.sqlalchemy.org/trac/ticket/2021

8.4.7.46 The ‘sqlalchemy.exceptions’ alias in sys.modules is removed
....................................................................

For a few years we’ve added the string ‘sqlalchemy.exceptions’ to
‘sys.modules’, so that a statement like “‘import sqlalchemy.exceptions’”
would work.  The name of the core exceptions module has been ‘exc’ for a
long time now, so the recommended import for this module is:

     from sqlalchemy import exc

The ‘exceptions’ name is still present in “‘sqlalchemy’” for
applications which might have said ‘from sqlalchemy import exceptions’,
but they should also start using the ‘exc’ name.

8.4.7.47 Query Timing Recipe Changes
....................................

While not part of SQLAlchemy itself, it’s worth mentioning that the
rework of the ‘ConnectionProxy’ into the new event system means it is no
longer appropriate for the “Timing all Queries” recipe.  Please adjust
query-timers to use the ‘before_cursor_execute()’ and
‘after_cursor_execute()’ events, demonstrated in the updated recipe
UsageRecipes/Profiling.

8.4.7.48 Deprecated API
.......................

8.4.7.49 Default constructor on types will not accept arguments
...............................................................

Simple types like ‘Integer’, ‘Date’ etc.  in the core types module don’t
accept arguments.  The default constructor that accepts/ignores a
catchall ‘\*args, \**kwargs’ is restored as of 0.7b4/0.7.0, but emits a
deprecation warning.

If arguments are being used with a core type like ‘Integer’, it may be
that you intended to use a dialect specific type, such as
‘sqlalchemy.dialects.mysql.INTEGER’ which does accept a “display_width”
argument for example.

8.4.7.50 compile_mappers() renamed configure_mappers(), simplified configuration internals
..........................................................................................

This system slowly morphed from something small, implemented local to an
individual mapper, and poorly named into something that’s more of a
global “registry-” level function and poorly named, so we’ve fixed both
by moving the implementation out of ‘Mapper’ altogether and renaming it
to ‘configure_mappers()’.  It is of course normally not needed for an
application to call ‘configure_mappers()’ as this process occurs on an
as-needed basis, as soon as the mappings are needed via attribute or
query access.

#1966(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1966

8.4.7.51 Core listener/proxy superseded by event listeners
..........................................................

‘PoolListener’, ‘ConnectionProxy’, ‘DDLElement.execute_at’ are
superseded by ‘event.listen()’, using the ‘PoolEvents’, ‘EngineEvents’,
‘DDLEvents’ dispatch targets, respectively.

8.4.7.52 ORM extensions superseded by event listeners
.....................................................

‘MapperExtension’, ‘AttributeExtension’, ‘SessionExtension’ are
superseded by ‘event.listen()’, using the
‘MapperEvents’/‘InstanceEvents’, ‘AttributeEvents’, ‘SessionEvents’,
dispatch targets, respectively.

8.4.7.53 Sending a string to ‘distinct’ in select() for MySQL should be done via prefixes
.........................................................................................

This obscure feature allows this pattern with the MySQL backend:

     select([mytable], distinct='ALL', prefixes=['HIGH_PRIORITY'])

The ‘prefixes’ keyword or ‘prefix_with()’ method should be used for
non-standard or unusual prefixes:

     select([mytable]).prefix_with('HIGH_PRIORITY', 'ALL')

8.4.7.54 ‘useexisting’ superseded by ‘extend_existing’ and ‘keep_existing’
..........................................................................

The ‘useexisting’ flag on Table has been superseded by a new pair of
flags ‘keep_existing’ and ‘extend_existing’.  ‘extend_existing’ is
equivalent to ‘useexisting’ - the existing Table is returned, and
additional constructor elements are added.  With ‘keep_existing’, the
existing Table is returned, but additional constructor elements are not
added - these elements are only applied when the Table is newly created.

8.4.7.55 Backwards Incompatible API Changes
...........................................

8.4.7.56 Callables passed to ‘bindparam()’ don’t get evaluated - affects the Beaker example
...........................................................................................

#1950(1)

Note this affects the Beaker caching example, where the workings of the
‘_params_from_query()’ function needed a slight adjustment.  If you’re
using code from the Beaker example, this change should be applied.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1950

8.4.7.57 types.type_map is now private, types._type_map
.......................................................

We noticed some users tapping into this dictionary inside of
‘sqlalchemy.types’ as a shortcut to associating Python types with SQL
types.  We can’t guarantee the contents or format of this dictionary,
and additionally the business of associating Python types in a
one-to-one fashion has some grey areas that should are best decided by
individual applications, so we’ve underscored this attribute.

#1870(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1870

8.4.7.58 Renamed the ‘alias’ keyword arg of standalone ‘alias()’ function to ‘name’
...................................................................................

This so that the keyword argument ‘name’ matches that of the ‘alias()’
methods on all ‘FromClause’ objects as well as the ‘name’ argument on
‘Query.subquery()’.

Only code that uses the standalone ‘alias()’ function, and not the
method bound functions, and passes the alias name using the explicit
keyword name ‘alias’, and not positionally, would need modification
here.

8.4.7.59 Non-public ‘Pool’ methods underscored
..............................................

All methods of ‘Pool’ and subclasses which are not intended for public
use have been renamed with underscores.  That they were not named this
way previously was a bug.

Pooling methods now underscored or removed:

‘Pool.create_connection()’ -> ‘Pool._create_connection()’

‘Pool.do_get()’ -> ‘Pool._do_get()’

‘Pool.do_return_conn()’ -> ‘Pool._do_return_conn()’

‘Pool.do_return_invalid()’ -> removed, was not used

‘Pool.return_conn()’ -> ‘Pool._return_conn()’

‘Pool.get()’ -> ‘Pool._get()’, public API is ‘Pool.connect()’

‘SingletonThreadPool.cleanup()’ -> ‘_cleanup()’

‘SingletonThreadPool.dispose_local()’ -> removed, use
‘conn.invalidate()’

#1982(1)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1982

8.4.7.60 Previously Deprecated, Now Removed
...........................................

8.4.7.61 Query.join(), Query.outerjoin(), eagerload(), eagerload_all(), others no longer allow lists of attributes as arguments
...............................................................................................................................

Passing a list of attributes or attribute names to ‘Query.join’,
‘eagerload()’, and similar has been deprecated since 0.5:

     # old way, deprecated since 0.5
     session.query(Houses).join([Houses.rooms, Room.closets])
     session.query(Houses).options(eagerload_all([Houses.rooms, Room.closets]))

These methods all accept *args as of the 0.5 series:

     # current way, in place since 0.5
     session.query(Houses).join(Houses.rooms, Room.closets)
     session.query(Houses).options(eagerload_all(Houses.rooms, Room.closets))

8.4.7.62 ‘ScopedSession.mapper’ is removed
..........................................

This feature provided a mapper extension which linked class- based
functionality with a particular ‘ScopedSession’, in particular providing
the behavior such that new object instances would be automatically
associated with that session.  The feature was overused by tutorials and
frameworks which led to great user confusion due to its implicit
behavior, and was deprecated in 0.5.5.  Techniques for replicating its
functionality are at [wiki:UsageRecipes/SessionAwareMapper]

8.4.8 What’s New in SQLAlchemy 0.6?
-----------------------------------

     About this Document: This document describes changes between
     SQLAlchemy version 0.5, last released January 16, 2010, and
     SQLAlchemy version 0.6, last released May 5, 2012.

     Document date: June 6, 2010

This guide documents API changes which affect users migrating their
applications from the 0.5 series of SQLAlchemy to 0.6.  Note that
SQLAlchemy 0.6 removes some behaviors which were deprecated throughout
the span of the 0.5 series, and also deprecates more behaviors specific
to 0.5.

8.4.8.1 Platform Support
........................

   * cPython versions 2.4 and upwards throughout the 2.xx series

   * Jython 2.5.1 - using the zxJDBC DBAPI included with Jython.

   * cPython 3.x - see [source:sqlalchemy/trunk/README.py3k] for
     information on how to build for python3.

8.4.8.2 New Dialect System
..........................

Dialect modules are now broken up into distinct subcomponents, within
the scope of a single database backend.  Dialect implementations are now
in the ‘sqlalchemy.dialects’ package.  The ‘sqlalchemy.databases’
package still exists as a placeholder to provide some level of backwards
compatibility for simple imports.

For each supported database, a sub-package exists within
‘sqlalchemy.dialects’ where several files are contained.  Each package
contains a module called ‘base.py’ which defines the specific SQL
dialect used by that database.  It also contains one or more “driver”
modules, each one corresponding to a specific DBAPI - these files are
named corresponding to the DBAPI itself, such as ‘pysqlite’,
‘cx_oracle’, or ‘pyodbc’.  The classes used by SQLAlchemy dialects are
first declared in the ‘base.py’ module, defining all behavioral
characteristics defined by the database.  These include capability
mappings, such as “supports sequences”, “supports returning”, etc., type
definitions, and SQL compilation rules.  Each “driver” module in turn
provides subclasses of those classes as needed which override the
default behavior to accommodate the additional features, behaviors, and
quirks of that DBAPI. For DBAPIs that support multiple backends (pyodbc,
zxJDBC, mxODBC), the dialect module will use mixins from the
‘sqlalchemy.connectors’ package, which provide functionality common to
that DBAPI across all backends, most typically dealing with connect
arguments.  This means that connecting using pyodbc, zxJDBC or mxODBC
(when implemented) is extremely consistent across supported backends.

The URL format used by ‘create_engine()’ has been enhanced to handle any
number of DBAPIs for a particular backend, using a scheme that is
inspired by that of JDBC. The previous format still works, and will
select a “default” DBAPI implementation, such as the PostgreSQL URL
below that will use psycopg2:

     create_engine('postgresql://scott:tiger@localhost/test')

However to specify a specific DBAPI backend such as pg8000, add it to
the “protocol” section of the URL using a plus sign “+”:

     create_engine('postgresql+pg8000://scott:tiger@localhost/test')

Important Dialect Links:

   * Documentation on connect arguments:
     ‘http://www.sqlalchemy.org/docs/06/dbengine.html#create’-
     engine-url-arguments.

   * Reference documentation for individual dialects: ‘http://ww’
     w.sqlalchemy.org/docs/06/reference/dialects/index.html

   * The tips and tricks at DatabaseNotes.

Other notes regarding dialects:

   * the type system has been changed dramatically in SQLAlchemy 0.6.
     This has an impact on all dialects regarding naming conventions,
     behaviors, and implementations.  See the section on “Types” below.

   * the ‘ResultProxy’ object now offers a 2x speed improvement in some
     cases thanks to some refactorings.

   * the ‘RowProxy’, i.e.  individual result row object, is now directly
     pickleable.

   * the setuptools entrypoint used to locate external dialects is now
     called ‘sqlalchemy.dialects’.  An external dialect written against
     0.4 or 0.5 will need to be modified to work with 0.6 in any case so
     this change does not add any additional difficulties.

   * dialects now receive an initialize() event on initial connection to
     determine connection properties.

   * Functions and operators generated by the compiler now use (almost)
     regular dispatch functions of the form “visit_<opname>” and
     “visit_<funcname>_fn” to provide customed processing.  This
     replaces the need to copy the “functions” and “operators”
     dictionaries in compiler subclasses with straightforward visitor
     methods, and also allows compiler subclasses complete control over
     rendering, as the full _Function or _BinaryExpression object is
     passed in.

8.4.8.3 Dialect Imports
.......................

The import structure of dialects has changed.  Each dialect now exports
its base “dialect” class as well as the full set of SQL types supported
on that dialect via ‘sqlalchemy.dialects.<name>’.  For example, to
import a set of PG types:

     from sqlalchemy.dialects.postgresql import INTEGER, BIGINT, SMALLINT,\
                                                 VARCHAR, MACADDR, DATE, BYTEA

Above, ‘INTEGER’ is actually the plain ‘INTEGER’ type from
‘sqlalchemy.types’, but the PG dialect makes it available in the same
way as those types which are specific to PG, such as ‘BYTEA’ and
‘MACADDR’.

8.4.8.4 Expression Language Changes
...................................

8.4.8.5 An Important Expression Language Gotcha
...............................................

There’s one quite significant behavioral change to the expression
language which may affect some applications.  The boolean value of
Python boolean expressions, i.e.  ‘==’, ‘!=’, and similar, now evaluates
accurately with regards to the two clause objects being compared.

As we know, comparing a ‘ClauseElement’ to any other object returns
another ‘ClauseElement’:

     >>> from sqlalchemy.sql import column
     >>> column('foo') == 5
     <sqlalchemy.sql.expression._BinaryExpression object at 0x1252490>

This so that Python expressions produce SQL expressions when converted
to strings:

     >>> str(column('foo') == 5)
     'foo = :foo_1'

But what happens if we say this?

     >>> if column('foo') == 5:
     ...     print("yes")
     ...

In previous versions of SQLAlchemy, the returned ‘_BinaryExpression’ was
a plain Python object which evaluated to ‘True’.  Now it evaluates to
whether or not the actual ‘ClauseElement’ should have the same hash
value as to that being compared.  Meaning:

     >>> bool(column('foo') == 5)
     False
     >>> bool(column('foo') == column('foo'))
     False
     >>> c = column('foo')
     >>> bool(c == c)
     True
     >>>

That means code such as the following:

     if expression:
         print("the expression is:", expression)

Would not evaluate if ‘expression’ was a binary clause.  Since the above
pattern should never be used, the base ‘ClauseElement’ now raises an
exception if called in a boolean context:

     >>> bool(c)
     Traceback (most recent call last):
       File "<stdin>", line 1, in <module>
       ...
         raise TypeError("Boolean value of this clause is not defined")
     TypeError: Boolean value of this clause is not defined

Code that wants to check for the presence of a ‘ClauseElement’
expression should instead say:

     if expression is not None:
         print("the expression is:", expression)

Keep in mind, `this applies to Table and Column objects too'.

The rationale for the change is twofold:

   * Comparisons of the form ‘if c1 == c2: <do something>’ can actually
     be written now

   * Support for correct hashing of ‘ClauseElement’ objects now works on
     alternate platforms, namely Jython.  Up until this point SQLAlchemy
     relied heavily on the specific behavior of cPython in this regard
     (and still had occasional problems with it).

8.4.8.6 Stricter “executemany” Behavior
.......................................

An “executemany” in SQLAlchemy corresponds to a call to ‘execute()’,
passing along a collection of bind parameter sets:

     connection.execute(table.insert(), {'data':'row1'}, {'data':'row2'}, {'data':'row3'})

When the ‘Connection’ object sends off the given ‘insert()’ construct
for compilation, it passes to the compiler the keynames present in the
first set of binds passed along to determine the construction of the
statement’s VALUES clause.  Users familiar with this construct will know
that additional keys present in the remaining dictionaries don’t have
any impact.  What’s different now is that all subsequent dictionaries
need to include at least `every' key that is present in the first
dictionary.  This means that a call like this no longer works:

     connection.execute(table.insert(),
                             {'timestamp':today, 'data':'row1'},
                             {'timestamp':today, 'data':'row2'},
                             {'data':'row3'})

Because the third row does not specify the ‘timestamp’ column.  Previous
versions of SQLAlchemy would simply insert NULL for these missing
columns.  However, if the ‘timestamp’ column in the above example
contained a Python-side default value or function, it would `not' be
used.  This because the “executemany” operation is optimized for maximum
performance across huge numbers of parameter sets, and does not attempt
to evaluate Python-side defaults for those missing keys.  Because
defaults are often implemented either as SQL expressions which are
embedded inline with the INSERT statement, or are server side
expressions which again are triggered based on the structure of the
INSERT string, which by definition cannot fire off conditionally based
on each parameter set, it would be inconsistent for Python side defaults
to behave differently vs.  SQL/server side defaults.  (SQL expression
based defaults are embedded inline as of the 0.5 series, again to
minimize the impact of huge numbers of parameter sets).

SQLAlchemy 0.6 therefore establishes predictable consistency by
forbidding any subsequent parameter sets from leaving any fields blank.
That way, there’s no more silent failure of Python side default values
and functions, which additionally are allowed to remain consistent in
their behavior versus SQL and server side defaults.

8.4.8.7 UNION and other “compound” constructs parenthesize consistently
.......................................................................

A rule that was designed to help SQLite has been removed, that of the
first compound element within another compound (such as, a ‘union()’
inside of an ‘except_()’) wouldn’t be parenthesized.  This is
inconsistent and produces the wrong results on PostgreSQL, which has
precedence rules regarding INTERSECTION, and its generally a surprise.
When using complex composites with SQLite, you now need to turn the
first element into a subquery (which is also compatible on PG). A new
example is in the SQL expression tutorial at the end of
[‘http://www.sqlalchemy.org/docs/06/sqlexpression.html’
#unions-and-other-set-operations].  See #1665(1) and r6690 for more
background.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/trac/ticket/1665

8.4.8.8 C Extensions for Result Fetching
........................................

The ‘ResultProxy’ and related elements, including most common “row
processing” functions such as unicode conversion, numerical/boolean
conversions and date parsing, have been re-implemented as optional C
extensions for the purposes of performance.  This represents the
beginning of SQLAlchemy’s path to the “dark side” where we hope to
continue improving performance by reimplementing critical sections in C.
The extensions can be built by specifying ‘--with-cextensions’, i.e.
‘python setup.py --with- cextensions install’.

The extensions have the most dramatic impact on result fetching using
direct ‘ResultProxy’ access, i.e.  that which is returned by
‘engine.execute()’, ‘connection.execute()’, or ‘session.execute()’.
Within results returned by an ORM ‘Query’ object, result fetching is not
as high a percentage of overhead, so ORM performance improves more
modestly, and mostly in the realm of fetching large result sets.  The
performance improvements highly depend on the dbapi in use and on the
syntax used to access the columns of each row (eg ‘row['name']’ is much
faster than ‘row.name’).  The current extensions have no impact on the
speed of inserts/updates/deletes, nor do they improve the latency of SQL
execution, that is, an application that spends most of its time
executing many statements with very small result sets will not see much
improvement.

Performance has been improved in 0.6 versus 0.5 regardless of the
extensions.  A quick overview of what connecting and fetching 50,000
rows looks like with SQLite, using mostly direct SQLite access, a
‘ResultProxy’, and a simple mapped ORM object:

     sqlite select/native: 0.260s

     0.6 / C extension

     sqlalchemy.sql select: 0.360s
     sqlalchemy.orm fetch: 2.500s

     0.6 / Pure Python

     sqlalchemy.sql select: 0.600s
     sqlalchemy.orm fetch: 3.000s

     0.5 / Pure Python

     sqlalchemy.sql select: 0.790s
     sqlalchemy.orm fetch: 4.030s

Above, the ORM fetches the rows 33% faster than 0.5 due to in-python
performance enhancements.  With the C extensions we get another 20%.
However, ‘ResultProxy’ fetches improve by 67% with the C extension
versus not.  Other tests report as much as a 200% speed improvement for
some scenarios, such as those where lots of string conversions are
occurring.

8.4.8.9 New Schema Capabilities
...............................

The ‘sqlalchemy.schema’ package has received some long- needed
attention.  The most visible change is the newly expanded DDL system.
In SQLAlchemy, it was possible since version 0.5 to create custom DDL
strings and associate them with tables or metadata objects:

     from sqlalchemy.schema import DDL

     DDL('CREATE TRIGGER users_trigger ...').execute_at('after-create', metadata)

Now the full suite of DDL constructs are available under the same
system, including those for CREATE TABLE, ADD CONSTRAINT, etc.:

     from sqlalchemy.schema import Constraint, AddConstraint

     AddContraint(CheckConstraint("value > 5")).execute_at('after-create', mytable)

Additionally, all the DDL objects are now regular ‘ClauseElement’
objects just like any other SQLAlchemy expression object:

     from sqlalchemy.schema import CreateTable

     create = CreateTable(mytable)

     # dumps the CREATE TABLE as a string
     print(create)

     # executes the CREATE TABLE statement
     engine.execute(create)

and using the ‘sqlalchemy.ext.compiler’ extension you can make your own:

     from sqlalchemy.schema import DDLElement
     from sqlalchemy.ext.compiler import compiles

     class AlterColumn(DDLElement):

         def __init__(self, column, cmd):
             self.column = column
             self.cmd = cmd

     @compiles(AlterColumn)
     def visit_alter_column(element, compiler, **kw):
         return "ALTER TABLE %s ALTER COLUMN %s %s ..." % (
             element.column.table.name,
             element.column.name,
             element.cmd
         )

     engine.execute(AlterColumn(table.c.mycolumn, "SET DEFAULT 'test'"))

8.4.8.10 Deprecated/Removed Schema Elements
...........................................

The schema package has also been greatly streamlined.  Many options and
methods which were deprecated throughout 0.5 have been removed.  Other
little known accessors and methods have also been removed.

   * the “owner” keyword argument is removed from ‘Table’.  Use “schema”
     to represent any namespaces to be prepended to the table name.

   * deprecated ‘MetaData.connect()’ and ‘ThreadLocalMetaData.connect()’
     have been removed - send the “bind” attribute to bind a metadata.

   * deprecated metadata.table_iterator() method removed (use
     sorted_tables)

   * the “metadata” argument is removed from ‘DefaultGenerator’ and
     subclasses, but remains locally present on ‘Sequence’, which is a
     standalone construct in DDL.

   * deprecated ‘PassiveDefault’ - use ‘DefaultClause’.

   * Removed public mutability from ‘Index’ and ‘Constraint’ objects:

        * ‘ForeignKeyConstraint.append_element()’

        * ‘Index.append_column()’

        * ‘UniqueConstraint.append_column()’

        * ‘PrimaryKeyConstraint.add()’

        * ‘PrimaryKeyConstraint.remove()’

These should be constructed declaratively (i.e.  in one construction).

   * Other removed things:

        * ‘Table.key’ (no idea what this was for)

        * ‘Column.bind’ (get via column.table.bind)

        * ‘Column.metadata’ (get via column.table.metadata)

        * ‘Column.sequence’ (use column.default)

8.4.8.11 Other Behavioral Changes
.................................

   * ‘UniqueConstraint’, ‘Index’, ‘PrimaryKeyConstraint’ all accept
     lists of column names or column objects as arguments.

   * The ‘use_alter’ flag on ‘ForeignKey’ is now a shortcut option for
     operations that can be hand-constructed using the ‘DDL()’ event
     system.  A side effect of this refactor is that
     ‘ForeignKeyConstraint’ objects with ‘use_alter=True’ will `not' be
     emitted on SQLite, which does not support ALTER for foreign keys.
     This has no effect on SQLite’s behavior since SQLite does not
     actually honor FOREIGN KEY constraints.

   * ‘Table.primary_key’ is not assignable - use
     ‘table.append_constraint(PrimaryKeyConstraint(...))’

   * A ‘Column’ definition with a ‘ForeignKey’ and no type, e.g.
     ‘Column(name, ForeignKey(sometable.c.somecol))’ used to get the
     type of the referenced column.  Now support for that automatic type
     inference is partial and may not work in all cases.

8.4.8.12 Logging opened up
..........................

At the expense of a few extra method calls here and there, you can set
log levels for INFO and DEBUG after an engine, pool, or mapper has been
created, and logging will commence.  The ‘isEnabledFor(INFO)’ method is
now called per-‘Connection’ and ‘isEnabledFor(DEBUG)’ per-‘ResultProxy’
if already enabled on the parent connection.  Pool logging sends to
‘log.info()’ and ‘log.debug()’ with no check - note that pool
checkout/checkin is typically once per transaction.

8.4.8.13 Reflection/Inspector API
.................................

The reflection system, which allows reflection of table columns via
‘Table('sometable', metadata, autoload=True)’ has been opened up into
its own fine-grained API, which allows direct inspection of database
elements such as tables, columns, constraints, indexes, and more.  This
API expresses return values as simple lists of strings, dictionaries,
and ‘TypeEngine’ objects.  The internals of ‘autoload=True’ now build
upon this system such that the translation of raw database information
into ‘sqlalchemy.schema’ constructs is centralized and the contract of
individual dialects greatly simplified, vastly reducing bugs and
inconsistencies across different backends.

To use an inspector:

     from sqlalchemy.engine.reflection import Inspector
     insp = Inspector.from_engine(my_engine)

     print(insp.get_schema_names())

the ‘from_engine()’ method will in some cases provide a backend-specific
inspector with additional capabilities, such as that of PostgreSQL which
provides a ‘get_table_oid()’ method:

     my_engine = create_engine('postgresql://...')
     pg_insp = Inspector.from_engine(my_engine)

     print(pg_insp.get_table_oid('my_table'))

8.4.8.14 RETURNING Support
..........................

The ‘insert()’, ‘update()’ and ‘delete()’ constructs now support a
‘returning()’ method, which corresponds to the SQL RETURNING clause as
supported by PostgreSQL, Oracle, MS-SQL, and Firebird.  It is not
supported for any other backend at this time.

Given a list of column expressions in the same manner as that of a
‘select()’ construct, the values of these columns will be returned as a
regular result set:

     result = connection.execute(
                 table.insert().values(data='some data').returning(table.c.id, table.c.timestamp)
             )
     row = result.first()
     print("ID:", row['id'], "Timestamp:", row['timestamp'])

The implementation of RETURNING across the four supported backends
varies wildly, in the case of Oracle requiring an intricate usage of OUT
parameters which are re-routed into a “mock” result set, and in the case
of MS-SQL using an awkward SQL syntax.  The usage of RETURNING is
subject to limitations:

   * it does not work for any “executemany()” style of execution.  This
     is a limitation of all supported DBAPIs.

   * Some backends, such as Oracle, only support RETURNING that returns
     a single row - this includes UPDATE and DELETE statements, meaning
     the update() or delete() construct must match only a single row, or
     an error is raised (by Oracle, not SQLAlchemy).

RETURNING is also used automatically by SQLAlchemy, when available and
when not otherwise specified by an explicit ‘returning()’ call, to fetch
the value of newly generated primary key values for single-row INSERT
statements.  This means there’s no more “SELECT nextval(sequence)” pre-
execution for insert statements where the primary key value is required.
Truth be told, implicit RETURNING feature does incur more method
overhead than the old “select nextval()” system, which used a quick and
dirty cursor.execute() to get at the sequence value, and in the case of
Oracle requires additional binding of out parameters.  So if
method/protocol overhead is proving to be more expensive than additional
database round trips, the feature can be disabled by specifying
‘implicit_returning=False’ to ‘create_engine()’.

8.4.8.15 Type System Changes
............................

8.4.8.16 New Architecture
.........................

The type system has been completely reworked behind the scenes to
provide two goals:

   * Separate the handling of bind parameters and result row values,
     typically a DBAPI requirement, from the SQL specification of the
     type itself, which is a database requirement.  This is consistent
     with the overall dialect refactor that separates database SQL
     behavior from DBAPI.

   * Establish a clear and consistent contract for generating DDL from a
     ‘TypeEngine’ object and for constructing ‘TypeEngine’ objects based
     on column reflection.

Highlights of these changes include:

   * The construction of types within dialects has been totally
     overhauled.  Dialects now define publicly available types as
     UPPERCASE names exclusively, and internal implementation types
     using underscore identifiers (i.e.  are private).  The system by
     which types are expressed in SQL and DDL has been moved to the
     compiler system.  This has the effect that there are much fewer
     type objects within most dialects.  A detailed document on this
     architecture for dialect authors is in [source:/lib/sqlalc
     hemy/dialects/type_migration_guidelines.txt].

   * Reflection of types now returns the exact UPPERCASE type within
     types.py, or the UPPERCASE type within the dialect itself if the
     type is not a standard SQL type.  This means reflection now returns
     more accurate information about reflected types.

   * User defined types that subclass ‘TypeEngine’ and wish to provide
     ‘get_col_spec()’ should now subclass ‘UserDefinedType’.

   * The ‘result_processor()’ method on all type classes now accepts an
     additional argument ‘coltype’.  This is the DBAPI type object
     attached to cursor.description, and should be used when applicable
     to make better decisions on what kind of result-processing callable
     should be returned.  Ideally result processor functions would never
     need to use ‘isinstance()’, which is an expensive call at this
     level.

8.4.8.17 Native Unicode Mode
............................

As more DBAPIs support returning Python unicode objects directly, the
base dialect now performs a check upon the first connection which
establishes whether or not the DBAPI returns a Python unicode object for
a basic select of a VARCHAR value.  If so, the ‘String’ type and all
subclasses (i.e.  ‘Text’, ‘Unicode’, etc.)  will skip the “unicode”
check/conversion step when result rows are received.  This offers a
dramatic performance increase for large result sets.  The “unicode mode”
currently is known to work with:

   * sqlite3 / pysqlite

   * psycopg2 - SQLA 0.6 now uses the “UNICODE” type extension by
     default on each psycopg2 connection object

   * pg8000

   * cx_oracle (we use an output processor - nice feature !)

Other types may choose to disable unicode processing as needed, such as
the ‘NVARCHAR’ type when used with MS-SQL.

In particular, if porting an application based on a DBAPI that formerly
returned non-unicode strings, the “native unicode” mode has a plainly
different default behavior - columns that are declared as ‘String’ or
‘VARCHAR’ now return unicode by default whereas they would return
strings before.  This can break code which expects non-unicode strings.
The psycopg2 “native unicode” mode can be disabled by passing
‘use_native_unicode=False’ to ‘create_engine()’.

A more general solution for string columns that explicitly do not want a
unicode object is to use a ‘TypeDecorator’ that converts unicode back to
utf-8, or whatever is desired:

     class UTF8Encoded(TypeDecorator):
         """Unicode type which coerces to utf-8."""

         impl = sa.VARCHAR

         def process_result_value(self, value, dialect):
             if isinstance(value, unicode):
                 value = value.encode('utf-8')
             return value

Note that the ‘assert_unicode’ flag is now deprecated.  SQLAlchemy
allows the DBAPI and backend database in use to handle Unicode
parameters when available, and does not add operational overhead by
checking the incoming type; modern systems like sqlite and PostgreSQL
will raise an encoding error on their end if invalid data is passed.  In
those cases where SQLAlchemy does need to coerce a bind parameter from
Python Unicode to an encoded string, or when the Unicode type is used
explicitly, a warning is raised if the object is a bytestring.  This
warning can be suppressed or converted to an exception using the Python
warnings filter documented at:
‘http://docs.python.org/library/warnings.html’

8.4.8.18 Generic Enum Type
..........................

We now have an ‘Enum’ in the ‘types’ module.  This is a string type that
is given a collection of “labels” which constrain the possible values
given to those labels.  By default, this type generates a ‘VARCHAR’
using the size of the largest label, and applies a CHECK constraint to
the table within the CREATE TABLE statement.  When using MySQL, the type
by default uses MySQL’s ENUM type, and when using PostgreSQL the type
will generate a user defined type using ‘CREATE TYPE <mytype> AS ENUM’.
In order to create the type using PostgreSQL, the ‘name’ parameter must
be specified to the constructor.  The type also accepts a
‘native_enum=False’ option which will issue the VARCHAR/CHECK strategy
for all databases.  Note that PostgreSQL ENUM types currently don’t work
with pg8000 or zxjdbc.

8.4.8.19 Reflection Returns Dialect-Specific Types
..................................................

Reflection now returns the most specific type possible from the
database.  That is, if you create a table using ‘String’, then reflect
it back, the reflected column will likely be ‘VARCHAR’.  For dialects
that support a more specific form of the type, that’s what you’ll get.
So a ‘Text’ type would come back as ‘oracle.CLOB’ on Oracle, a
‘LargeBinary’ might be an ‘mysql.MEDIUMBLOB’ etc.  The obvious advantage
here is that reflection preserves as much information possible from what
the database had to say.

Some applications that deal heavily in table metadata may wish to
compare types across reflected tables and/or non- reflected tables.
There’s a semi-private accessor available on ‘TypeEngine’ called
‘_type_affinity’ and an associated comparison helper
‘_compare_type_affinity’.  This accessor returns the “generic” ‘types’
class which the type corresponds to:

     >>> String(50)._compare_type_affinity(postgresql.VARCHAR(50))
     True
     >>> Integer()._compare_type_affinity(mysql.REAL)
     False

8.4.8.20 Miscellaneous API Changes
..................................

The usual “generic” types are still the general system in use, i.e.
‘String’, ‘Float’, ‘DateTime’.  There’s a few changes there:

   * Types no longer make any guesses as to default parameters.  In
     particular, ‘Numeric’, ‘Float’, as well as subclasses NUMERIC,
     FLOAT, DECIMAL don’t generate any length or scale unless specified.
     This also continues to include the controversial ‘String’ and
     ‘VARCHAR’ types (although MySQL dialect will pre-emptively raise
     when asked to render VARCHAR with no length).  No defaults are
     assumed, and if they are used in a CREATE TABLE statement, an error
     will be raised if the underlying database does not allow
     non-lengthed versions of these types.

   * the ‘Binary’ type has been renamed to ‘LargeBinary’, for
     BLOB/BYTEA/similar types.  For ‘BINARY’ and ‘VARBINARY’, those are
     present directly as ‘types.BINARY’, ‘types.VARBINARY’, as well as
     in the MySQL and MS-SQL dialects.

   * ‘PickleType’ now uses == for comparison of values when
     mutable=True, unless the “comparator” argument with a comparison
     function is specified to the type.  If you are pickling a custom
     object you should implement an ‘__eq__()’ method so that
     value-based comparisons are accurate.

   * The default “precision” and “scale” arguments of Numeric and Float
     have been removed and now default to None.  NUMERIC and FLOAT will
     be rendered with no numeric arguments by default unless these
     values are provided.

   * DATE, TIME and DATETIME types on SQLite can now take optional
     “storage_format” and “regexp” argument.  “storage_format” can be
     used to store those types using a custom string format.  “regexp”
     allows to use a custom regular expression to match string values
     from the database.

   * ‘__legacy_microseconds__’ on SQLite ‘Time’ and ‘DateTime’ types is
     not supported anymore.  You should use the new “storage_format”
     argument instead.

   * ‘DateTime’ types on SQLite now use by a default a stricter regular
     expression to match strings from the database.  Use the new
     “regexp” argument if you are using data stored in a legacy format.

8.4.8.21 ORM Changes
....................

Upgrading an ORM application from 0.5 to 0.6 should require little to no
changes, as the ORM’s behavior remains almost identical.  There are some
default argument and name changes, and some loading behaviors have been
improved.

8.4.8.22 New Unit of Work
.........................

The internals for the unit of work, primarily ‘topological.py’ and
‘unitofwork.py’, have been completely rewritten and are vastly
simplified.  This should have no impact on usage, as all existing
behavior during flush has been maintained exactly (or at least, as far
as it is exercised by our testsuite and the handful of production
environments which have tested it heavily).  The performance of flush()
now uses 20-30% fewer method calls and should also use less memory.  The
intent and flow of the source code should now be reasonably easy to
follow, and the architecture of the flush is fairly open-ended at this
point, creating room for potential new areas of sophistication.  The
flush process no longer has any reliance on recursion so flush plans of
arbitrary size and complexity can be flushed.  Additionally, the
mapper’s “save” process, which issues INSERT and UPDATE statements, now
caches the “compiled” form of the two statements so that callcounts are
further dramatically reduced with very large flushes.

Any changes in behavior observed with flush versus earlier versions of
0.6 or 0.5 should be reported to us ASAP - we’ll make sure no
functionality is lost.

8.4.8.23 Changes to ‘query.update()’ and ‘query.delete()’
.........................................................

   * the ‘expire’ option on query.update() has been renamed to ‘fetch’,
     thus matching that of query.delete()

   * ‘query.update()’ and ‘query.delete()’ both default to ‘evaluate’
     for the synchronize strategy.

   * the ‘synchronize’ strategy for update() and delete() raises an
     error on failure.  There is no implicit fallback onto “fetch”.
     Failure of evaluation is based on the structure of criteria, so
     success/failure is deterministic based on code structure.

8.4.8.24 ‘relation()’ is officially named ‘relationship()’
..........................................................

This to solve the long running issue that “relation” means a “table or
derived table” in relational algebra terms.  The ‘relation()’ name,
which is less typing, will hang around for the foreseeable future so
this change should be entirely painless.

8.4.8.25 Subquery eager loading
...............................

A new kind of eager loading is added called “subquery” loading.  This is
a load that emits a second SQL query immediately after the first which
loads full collections for all the parents in the first query, joining
upwards to the parent using INNER JOIN. Subquery loading is used
similarly to the current joined-eager loading, using the
‘`subqueryload()``’ and ‘``subqueryload_all()``’ options as well as the
‘``lazy='subquery'``’ setting on ‘``relationship()`’.  The subquery load
is usually much more efficient for loading many larger collections as it
uses INNER JOIN unconditionally and also doesn’t re-load parent rows.

8.4.8.26 ‘`eagerload()``’, ‘``eagerload_all()``’ is now ‘``joinedload()``’, ‘``joinedload_all()`’
.................................................................................................

To make room for the new subquery load feature, the existing
‘`eagerload()``’/‘``eagerload_all()``’ options are now superseded by
‘``joinedload()``’ and ‘``joinedload_all()``’.  The old names will hang
around for the foreseeable future just like ‘``relation()`’.

8.4.8.27 ‘`lazy=False|None|True|'dynamic'``’ now accepts ‘``lazy='noload'|'joined'|'subquery'|'select'|'dynamic'`’
..................................................................................................................

Continuing on the theme of loader strategies opened up, the standard
keywords for the ‘`lazy``’ option on ‘``relationship()``’ are now
‘``select``’ for lazy loading (via a SELECT issued on attribute access),
‘``joined``’ for joined-eager loading, ‘``subquery``’ for subquery-eager
loading, ‘``noload``’ for no loading should occur, and ‘``dynamic``’ for
a “dynamic” relationship.  The old ‘``True``’, ‘``False``’, ‘``None`’
arguments are still accepted with the identical behavior as before.

8.4.8.28 innerjoin=True on relation, joinedload
...............................................

Joined-eagerly loaded scalars and collections can now be instructed to
use INNER JOIN instead of OUTER JOIN. On PostgreSQL this is observed to
provide a 300-600% speedup on some queries.  Set this flag for any
many-to-one which is on a NOT NULLable foreign key, and similarly for
any collection where related items are guaranteed to exist.

At mapper level:

     mapper(Child, child)
     mapper(Parent, parent, properties={
         'child':relationship(Child, lazy='joined', innerjoin=True)
     })

At query time level:

     session.query(Parent).options(joinedload(Parent.child, innerjoin=True)).all()

The ‘innerjoin=True’ flag at the ‘relationship()’ level will also take
effect for any ‘joinedload()’ option which does not override the value.

8.4.8.29 Many-to-one Enhancements
.................................

   * many-to-one relations now fire off a lazyload in fewer cases,
     including in most cases will not fetch the “old” value when a new
     one is replaced.

   * many-to-one relation to a joined-table subclass now uses get() for
     a simple load (known as the “use_get” condition), i.e.
     ‘Related’->‘‘Sub(Base)‘‘, without the need to redefine the
     primaryjoin condition in terms of the base table.  [ticket:1186]

   * specifying a foreign key with a declarative column, i.e.
     ‘ForeignKey(MyRelatedClass.id)’ doesn’t break the “use_get”
     condition from taking place [ticket:1492]

   * relationship(), joinedload(), and joinedload_all() now feature an
     option called “innerjoin”.  Specify ‘True’ or ‘False’ to control
     whether an eager join is constructed as an INNER or OUTER join.
     Default is ‘False’ as always.  The mapper options will override
     whichever setting is specified on relationship().  Should generally
     be set for many-to-one, not nullable foreign key relations to allow
     improved join performance.  [ticket:1544]

   * the behavior of joined eager loading such that the main query is
     wrapped in a subquery when LIMIT/OFFSET are present now makes an
     exception for the case when all eager loads are many-to-one joins.
     In those cases, the eager joins are against the parent table
     directly along with the limit/offset without the extra overhead of
     a subquery, since a many-to-one join does not add rows to the
     result.

     For example, in 0.5 this query:

          session.query(Address).options(eagerload(Address.user)).limit(10)

     would produce SQL like:

          SELECT * FROM
            (SELECT * FROM addresses LIMIT 10) AS anon_1
            LEFT OUTER JOIN users AS users_1 ON users_1.id = anon_1.addresses_user_id

     This because the presence of any eager loaders suggests that some
     or all of them may relate to multi-row collections, which would
     necessitate wrapping any kind of rowcount-sensitive modifiers like
     LIMIT inside of a subquery.

     In 0.6, that logic is more sensitive and can detect if all eager
     loaders represent many-to-ones, in which case the eager joins don’t
     affect the rowcount:

          SELECT * FROM addresses LEFT OUTER JOIN users AS users_1 ON users_1.id = addresses.user_id LIMIT 10

8.4.8.30 Mutable Primary Keys with Joined Table Inheritance
...........................................................

A joined table inheritance config where the child table has a PK that
foreign keys to the parent PK can now be updated on a CASCADE-capable
database like PostgreSQL. ‘mapper()’ now has an option
‘passive_updates=True’ which indicates this foreign key is updated
automatically.  If on a non-cascading database like SQLite or
MySQL/MyISAM, set this flag to ‘False’.  A future feature enhancement
will try to get this flag to be auto-configuring based on dialect/table
style in use.

8.4.8.31 Beaker Caching
.......................

A promising new example of Beaker integration is in
‘examples/beaker_caching’.  This is a straightforward recipe which
applies a Beaker cache within the result- generation engine of ‘Query’.
Cache parameters are provided via ‘query.options()’, and allows full
control over the contents of the cache.  SQLAlchemy 0.6 includes
improvements to the ‘Session.merge()’ method to support this and similar
recipes, as well as to provide significantly improved performance in
most scenarios.

8.4.8.32 Other Changes
......................

   * the “row tuple” object returned by ‘Query’ when multiple
     column/entities are selected is now picklable as well as higher
     performing.

   * ‘query.join()’ has been reworked to provide more consistent
     behavior and more flexibility (includes [ticket:1537])

   * ‘query.select_from()’ accepts multiple clauses to produce multiple
     comma separated entries within the FROM clause.  Useful when
     selecting from multiple-homed join() clauses.

   * the “dont_load=True” flag on ‘Session.merge()’ is deprecated and is
     now “load=False”.

   * added “make_transient()” helper function which transforms a
     persistent/ detached instance into a transient one (i.e.  deletes
     the instance_key and removes from any session.)  [ticket:1052]

   * the allow_null_pks flag on mapper() is deprecated and has been
     renamed to allow_partial_pks.  It is turned “on” by default.  This
     means that a row which has a non-null value for any of its primary
     key columns will be considered an identity.  The need for this
     scenario typically only occurs when mapping to an outer join.  When
     set to False, a PK that has NULLs in it will not be considered a
     primary key - in particular this means a result row will come back
     as None (or not be filled into a collection), and new in 0.6 also
     indicates that session.merge() won’t issue a round trip to the
     database for such a PK value.  [ticket:1680]

   * the mechanics of “backref” have been fully merged into the finer
     grained “back_populates” system, and take place entirely within the
     ‘_generate_backref()’ method of ‘RelationProperty’.  This makes the
     initialization procedure of ‘RelationProperty’ simpler and allows
     easier propagation of settings (such as from subclasses of
     ‘RelationProperty’) into the reverse reference.  The internal
     ‘BackRef()’ is gone and ‘backref()’ returns a plain tuple that is
     understood by ‘RelationProperty’.

   * the keys attribute of ‘ResultProxy’ is now a method, so references
     to it (‘result.keys’) must be changed to method invocations
     (‘result.keys()’)

   * ‘ResultProxy.last_inserted_ids’ is now deprecated, use
     ‘ResultProxy.inserted_primary_key’ instead.

8.4.8.33 Deprecated/Removed ORM Elements
........................................

Most elements that were deprecated throughout 0.5 and raised deprecation
warnings have been removed (with a few exceptions).  All elements that
were marked “pending deprecation” are now deprecated and will raise a
warning upon use.

   * ‘transactional’ flag on sessionmaker() and others is removed.  Use
     ‘autocommit=True’ to indicate ‘transactional=False’.

   * ‘polymorphic_fetch’ argument on mapper() is removed.  Loading can
     be controlled using the ‘with_polymorphic’ option.

   * ‘select_table’ argument on mapper() is removed.  Use
     ‘with_polymorphic=(“*”, <some selectable>)’ for this functionality.

   * ‘proxy’ argument on synonym() is removed.  This flag did nothing
     throughout 0.5, as the “proxy generation” behavior is now
     automatic.

   * Passing a single list of elements to joinedload(),
     joinedload_all(), contains_eager(), lazyload(), defer(), and
     undefer() instead of multiple positional *args is deprecated.

   * Passing a single list of elements to query.order_by(),
     query.group_by(), query.join(), or query.outerjoin() instead of
     multiple positional *args is deprecated.

   * ‘query.iterate_instances()’ is removed.  Use ‘query.instances()’.

   * ‘Query.query_from_parent()’ is removed.  Use the
     sqlalchemy.orm.with_parent() function to produce a “parent” clause,
     or alternatively ‘query.with_parent()’.

   * ‘query._from_self()’ is removed, use ‘query.from_self()’ instead.

   * the “comparator” argument to composite() is removed.  Use
     “comparator_factory”.

   * ‘RelationProperty._get_join()’ is removed.

   * the ‘echo_uow’ flag on Session is removed.  Use logging on the
     “sqlalchemy.orm.unitofwork” name.

   * ‘session.clear()’ is removed.  use ‘session.expunge_all()’.

   * ‘session.save()’, ‘session.update()’, ‘session.save_or_update()’
     are removed.  Use ‘session.add()’ and ‘session.add_all()’.

   * the “objects” flag on session.flush() remains deprecated.

   * the “dont_load=True” flag on session.merge() is deprecated in favor
     of “load=False”.

   * ‘ScopedSession.mapper’ remains deprecated.  See the usage recipe at
     ‘http://www.sqlalchemy.org/trac/wiki/Usag’
     eRecipes/SessionAwareMapper

   * passing an ‘InstanceState’ (internal SQLAlchemy state object) to
     ‘attributes.init_collection()’ or ‘attributes.get_history()’ is
     deprecated.  These functions are public API and normally expect a
     regular mapped object instance.

   * the ‘engine’ parameter to ‘declarative_base()’ is removed.  Use the
     ‘bind’ keyword argument.

8.4.8.34 Extensions
...................

8.4.8.35 SQLSoup
................

SQLSoup has been modernized and updated to reflect common 0.5/0.6
capabilities, including well defined session integration.  Please read
the new docs at [‘http://www.sqlalc’
hemy.org/docs/06/reference/ext/sqlsoup.html].

8.4.8.36 Declarative
....................

The ‘DeclarativeMeta’ (default metaclass for ‘declarative_base’)
previously allowed subclasses to modify ‘dict_’ to add class attributes
(e.g.  columns).  This no longer works, the ‘DeclarativeMeta’
constructor now ignores ‘dict_’.  Instead, the class attributes should
be assigned directly, e.g.  ‘cls.id=Column(...)’, or the MixIn class(1)
approach should be used instead of the metaclass approach.

   ---------- Footnotes ----------

   (1)
http://www.sqlalchemy.org/docs/reference/ext/declarative.html#mix-in-classes

8.4.9 What’s new in SQLAlchemy 0.5?
-----------------------------------

     About this Document: This document describes changes between
     SQLAlchemy version 0.4, last released October 12, 2008, and
     SQLAlchemy version 0.5, last released January 16, 2010.

     Document date: August 4, 2009

This guide documents API changes which affect users migrating their
applications from the 0.4 series of SQLAlchemy to 0.5.  It’s also
recommended for those working from Essential SQLAlchemy(1), which only
covers 0.4 and seems to even have some old 0.3isms in it.  Note that
SQLAlchemy 0.5 removes many behaviors which were deprecated throughout
the span of the 0.4 series, and also deprecates more behaviors specific
to 0.4.

   ---------- Footnotes ----------

   (1) http://oreilly.com/catalog/9780596516147/

8.4.9.1 Major Documentation Changes
...................................

Some sections of the documentation have been completely rewritten and
can serve as an introduction to new ORM features.  The ‘Query’ and
‘Session’ objects in particular have some distinct differences in API
and behavior which fundamentally change many of the basic ways things
are done, particularly with regards to constructing highly customized
ORM queries and dealing with stale session state, commits and rollbacks.

   * ORM Tutorial(1)

   * Session Documentation(2)

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/docs/05/ormtutorial.html

   (2) http://www.sqlalchemy.org/docs/05/session.html

8.4.9.2 Deprecations Source
...........................

Another source of information is documented within a series of unit
tests illustrating up to date usages of some common ‘Query’ patterns;
this file can be viewed at
[source:sqlalchemy/trunk/test/orm/test_deprecations.py].

8.4.9.3 Requirements Changes
............................

   * Python 2.4 or higher is required.  The SQLAlchemy 0.4 line is the
     last version with Python 2.3 support.

8.4.9.4 Object Relational Mapping
.................................

   * `Column level expressions within Query.'  - as detailed in the
     tutorial(1), ‘Query’ has the capability to create specific SELECT
     statements, not just those against full rows:

          session.query(User.name, func.count(Address.id).label("numaddresses")).join(Address).group_by(User.name)

     The tuples returned by any multi-column/entity query are `named'’
     tuples:

          for row in session.query(User.name, func.count(Address.id).label('numaddresses')).join(Address).group_by(User.name):
             print("name", row.name, "number", row.numaddresses)

     ‘Query’ has a ‘statement’ accessor, as well as a ‘subquery()’
     method which allow ‘Query’ to be used to create more complex
     combinations:

          subq = session.query(Keyword.id.label('keyword_id')).filter(Keyword.name.in_(['beans', 'carrots'])).subquery()
          recipes = session.query(Recipe).filter(exists().
             where(Recipe.id==recipe_keywords.c.recipe_id).
             where(recipe_keywords.c.keyword_id==subq.c.keyword_id)
          )

   * `Explicit ORM aliases are recommended for aliased joins' - The
     ‘aliased()’ function produces an “alias” of a class, which allows
     fine-grained control of aliases in conjunction with ORM queries.
     While a table-level alias (i.e.  ‘table.alias()’) is still usable,
     an ORM level alias retains the semantics of the ORM mapped object
     which is significant for inheritance mappings, options, and other
     scenarios.  E.g.:

          Friend = aliased(Person)
          session.query(Person, Friend).join((Friend, Person.friends)).all()

   * `query.join() greatly enhanced.'  - You can now specify the target
     and ON clause for a join in multiple ways.  A target class alone
     can be provided where SQLA will attempt to form a join to it via
     foreign key in the same way as ‘table.join(someothertable)’.  A
     target and an explicit ON condition can be provided, where the ON
     condition can be a ‘relation()’ name, an actual class descriptor,
     or a SQL expression.  Or the old way of just a ‘relation()’ name or
     class descriptor works too.  See the ORM tutorial which has several
     examples.

   * `Declarative is recommended for applications which don’t require
     (and don’t prefer) abstraction between tables and mappers' - The
     [/docs/05/reference/ext/declarative.html Declarative] module, which
     is used to combine the expression of ‘Table’, ‘mapper()’, and user
     defined class objects together, is highly recommended as it
     simplifies application configuration, ensures the “one mapper per
     class” pattern, and allows the full range of configuration
     available to distinct ‘mapper()’ calls.  Separate ‘mapper()’ and
     ‘Table’ usage is now referred to as “classical SQLAlchemy usage”
     and of course is freely mixable with declarative.

   * `The .c.  attribute has been removed' from classes (i.e.
     ‘MyClass.c.somecolumn’).  As is the case in 0.4, class- level
     properties are usable as query elements, i.e.  ‘Class.c.propname’
     is now superseded by ‘Class.propname’, and the ‘c’ attribute
     continues to remain on ‘Table’ objects where they indicate the
     namespace of ‘Column’ objects present on the table.

     To get at the Table for a mapped class (if you didn’t keep it
     around already):

          table = class_mapper(someclass).mapped_table

     Iterate through columns:

          for col in table.c:
              print(col)

     Work with a specific column:

          table.c.somecolumn

     The class-bound descriptors support the full set of Column
     operators as well as the documented relation-oriented operators
     like ‘has()’, ‘any()’, ‘contains()’, etc.

     The reason for the hard removal of ‘.c.’ is that in 0.5,
     class-bound descriptors carry potentially different meaning, as
     well as information regarding class mappings, versus plain ‘Column’
     objects - and there are use cases where you’d specifically want to
     use one or the other.  Generally, using class-bound descriptors
     invokes a set of mapping/polymorphic aware translations, and using
     table- bound columns does not.  In 0.4, these translations were
     applied across the board to all expressions, but 0.5 differentiates
     completely between columns and mapped descriptors, only applying
     translations to the latter.  So in many cases, particularly when
     dealing with joined table inheritance configurations as well as
     when using ‘query(<columns>)’, ‘Class.propname’ and
     ‘table.c.colname’ are not interchangeable.

     For example, ‘session.query(users.c.id, users.c.name)’ is different
     versus ‘session.query(User.id, User.name)’; in the latter case, the
     ‘Query’ is aware of the mapper in use and further mapper-specific
     operations like ‘query.join(<propname>)’, ‘query.with_parent()’
     etc.  may be used, but in the former case cannot.  Additionally, in
     polymorphic inheritance scenarios, the class-bound descriptors
     refer to the columns present in the polymorphic selectable in use,
     not necessarily the table column which directly corresponds to the
     descriptor.  For example, a set of classes related by joined-table
     inheritance to the ‘person’ table along the ‘person_id’ column of
     each table will all have their ‘Class.person_id’ attribute mapped
     to the ‘person_id’ column in ‘person’, and not their subclass
     table.  Version 0.4 would map this behavior onto table-bound
     ‘Column’ objects automatically.  In 0.5, this automatic conversion
     has been removed, so that you in fact `can' use table-bound columns
     as a means to override the translations which occur with
     polymorphic querying; this allows ‘Query’ to be able to create
     optimized selects among joined-table or concrete-table inheritance
     setups, as well as portable subqueries, etc.

   * `Session Now Synchronizes Automatically with Transactions.'
     Session now synchronizes against the transaction automatically by
     default, including autoflush and autoexpire.  A transaction is
     present at all times unless disabled using the ‘autocommit’ option.
     When all three flags are set to their default, the Session recovers
     gracefully after rollbacks and it’s very difficult to get stale
     data into the session.  See the new Session documentation for
     details.

   * `Implicit Order By Is Removed'.  This will impact ORM users who
     rely upon SA’s “implicit ordering” behavior, which states that all
     Query objects which don’t have an ‘order_by()’ will ORDER BY the
     “id” or “oid” column of the primary mapped table, and all
     lazy/eagerly loaded collections apply a similar ordering.  In 0.5,
     automatic ordering must be explicitly configured on ‘mapper()’ and
     ‘relation()’ objects (if desired), or otherwise when using ‘Query’.

     To convert an 0.4 mapping to 0.5, such that its ordering behavior
     will be extremely similar to 0.4 or previous, use the ‘order_by’
     setting on ‘mapper()’ and ‘relation()’:

          mapper(User, users, properties={
              'addresses':relation(Address, order_by=addresses.c.id)
          }, order_by=users.c.id)

     To set ordering on a backref, use the ‘backref()’ function:

          'keywords':relation(Keyword, secondary=item_keywords,
                order_by=keywords.c.name, backref=backref('items', order_by=items.c.id))

     Using declarative ?  To help with the new ‘order_by’ requirement,
     ‘order_by’ and friends can now be set using strings which are
     evaluated in Python later on (this works `only' with declarative,
     not plain mappers):

          class MyClass(MyDeclarativeBase):
              ...
              'addresses':relation("Address", order_by="Address.id")

     It’s generally a good idea to set ‘order_by’ on ‘relation()s’ which
     load list-based collections of items, since that ordering cannot
     otherwise be affected.  Other than that, the best practice is to
     use ‘Query.order_by()’ to control ordering of the primary entities
     being loaded.

   * `Session is now autoflush=True/autoexpire=True/autocommit=False.'
     - To set it up, just call ‘sessionmaker()’ with no arguments.  The
     name ‘transactional=True’ is now ‘autocommit=False’.  Flushes occur
     upon each query issued (disable with ‘autoflush=False’), within
     each ‘commit()’ (as always), and before each ‘begin_nested()’ (so
     rolling back to the SAVEPOINT is meaningful).  All objects are
     expired after each ‘commit()’ and after each ‘rollback()’.  After
     rollback, pending objects are expunged, deleted objects move back
     to persistent.  These defaults work together very nicely and
     there’s really no more need for old techniques like ‘clear()’
     (which is renamed to ‘expunge_all()’ as well).

     P.S.: sessions are now reusable after a ‘rollback()’.  Scalar and
     collection attribute changes, adds and deletes are all rolled back.

   * `session.add() replaces session.save(), session.update(),
     session.save_or_update().'  - the ‘session.add(someitem)’ and
     ‘session.add_all([list of items])’ methods replace ‘save()’,
     ‘update()’, and ‘save_or_update()’.  Those methods will remain
     deprecated throughout 0.5.

   * `backref configuration made less verbose.'  - The ‘backref()’
     function now uses the ‘primaryjoin’ and ‘secondaryjoin’ arguments
     of the forwards-facing ‘relation()’ when they are not explicitly
     stated.  It’s no longer necessary to specify
     ‘primaryjoin’/‘secondaryjoin’ in both directions separately.

   * `Simplified polymorphic options.'  - The ORM’s “polymorphic load”
     behavior has been simplified.  In 0.4, mapper() had an argument
     called ‘polymorphic_fetch’ which could be configured as ‘select’ or
     ‘deferred’.  This option is removed; the mapper will now just defer
     any columns which were not present in the SELECT statement.  The
     actual SELECT statement used is controlled by the
     ‘with_polymorphic’ mapper argument (which is also in 0.4 and
     replaces ‘select_table’), as well as the ‘with_polymorphic()’
     method on ‘Query’ (also in 0.4).

     An improvement to the deferred loading of inheriting classes is
     that the mapper now produces the “optimized” version of the SELECT
     statement in all cases; that is, if class B inherits from A, and
     several attributes only present on class B have been expired, the
     refresh operation will only include B’s table in the SELECT
     statement and will not JOIN to A.

   * The ‘execute()’ method on ‘Session’ converts plain strings into
     ‘text()’ constructs, so that bind parameters may all be specified
     as “:bindname” without needing to call ‘text()’ explicitly.  If
     “raw” SQL is desired here, use ‘session.connection().execute("raw
     text")’.

   * ‘session.Query().iterate_instances()’ has been renamed to just
     ‘instances()’.  The old ‘instances()’ method returning a list
     instead of an iterator no longer exists.  If you were relying on
     that behavior, you should use ‘list(your_query.instances())’.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/docs/05/ormtutorial.html

8.4.9.5 Extending the ORM
.........................

In 0.5 we’re moving forward with more ways to modify and extend the ORM.
Heres a summary:

   * `MapperExtension.'  - This is the classic extension class, which
     remains.  Methods which should rarely be needed are
     ‘create_instance()’ and ‘populate_instance()’.  To control the
     initialization of an object when it’s loaded from the database, use
     the ‘reconstruct_instance()’ method, or more easily the
     ‘@reconstructor’ decorator described in the documentation.

   * `SessionExtension.'  - This is an easy to use extension class for
     session events.  In particular, it provides ‘before_flush()’,
     ‘after_flush()’ and ‘after_flush_postexec()’ methods.  This usage
     is recommended over ‘MapperExtension.before_XXX’ in many cases
     since within ‘before_flush()’ you can modify the flush plan of the
     session freely, something which cannot be done from within
     ‘MapperExtension’.

   * `AttributeExtension.'  - This class is now part of the public API,
     and allows the interception of userland events on attributes,
     including attribute set and delete operations, and collection
     appends and removes.  It also allows the value to be set or
     appended to be modified.  The ‘@validates’ decorator, described in
     the documentation, provides a quick way to mark any mapped
     attributes as being “validated” by a particular class method.

   * `Attribute Instrumentation Customization.'  - An API is provided
     for ambitious efforts to entirely replace SQLAlchemy’s attribute
     instrumentation, or just to augment it in some cases.  This API was
     produced for the purposes of the Trellis toolkit, but is available
     as a public API. Some examples are provided in the distribution in
     the ‘/examples/custom_attributes’ directory.

8.4.9.6 Schema/Types
....................

   * `String with no length no longer generates TEXT, it generates
     VARCHAR' - The ‘String’ type no longer magically converts into a
     ‘Text’ type when specified with no length.  This only has an effect
     when CREATE TABLE is issued, as it will issue ‘VARCHAR’ with no
     length parameter, which is not valid on many (but not all)
     databases.  To create a TEXT (or CLOB, i.e.  unbounded string)
     column, use the ‘Text’ type.

   * `PickleType() with mutable=True requires an __eq__() method' - The
     ‘PickleType’ type needs to compare values when mutable=True.  The
     method of comparing ‘pickle.dumps()’ is inefficient and unreliable.
     If an incoming object does not implement ‘__eq__()’ and is also not
     ‘None’, the ‘dumps()’ comparison is used but a warning is raised.
     For types which implement ‘__eq__()’ which includes all
     dictionaries, lists, etc., comparison will use ‘==’ and is now
     reliable by default.

   * `convert_bind_param() and convert_result_value() methods of
     TypeEngine/TypeDecorator are removed.'  - The O’Reilly book
     unfortunately documented these methods even though they were
     deprecated post 0.3.  For a user-defined type which subclasses
     ‘TypeEngine’, the ‘bind_processor()’ and ‘result_processor()’
     methods should be used for bind/result processing.  Any user
     defined type, whether extending ‘TypeEngine’ or ‘TypeDecorator’,
     which uses the old 0.3 style can be easily adapted to the new style
     using the following adapter:

          class AdaptOldConvertMethods(object):
              """A mixin which adapts 0.3-style convert_bind_param and
              convert_result_value methods

              """
              def bind_processor(self, dialect):
                  def convert(value):
                      return self.convert_bind_param(value, dialect)
                  return convert

              def result_processor(self, dialect):
                  def convert(value):
                      return self.convert_result_value(value, dialect)
                  return convert

              def convert_result_value(self, value, dialect):
                  return value

              def convert_bind_param(self, value, dialect):
                  return value

     To use the above mixin:

          class MyType(AdaptOldConvertMethods, TypeEngine):
             # ...

   * The ‘quote’ flag on ‘Column’ and ‘Table’ as well as the
     ‘quote_schema’ flag on ‘Table’ now control quoting both positively
     and negatively.  The default is ‘None’, meaning let regular quoting
     rules take effect.  When ‘True’, quoting is forced on.  When
     ‘False’, quoting is forced off.

   * Column ‘DEFAULT’ value DDL can now be more conveniently specified
     with ‘Column(..., server_default='val')’, deprecating ‘Column(...,
     PassiveDefault('val'))’.  ‘default=’ is now exclusively for
     Python-initiated default values, and can coexist with
     server_default.  A new ‘server_default=FetchedValue()’ replaces the
     ‘PassiveDefault('')’ idiom for marking columns as subject to
     influence from external triggers and has no DDL side effects.

   * SQLite’s ‘DateTime’, ‘Time’ and ‘Date’ types now `only accept
     datetime objects, not strings' as bind parameter input.  If you’d
     like to create your own “hybrid” type which accepts strings and
     returns results as date objects (from whatever format you’d like),
     create a ‘TypeDecorator’ that builds on ‘String’.  If you only want
     string-based dates, just use ‘String’.

   * Additionally, the ‘DateTime’ and ‘Time’ types, when used with
     SQLite, now represent the “microseconds” field of the Python
     ‘datetime.datetime’ object in the same manner as ‘str(datetime)’ -
     as fractional seconds, not a count of microseconds.  That is:

          dt = datetime.datetime(2008, 6, 27, 12, 0, 0, 125)  # 125 usec

          # old way
          '2008-06-27 12:00:00.125'

          # new way
          '2008-06-27 12:00:00.000125'

     So if an existing SQLite file-based database intends to be used
     across 0.4 and 0.5, you either have to upgrade the datetime columns
     to store the new format (NOTE: please test this, I’m pretty sure
     its correct):

          UPDATE mytable SET somedatecol =
            substr(somedatecol, 0, 19) || '.' || substr((substr(somedatecol, 21, -1) / 1000000), 3, -1);

     or, enable “legacy” mode as follows:

          from sqlalchemy.databases.sqlite import DateTimeMixin
          DateTimeMixin.__legacy_microseconds__ = True

8.4.9.7 Connection Pool no longer threadlocal by default
........................................................

0.4 has an unfortunate default setting of “pool_threadlocal=True”,
leading to surprise behavior when, for example, using multiple Sessions
within a single thread.  This flag is now off in 0.5.  To re-enable
0.4’s behavior, specify ‘pool_threadlocal=True’ to ‘create_engine()’, or
alternatively use the “threadlocal” strategy via
‘strategy="threadlocal"’.

8.4.9.8 *args Accepted, *args No Longer Accepted
................................................

The policy with ‘method(\*args)’ vs.  ‘method([args])’ is, if the method
accepts a variable-length set of items which represent a fixed
structure, it takes ‘\*args’.  If the method accepts a variable-length
set of items that are data-driven, it takes ‘[args]’.

   * The various Query.options() functions ‘eagerload()’,
     ‘eagerload_all()’, ‘lazyload()’, ‘contains_eager()’, ‘defer()’,
     ‘undefer()’ all accept variable-length ‘\*keys’ as their argument
     now, which allows a path to be formulated using descriptors, ie.:

          query.options(eagerload_all(User.orders, Order.items, Item.keywords))

     A single array argument is still accepted for backwards
     compatibility.

   * Similarly, the ‘Query.join()’ and ‘Query.outerjoin()’ methods
     accept a variable length *args, with a single array accepted for
     backwards compatibility:

          query.join('orders', 'items')
          query.join(User.orders, Order.items)

   * the ‘in_()’ method on columns and similar only accepts a list
     argument now.  It no longer accepts ‘\*args’.

8.4.9.9 Removed
...............

   * `entity_name' - This feature was always problematic and rarely
     used.  0.5’s more deeply fleshed out use cases revealed further
     issues with ‘entity_name’ which led to its removal.  If different
     mappings are required for a single class, break the class into
     separate subclasses and map them separately.  An example of this is
     at [wiki:UsageRecipes/EntityName].  More information regarding
     rationale is described at http://groups.google.c
     om/group/sqlalchemy/browse_thread/thread/9e23a0641a88b96d?  hl=en .

   * `get()/load() cleanup'

     The ‘load()’ method has been removed.  Its functionality was kind
     of arbitrary and basically copied from Hibernate, where it’s also
     not a particularly meaningful method.

     To get equivalent functionality:

          x = session.query(SomeClass).populate_existing().get(7)

     ‘Session.get(cls, id)’ and ‘Session.load(cls, id)’ have been
     removed.  ‘Session.get()’ is redundant vs.
     ‘session.query(cls).get(id)’.

     ‘MapperExtension.get()’ is also removed (as is
     ‘MapperExtension.load()’).  To override the functionality of
     ‘Query.get()’, use a subclass:

          class MyQuery(Query):
              def get(self, ident):
                  # ...

          session = sessionmaker(query_cls=MyQuery)()

          ad1 = session.query(Address).get(1)

   * ‘sqlalchemy.orm.relation()’

     The following deprecated keyword arguments have been removed:

     foreignkey, association, private, attributeext, is_backref

     In particular, ‘attributeext’ is replaced with ‘extension’ - the
     ‘AttributeExtension’ class is now in the public API.

   * ‘session.Query()’

     The following deprecated functions have been removed:

     list, scalar, count_by, select_whereclause, get_by, select_by,
     join_by, selectfirst, selectone, select, execute, select_statement,
     select_text, join_to, join_via, selectfirst_by, selectone_by,
     apply_max, apply_min, apply_avg, apply_sum

     Additionally, the ‘id’ keyword argument to ‘join()’, ‘outerjoin()’,
     ‘add_entity()’ and ‘add_column()’ has been removed.  To target
     table aliases in ‘Query’ to result columns, use the ‘aliased’
     construct:

          from sqlalchemy.orm import aliased
          address_alias = aliased(Address)
          print(session.query(User, address_alias).join((address_alias, User.addresses)).all())

   * ‘sqlalchemy.orm.Mapper’

        * instances()

        * get_session() - this method was not very noticeable, but had
          the effect of associating lazy loads with a particular session
          even if the parent object was entirely detached, when an
          extension such as ‘scoped_session()’ or the old
          ‘SessionContextExt’ was used.  It’s possible that some
          applications which relied upon this behavior will no longer
          work as expected; but the better programming practice here is
          to always ensure objects are present within sessions if
          database access from their attributes are required.

   * ‘mapper(MyClass, mytable)’

     Mapped classes no are longer instrumented with a “c” class
     attribute; e.g.  ‘MyClass.c’

   * ‘sqlalchemy.orm.collections’

     The _prepare_instrumentation alias for prepare_instrumentation has
     been removed.

   * ‘sqlalchemy.orm’

     Removed the ‘EXT_PASS’ alias of ‘EXT_CONTINUE’.

   * ‘sqlalchemy.engine’

     The alias from ‘DefaultDialect.preexecute_sequences’ to
     ‘.preexecute_pk_sequences’ has been removed.

     The deprecated engine_descriptors() function has been removed.

   * ‘sqlalchemy.ext.activemapper’

     Module removed.

   * ‘sqlalchemy.ext.assignmapper’

     Module removed.

   * ‘sqlalchemy.ext.associationproxy’

     Pass-through of keyword args on the proxy’s ‘.append(item, \**kw)’
     has been removed and is now simply ‘.append(item)’

   * ‘sqlalchemy.ext.selectresults’, ‘sqlalchemy.mods.selectresults’

     Modules removed.

   * ‘sqlalchemy.ext.declarative’

     ‘declared_synonym()’ removed.

   * ‘sqlalchemy.ext.sessioncontext’

     Module removed.

   * ‘sqlalchemy.log’

     The ‘SADeprecationWarning’ alias to
     ‘sqlalchemy.exc.SADeprecationWarning’ has been removed.

   * ‘sqlalchemy.exc’

     ‘exc.AssertionError’ has been removed and usage replaced by the
     Python built-in of the same name.

   * ‘sqlalchemy.databases.mysql’

     The deprecated ‘get_version_info’ dialect method has been removed.

8.4.9.10 Renamed or Moved
.........................

   * ‘sqlalchemy.exceptions’ is now ‘sqlalchemy.exc’

     The module may still be imported under the old name until 0.6.

   * ‘FlushError’, ‘ConcurrentModificationError’, ‘UnmappedColumnError’
     -> sqlalchemy.orm.exc

     These exceptions moved to the orm package.  Importing
     ‘sqlalchemy.orm’ will install aliases in sqlalchemy.exc for
     compatibility until 0.6.

   * ‘sqlalchemy.logging’ -> ‘sqlalchemy.log’

     This internal module was renamed.  No longer needs to be special
     cased when packaging SA with py2app and similar tools that scan
     imports.

   * ‘session.Query().iterate_instances()’ ->
     ‘session.Query().instances()’.

8.4.9.11 Deprecated
...................

   * ‘Session.save()’, ‘Session.update()’, ‘Session.save_or_update()’

     All three replaced by ‘Session.add()’

   * ‘sqlalchemy.PassiveDefault’

     Use ‘Column(server_default=...)’ Translates to
     sqlalchemy.DefaultClause() under the hood.

   * ‘session.Query().iterate_instances()’.  It has been renamed to
     ‘instances()’.

8.4.10 What’s new in SQLAlchemy 0.4?
------------------------------------

     About this Document: This document describes changes between
     SQLAlchemy version 0.3, last released October 14, 2007, and
     SQLAlchemy version 0.4, last released October 12, 2008.

     Document date: March 21, 2008

8.4.10.1 First Things First
...........................

If you’re using any ORM features, make sure you import from
‘sqlalchemy.orm’:

     from sqlalchemy import *
     from sqlalchemy.orm import *

Secondly, anywhere you used to say ‘engine=’, ‘connectable=’,
‘bind_to=’, ‘something.engine’, ‘metadata.connect()’, use ‘bind’:

     myengine = create_engine('sqlite://')

     meta = MetaData(myengine)

     meta2 = MetaData()
     meta2.bind = myengine

     session = create_session(bind=myengine)

     statement = select([table], bind=myengine)

Got those ?  Good!  You’re now (95%) 0.4 compatible.  If you’re using
0.3.10, you can make these changes immediately; they’ll work there too.

8.4.10.2 Module Imports
.......................

In 0.3, “‘from sqlalchemy import *’” would import all of sqlalchemy’s
sub-modules into your namespace.  Version 0.4 no longer imports
sub-modules into the namespace.  This may mean you need to add extra
imports into your code.

In 0.3, this code worked:

     from sqlalchemy import *

     class UTCDateTime(types.TypeDecorator):
         pass

In 0.4, one must do:

     from sqlalchemy import *
     from sqlalchemy import types

     class UTCDateTime(types.TypeDecorator):
         pass

8.4.10.3 Object Relational Mapping
..................................

8.4.10.4 Querying
.................

8.4.10.5 New Query API
......................

Query is standardized on the generative interface (old interface is
still there, just deprecated).  While most of the generative interface
is available in 0.3, the 0.4 Query has the inner guts to match the
generative outside, and has a lot more tricks.  All result narrowing is
via ‘filter()’ and ‘filter_by()’, limiting/offset is either through
array slices or ‘limit()’/‘offset()’, joining is via ‘join()’ and
‘outerjoin()’ (or more manually, through ‘select_from()’ as well as
manually-formed criteria).

To avoid deprecation warnings, you must make some changes to your 03
code

User.query.get_by( **kwargs )

     User.query.filter_by(**kwargs).first()

User.query.select_by( **kwargs )

     User.query.filter_by(**kwargs).all()

User.query.select()

     User.query.filter(xxx).all()

8.4.10.6 New Property-Based Expression Constructs
.................................................

By far the most palpable difference within the ORM is that you can now
construct your query criterion using class-based attributes directly.
The “.c.” prefix is no longer needed when working with mapped classes:

     session.query(User).filter(and_(User.name == 'fred', User.id > 17))

While simple column-based comparisons are no big deal, the class
attributes have some new “higher level” constructs available, including
what was previously only available in ‘filter_by()’:

     # comparison of scalar relations to an instance
     filter(Address.user == user)

     # return all users who contain a particular address
     filter(User.addresses.contains(address))

     # return all users who *dont* contain the address
     filter(~User.address.contains(address))

     # return all users who contain a particular address with
     # the email_address like '%foo%'
     filter(User.addresses.any(Address.email_address.like('%foo%')))

     # same, email address equals 'foo@bar.com'.  can fall back to keyword
     # args for simple comparisons
     filter(User.addresses.any(email_address = 'foo@bar.com'))

     # return all Addresses whose user attribute has the username 'ed'
     filter(Address.user.has(name='ed'))

     # return all Addresses whose user attribute has the username 'ed'
     # and an id > 5 (mixing clauses with kwargs)
     filter(Address.user.has(User.id > 5, name='ed'))

The ‘Column’ collection remains available on mapped classes in the ‘.c’
attribute.  Note that property-based expressions are only available with
mapped properties of mapped classes.  ‘.c’ is still used to access
columns in regular tables and selectable objects produced from SQL
Expressions.

8.4.10.7 Automatic Join Aliasing
................................

We’ve had join() and outerjoin() for a while now:

     session.query(Order).join('items')...

Now you can alias them:

     session.query(Order).join('items', aliased=True).
        filter(Item.name='item 1').join('items', aliased=True).filter(Item.name=='item 3')

The above will create two joins from orders->items using aliases.  the
‘filter()’ call subsequent to each will adjust its table criterion to
that of the alias.  To get at the ‘Item’ objects, use ‘add_entity()’ and
target each join with an ‘id’:

     session.query(Order).join('items', id='j1', aliased=True).
     filter(Item.name == 'item 1').join('items', aliased=True, id='j2').
     filter(Item.name == 'item 3').add_entity(Item, id='j1').add_entity(Item, id='j2')

Returns tuples in the form: ‘(Order, Item, Item)’.

8.4.10.8 Self-referential Queries
.................................

So query.join() can make aliases now.  What does that give us ?
Self-referential queries !  Joins can be done without any ‘Alias’
objects:

     # standard self-referential TreeNode mapper with backref
     mapper(TreeNode, tree_nodes, properties={
         'children':relation(TreeNode, backref=backref('parent', remote_side=tree_nodes.id))
     })

     # query for node with child containing "bar" two levels deep
     session.query(TreeNode).join(["children", "children"], aliased=True).filter_by(name='bar')

To add criterion for each table along the way in an aliased join, you
can use ‘from_joinpoint’ to keep joining against the same line of
aliases:

     # search for the treenode along the path "n1/n12/n122"

     # first find a Node with name="n122"
     q = sess.query(Node).filter_by(name='n122')

     # then join to parent with "n12"
     q = q.join('parent', aliased=True).filter_by(name='n12')

     # join again to the next parent with 'n1'.  use 'from_joinpoint'
     # so we join from the previous point, instead of joining off the
     # root table
     q = q.join('parent', aliased=True, from_joinpoint=True).filter_by(name='n1')

     node = q.first()

8.4.10.9 ‘query.populate_existing()’
....................................

The eager version of ‘query.load()’ (or ‘session.refresh()’).  Every
instance loaded from the query, including all eagerly loaded items, get
refreshed immediately if already present in the session:

     session.query(Blah).populate_existing().all()

8.4.10.10 Relations
...................

8.4.10.11 SQL Clauses Embedded in Updates/Inserts
.................................................

For inline execution of SQL clauses, embedded right in the UPDATE or
INSERT, during a ‘flush()’:

     myobject.foo = mytable.c.value + 1

     user.pwhash = func.md5(password)

     order.hash = text("select hash from hashing_table")

The column-attribute is set up with a deferred loader after the
operation, so that it issues the SQL to load the new value when you next
access.

8.4.10.12 Self-referential and Cyclical Eager Loading
.....................................................

Since our alias-fu has improved, ‘relation()’ can join along the same
table *any number of times*; you tell it how deep you want to go.  Lets
show the self-referential ‘TreeNode’ more clearly:

     nodes = Table('nodes', metadata,
          Column('id', Integer, primary_key=True),
          Column('parent_id', Integer, ForeignKey('nodes.id')),
          Column('name', String(30)))

     class TreeNode(object):
         pass

     mapper(TreeNode, nodes, properties={
         'children':relation(TreeNode, lazy=False, join_depth=3)
     })

So what happens when we say:

     create_session().query(TreeNode).all()

?  A join along aliases, three levels deep off the parent:

     SELECT
     nodes_3.id AS nodes_3_id, nodes_3.parent_id AS nodes_3_parent_id, nodes_3.name AS nodes_3_name,
     nodes_2.id AS nodes_2_id, nodes_2.parent_id AS nodes_2_parent_id, nodes_2.name AS nodes_2_name,
     nodes_1.id AS nodes_1_id, nodes_1.parent_id AS nodes_1_parent_id, nodes_1.name AS nodes_1_name,
     nodes.id AS nodes_id, nodes.parent_id AS nodes_parent_id, nodes.name AS nodes_name
     FROM nodes LEFT OUTER JOIN nodes AS nodes_1 ON nodes.id = nodes_1.parent_id
     LEFT OUTER JOIN nodes AS nodes_2 ON nodes_1.id = nodes_2.parent_id
     LEFT OUTER JOIN nodes AS nodes_3 ON nodes_2.id = nodes_3.parent_id
     ORDER BY nodes.oid, nodes_1.oid, nodes_2.oid, nodes_3.oid

Notice the nice clean alias names too.  The joining doesn’t care if it’s
against the same immediate table or some other object which then cycles
back to the beginning.  Any kind of chain of eager loads can cycle back
onto itself when ‘join_depth’ is specified.  When not present, eager
loading automatically stops when it hits a cycle.

8.4.10.13 Composite Types
.........................

This is one from the Hibernate camp.  Composite Types let you define a
custom datatype that is composed of more than one column (or one column,
if you wanted).  Lets define a new type, ‘Point’.  Stores an x/y
coordinate:

     class Point(object):
         def __init__(self, x, y):
             self.x = x
             self.y = y
         def __composite_values__(self):
             return self.x, self.y
         def __eq__(self, other):
             return other.x == self.x and other.y == self.y
         def __ne__(self, other):
             return not self.__eq__(other)

The way the ‘Point’ object is defined is specific to a custom type;
constructor takes a list of arguments, and the ‘__composite_values__()’
method produces a sequence of those arguments.  The order will match up
to our mapper, as we’ll see in a moment.

Let’s create a table of vertices storing two points per row:

     vertices = Table('vertices', metadata,
         Column('id', Integer, primary_key=True),
         Column('x1', Integer),
         Column('y1', Integer),
         Column('x2', Integer),
         Column('y2', Integer),
         )

Then, map it !  We’ll create a ‘Vertex’ object which stores two ‘Point’
objects:

     class Vertex(object):
         def __init__(self, start, end):
             self.start = start
             self.end = end

     mapper(Vertex, vertices, properties={
         'start':composite(Point, vertices.c.x1, vertices.c.y1),
         'end':composite(Point, vertices.c.x2, vertices.c.y2)
     })

Once you’ve set up your composite type, it’s usable just like any other
type:

     v = Vertex(Point(3, 4), Point(26,15))
     session.save(v)
     session.flush()

     # works in queries too
     q = session.query(Vertex).filter(Vertex.start == Point(3, 4))

If you’d like to define the way the mapped attributes generate SQL
clauses when used in expressions, create your own
‘sqlalchemy.orm.PropComparator’ subclass, defining any of the common
operators (like ‘__eq__()’, ‘__le__()’, etc.), and send it in to
‘composite()’.  Composite types work as primary keys too, and are usable
in ‘query.get()’:

     # a Document class which uses a composite Version
     # object as primary key
     document = query.get(Version(1, 'a'))

8.4.10.14 ‘dynamic_loader()’ relations
......................................

A ‘relation()’ that returns a live ‘Query’ object for all read
operations.  Write operations are limited to just ‘append()’ and
‘remove()’, changes to the collection are not visible until the session
is flushed.  This feature is particularly handy with an “autoflushing”
session which will flush before each query.

     mapper(Foo, foo_table, properties={
         'bars':dynamic_loader(Bar, backref='foo', <other relation() opts>)
     })

     session = create_session(autoflush=True)
     foo = session.query(Foo).first()

     foo.bars.append(Bar(name='lala'))

     for bar in foo.bars.filter(Bar.name=='lala'):
         print(bar)

     session.commit()

8.4.10.15 New Options: ‘undefer_group()’, ‘eagerload_all()’
...........................................................

A couple of query options which are handy.  ‘undefer_group()’ marks a
whole group of “deferred” columns as undeferred:

     mapper(Class, table, properties={
         'foo' : deferred(table.c.foo, group='group1'),
         'bar' : deferred(table.c.bar, group='group1'),
         'bat' : deferred(table.c.bat, group='group1'),
     )

     session.query(Class).options(undefer_group('group1')).filter(...).all()

and ‘eagerload_all()’ sets a chain of attributes to be eager in one
pass:

     mapper(Foo, foo_table, properties={
        'bar':relation(Bar)
     })
     mapper(Bar, bar_table, properties={
        'bat':relation(Bat)
     })
     mapper(Bat, bat_table)

     # eager load bar and bat
     session.query(Foo).options(eagerload_all('bar.bat')).filter(...).all()

8.4.10.16 New Collection API
............................

Collections are no longer proxied by an {{{InstrumentedList}}} proxy,
and access to members, methods and attributes is direct.  Decorators now
intercept objects entering and leaving the collection, and it is now
possible to easily write a custom collection class that manages its own
membership.  Flexible decorators also replace the named method interface
of custom collections in 0.3, allowing any class to be easily adapted to
use as a collection container.

Dictionary-based collections are now much easier to use and fully
‘dict’-like.  Changing ‘__iter__’ is no longer needed for ‘dict``s, and
new built-in ``dict’ types cover many needs:

     # use a dictionary relation keyed by a column
     relation(Item, collection_class=column_mapped_collection(items.c.keyword))
     # or named attribute
     relation(Item, collection_class=attribute_mapped_collection('keyword'))
     # or any function you like
     relation(Item, collection_class=mapped_collection(lambda entity: entity.a + entity.b))

Existing 0.3 ‘dict’-like and freeform object derived collection classes
will need to be updated for the new API. In most cases this is simply a
matter of adding a couple decorators to the class definition.

8.4.10.17 Mapped Relations from External Tables/Subqueries
..........................................................

This feature quietly appeared in 0.3 but has been improved in 0.4 thanks
to better ability to convert subqueries against a table into subqueries
against an alias of that table; this is key for eager loading, aliased
joins in queries, etc.  It reduces the need to create mappers against
select statements when you just need to add some extra columns or
subqueries:

     mapper(User, users, properties={
            'fullname': column_property((users.c.firstname + users.c.lastname).label('fullname')),
            'numposts': column_property(
                 select([func.count(1)], users.c.id==posts.c.user_id).correlate(users).label('posts')
            )
         })

a typical query looks like:

     SELECT (SELECT count(1) FROM posts WHERE users.id = posts.user_id) AS count,
     users.firstname || users.lastname AS fullname,
     users.id AS users_id, users.firstname AS users_firstname, users.lastname AS users_lastname
     FROM users ORDER BY users.oid

8.4.10.18 Horizontal Scaling (Sharding) API
...........................................

[browser:/sqlalchemy/trunk/examples/sharding/attribute_shard .py]

8.4.10.19 Sessions
..................

8.4.10.20 New Session Create Paradigm; SessionContext, assignmapper Deprecated
..............................................................................

That’s right, the whole shebang is being replaced with two
configurational functions.  Using both will produce the most 0.1-ish
feel we’ve had since 0.1 (i.e., the least amount of typing).

Configure your own ‘Session’ class right where you define your ‘engine’
(or anywhere):

     from sqlalchemy import create_engine
     from sqlalchemy.orm import sessionmaker

     engine = create_engine('myengine://')
     Session = sessionmaker(bind=engine, autoflush=True, transactional=True)

     # use the new Session() freely
     sess = Session()
     sess.save(someobject)
     sess.flush()

If you need to post-configure your Session, say with an engine, add it
later with ‘configure()’:

     Session.configure(bind=create_engine(...))

All the behaviors of ‘SessionContext’ and the ‘query’ and ‘__init__’
methods of ‘assignmapper’ are moved into the new ‘scoped_session()’
function, which is compatible with both ‘sessionmaker’ as well as
‘create_session()’:

     from sqlalchemy.orm import scoped_session, sessionmaker

     Session = scoped_session(sessionmaker(autoflush=True, transactional=True))
     Session.configure(bind=engine)

     u = User(name='wendy')

     sess = Session()
     sess.save(u)
     sess.commit()

     # Session constructor is thread-locally scoped.  Everyone gets the same
     # Session in the thread when scope="thread".
     sess2 = Session()
     assert sess is sess2

When using a thread-local ‘Session’, the returned class has all of
‘Session's’ interface implemented as classmethods, and “assignmapper“‘s
functionality is available using the ‘mapper’ classmethod.  Just like
the old ‘objectstore’ days….

     # "assignmapper"-like functionality available via ScopedSession.mapper
     Session.mapper(User, users_table)

     u = User(name='wendy')

     Session.commit()

8.4.10.21 Sessions are again Weak Referencing By Default
........................................................

The weak_identity_map flag is now set to ‘True’ by default on Session.
Instances which are externally deferenced and fall out of scope are
removed from the session automatically.  However, items which have
“dirty” changes present will remain strongly referenced until those
changes are flushed at which case the object reverts to being weakly
referenced (this works for ‘mutable’ types, like picklable attributes,
as well).  Setting weak_identity_map to ‘False’ restores the old
strong-referencing behavior for those of you using the session like a
cache.

8.4.10.22 Auto-Transactional Sessions
.....................................

As you might have noticed above, we are calling ‘commit()’ on ‘Session’.
The flag ‘transactional=True’ means the ‘Session’ is always in a
transaction, ‘commit()’ persists permanently.

8.4.10.23 Auto-Flushing Sessions
................................

Also, ‘autoflush=True’ means the ‘Session’ will ‘flush()’ before each
‘query’ as well as when you call ‘flush()’ or ‘commit()’.  So now this
will work:

     Session = sessionmaker(bind=engine, autoflush=True, transactional=True)

     u = User(name='wendy')

     sess = Session()
     sess.save(u)

     # wendy is flushed, comes right back from a query
     wendy = sess.query(User).filter_by(name='wendy').one()

8.4.10.24 Transactional methods moved onto sessions
...................................................

‘commit()’ and ‘rollback()’, as well as ‘begin()’ are now directly on
‘Session’.  No more need to use ‘SessionTransaction’ for anything (it
remains in the background).

     Session = sessionmaker(autoflush=True, transactional=False)

     sess = Session()
     sess.begin()

     # use the session

     sess.commit() # commit transaction

Sharing a ‘Session’ with an enclosing engine-level (i.e.  non-ORM)
transaction is easy:

     Session = sessionmaker(autoflush=True, transactional=False)

     conn = engine.connect()
     trans = conn.begin()
     sess = Session(bind=conn)

     # ... session is transactional

     # commit the outermost transaction
     trans.commit()

8.4.10.25 Nested Session Transactions with SAVEPOINT
....................................................

Available at the Engine and ORM level.  ORM docs so far:

‘http://www.sqlalchemy.org/docs/04/session.html#unitofwork_managing’

8.4.10.26 Two-Phase Commit Sessions
...................................

Available at the Engine and ORM level.  ORM docs so far:

‘http://www.sqlalchemy.org/docs/04/session.html#unitofwork_managing’

8.4.10.27 Inheritance
.....................

8.4.10.28 Polymorphic Inheritance with No Joins or Unions
.........................................................

New docs for inheritance: ‘http://www.sqlalchemy.org/docs/04’
/mappers.html#advdatamapping_mapper_inheritance_joined

8.4.10.29 Better Polymorphic Behavior with ‘get()’
..................................................

All classes within a joined-table inheritance hierarchy get an
‘_instance_key’ using the base class, i.e.  ‘(BaseClass, (1, ), None)’.
That way when you call ‘get()’ a ‘Query’ against the base class, it can
locate subclass instances in the current identity map without querying
the database.

8.4.10.30 Types
...............

8.4.10.31 Custom Subclasses of ‘sqlalchemy.types.TypeDecorator’
...............................................................

There is a New API(1) for subclassing a TypeDecorator.  Using the 0.3
API causes compilation errors in some cases.

   ---------- Footnotes ----------

   (1) http://www.sqlalchemy.org/docs/04/types.html#types_custom

8.4.10.32 SQL Expressions
.........................

8.4.10.33 All New, Deterministic Label/Alias Generation
.......................................................

All the “anonymous” labels and aliases use a simple <name>_<number>
format now.  SQL is much easier to read and is compatible with plan
optimizer caches.  Just check out some of the examples in the tutorials:
‘http://www.sqlalchemy.org/docs/04/ormtutorial.html’
‘http://www.sqlalchemy.org/docs/04/sqlexpression.html’

8.4.10.34 Generative select() Constructs
........................................

This is definitely the way to go with ‘select()’.  See htt
p://www.sqlalchemy.org/docs/04/sqlexpression.html#sql_transf orm .

8.4.10.35 New Operator System
.............................

SQL operators and more or less every SQL keyword there is are now
abstracted into the compiler layer.  They now act intelligently and are
type/backend aware, see:
‘http://www.sqlalchemy.org/docs/04/sqlexpression.html#sql_operators’

8.4.10.36 All ‘type’ Keyword Arguments Renamed to ‘type_’
.........................................................

Just like it says:

     b = bindparam('foo', type_=String)

8.4.10.37 in_ Function Changed to Accept Sequence or Selectable
...............................................................

The in_ function now takes a sequence of values or a selectable as its
sole argument.  The previous API of passing in values as positional
arguments still works, but is now deprecated.  This means that

     my_table.select(my_table.c.id.in_(1,2,3)
     my_table.select(my_table.c.id.in_(*listOfIds)

should be changed to

     my_table.select(my_table.c.id.in_([1,2,3])
     my_table.select(my_table.c.id.in_(listOfIds)

8.4.10.38 Schema and Reflection
...............................

8.4.10.39 ‘MetaData’, ‘BoundMetaData’, ‘DynamicMetaData’…
.........................................................

In the 0.3.x series, ‘BoundMetaData’ and ‘DynamicMetaData’ were
deprecated in favor of ‘MetaData’ and ‘ThreadLocalMetaData’.  The older
names have been removed in 0.4.  Updating is simple:

     +-------------------------------------+-------------------------+
     |If You Had                           | Now Use                 |
     +=====================================+=========================+
     | ``MetaData``                        | ``MetaData``            |
     +-------------------------------------+-------------------------+
     | ``BoundMetaData``                   | ``MetaData``            |
     +-------------------------------------+-------------------------+
     | ``DynamicMetaData`` (with one       | ``MetaData``            |
     | engine or threadlocal=False)        |                         |
     +-------------------------------------+-------------------------+
     | ``DynamicMetaData``                 | ``ThreadLocalMetaData`` |
     | (with different engines per thread) |                         |
     +-------------------------------------+-------------------------+

The seldom-used ‘name’ parameter to ‘MetaData’ types has been removed.
The ‘ThreadLocalMetaData’ constructor now takes no arguments.  Both
types can now be bound to an ‘Engine’ or a single ‘Connection’.

8.4.10.40 One Step Multi-Table Reflection
.........................................

You can now load table definitions and automatically create ‘Table’
objects from an entire database or schema in one pass:

     >>> metadata = MetaData(myengine, reflect=True)
     >>> metadata.tables.keys()
     ['table_a', 'table_b', 'table_c', '...']

‘MetaData’ also gains a ‘.reflect()’ method enabling finer control over
the loading process, including specification of a subset of available
tables to load.

8.4.10.41 SQL Execution
.......................

8.4.10.42 ‘engine’, ‘connectable’, and ‘bind_to’ are all now ‘bind’
...................................................................

8.4.10.43 ‘Transactions’, ‘NestedTransactions’ and ‘TwoPhaseTransactions’
.........................................................................

8.4.10.44 Connection Pool Events
................................

The connection pool now fires events when new DB-API connections are
created, checked out and checked back into the pool.  You can use these
to execute session-scoped SQL setup statements on fresh connections, for
example.

8.4.10.45 Oracle Engine Fixed
.............................

In 0.3.11, there were bugs in the Oracle Engine on how Primary Keys are
handled.  These bugs could cause programs that worked fine with other
engines, such as sqlite, to fail when using the Oracle Engine.  In 0.4,
the Oracle Engine has been reworked, fixing these Primary Key problems.

8.4.10.46 Out Parameters for Oracle
...................................

     result = engine.execute(text("begin foo(:x, :y, :z); end;", bindparams=[bindparam('x', Numeric), outparam('y', Numeric), outparam('z', Numeric)]), x=5)
     assert result.out_parameters == {'y':10, 'z':75}

8.4.10.47 Connection-bound ‘MetaData’, ‘Sessions’
.................................................

‘MetaData’ and ‘Session’ can be explicitly bound to a connection:

     conn = engine.connect()
     sess = create_session(bind=conn)

8.4.10.48 Faster, More Foolproof ‘ResultProxy’ Objects
......................................................

9 Indices and tables
********************

   * glossary

   * genindex