summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/dialects/mssql/base.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/dialects/mssql/base.py')
-rw-r--r--lib/sqlalchemy/dialects/mssql/base.py128
1 files changed, 88 insertions, 40 deletions
diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py
index 5e0704597..9a38a7881 100644
--- a/lib/sqlalchemy/dialects/mssql/base.py
+++ b/lib/sqlalchemy/dialects/mssql/base.py
@@ -22,7 +22,8 @@ behavior for an integer primary key column, described at
the first
integer primary key column in a :class:`_schema.Table`
will be considered to be the
-identity column and will generate DDL as such::
+identity column - unless it is associated with a :class:`.Sequence` - and will
+generate DDL as such::
from sqlalchemy import Table, MetaData, Column, Integer
@@ -76,6 +77,10 @@ is set to ``False`` on any integer primary key column::
the ``mssql_identity_start`` and ``mssql_identity_increment`` parameters
documented at :ref:`mssql_identity`.
+.. versionchanged:: 1.4 Removed the ability to use a :class:`.Sequence`
+ object to modify IDENTITY characteristics. :class:`.Sequence` objects
+ now only manipulate true T-SQL SEQUENCE types.
+
.. note::
There can only be one IDENTITY column on the table. When using
@@ -216,6 +221,17 @@ how SQLAlchemy handles this:
This
is an auxiliary use case suitable for testing and bulk insert scenarios.
+SEQUENCE support
+----------------
+
+The :class:`.Sequence` object now creates "real" sequences, i.e.,
+``CREATE SEQUENCE``. To provide compatibility with other dialects,
+:class:`.Sequence` defaults to a data type of Integer and a start value of 1,
+even though the T-SQL defaults are BIGINT and -9223372036854775808,
+respectively.
+
+.. versionadded:: 1.4.0
+
MAX on VARCHAR / NVARCHAR
-------------------------
@@ -701,6 +717,7 @@ import re
from . import information_schema as ischema
from ... import exc
from ... import schema as sa_schema
+from ... import Sequence
from ... import sql
from ... import types as sqltypes
from ... import util
@@ -713,6 +730,7 @@ from ...sql import expression
from ...sql import func
from ...sql import quoted_name
from ...sql import util as sql_util
+from ...sql.type_api import to_instance
from ...types import BIGINT
from ...types import BINARY
from ...types import CHAR
@@ -1465,18 +1483,20 @@ class MSExecutionContext(default.DefaultExecutionContext):
if self.isinsert:
tbl = self.compiled.statement.table
- seq_column = tbl._autoincrement_column
- insert_has_sequence = seq_column is not None
+ id_column = tbl._autoincrement_column
+ insert_has_identity = (id_column is not None) and (
+ not isinstance(id_column.default, Sequence)
+ )
- if insert_has_sequence:
+ if insert_has_identity:
compile_state = self.compiled.compile_state
self._enable_identity_insert = (
- seq_column.key in self.compiled_parameters[0]
+ id_column.key in self.compiled_parameters[0]
) or (
compile_state._dict_parameters
and (
- seq_column.key in compile_state._dict_parameters
- or seq_column in compile_state._dict_parameters
+ id_column.key in compile_state._dict_parameters
+ or id_column in compile_state._dict_parameters
)
)
@@ -1485,7 +1505,7 @@ class MSExecutionContext(default.DefaultExecutionContext):
self._select_lastrowid = (
not self.compiled.inline
- and insert_has_sequence
+ and insert_has_identity
and not self.compiled.returning
and not self._enable_identity_insert
and not self.executemany
@@ -1570,6 +1590,23 @@ class MSExecutionContext(default.DefaultExecutionContext):
except Exception:
pass
+ def get_result_cursor_strategy(self, result):
+ if self._result_strategy:
+ return self._result_strategy
+ else:
+ return super(MSExecutionContext, self).get_result_cursor_strategy(
+ result
+ )
+
+ def fire_sequence(self, seq, type_):
+ return self._execute_scalar(
+ (
+ "SELECT NEXT VALUE FOR %s"
+ % self.dialect.identifier_preparer.format_sequence(seq)
+ ),
+ type_,
+ )
+
class MSSQLCompiler(compiler.SQLCompiler):
returning_precedes_values = True
@@ -1972,6 +2009,9 @@ class MSSQLCompiler(compiler.SQLCompiler):
self.process(binary.right),
)
+ def visit_sequence(self, seq, **kw):
+ return "NEXT VALUE FOR %s" % self.preparer.format_sequence(seq)
+
class MSSQLStrictCompiler(MSSQLCompiler):
@@ -2050,41 +2090,16 @@ class MSDDLCompiler(compiler.DDLCompiler):
"in order to generate DDL"
)
- # install an IDENTITY Sequence if we either a sequence or an implicit
- # IDENTITY column
- if isinstance(column.default, sa_schema.Sequence):
-
- if (
- column.default.start is not None
- or column.default.increment is not None
- or column is not column.table._autoincrement_column
- ):
- util.warn_deprecated(
- "Use of Sequence with SQL Server in order to affect the "
- "parameters of the IDENTITY value is deprecated, as "
- "Sequence "
- "will correspond to an actual SQL Server "
- "CREATE SEQUENCE in "
- "a future release. Please use the mssql_identity_start "
- "and mssql_identity_increment parameters.",
- version="1.3",
- )
- if column.default.start == 0:
- start = 0
- else:
- start = column.default.start or 1
-
- colspec += " IDENTITY(%s,%s)" % (
- start,
- column.default.increment or 1,
- )
- elif (
+ if (
column is column.table._autoincrement_column
or column.autoincrement is True
):
- start = column.dialect_options["mssql"]["identity_start"]
- increment = column.dialect_options["mssql"]["identity_increment"]
- colspec += " IDENTITY(%s,%s)" % (start, increment)
+ if not isinstance(column.default, Sequence):
+ start = column.dialect_options["mssql"]["identity_start"]
+ increment = column.dialect_options["mssql"][
+ "identity_increment"
+ ]
+ colspec += " IDENTITY(%s,%s)" % (start, increment)
else:
default = self.get_column_default_string(column)
if default is not None:
@@ -2203,6 +2218,18 @@ class MSDDLCompiler(compiler.DDLCompiler):
text += " PERSISTED"
return text
+ def visit_create_sequence(self, create, **kw):
+
+ if create.element.data_type is not None:
+ data_type = create.element.data_type
+ else:
+ data_type = to_instance(self.dialect.sequence_default_column_type)
+
+ prefix = " AS %s" % self.type_compiler.process(data_type)
+ return super(MSDDLCompiler, self).visit_create_sequence(
+ create, prefix=prefix, **kw
+ )
+
class MSIdentifierPreparer(compiler.IdentifierPreparer):
reserved_words = RESERVED_WORDS
@@ -2363,6 +2390,12 @@ class MSDialect(default.DefaultDialect):
ischema_names = ischema_names
+ supports_sequences = True
+ # T-SQL's actual default is BIGINT
+ sequence_default_column_type = INTEGER
+ # T-SQL's actual default is -9223372036854775808
+ default_sequence_base = 1
+
supports_native_boolean = False
non_native_boolean_check_constraint = False
supports_unicode_binds = True
@@ -2565,6 +2598,21 @@ class MSDialect(default.DefaultDialect):
return c.first() is not None
+ @_db_plus_owner
+ def has_sequence(self, connection, sequencename, dbname, owner, schema):
+ sequences = ischema.sequences
+
+ s = sql.select([sequences.c.sequence_name]).where(
+ sequences.c.sequence_name == sequencename
+ )
+
+ if owner:
+ s = s.where(sequences.c.sequence_schema == owner)
+
+ c = connection.execute(s)
+
+ return c.first() is not None
+
@reflection.cache
def get_schema_names(self, connection, **kw):
s = sql.select(