summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/dialects/firebird/base.py1
-rw-r--r--lib/sqlalchemy/dialects/firebird/fdb.py2
-rw-r--r--lib/sqlalchemy/dialects/firebird/kinterbasdb.py1
-rw-r--r--lib/sqlalchemy/dialects/mssql/base.py1
-rw-r--r--lib/sqlalchemy/dialects/mssql/mxodbc.py1
-rw-r--r--lib/sqlalchemy/dialects/mssql/pymssql.py1
-rw-r--r--lib/sqlalchemy/dialects/mssql/pyodbc.py1
-rw-r--r--lib/sqlalchemy/dialects/mysql/aiomysql.py1
-rw-r--r--lib/sqlalchemy/dialects/mysql/base.py2
-rw-r--r--lib/sqlalchemy/dialects/mysql/cymysql.py1
-rw-r--r--lib/sqlalchemy/dialects/mysql/mariadb.py3
-rw-r--r--lib/sqlalchemy/dialects/mysql/mariadbconnector.py1
-rw-r--r--lib/sqlalchemy/dialects/mysql/mysqlconnector.py1
-rw-r--r--lib/sqlalchemy/dialects/mysql/mysqldb.py1
-rw-r--r--lib/sqlalchemy/dialects/mysql/oursql.py1
-rw-r--r--lib/sqlalchemy/dialects/mysql/pymysql.py1
-rw-r--r--lib/sqlalchemy/dialects/mysql/pyodbc.py1
-rw-r--r--lib/sqlalchemy/dialects/oracle/base.py5
-rw-r--r--lib/sqlalchemy/dialects/oracle/cx_oracle.py1
-rw-r--r--lib/sqlalchemy/dialects/postgresql/asyncpg.py1
-rw-r--r--lib/sqlalchemy/dialects/postgresql/base.py1
-rw-r--r--lib/sqlalchemy/dialects/postgresql/pg8000.py1
-rw-r--r--lib/sqlalchemy/dialects/postgresql/psycopg2.py3
-rw-r--r--lib/sqlalchemy/dialects/postgresql/psycopg2cffi.py1
-rw-r--r--lib/sqlalchemy/dialects/postgresql/pygresql.py1
-rw-r--r--lib/sqlalchemy/dialects/postgresql/pypostgresql.py1
-rw-r--r--lib/sqlalchemy/dialects/sqlite/aiosqlite.py1
-rw-r--r--lib/sqlalchemy/dialects/sqlite/base.py1
-rw-r--r--lib/sqlalchemy/dialects/sqlite/pysqlcipher.py1
-rw-r--r--lib/sqlalchemy/dialects/sqlite/pysqlite.py1
-rw-r--r--lib/sqlalchemy/dialects/sybase/base.py1
-rw-r--r--lib/sqlalchemy/dialects/sybase/mxodbc.py1
-rw-r--r--lib/sqlalchemy/dialects/sybase/pyodbc.py1
-rw-r--r--lib/sqlalchemy/dialects/sybase/pysybase.py2
-rw-r--r--lib/sqlalchemy/engine/default.py18
-rw-r--r--lib/sqlalchemy/engine/interfaces.py18
-rw-r--r--lib/sqlalchemy/sql/elements.py42
-rw-r--r--lib/sqlalchemy/sql/selectable.py8
38 files changed, 114 insertions, 17 deletions
diff --git a/lib/sqlalchemy/dialects/firebird/base.py b/lib/sqlalchemy/dialects/firebird/base.py
index 7fc914f1b..fcf0c31d3 100644
--- a/lib/sqlalchemy/dialects/firebird/base.py
+++ b/lib/sqlalchemy/dialects/firebird/base.py
@@ -623,6 +623,7 @@ class FBDialect(default.DefaultDialect):
"""Firebird dialect"""
name = "firebird"
+ supports_statement_cache = True
max_identifier_length = 31
diff --git a/lib/sqlalchemy/dialects/firebird/fdb.py b/lib/sqlalchemy/dialects/firebird/fdb.py
index 14954b073..18ed65f45 100644
--- a/lib/sqlalchemy/dialects/firebird/fdb.py
+++ b/lib/sqlalchemy/dialects/firebird/fdb.py
@@ -66,6 +66,8 @@ from ... import util
class FBDialect_fdb(FBDialect_kinterbasdb):
+ supports_statement_cache = True
+
def __init__(self, enable_rowcount=True, retaining=False, **kwargs):
super(FBDialect_fdb, self).__init__(
enable_rowcount=enable_rowcount, retaining=retaining, **kwargs
diff --git a/lib/sqlalchemy/dialects/firebird/kinterbasdb.py b/lib/sqlalchemy/dialects/firebird/kinterbasdb.py
index 4c937e0de..7c91db639 100644
--- a/lib/sqlalchemy/dialects/firebird/kinterbasdb.py
+++ b/lib/sqlalchemy/dialects/firebird/kinterbasdb.py
@@ -78,6 +78,7 @@ class FBExecutionContext_kinterbasdb(FBExecutionContext):
class FBDialect_kinterbasdb(FBDialect):
driver = "kinterbasdb"
+ supports_statement_cache = True
supports_sane_rowcount = False
supports_sane_multi_rowcount = False
execution_ctx_cls = FBExecutionContext_kinterbasdb
diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py
index bfa1cf08c..1fef42c53 100644
--- a/lib/sqlalchemy/dialects/mssql/base.py
+++ b/lib/sqlalchemy/dialects/mssql/base.py
@@ -2576,6 +2576,7 @@ def _schema_elements(schema):
class MSDialect(default.DefaultDialect):
# will assume it's at least mssql2005
name = "mssql"
+ supports_statement_cache = True
supports_default_values = True
supports_empty_insert = False
execution_ctx_cls = MSExecutionContext
diff --git a/lib/sqlalchemy/dialects/mssql/mxodbc.py b/lib/sqlalchemy/dialects/mssql/mxodbc.py
index da4e45f07..637b04869 100644
--- a/lib/sqlalchemy/dialects/mssql/mxodbc.py
+++ b/lib/sqlalchemy/dialects/mssql/mxodbc.py
@@ -126,6 +126,7 @@ class MSDialect_mxodbc(MxODBCConnector, MSDialect):
# this is only needed if "native ODBC" mode is used,
# which is now disabled by default.
# statement_compiler = MSSQLStrictCompiler
+ supports_statement_cache = True
execution_ctx_cls = MSExecutionContext_mxodbc
diff --git a/lib/sqlalchemy/dialects/mssql/pymssql.py b/lib/sqlalchemy/dialects/mssql/pymssql.py
index 5110badb9..4cc6c4696 100644
--- a/lib/sqlalchemy/dialects/mssql/pymssql.py
+++ b/lib/sqlalchemy/dialects/mssql/pymssql.py
@@ -65,6 +65,7 @@ class MSIdentifierPreparer_pymssql(MSIdentifierPreparer):
class MSDialect_pymssql(MSDialect):
+ supports_statement_cache = True
supports_native_decimal = True
driver = "pymssql"
diff --git a/lib/sqlalchemy/dialects/mssql/pyodbc.py b/lib/sqlalchemy/dialects/mssql/pyodbc.py
index 6b2fffc4e..99ab37228 100644
--- a/lib/sqlalchemy/dialects/mssql/pyodbc.py
+++ b/lib/sqlalchemy/dialects/mssql/pyodbc.py
@@ -431,6 +431,7 @@ class MSExecutionContext_pyodbc(MSExecutionContext):
class MSDialect_pyodbc(PyODBCConnector, MSDialect):
+ supports_statement_cache = True
# mssql still has problems with this on Linux
supports_sane_rowcount_returning = False
diff --git a/lib/sqlalchemy/dialects/mysql/aiomysql.py b/lib/sqlalchemy/dialects/mysql/aiomysql.py
index c8c7c0f97..6c77e7525 100644
--- a/lib/sqlalchemy/dialects/mysql/aiomysql.py
+++ b/lib/sqlalchemy/dialects/mysql/aiomysql.py
@@ -266,6 +266,7 @@ class AsyncAdapt_aiomysql_dbapi:
class MySQLDialect_aiomysql(MySQLDialect_pymysql):
driver = "aiomysql"
+ supports_statement_cache = True
supports_server_side_cursors = True
_sscursor = AsyncAdapt_aiomysql_ss_cursor
diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py
index b3c338bad..986ed8757 100644
--- a/lib/sqlalchemy/dialects/mysql/base.py
+++ b/lib/sqlalchemy/dialects/mysql/base.py
@@ -2511,6 +2511,8 @@ class MySQLDialect(default.DefaultDialect):
"""
name = "mysql"
+ supports_statement_cache = True
+
supports_alter = True
# MySQL has no true "boolean" type; we
diff --git a/lib/sqlalchemy/dialects/mysql/cymysql.py b/lib/sqlalchemy/dialects/mysql/cymysql.py
index 0d7ba5594..ec9fd6edd 100644
--- a/lib/sqlalchemy/dialects/mysql/cymysql.py
+++ b/lib/sqlalchemy/dialects/mysql/cymysql.py
@@ -43,6 +43,7 @@ class _cymysqlBIT(BIT):
class MySQLDialect_cymysql(MySQLDialect_mysqldb):
driver = "cymysql"
+ supports_statement_cache = True
description_encoding = None
supports_sane_rowcount = True
diff --git a/lib/sqlalchemy/dialects/mysql/mariadb.py b/lib/sqlalchemy/dialects/mysql/mariadb.py
index 0dbb579e8..8ebde462b 100644
--- a/lib/sqlalchemy/dialects/mysql/mariadb.py
+++ b/lib/sqlalchemy/dialects/mysql/mariadb.py
@@ -3,6 +3,7 @@ from .base import MySQLDialect
class MariaDBDialect(MySQLDialect):
is_mariadb = True
+ supports_statement_cache = True
name = "mariadb"
@@ -18,5 +19,5 @@ def loader(driver):
MariaDBDialect,
driver_cls,
),
- {},
+ {"supports_statement_cache": True},
)
diff --git a/lib/sqlalchemy/dialects/mysql/mariadbconnector.py b/lib/sqlalchemy/dialects/mysql/mariadbconnector.py
index ddc11f6e6..6e3a24950 100644
--- a/lib/sqlalchemy/dialects/mysql/mariadbconnector.py
+++ b/lib/sqlalchemy/dialects/mysql/mariadbconnector.py
@@ -57,6 +57,7 @@ class MySQLIdentifierPreparer_mariadbconnector(MySQLIdentifierPreparer):
class MySQLDialect_mariadbconnector(MySQLDialect):
driver = "mariadbconnector"
+ supports_statement_cache = True
# set this to True at the module level to prevent the driver from running
# against a backend that server detects as MySQL. currently this appears to
diff --git a/lib/sqlalchemy/dialects/mysql/mysqlconnector.py b/lib/sqlalchemy/dialects/mysql/mysqlconnector.py
index 5ed675b13..80f20688b 100644
--- a/lib/sqlalchemy/dialects/mysql/mysqlconnector.py
+++ b/lib/sqlalchemy/dialects/mysql/mysqlconnector.py
@@ -85,6 +85,7 @@ class _myconnpyBIT(BIT):
class MySQLDialect_mysqlconnector(MySQLDialect):
driver = "mysqlconnector"
+ supports_statement_cache = True
supports_unicode_binds = True
diff --git a/lib/sqlalchemy/dialects/mysql/mysqldb.py b/lib/sqlalchemy/dialects/mysql/mysqldb.py
index 0318b5077..274f3eea4 100644
--- a/lib/sqlalchemy/dialects/mysql/mysqldb.py
+++ b/lib/sqlalchemy/dialects/mysql/mysqldb.py
@@ -77,6 +77,7 @@ class MySQLIdentifierPreparer_mysqldb(MySQLIdentifierPreparer):
class MySQLDialect_mysqldb(MySQLDialect):
driver = "mysqldb"
+ supports_statement_cache = True
supports_unicode_statements = True
supports_sane_rowcount = True
supports_sane_multi_rowcount = True
diff --git a/lib/sqlalchemy/dialects/mysql/oursql.py b/lib/sqlalchemy/dialects/mysql/oursql.py
index 5c8c7b7c2..06a6115b4 100644
--- a/lib/sqlalchemy/dialects/mysql/oursql.py
+++ b/lib/sqlalchemy/dialects/mysql/oursql.py
@@ -55,6 +55,7 @@ class MySQLExecutionContext_oursql(MySQLExecutionContext):
class MySQLDialect_oursql(MySQLDialect):
driver = "oursql"
+ supports_statement_cache = True
if util.py2k:
supports_unicode_binds = True
diff --git a/lib/sqlalchemy/dialects/mysql/pymysql.py b/lib/sqlalchemy/dialects/mysql/pymysql.py
index 0c321f854..09b5abffe 100644
--- a/lib/sqlalchemy/dialects/mysql/pymysql.py
+++ b/lib/sqlalchemy/dialects/mysql/pymysql.py
@@ -35,6 +35,7 @@ from ...util import py3k
class MySQLDialect_pymysql(MySQLDialect_mysqldb):
driver = "pymysql"
+ supports_statement_cache = True
description_encoding = None
diff --git a/lib/sqlalchemy/dialects/mysql/pyodbc.py b/lib/sqlalchemy/dialects/mysql/pyodbc.py
index 048586b59..7bc9ff14f 100644
--- a/lib/sqlalchemy/dialects/mysql/pyodbc.py
+++ b/lib/sqlalchemy/dialects/mysql/pyodbc.py
@@ -72,6 +72,7 @@ class MySQLExecutionContext_pyodbc(MySQLExecutionContext):
class MySQLDialect_pyodbc(PyODBCConnector, MySQLDialect):
+ supports_statement_cache = True
colspecs = util.update_copy(MySQLDialect.colspecs, {Time: _pyodbcTIME})
supports_unicode_statements = True
execution_ctx_cls = MySQLExecutionContext_pyodbc
diff --git a/lib/sqlalchemy/dialects/oracle/base.py b/lib/sqlalchemy/dialects/oracle/base.py
index 46fcbbbe1..11ad61675 100644
--- a/lib/sqlalchemy/dialects/oracle/base.py
+++ b/lib/sqlalchemy/dialects/oracle/base.py
@@ -1093,10 +1093,10 @@ class OracleCompiler(compiler.SQLCompiler):
offset_clause = select._offset_clause
if select._simple_int_clause(limit_clause):
- limit_clause = limit_clause._render_literal_execute()
+ limit_clause = limit_clause.render_literal_execute()
if select._simple_int_clause(offset_clause):
- offset_clause = offset_clause._render_literal_execute()
+ offset_clause = offset_clause.render_literal_execute()
# currently using form at:
# https://blogs.oracle.com/oraclemagazine/\
@@ -1434,6 +1434,7 @@ class OracleExecutionContext(default.DefaultExecutionContext):
class OracleDialect(default.DefaultDialect):
name = "oracle"
+ supports_statement_cache = True
supports_alter = True
supports_unicode_statements = False
supports_unicode_binds = False
diff --git a/lib/sqlalchemy/dialects/oracle/cx_oracle.py b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
index 38b92117b..87c817066 100644
--- a/lib/sqlalchemy/dialects/oracle/cx_oracle.py
+++ b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
@@ -797,6 +797,7 @@ class OracleExecutionContext_cx_oracle(OracleExecutionContext):
class OracleDialect_cx_oracle(OracleDialect):
+ supports_statement_cache = True
execution_ctx_cls = OracleExecutionContext_cx_oracle
statement_compiler = OracleCompiler_cx_oracle
diff --git a/lib/sqlalchemy/dialects/postgresql/asyncpg.py b/lib/sqlalchemy/dialects/postgresql/asyncpg.py
index 4580421f6..8cd5bee41 100644
--- a/lib/sqlalchemy/dialects/postgresql/asyncpg.py
+++ b/lib/sqlalchemy/dialects/postgresql/asyncpg.py
@@ -850,6 +850,7 @@ _pg_types = {
class PGDialect_asyncpg(PGDialect):
driver = "asyncpg"
+ supports_statement_cache = True
supports_unicode_statements = True
supports_server_side_cursors = True
diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py
index 97eb07bdb..2c4e316b3 100644
--- a/lib/sqlalchemy/dialects/postgresql/base.py
+++ b/lib/sqlalchemy/dialects/postgresql/base.py
@@ -3062,6 +3062,7 @@ class PGDeferrableConnectionCharacteristic(
class PGDialect(default.DefaultDialect):
name = "postgresql"
+ supports_statement_cache = True
supports_alter = True
max_identifier_length = 63
supports_sane_rowcount = True
diff --git a/lib/sqlalchemy/dialects/postgresql/pg8000.py b/lib/sqlalchemy/dialects/postgresql/pg8000.py
index 43df6edea..eaf6ccbb8 100644
--- a/lib/sqlalchemy/dialects/postgresql/pg8000.py
+++ b/lib/sqlalchemy/dialects/postgresql/pg8000.py
@@ -252,6 +252,7 @@ class PGIdentifierPreparer_pg8000(PGIdentifierPreparer):
class PGDialect_pg8000(PGDialect):
driver = "pg8000"
+ supports_statement_cache = True
supports_unicode_statements = True
diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py
index 16f9ecefa..c2b679022 100644
--- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py
+++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py
@@ -634,6 +634,9 @@ EXECUTEMANY_VALUES_PLUS_BATCH = util.symbol(
class PGDialect_psycopg2(PGDialect):
driver = "psycopg2"
+
+ supports_statement_cache = True
+
if util.py2k:
# turn off supports_unicode_statements for Python 2. psycopg2 supports
# unicode statements in Py2K. But! it does not support unicode *bound
diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2cffi.py b/lib/sqlalchemy/dialects/postgresql/psycopg2cffi.py
index a449f9e65..780244be9 100644
--- a/lib/sqlalchemy/dialects/postgresql/psycopg2cffi.py
+++ b/lib/sqlalchemy/dialects/postgresql/psycopg2cffi.py
@@ -28,6 +28,7 @@ from .psycopg2 import PGDialect_psycopg2
class PGDialect_psycopg2cffi(PGDialect_psycopg2):
driver = "psycopg2cffi"
supports_unicode_statements = True
+ supports_statement_cache = True
# psycopg2cffi's first release is 2.5.0, but reports
# __version__ as 2.4.4. Subsequent releases seem to have
diff --git a/lib/sqlalchemy/dialects/postgresql/pygresql.py b/lib/sqlalchemy/dialects/postgresql/pygresql.py
index 64dd7262d..718bbf78f 100644
--- a/lib/sqlalchemy/dialects/postgresql/pygresql.py
+++ b/lib/sqlalchemy/dialects/postgresql/pygresql.py
@@ -193,6 +193,7 @@ class _PGIdentifierPreparer(PGIdentifierPreparer):
class PGDialect_pygresql(PGDialect):
driver = "pygresql"
+ supports_statement_cache = True
statement_compiler = _PGCompiler
preparer = _PGIdentifierPreparer
diff --git a/lib/sqlalchemy/dialects/postgresql/pypostgresql.py b/lib/sqlalchemy/dialects/postgresql/pypostgresql.py
index 6e4db217d..7d4783867 100644
--- a/lib/sqlalchemy/dialects/postgresql/pypostgresql.py
+++ b/lib/sqlalchemy/dialects/postgresql/pypostgresql.py
@@ -52,6 +52,7 @@ class PGExecutionContext_pypostgresql(PGExecutionContext):
class PGDialect_pypostgresql(PGDialect):
driver = "pypostgresql"
+ supports_statement_cache = True
supports_unicode_statements = True
supports_unicode_binds = True
description_encoding = None
diff --git a/lib/sqlalchemy/dialects/sqlite/aiosqlite.py b/lib/sqlalchemy/dialects/sqlite/aiosqlite.py
index e4b7d1d52..1d09a619d 100644
--- a/lib/sqlalchemy/dialects/sqlite/aiosqlite.py
+++ b/lib/sqlalchemy/dialects/sqlite/aiosqlite.py
@@ -299,6 +299,7 @@ class SQLiteExecutionContext_aiosqlite(SQLiteExecutionContext):
class SQLiteDialect_aiosqlite(SQLiteDialect_pysqlite):
driver = "aiosqlite"
+ supports_statement_cache = True
is_async = True
diff --git a/lib/sqlalchemy/dialects/sqlite/base.py b/lib/sqlalchemy/dialects/sqlite/base.py
index 691ca642d..83c2a8ea7 100644
--- a/lib/sqlalchemy/dialects/sqlite/base.py
+++ b/lib/sqlalchemy/dialects/sqlite/base.py
@@ -1796,6 +1796,7 @@ class SQLiteDialect(default.DefaultDialect):
supports_cast = True
supports_multivalues_insert = True
tuple_in_values = True
+ supports_statement_cache = True
default_paramstyle = "qmark"
execution_ctx_cls = SQLiteExecutionContext
diff --git a/lib/sqlalchemy/dialects/sqlite/pysqlcipher.py b/lib/sqlalchemy/dialects/sqlite/pysqlcipher.py
index 8f0f46acb..ff02d4dee 100644
--- a/lib/sqlalchemy/dialects/sqlite/pysqlcipher.py
+++ b/lib/sqlalchemy/dialects/sqlite/pysqlcipher.py
@@ -98,6 +98,7 @@ from ... import util
class SQLiteDialect_pysqlcipher(SQLiteDialect_pysqlite):
driver = "pysqlcipher"
+ supports_statement_cache = True
pragmas = ("kdf_iter", "cipher", "cipher_page_size", "cipher_use_hmac")
diff --git a/lib/sqlalchemy/dialects/sqlite/pysqlite.py b/lib/sqlalchemy/dialects/sqlite/pysqlite.py
index c940faf38..0b091e73b 100644
--- a/lib/sqlalchemy/dialects/sqlite/pysqlite.py
+++ b/lib/sqlalchemy/dialects/sqlite/pysqlite.py
@@ -443,6 +443,7 @@ class _SQLite_pysqliteDate(DATE):
class SQLiteDialect_pysqlite(SQLiteDialect):
default_paramstyle = "qmark"
+ supports_statement_cache = True
colspecs = util.update_copy(
SQLiteDialect.colspecs,
diff --git a/lib/sqlalchemy/dialects/sybase/base.py b/lib/sqlalchemy/dialects/sybase/base.py
index 49243be78..fd5e5b3b6 100644
--- a/lib/sqlalchemy/dialects/sybase/base.py
+++ b/lib/sqlalchemy/dialects/sybase/base.py
@@ -632,6 +632,7 @@ class SybaseDialect(default.DefaultDialect):
supports_unicode_statements = False
supports_sane_rowcount = False
supports_sane_multi_rowcount = False
+ supports_statement_cache = True
supports_native_boolean = False
supports_unicode_binds = False
diff --git a/lib/sqlalchemy/dialects/sybase/mxodbc.py b/lib/sqlalchemy/dialects/sybase/mxodbc.py
index 6b2f07c54..7002217c0 100644
--- a/lib/sqlalchemy/dialects/sybase/mxodbc.py
+++ b/lib/sqlalchemy/dialects/sybase/mxodbc.py
@@ -28,6 +28,7 @@ class SybaseExecutionContext_mxodbc(SybaseExecutionContext):
class SybaseDialect_mxodbc(MxODBCConnector, SybaseDialect):
execution_ctx_cls = SybaseExecutionContext_mxodbc
+ supports_statement_cache = True
dialect = SybaseDialect_mxodbc
diff --git a/lib/sqlalchemy/dialects/sybase/pyodbc.py b/lib/sqlalchemy/dialects/sybase/pyodbc.py
index bbd6d968a..bbaaa7e02 100644
--- a/lib/sqlalchemy/dialects/sybase/pyodbc.py
+++ b/lib/sqlalchemy/dialects/sybase/pyodbc.py
@@ -77,6 +77,7 @@ class SybaseExecutionContext_pyodbc(SybaseExecutionContext):
class SybaseDialect_pyodbc(PyODBCConnector, SybaseDialect):
execution_ctx_cls = SybaseExecutionContext_pyodbc
+ supports_statement_cache = True
colspecs = {sqltypes.Numeric: _SybNumeric_pyodbc}
diff --git a/lib/sqlalchemy/dialects/sybase/pysybase.py b/lib/sqlalchemy/dialects/sybase/pysybase.py
index d6d2f2ed2..0c5557e99 100644
--- a/lib/sqlalchemy/dialects/sybase/pysybase.py
+++ b/lib/sqlalchemy/dialects/sybase/pysybase.py
@@ -62,6 +62,8 @@ class SybaseDialect_pysybase(SybaseDialect):
execution_ctx_cls = SybaseExecutionContext_pysybase
statement_compiler = SybaseSQLCompiler_pysybase
+ supports_statement_cache = True
+
colspecs = {sqltypes.Numeric: _SybNumeric, sqltypes.Float: sqltypes.Float}
@classmethod
diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py
index 7391e7b01..5193a0273 100644
--- a/lib/sqlalchemy/engine/default.py
+++ b/lib/sqlalchemy/engine/default.py
@@ -44,6 +44,7 @@ CACHE_HIT = util.symbol("CACHE_HIT")
CACHE_MISS = util.symbol("CACHE_MISS")
CACHING_DISABLED = util.symbol("CACHING_DISABLED")
NO_CACHE_KEY = util.symbol("NO_CACHE_KEY")
+NO_DIALECT_SUPPORT = util.symbol("NO_DIALECT_SUPPORT")
class DefaultDialect(interfaces.Dialect):
@@ -57,6 +58,7 @@ class DefaultDialect(interfaces.Dialect):
supports_comments = False
inline_comments = False
use_setinputsizes = False
+ supports_statement_cache = True
# the first value we'd get for an autoincrement
# column.
@@ -215,6 +217,7 @@ class DefaultDialect(interfaces.Dialect):
CACHE_MISS = CACHE_MISS
CACHING_DISABLED = CACHING_DISABLED
NO_CACHE_KEY = NO_CACHE_KEY
+ NO_DIALECT_SUPPORT = NO_DIALECT_SUPPORT
@util.deprecated_params(
convert_unicode=(
@@ -320,6 +323,13 @@ class DefaultDialect(interfaces.Dialect):
self._decoder = processors.to_unicode_processor_factory(self.encoding)
@util.memoized_property
+ def _supports_statement_cache(self):
+ return (
+ self.__class__.__dict__.get("supports_statement_cache", False)
+ is True
+ )
+
+ @util.memoized_property
def _type_memos(self):
return weakref.WeakKeyDictionary()
@@ -771,6 +781,8 @@ class StrCompileDialect(DefaultDialect):
type_compiler = compiler.StrSQLTypeCompiler
preparer = compiler.IdentifierPreparer
+ supports_statement_cache = True
+
supports_sequences = True
sequences_optional = True
preexecute_autoincrement_sequences = False
@@ -1137,6 +1149,12 @@ class DefaultExecutionContext(interfaces.ExecutionContext):
return "generated in %.5fs" % (now - self.compiled._gen_time,)
elif ch is CACHING_DISABLED:
return "caching disabled %.5fs" % (now - self.compiled._gen_time,)
+ elif ch is NO_DIALECT_SUPPORT:
+ return "dialect %s+%s does not support caching %.5fs" % (
+ self.dialect.name,
+ self.dialect.driver,
+ now - self.compiled._gen_time,
+ )
else:
return "unknown"
diff --git a/lib/sqlalchemy/engine/interfaces.py b/lib/sqlalchemy/engine/interfaces.py
index 24e0e5b0d..5e6cc524e 100644
--- a/lib/sqlalchemy/engine/interfaces.py
+++ b/lib/sqlalchemy/engine/interfaces.py
@@ -152,6 +152,24 @@ class Dialect(object):
_has_events = False
+ supports_statement_cache = True
+ """indicates if this dialect supports caching.
+
+ All dialects that are compatible with statement caching should set this
+ flag to True directly on each dialect class and subclass that supports
+ it. SQLAlchemy tests that this flag is locally present on each dialect
+ subclass before it will use statement caching. This is to provide
+ safety for legacy or new dialects that are not yet fully tested to be
+ compliant with SQL statement caching.
+
+ .. versionadded:: 1.4.5
+
+ .. seealso::
+
+ :ref:`engine_thirdparty_caching`
+
+ """
+
def create_connect_args(self, url):
"""Build DB-API compatible connection arguments.
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py
index b64427d51..7a27690b8 100644
--- a/lib/sqlalchemy/sql/elements.py
+++ b/lib/sqlalchemy/sql/elements.py
@@ -514,7 +514,7 @@ class ClauseElement(
schema_translate_map=None,
**kw
):
- if compiled_cache is not None:
+ if compiled_cache is not None and dialect._supports_statement_cache:
elem_cache_key = self._generate_cache_key()
else:
elem_cache_key = None
@@ -553,11 +553,13 @@ class ClauseElement(
schema_translate_map=schema_translate_map,
**kw
)
- cache_hit = (
- dialect.CACHING_DISABLED
- if compiled_cache is None
- else dialect.NO_CACHE_KEY
- )
+
+ if not dialect._supports_statement_cache:
+ cache_hit = dialect.NO_DIALECT_SUPPORT
+ elif compiled_cache is None:
+ cache_hit = dialect.CACHING_DISABLED
+ else:
+ cache_hit = dialect.NO_CACHE_KEY
return compiled_sql, extracted_params, cache_hit
@@ -1429,6 +1431,34 @@ class BindParameter(roles.InElementRole, ColumnElement):
else:
return self.value
+ def render_literal_execute(self):
+ """Produce a copy of this bound parameter that will enable the
+ :paramref:`_sql.BindParameter.literal_execute` flag.
+
+ The :paramref:`_sql.BindParameter.literal_execute` flag will
+ have the effect of the parameter rendered in the compiled SQL
+ string using ``[POSTCOMPILE]`` form, which is a special form that
+ is converted to be a rendering of the literal value of the parameter
+ at SQL execution time. The rationale is to support caching
+ of SQL statement strings that can embed per-statement literal values,
+ such as LIMIT and OFFSET parameters, in the final SQL string that
+ is passed to the DBAPI. Dialects in particular may want to use
+ this method within custom compilation schemes.
+
+ .. versionadded:: 1.4.5
+
+ .. seealso::
+
+ :ref:`engine_thirdparty_caching`
+
+ """
+ return self.__class__(
+ self.key,
+ self.value,
+ type_=self.type,
+ literal_execute=True,
+ )
+
def _with_binary_element_type(self, type_):
c = ClauseElement._clone(self)
c.type = type_
diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py
index 189deec41..a2e5780f8 100644
--- a/lib/sqlalchemy/sql/selectable.py
+++ b/lib/sqlalchemy/sql/selectable.py
@@ -69,14 +69,6 @@ class _OffsetLimitParam(BindParameter):
def _limit_offset_value(self):
return self.effective_value
- def _render_literal_execute(self):
- return _OffsetLimitParam(
- self.key,
- self.value,
- type_=self.type,
- literal_execute=True,
- )
-
@util.deprecated(
"1.4",