SQLAlchemy 2.0.47__cp313-cp313t-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sqlalchemy/__init__.py +283 -0
- sqlalchemy/connectors/__init__.py +18 -0
- sqlalchemy/connectors/aioodbc.py +184 -0
- sqlalchemy/connectors/asyncio.py +429 -0
- sqlalchemy/connectors/pyodbc.py +250 -0
- sqlalchemy/cyextension/__init__.py +6 -0
- sqlalchemy/cyextension/collections.cp313t-win32.pyd +0 -0
- sqlalchemy/cyextension/collections.pyx +409 -0
- sqlalchemy/cyextension/immutabledict.cp313t-win32.pyd +0 -0
- sqlalchemy/cyextension/immutabledict.pxd +8 -0
- sqlalchemy/cyextension/immutabledict.pyx +133 -0
- sqlalchemy/cyextension/processors.cp313t-win32.pyd +0 -0
- sqlalchemy/cyextension/processors.pyx +68 -0
- sqlalchemy/cyextension/resultproxy.cp313t-win32.pyd +0 -0
- sqlalchemy/cyextension/resultproxy.pyx +102 -0
- sqlalchemy/cyextension/util.cp313t-win32.pyd +0 -0
- sqlalchemy/cyextension/util.pyx +90 -0
- sqlalchemy/dialects/__init__.py +62 -0
- sqlalchemy/dialects/_typing.py +30 -0
- sqlalchemy/dialects/mssql/__init__.py +88 -0
- sqlalchemy/dialects/mssql/aioodbc.py +63 -0
- sqlalchemy/dialects/mssql/base.py +4093 -0
- sqlalchemy/dialects/mssql/information_schema.py +285 -0
- sqlalchemy/dialects/mssql/json.py +129 -0
- sqlalchemy/dialects/mssql/provision.py +185 -0
- sqlalchemy/dialects/mssql/pymssql.py +126 -0
- sqlalchemy/dialects/mssql/pyodbc.py +760 -0
- sqlalchemy/dialects/mysql/__init__.py +104 -0
- sqlalchemy/dialects/mysql/aiomysql.py +250 -0
- sqlalchemy/dialects/mysql/asyncmy.py +231 -0
- sqlalchemy/dialects/mysql/base.py +3949 -0
- sqlalchemy/dialects/mysql/cymysql.py +106 -0
- sqlalchemy/dialects/mysql/dml.py +225 -0
- sqlalchemy/dialects/mysql/enumerated.py +282 -0
- sqlalchemy/dialects/mysql/expression.py +146 -0
- sqlalchemy/dialects/mysql/json.py +91 -0
- sqlalchemy/dialects/mysql/mariadb.py +72 -0
- sqlalchemy/dialects/mysql/mariadbconnector.py +322 -0
- sqlalchemy/dialects/mysql/mysqlconnector.py +302 -0
- sqlalchemy/dialects/mysql/mysqldb.py +314 -0
- sqlalchemy/dialects/mysql/provision.py +153 -0
- sqlalchemy/dialects/mysql/pymysql.py +158 -0
- sqlalchemy/dialects/mysql/pyodbc.py +157 -0
- sqlalchemy/dialects/mysql/reflection.py +727 -0
- sqlalchemy/dialects/mysql/reserved_words.py +570 -0
- sqlalchemy/dialects/mysql/types.py +835 -0
- sqlalchemy/dialects/oracle/__init__.py +81 -0
- sqlalchemy/dialects/oracle/base.py +3802 -0
- sqlalchemy/dialects/oracle/cx_oracle.py +1555 -0
- sqlalchemy/dialects/oracle/dictionary.py +507 -0
- sqlalchemy/dialects/oracle/oracledb.py +941 -0
- sqlalchemy/dialects/oracle/provision.py +297 -0
- sqlalchemy/dialects/oracle/types.py +316 -0
- sqlalchemy/dialects/oracle/vector.py +365 -0
- sqlalchemy/dialects/postgresql/__init__.py +167 -0
- sqlalchemy/dialects/postgresql/_psycopg_common.py +189 -0
- sqlalchemy/dialects/postgresql/array.py +519 -0
- sqlalchemy/dialects/postgresql/asyncpg.py +1284 -0
- sqlalchemy/dialects/postgresql/base.py +5378 -0
- sqlalchemy/dialects/postgresql/dml.py +339 -0
- sqlalchemy/dialects/postgresql/ext.py +540 -0
- sqlalchemy/dialects/postgresql/hstore.py +406 -0
- sqlalchemy/dialects/postgresql/json.py +404 -0
- sqlalchemy/dialects/postgresql/named_types.py +524 -0
- sqlalchemy/dialects/postgresql/operators.py +129 -0
- sqlalchemy/dialects/postgresql/pg8000.py +669 -0
- sqlalchemy/dialects/postgresql/pg_catalog.py +326 -0
- sqlalchemy/dialects/postgresql/provision.py +183 -0
- sqlalchemy/dialects/postgresql/psycopg.py +862 -0
- sqlalchemy/dialects/postgresql/psycopg2.py +892 -0
- sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
- sqlalchemy/dialects/postgresql/ranges.py +1031 -0
- sqlalchemy/dialects/postgresql/types.py +313 -0
- sqlalchemy/dialects/sqlite/__init__.py +57 -0
- sqlalchemy/dialects/sqlite/aiosqlite.py +482 -0
- sqlalchemy/dialects/sqlite/base.py +3056 -0
- sqlalchemy/dialects/sqlite/dml.py +263 -0
- sqlalchemy/dialects/sqlite/json.py +92 -0
- sqlalchemy/dialects/sqlite/provision.py +229 -0
- sqlalchemy/dialects/sqlite/pysqlcipher.py +157 -0
- sqlalchemy/dialects/sqlite/pysqlite.py +756 -0
- sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
- sqlalchemy/engine/__init__.py +62 -0
- sqlalchemy/engine/_py_processors.py +136 -0
- sqlalchemy/engine/_py_row.py +128 -0
- sqlalchemy/engine/_py_util.py +74 -0
- sqlalchemy/engine/base.py +3390 -0
- sqlalchemy/engine/characteristics.py +155 -0
- sqlalchemy/engine/create.py +893 -0
- sqlalchemy/engine/cursor.py +2298 -0
- sqlalchemy/engine/default.py +2394 -0
- sqlalchemy/engine/events.py +965 -0
- sqlalchemy/engine/interfaces.py +3471 -0
- sqlalchemy/engine/mock.py +134 -0
- sqlalchemy/engine/processors.py +61 -0
- sqlalchemy/engine/reflection.py +2102 -0
- sqlalchemy/engine/result.py +2399 -0
- sqlalchemy/engine/row.py +400 -0
- sqlalchemy/engine/strategies.py +16 -0
- sqlalchemy/engine/url.py +924 -0
- sqlalchemy/engine/util.py +167 -0
- sqlalchemy/event/__init__.py +26 -0
- sqlalchemy/event/api.py +220 -0
- sqlalchemy/event/attr.py +676 -0
- sqlalchemy/event/base.py +472 -0
- sqlalchemy/event/legacy.py +258 -0
- sqlalchemy/event/registry.py +390 -0
- sqlalchemy/events.py +17 -0
- sqlalchemy/exc.py +832 -0
- sqlalchemy/ext/__init__.py +11 -0
- sqlalchemy/ext/associationproxy.py +2027 -0
- sqlalchemy/ext/asyncio/__init__.py +25 -0
- sqlalchemy/ext/asyncio/base.py +281 -0
- sqlalchemy/ext/asyncio/engine.py +1471 -0
- sqlalchemy/ext/asyncio/exc.py +21 -0
- sqlalchemy/ext/asyncio/result.py +965 -0
- sqlalchemy/ext/asyncio/scoping.py +1599 -0
- sqlalchemy/ext/asyncio/session.py +1947 -0
- sqlalchemy/ext/automap.py +1701 -0
- sqlalchemy/ext/baked.py +570 -0
- sqlalchemy/ext/compiler.py +600 -0
- sqlalchemy/ext/declarative/__init__.py +65 -0
- sqlalchemy/ext/declarative/extensions.py +564 -0
- sqlalchemy/ext/horizontal_shard.py +478 -0
- sqlalchemy/ext/hybrid.py +1535 -0
- sqlalchemy/ext/indexable.py +364 -0
- sqlalchemy/ext/instrumentation.py +450 -0
- sqlalchemy/ext/mutable.py +1085 -0
- sqlalchemy/ext/mypy/__init__.py +6 -0
- sqlalchemy/ext/mypy/apply.py +324 -0
- sqlalchemy/ext/mypy/decl_class.py +515 -0
- sqlalchemy/ext/mypy/infer.py +590 -0
- sqlalchemy/ext/mypy/names.py +335 -0
- sqlalchemy/ext/mypy/plugin.py +303 -0
- sqlalchemy/ext/mypy/util.py +357 -0
- sqlalchemy/ext/orderinglist.py +439 -0
- sqlalchemy/ext/serializer.py +185 -0
- sqlalchemy/future/__init__.py +16 -0
- sqlalchemy/future/engine.py +15 -0
- sqlalchemy/inspection.py +174 -0
- sqlalchemy/log.py +288 -0
- sqlalchemy/orm/__init__.py +171 -0
- sqlalchemy/orm/_orm_constructors.py +2661 -0
- sqlalchemy/orm/_typing.py +179 -0
- sqlalchemy/orm/attributes.py +2845 -0
- sqlalchemy/orm/base.py +971 -0
- sqlalchemy/orm/bulk_persistence.py +2135 -0
- sqlalchemy/orm/clsregistry.py +571 -0
- sqlalchemy/orm/collections.py +1627 -0
- sqlalchemy/orm/context.py +3334 -0
- sqlalchemy/orm/decl_api.py +2004 -0
- sqlalchemy/orm/decl_base.py +2192 -0
- sqlalchemy/orm/dependency.py +1302 -0
- sqlalchemy/orm/descriptor_props.py +1092 -0
- sqlalchemy/orm/dynamic.py +300 -0
- sqlalchemy/orm/evaluator.py +379 -0
- sqlalchemy/orm/events.py +3252 -0
- sqlalchemy/orm/exc.py +237 -0
- sqlalchemy/orm/identity.py +302 -0
- sqlalchemy/orm/instrumentation.py +754 -0
- sqlalchemy/orm/interfaces.py +1496 -0
- sqlalchemy/orm/loading.py +1686 -0
- sqlalchemy/orm/mapped_collection.py +557 -0
- sqlalchemy/orm/mapper.py +4444 -0
- sqlalchemy/orm/path_registry.py +809 -0
- sqlalchemy/orm/persistence.py +1788 -0
- sqlalchemy/orm/properties.py +935 -0
- sqlalchemy/orm/query.py +3459 -0
- sqlalchemy/orm/relationships.py +3508 -0
- sqlalchemy/orm/scoping.py +2148 -0
- sqlalchemy/orm/session.py +5280 -0
- sqlalchemy/orm/state.py +1168 -0
- sqlalchemy/orm/state_changes.py +196 -0
- sqlalchemy/orm/strategies.py +3470 -0
- sqlalchemy/orm/strategy_options.py +2568 -0
- sqlalchemy/orm/sync.py +164 -0
- sqlalchemy/orm/unitofwork.py +796 -0
- sqlalchemy/orm/util.py +2403 -0
- sqlalchemy/orm/writeonly.py +674 -0
- sqlalchemy/pool/__init__.py +44 -0
- sqlalchemy/pool/base.py +1524 -0
- sqlalchemy/pool/events.py +375 -0
- sqlalchemy/pool/impl.py +588 -0
- sqlalchemy/py.typed +0 -0
- sqlalchemy/schema.py +69 -0
- sqlalchemy/sql/__init__.py +145 -0
- sqlalchemy/sql/_dml_constructors.py +132 -0
- sqlalchemy/sql/_elements_constructors.py +1872 -0
- sqlalchemy/sql/_orm_types.py +20 -0
- sqlalchemy/sql/_py_util.py +75 -0
- sqlalchemy/sql/_selectable_constructors.py +763 -0
- sqlalchemy/sql/_typing.py +482 -0
- sqlalchemy/sql/annotation.py +587 -0
- sqlalchemy/sql/base.py +2293 -0
- sqlalchemy/sql/cache_key.py +1057 -0
- sqlalchemy/sql/coercions.py +1404 -0
- sqlalchemy/sql/compiler.py +8081 -0
- sqlalchemy/sql/crud.py +1752 -0
- sqlalchemy/sql/ddl.py +1444 -0
- sqlalchemy/sql/default_comparator.py +551 -0
- sqlalchemy/sql/dml.py +1850 -0
- sqlalchemy/sql/elements.py +5589 -0
- sqlalchemy/sql/events.py +458 -0
- sqlalchemy/sql/expression.py +159 -0
- sqlalchemy/sql/functions.py +2158 -0
- sqlalchemy/sql/lambdas.py +1442 -0
- sqlalchemy/sql/naming.py +209 -0
- sqlalchemy/sql/operators.py +2623 -0
- sqlalchemy/sql/roles.py +323 -0
- sqlalchemy/sql/schema.py +6222 -0
- sqlalchemy/sql/selectable.py +7265 -0
- sqlalchemy/sql/sqltypes.py +3930 -0
- sqlalchemy/sql/traversals.py +1024 -0
- sqlalchemy/sql/type_api.py +2368 -0
- sqlalchemy/sql/util.py +1485 -0
- sqlalchemy/sql/visitors.py +1164 -0
- sqlalchemy/testing/__init__.py +96 -0
- sqlalchemy/testing/assertions.py +994 -0
- sqlalchemy/testing/assertsql.py +520 -0
- sqlalchemy/testing/asyncio.py +135 -0
- sqlalchemy/testing/config.py +434 -0
- sqlalchemy/testing/engines.py +483 -0
- sqlalchemy/testing/entities.py +117 -0
- sqlalchemy/testing/exclusions.py +476 -0
- sqlalchemy/testing/fixtures/__init__.py +28 -0
- sqlalchemy/testing/fixtures/base.py +384 -0
- sqlalchemy/testing/fixtures/mypy.py +332 -0
- sqlalchemy/testing/fixtures/orm.py +227 -0
- sqlalchemy/testing/fixtures/sql.py +482 -0
- sqlalchemy/testing/pickleable.py +155 -0
- sqlalchemy/testing/plugin/__init__.py +6 -0
- sqlalchemy/testing/plugin/bootstrap.py +51 -0
- sqlalchemy/testing/plugin/plugin_base.py +828 -0
- sqlalchemy/testing/plugin/pytestplugin.py +892 -0
- sqlalchemy/testing/profiling.py +329 -0
- sqlalchemy/testing/provision.py +603 -0
- sqlalchemy/testing/requirements.py +1945 -0
- sqlalchemy/testing/schema.py +198 -0
- sqlalchemy/testing/suite/__init__.py +19 -0
- sqlalchemy/testing/suite/test_cte.py +237 -0
- sqlalchemy/testing/suite/test_ddl.py +389 -0
- sqlalchemy/testing/suite/test_deprecations.py +153 -0
- sqlalchemy/testing/suite/test_dialect.py +776 -0
- sqlalchemy/testing/suite/test_insert.py +630 -0
- sqlalchemy/testing/suite/test_reflection.py +3557 -0
- sqlalchemy/testing/suite/test_results.py +504 -0
- sqlalchemy/testing/suite/test_rowcount.py +258 -0
- sqlalchemy/testing/suite/test_select.py +2010 -0
- sqlalchemy/testing/suite/test_sequence.py +317 -0
- sqlalchemy/testing/suite/test_types.py +2147 -0
- sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
- sqlalchemy/testing/suite/test_update_delete.py +139 -0
- sqlalchemy/testing/util.py +535 -0
- sqlalchemy/testing/warnings.py +52 -0
- sqlalchemy/types.py +74 -0
- sqlalchemy/util/__init__.py +162 -0
- sqlalchemy/util/_collections.py +712 -0
- sqlalchemy/util/_concurrency_py3k.py +288 -0
- sqlalchemy/util/_has_cy.py +40 -0
- sqlalchemy/util/_py_collections.py +541 -0
- sqlalchemy/util/compat.py +421 -0
- sqlalchemy/util/concurrency.py +110 -0
- sqlalchemy/util/deprecations.py +401 -0
- sqlalchemy/util/langhelpers.py +2203 -0
- sqlalchemy/util/preloaded.py +150 -0
- sqlalchemy/util/queue.py +322 -0
- sqlalchemy/util/tool_support.py +201 -0
- sqlalchemy/util/topological.py +120 -0
- sqlalchemy/util/typing.py +734 -0
- sqlalchemy-2.0.47.dist-info/METADATA +243 -0
- sqlalchemy-2.0.47.dist-info/RECORD +274 -0
- sqlalchemy-2.0.47.dist-info/WHEEL +5 -0
- sqlalchemy-2.0.47.dist-info/licenses/LICENSE +19 -0
- sqlalchemy-2.0.47.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# dialects/mssql/information_schema.py
|
|
2
|
+
# Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
|
|
3
|
+
# <see AUTHORS file>
|
|
4
|
+
#
|
|
5
|
+
# This module is part of SQLAlchemy and is released under
|
|
6
|
+
# the MIT License: https://www.opensource.org/licenses/mit-license.php
|
|
7
|
+
# mypy: ignore-errors
|
|
8
|
+
|
|
9
|
+
from ... import cast
|
|
10
|
+
from ... import Column
|
|
11
|
+
from ... import MetaData
|
|
12
|
+
from ... import Table
|
|
13
|
+
from ...ext.compiler import compiles
|
|
14
|
+
from ...sql import expression
|
|
15
|
+
from ...types import Boolean
|
|
16
|
+
from ...types import Integer
|
|
17
|
+
from ...types import Numeric
|
|
18
|
+
from ...types import NVARCHAR
|
|
19
|
+
from ...types import String
|
|
20
|
+
from ...types import TypeDecorator
|
|
21
|
+
from ...types import Unicode
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
ischema = MetaData()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class CoerceUnicode(TypeDecorator):
|
|
28
|
+
impl = Unicode
|
|
29
|
+
cache_ok = True
|
|
30
|
+
|
|
31
|
+
def bind_expression(self, bindvalue):
|
|
32
|
+
return _cast_on_2005(bindvalue)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class _cast_on_2005(expression.ColumnElement):
|
|
36
|
+
def __init__(self, bindvalue):
|
|
37
|
+
self.bindvalue = bindvalue
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@compiles(_cast_on_2005)
|
|
41
|
+
def _compile(element, compiler, **kw):
|
|
42
|
+
from . import base
|
|
43
|
+
|
|
44
|
+
if (
|
|
45
|
+
compiler.dialect.server_version_info is None
|
|
46
|
+
or compiler.dialect.server_version_info < base.MS_2005_VERSION
|
|
47
|
+
):
|
|
48
|
+
return compiler.process(element.bindvalue, **kw)
|
|
49
|
+
else:
|
|
50
|
+
return compiler.process(cast(element.bindvalue, Unicode), **kw)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
schemata = Table(
|
|
54
|
+
"SCHEMATA",
|
|
55
|
+
ischema,
|
|
56
|
+
Column("CATALOG_NAME", CoerceUnicode, key="catalog_name"),
|
|
57
|
+
Column("SCHEMA_NAME", CoerceUnicode, key="schema_name"),
|
|
58
|
+
Column("SCHEMA_OWNER", CoerceUnicode, key="schema_owner"),
|
|
59
|
+
schema="INFORMATION_SCHEMA",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
tables = Table(
|
|
63
|
+
"TABLES",
|
|
64
|
+
ischema,
|
|
65
|
+
Column("TABLE_CATALOG", CoerceUnicode, key="table_catalog"),
|
|
66
|
+
Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
|
|
67
|
+
Column("TABLE_NAME", CoerceUnicode, key="table_name"),
|
|
68
|
+
Column("TABLE_TYPE", CoerceUnicode, key="table_type"),
|
|
69
|
+
schema="INFORMATION_SCHEMA",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
columns = Table(
|
|
73
|
+
"COLUMNS",
|
|
74
|
+
ischema,
|
|
75
|
+
Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
|
|
76
|
+
Column("TABLE_NAME", CoerceUnicode, key="table_name"),
|
|
77
|
+
Column("COLUMN_NAME", CoerceUnicode, key="column_name"),
|
|
78
|
+
Column("IS_NULLABLE", Integer, key="is_nullable"),
|
|
79
|
+
Column("DATA_TYPE", String, key="data_type"),
|
|
80
|
+
Column("ORDINAL_POSITION", Integer, key="ordinal_position"),
|
|
81
|
+
Column(
|
|
82
|
+
"CHARACTER_MAXIMUM_LENGTH", Integer, key="character_maximum_length"
|
|
83
|
+
),
|
|
84
|
+
Column("NUMERIC_PRECISION", Integer, key="numeric_precision"),
|
|
85
|
+
Column("NUMERIC_SCALE", Integer, key="numeric_scale"),
|
|
86
|
+
Column("COLUMN_DEFAULT", Integer, key="column_default"),
|
|
87
|
+
Column("COLLATION_NAME", String, key="collation_name"),
|
|
88
|
+
schema="INFORMATION_SCHEMA",
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
sys_columns = Table(
|
|
92
|
+
"columns",
|
|
93
|
+
ischema,
|
|
94
|
+
Column("object_id", Integer),
|
|
95
|
+
Column("name", CoerceUnicode),
|
|
96
|
+
Column("column_id", Integer),
|
|
97
|
+
Column("default_object_id", Integer),
|
|
98
|
+
Column("user_type_id", Integer),
|
|
99
|
+
Column("is_nullable", Integer),
|
|
100
|
+
Column("ordinal_position", Integer),
|
|
101
|
+
Column("max_length", Integer),
|
|
102
|
+
Column("precision", Integer),
|
|
103
|
+
Column("scale", Integer),
|
|
104
|
+
Column("collation_name", String),
|
|
105
|
+
schema="sys",
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
sys_types = Table(
|
|
109
|
+
"types",
|
|
110
|
+
ischema,
|
|
111
|
+
Column("name", CoerceUnicode, key="name"),
|
|
112
|
+
Column("system_type_id", Integer, key="system_type_id"),
|
|
113
|
+
Column("user_type_id", Integer, key="user_type_id"),
|
|
114
|
+
Column("schema_id", Integer, key="schema_id"),
|
|
115
|
+
Column("max_length", Integer, key="max_length"),
|
|
116
|
+
Column("precision", Integer, key="precision"),
|
|
117
|
+
Column("scale", Integer, key="scale"),
|
|
118
|
+
Column("collation_name", CoerceUnicode, key="collation_name"),
|
|
119
|
+
Column("is_nullable", Boolean, key="is_nullable"),
|
|
120
|
+
Column("is_user_defined", Boolean, key="is_user_defined"),
|
|
121
|
+
Column("is_assembly_type", Boolean, key="is_assembly_type"),
|
|
122
|
+
Column("default_object_id", Integer, key="default_object_id"),
|
|
123
|
+
Column("rule_object_id", Integer, key="rule_object_id"),
|
|
124
|
+
Column("is_table_type", Boolean, key="is_table_type"),
|
|
125
|
+
schema="sys",
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
constraints = Table(
|
|
129
|
+
"TABLE_CONSTRAINTS",
|
|
130
|
+
ischema,
|
|
131
|
+
Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
|
|
132
|
+
Column("TABLE_NAME", CoerceUnicode, key="table_name"),
|
|
133
|
+
Column("CONSTRAINT_NAME", CoerceUnicode, key="constraint_name"),
|
|
134
|
+
Column("CONSTRAINT_TYPE", CoerceUnicode, key="constraint_type"),
|
|
135
|
+
schema="INFORMATION_SCHEMA",
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
sys_default_constraints = Table(
|
|
139
|
+
"default_constraints",
|
|
140
|
+
ischema,
|
|
141
|
+
Column("object_id", Integer),
|
|
142
|
+
Column("name", CoerceUnicode),
|
|
143
|
+
Column("schema_id", Integer),
|
|
144
|
+
Column("parent_column_id", Integer),
|
|
145
|
+
Column("definition", CoerceUnicode),
|
|
146
|
+
schema="sys",
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
column_constraints = Table(
|
|
150
|
+
"CONSTRAINT_COLUMN_USAGE",
|
|
151
|
+
ischema,
|
|
152
|
+
Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
|
|
153
|
+
Column("TABLE_NAME", CoerceUnicode, key="table_name"),
|
|
154
|
+
Column("COLUMN_NAME", CoerceUnicode, key="column_name"),
|
|
155
|
+
Column("CONSTRAINT_NAME", CoerceUnicode, key="constraint_name"),
|
|
156
|
+
schema="INFORMATION_SCHEMA",
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
key_constraints = Table(
|
|
160
|
+
"KEY_COLUMN_USAGE",
|
|
161
|
+
ischema,
|
|
162
|
+
Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
|
|
163
|
+
Column("TABLE_NAME", CoerceUnicode, key="table_name"),
|
|
164
|
+
Column("COLUMN_NAME", CoerceUnicode, key="column_name"),
|
|
165
|
+
Column("CONSTRAINT_NAME", CoerceUnicode, key="constraint_name"),
|
|
166
|
+
Column("CONSTRAINT_SCHEMA", CoerceUnicode, key="constraint_schema"),
|
|
167
|
+
Column("ORDINAL_POSITION", Integer, key="ordinal_position"),
|
|
168
|
+
schema="INFORMATION_SCHEMA",
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
ref_constraints = Table(
|
|
172
|
+
"REFERENTIAL_CONSTRAINTS",
|
|
173
|
+
ischema,
|
|
174
|
+
Column("CONSTRAINT_CATALOG", CoerceUnicode, key="constraint_catalog"),
|
|
175
|
+
Column("CONSTRAINT_SCHEMA", CoerceUnicode, key="constraint_schema"),
|
|
176
|
+
Column("CONSTRAINT_NAME", CoerceUnicode, key="constraint_name"),
|
|
177
|
+
# TODO: is CATLOG misspelled ?
|
|
178
|
+
Column(
|
|
179
|
+
"UNIQUE_CONSTRAINT_CATLOG",
|
|
180
|
+
CoerceUnicode,
|
|
181
|
+
key="unique_constraint_catalog",
|
|
182
|
+
),
|
|
183
|
+
Column(
|
|
184
|
+
"UNIQUE_CONSTRAINT_SCHEMA",
|
|
185
|
+
CoerceUnicode,
|
|
186
|
+
key="unique_constraint_schema",
|
|
187
|
+
),
|
|
188
|
+
Column(
|
|
189
|
+
"UNIQUE_CONSTRAINT_NAME", CoerceUnicode, key="unique_constraint_name"
|
|
190
|
+
),
|
|
191
|
+
Column("MATCH_OPTION", String, key="match_option"),
|
|
192
|
+
Column("UPDATE_RULE", String, key="update_rule"),
|
|
193
|
+
Column("DELETE_RULE", String, key="delete_rule"),
|
|
194
|
+
schema="INFORMATION_SCHEMA",
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
views = Table(
|
|
198
|
+
"VIEWS",
|
|
199
|
+
ischema,
|
|
200
|
+
Column("TABLE_CATALOG", CoerceUnicode, key="table_catalog"),
|
|
201
|
+
Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
|
|
202
|
+
Column("TABLE_NAME", CoerceUnicode, key="table_name"),
|
|
203
|
+
Column("VIEW_DEFINITION", CoerceUnicode, key="view_definition"),
|
|
204
|
+
Column("CHECK_OPTION", String, key="check_option"),
|
|
205
|
+
Column("IS_UPDATABLE", String, key="is_updatable"),
|
|
206
|
+
schema="INFORMATION_SCHEMA",
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
computed_columns = Table(
|
|
210
|
+
"computed_columns",
|
|
211
|
+
ischema,
|
|
212
|
+
Column("object_id", Integer),
|
|
213
|
+
Column("name", CoerceUnicode),
|
|
214
|
+
Column("column_id", Integer),
|
|
215
|
+
Column("is_computed", Boolean),
|
|
216
|
+
Column("is_persisted", Boolean),
|
|
217
|
+
Column("definition", CoerceUnicode),
|
|
218
|
+
schema="sys",
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
sequences = Table(
|
|
222
|
+
"SEQUENCES",
|
|
223
|
+
ischema,
|
|
224
|
+
Column("SEQUENCE_CATALOG", CoerceUnicode, key="sequence_catalog"),
|
|
225
|
+
Column("SEQUENCE_SCHEMA", CoerceUnicode, key="sequence_schema"),
|
|
226
|
+
Column("SEQUENCE_NAME", CoerceUnicode, key="sequence_name"),
|
|
227
|
+
schema="INFORMATION_SCHEMA",
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class NumericSqlVariant(TypeDecorator):
|
|
232
|
+
r"""This type casts sql_variant columns in the identity_columns view
|
|
233
|
+
to numeric. This is required because:
|
|
234
|
+
|
|
235
|
+
* pyodbc does not support sql_variant
|
|
236
|
+
* pymssql under python 2 return the byte representation of the number,
|
|
237
|
+
int 1 is returned as "\x01\x00\x00\x00". On python 3 it returns the
|
|
238
|
+
correct value as string.
|
|
239
|
+
"""
|
|
240
|
+
|
|
241
|
+
impl = Unicode
|
|
242
|
+
cache_ok = True
|
|
243
|
+
|
|
244
|
+
def column_expression(self, colexpr):
|
|
245
|
+
return cast(colexpr, Numeric(38, 0))
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
identity_columns = Table(
|
|
249
|
+
"identity_columns",
|
|
250
|
+
ischema,
|
|
251
|
+
Column("object_id", Integer),
|
|
252
|
+
Column("name", CoerceUnicode),
|
|
253
|
+
Column("column_id", Integer),
|
|
254
|
+
Column("is_identity", Boolean),
|
|
255
|
+
Column("seed_value", NumericSqlVariant),
|
|
256
|
+
Column("increment_value", NumericSqlVariant),
|
|
257
|
+
Column("last_value", NumericSqlVariant),
|
|
258
|
+
Column("is_not_for_replication", Boolean),
|
|
259
|
+
schema="sys",
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
class NVarcharSqlVariant(TypeDecorator):
|
|
264
|
+
"""This type casts sql_variant columns in the extended_properties view
|
|
265
|
+
to nvarchar. This is required because pyodbc does not support sql_variant
|
|
266
|
+
"""
|
|
267
|
+
|
|
268
|
+
impl = Unicode
|
|
269
|
+
cache_ok = True
|
|
270
|
+
|
|
271
|
+
def column_expression(self, colexpr):
|
|
272
|
+
return cast(colexpr, NVARCHAR)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
extended_properties = Table(
|
|
276
|
+
"extended_properties",
|
|
277
|
+
ischema,
|
|
278
|
+
Column("class", Integer), # TINYINT
|
|
279
|
+
Column("class_desc", CoerceUnicode),
|
|
280
|
+
Column("major_id", Integer),
|
|
281
|
+
Column("minor_id", Integer),
|
|
282
|
+
Column("name", CoerceUnicode),
|
|
283
|
+
Column("value", NVarcharSqlVariant),
|
|
284
|
+
schema="sys",
|
|
285
|
+
)
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# dialects/mssql/json.py
|
|
2
|
+
# Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
|
|
3
|
+
# <see AUTHORS file>
|
|
4
|
+
#
|
|
5
|
+
# This module is part of SQLAlchemy and is released under
|
|
6
|
+
# the MIT License: https://www.opensource.org/licenses/mit-license.php
|
|
7
|
+
# mypy: ignore-errors
|
|
8
|
+
|
|
9
|
+
from ... import types as sqltypes
|
|
10
|
+
|
|
11
|
+
# technically, all the dialect-specific datatypes that don't have any special
|
|
12
|
+
# behaviors would be private with names like _MSJson. However, we haven't been
|
|
13
|
+
# doing this for mysql.JSON or sqlite.JSON which both have JSON / JSONIndexType
|
|
14
|
+
# / JSONPathType in their json.py files, so keep consistent with that
|
|
15
|
+
# sub-convention for now. A future change can update them all to be
|
|
16
|
+
# package-private at once.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class JSON(sqltypes.JSON):
|
|
20
|
+
"""MSSQL JSON type.
|
|
21
|
+
|
|
22
|
+
MSSQL supports JSON-formatted data as of SQL Server 2016.
|
|
23
|
+
|
|
24
|
+
The :class:`_mssql.JSON` datatype at the DDL level will represent the
|
|
25
|
+
datatype as ``NVARCHAR(max)``, but provides for JSON-level comparison
|
|
26
|
+
functions as well as Python coercion behavior.
|
|
27
|
+
|
|
28
|
+
:class:`_mssql.JSON` is used automatically whenever the base
|
|
29
|
+
:class:`_types.JSON` datatype is used against a SQL Server backend.
|
|
30
|
+
|
|
31
|
+
.. seealso::
|
|
32
|
+
|
|
33
|
+
:class:`_types.JSON` - main documentation for the generic
|
|
34
|
+
cross-platform JSON datatype.
|
|
35
|
+
|
|
36
|
+
The :class:`_mssql.JSON` type supports persistence of JSON values
|
|
37
|
+
as well as the core index operations provided by :class:`_types.JSON`
|
|
38
|
+
datatype, by adapting the operations to render the ``JSON_VALUE``
|
|
39
|
+
or ``JSON_QUERY`` functions at the database level.
|
|
40
|
+
|
|
41
|
+
The SQL Server :class:`_mssql.JSON` type necessarily makes use of the
|
|
42
|
+
``JSON_QUERY`` and ``JSON_VALUE`` functions when querying for elements
|
|
43
|
+
of a JSON object. These two functions have a major restriction in that
|
|
44
|
+
they are **mutually exclusive** based on the type of object to be returned.
|
|
45
|
+
The ``JSON_QUERY`` function **only** returns a JSON dictionary or list,
|
|
46
|
+
but not an individual string, numeric, or boolean element; the
|
|
47
|
+
``JSON_VALUE`` function **only** returns an individual string, numeric,
|
|
48
|
+
or boolean element. **both functions either return NULL or raise
|
|
49
|
+
an error if they are not used against the correct expected value**.
|
|
50
|
+
|
|
51
|
+
To handle this awkward requirement, indexed access rules are as follows:
|
|
52
|
+
|
|
53
|
+
1. When extracting a sub element from a JSON that is itself a JSON
|
|
54
|
+
dictionary or list, the :meth:`_types.JSON.Comparator.as_json` accessor
|
|
55
|
+
should be used::
|
|
56
|
+
|
|
57
|
+
stmt = select(data_table.c.data["some key"].as_json()).where(
|
|
58
|
+
data_table.c.data["some key"].as_json() == {"sub": "structure"}
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
2. When extracting a sub element from a JSON that is a plain boolean,
|
|
62
|
+
string, integer, or float, use the appropriate method among
|
|
63
|
+
:meth:`_types.JSON.Comparator.as_boolean`,
|
|
64
|
+
:meth:`_types.JSON.Comparator.as_string`,
|
|
65
|
+
:meth:`_types.JSON.Comparator.as_integer`,
|
|
66
|
+
:meth:`_types.JSON.Comparator.as_float`::
|
|
67
|
+
|
|
68
|
+
stmt = select(data_table.c.data["some key"].as_string()).where(
|
|
69
|
+
data_table.c.data["some key"].as_string() == "some string"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
.. versionadded:: 1.4
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
# note there was a result processor here that was looking for "number",
|
|
78
|
+
# but none of the tests seem to exercise it.
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# Note: these objects currently match exactly those of MySQL, however since
|
|
82
|
+
# these are not generalizable to all JSON implementations, remain separately
|
|
83
|
+
# implemented for each dialect.
|
|
84
|
+
class _FormatTypeMixin:
|
|
85
|
+
def _format_value(self, value):
|
|
86
|
+
raise NotImplementedError()
|
|
87
|
+
|
|
88
|
+
def bind_processor(self, dialect):
|
|
89
|
+
super_proc = self.string_bind_processor(dialect)
|
|
90
|
+
|
|
91
|
+
def process(value):
|
|
92
|
+
value = self._format_value(value)
|
|
93
|
+
if super_proc:
|
|
94
|
+
value = super_proc(value)
|
|
95
|
+
return value
|
|
96
|
+
|
|
97
|
+
return process
|
|
98
|
+
|
|
99
|
+
def literal_processor(self, dialect):
|
|
100
|
+
super_proc = self.string_literal_processor(dialect)
|
|
101
|
+
|
|
102
|
+
def process(value):
|
|
103
|
+
value = self._format_value(value)
|
|
104
|
+
if super_proc:
|
|
105
|
+
value = super_proc(value)
|
|
106
|
+
return value
|
|
107
|
+
|
|
108
|
+
return process
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class JSONIndexType(_FormatTypeMixin, sqltypes.JSON.JSONIndexType):
|
|
112
|
+
def _format_value(self, value):
|
|
113
|
+
if isinstance(value, int):
|
|
114
|
+
value = "$[%s]" % value
|
|
115
|
+
else:
|
|
116
|
+
value = '$."%s"' % value
|
|
117
|
+
return value
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class JSONPathType(_FormatTypeMixin, sqltypes.JSON.JSONPathType):
|
|
121
|
+
def _format_value(self, value):
|
|
122
|
+
return "$%s" % (
|
|
123
|
+
"".join(
|
|
124
|
+
[
|
|
125
|
+
"[%s]" % elem if isinstance(elem, int) else '."%s"' % elem
|
|
126
|
+
for elem in value
|
|
127
|
+
]
|
|
128
|
+
)
|
|
129
|
+
)
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# dialects/mssql/provision.py
|
|
2
|
+
# Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
|
|
3
|
+
# <see AUTHORS file>
|
|
4
|
+
#
|
|
5
|
+
# This module is part of SQLAlchemy and is released under
|
|
6
|
+
# the MIT License: https://www.opensource.org/licenses/mit-license.php
|
|
7
|
+
# mypy: ignore-errors
|
|
8
|
+
|
|
9
|
+
from sqlalchemy import inspect
|
|
10
|
+
from sqlalchemy import Integer
|
|
11
|
+
from ... import create_engine
|
|
12
|
+
from ... import exc
|
|
13
|
+
from ...schema import Column
|
|
14
|
+
from ...schema import DropConstraint
|
|
15
|
+
from ...schema import ForeignKeyConstraint
|
|
16
|
+
from ...schema import MetaData
|
|
17
|
+
from ...schema import Table
|
|
18
|
+
from ...testing.provision import create_db
|
|
19
|
+
from ...testing.provision import drop_all_schema_objects_pre_tables
|
|
20
|
+
from ...testing.provision import drop_db
|
|
21
|
+
from ...testing.provision import generate_driver_url
|
|
22
|
+
from ...testing.provision import get_temp_table_name
|
|
23
|
+
from ...testing.provision import log
|
|
24
|
+
from ...testing.provision import normalize_sequence
|
|
25
|
+
from ...testing.provision import post_configure_engine
|
|
26
|
+
from ...testing.provision import run_reap_dbs
|
|
27
|
+
from ...testing.provision import temp_table_keyword_args
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@post_configure_engine.for_db("mssql")
|
|
31
|
+
def post_configure_engine(url, engine, follower_ident):
|
|
32
|
+
if engine.driver == "pyodbc":
|
|
33
|
+
engine.dialect.dbapi.pooling = False
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@generate_driver_url.for_db("mssql")
|
|
37
|
+
def generate_driver_url(url, driver, query_str):
|
|
38
|
+
backend = url.get_backend_name()
|
|
39
|
+
|
|
40
|
+
new_url = url.set(drivername="%s+%s" % (backend, driver))
|
|
41
|
+
|
|
42
|
+
if driver not in ("pyodbc", "aioodbc"):
|
|
43
|
+
new_url = new_url.set(query="")
|
|
44
|
+
|
|
45
|
+
if driver == "aioodbc":
|
|
46
|
+
new_url = new_url.update_query_dict({"MARS_Connection": "Yes"})
|
|
47
|
+
|
|
48
|
+
if query_str:
|
|
49
|
+
new_url = new_url.update_query_string(query_str)
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
new_url.get_dialect()
|
|
53
|
+
except exc.NoSuchModuleError:
|
|
54
|
+
return None
|
|
55
|
+
else:
|
|
56
|
+
return new_url
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@create_db.for_db("mssql")
|
|
60
|
+
def _mssql_create_db(cfg, eng, ident):
|
|
61
|
+
with eng.connect().execution_options(isolation_level="AUTOCOMMIT") as conn:
|
|
62
|
+
conn.exec_driver_sql("create database %s" % ident)
|
|
63
|
+
conn.exec_driver_sql(
|
|
64
|
+
"ALTER DATABASE %s SET ALLOW_SNAPSHOT_ISOLATION ON" % ident
|
|
65
|
+
)
|
|
66
|
+
conn.exec_driver_sql(
|
|
67
|
+
"ALTER DATABASE %s SET READ_COMMITTED_SNAPSHOT ON" % ident
|
|
68
|
+
)
|
|
69
|
+
conn.exec_driver_sql("use %s" % ident)
|
|
70
|
+
conn.exec_driver_sql("create schema test_schema")
|
|
71
|
+
conn.exec_driver_sql("create schema test_schema_2")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@drop_db.for_db("mssql")
|
|
75
|
+
def _mssql_drop_db(cfg, eng, ident):
|
|
76
|
+
with eng.connect().execution_options(isolation_level="AUTOCOMMIT") as conn:
|
|
77
|
+
_mssql_drop_ignore(conn, ident)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _mssql_drop_ignore(conn, ident):
|
|
81
|
+
try:
|
|
82
|
+
# typically when this happens, we can't KILL the session anyway,
|
|
83
|
+
# so let the cleanup process drop the DBs
|
|
84
|
+
# for row in conn.exec_driver_sql(
|
|
85
|
+
# "select session_id from sys.dm_exec_sessions "
|
|
86
|
+
# "where database_id=db_id('%s')" % ident):
|
|
87
|
+
# log.info("killing SQL server session %s", row['session_id'])
|
|
88
|
+
# conn.exec_driver_sql("kill %s" % row['session_id'])
|
|
89
|
+
conn.exec_driver_sql("drop database %s" % ident)
|
|
90
|
+
log.info("Reaped db: %s", ident)
|
|
91
|
+
return True
|
|
92
|
+
except exc.DatabaseError as err:
|
|
93
|
+
log.warning("couldn't drop db: %s", err)
|
|
94
|
+
return False
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@run_reap_dbs.for_db("mssql")
|
|
98
|
+
def _reap_mssql_dbs(url, idents):
|
|
99
|
+
log.info("db reaper connecting to %r", url)
|
|
100
|
+
eng = create_engine(url)
|
|
101
|
+
with eng.connect().execution_options(isolation_level="AUTOCOMMIT") as conn:
|
|
102
|
+
log.info("identifiers in file: %s", ", ".join(idents))
|
|
103
|
+
|
|
104
|
+
to_reap = conn.exec_driver_sql(
|
|
105
|
+
"select d.name from sys.databases as d where name "
|
|
106
|
+
"like 'TEST_%' and not exists (select session_id "
|
|
107
|
+
"from sys.dm_exec_sessions "
|
|
108
|
+
"where database_id=d.database_id)"
|
|
109
|
+
)
|
|
110
|
+
all_names = {dbname.lower() for (dbname,) in to_reap}
|
|
111
|
+
to_drop = set()
|
|
112
|
+
for name in all_names:
|
|
113
|
+
if name in idents:
|
|
114
|
+
to_drop.add(name)
|
|
115
|
+
|
|
116
|
+
dropped = total = 0
|
|
117
|
+
for total, dbname in enumerate(to_drop, 1):
|
|
118
|
+
if _mssql_drop_ignore(conn, dbname):
|
|
119
|
+
dropped += 1
|
|
120
|
+
log.info(
|
|
121
|
+
"Dropped %d out of %d stale databases detected", dropped, total
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@temp_table_keyword_args.for_db("mssql")
|
|
126
|
+
def _mssql_temp_table_keyword_args(cfg, eng):
|
|
127
|
+
return {}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@get_temp_table_name.for_db("mssql")
|
|
131
|
+
def _mssql_get_temp_table_name(cfg, eng, base_name):
|
|
132
|
+
return "##" + base_name
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@drop_all_schema_objects_pre_tables.for_db("mssql")
|
|
136
|
+
def drop_all_schema_objects_pre_tables(cfg, eng):
|
|
137
|
+
with eng.connect().execution_options(isolation_level="AUTOCOMMIT") as conn:
|
|
138
|
+
inspector = inspect(conn)
|
|
139
|
+
|
|
140
|
+
# Drop all full-text indexes before dropping catalogs
|
|
141
|
+
fulltext_indexes = conn.exec_driver_sql(
|
|
142
|
+
"SELECT OBJECT_SCHEMA_NAME(object_id) AS schema_name, "
|
|
143
|
+
"OBJECT_NAME(object_id) AS table_name "
|
|
144
|
+
"FROM sys.fulltext_indexes"
|
|
145
|
+
).fetchall()
|
|
146
|
+
|
|
147
|
+
for schema_name, table_name in fulltext_indexes:
|
|
148
|
+
if schema_name:
|
|
149
|
+
qualified_name = f"[{schema_name}].[{table_name}]"
|
|
150
|
+
else:
|
|
151
|
+
qualified_name = f"[{table_name}]"
|
|
152
|
+
conn.exec_driver_sql(f"DROP FULLTEXT INDEX ON {qualified_name}")
|
|
153
|
+
|
|
154
|
+
# Now drop all full-text catalogs
|
|
155
|
+
fulltext_catalogs = conn.exec_driver_sql(
|
|
156
|
+
"SELECT name FROM sys.fulltext_catalogs"
|
|
157
|
+
).fetchall()
|
|
158
|
+
|
|
159
|
+
for (catalog_name,) in fulltext_catalogs:
|
|
160
|
+
conn.exec_driver_sql(f"DROP FULLTEXT CATALOG [{catalog_name}]")
|
|
161
|
+
|
|
162
|
+
for schema in (None, "dbo", cfg.test_schema, cfg.test_schema_2):
|
|
163
|
+
for tname in inspector.get_table_names(schema=schema):
|
|
164
|
+
tb = Table(
|
|
165
|
+
tname,
|
|
166
|
+
MetaData(),
|
|
167
|
+
Column("x", Integer),
|
|
168
|
+
Column("y", Integer),
|
|
169
|
+
schema=schema,
|
|
170
|
+
)
|
|
171
|
+
for fk in inspect(conn).get_foreign_keys(tname, schema=schema):
|
|
172
|
+
conn.execute(
|
|
173
|
+
DropConstraint(
|
|
174
|
+
ForeignKeyConstraint(
|
|
175
|
+
[tb.c.x], [tb.c.y], name=fk["name"]
|
|
176
|
+
)
|
|
177
|
+
)
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@normalize_sequence.for_db("mssql")
|
|
182
|
+
def normalize_sequence(cfg, sequence):
|
|
183
|
+
if sequence.start is None:
|
|
184
|
+
sequence.start = 1
|
|
185
|
+
return sequence
|