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.
Files changed (274) hide show
  1. sqlalchemy/__init__.py +283 -0
  2. sqlalchemy/connectors/__init__.py +18 -0
  3. sqlalchemy/connectors/aioodbc.py +184 -0
  4. sqlalchemy/connectors/asyncio.py +429 -0
  5. sqlalchemy/connectors/pyodbc.py +250 -0
  6. sqlalchemy/cyextension/__init__.py +6 -0
  7. sqlalchemy/cyextension/collections.cp313t-win32.pyd +0 -0
  8. sqlalchemy/cyextension/collections.pyx +409 -0
  9. sqlalchemy/cyextension/immutabledict.cp313t-win32.pyd +0 -0
  10. sqlalchemy/cyextension/immutabledict.pxd +8 -0
  11. sqlalchemy/cyextension/immutabledict.pyx +133 -0
  12. sqlalchemy/cyextension/processors.cp313t-win32.pyd +0 -0
  13. sqlalchemy/cyextension/processors.pyx +68 -0
  14. sqlalchemy/cyextension/resultproxy.cp313t-win32.pyd +0 -0
  15. sqlalchemy/cyextension/resultproxy.pyx +102 -0
  16. sqlalchemy/cyextension/util.cp313t-win32.pyd +0 -0
  17. sqlalchemy/cyextension/util.pyx +90 -0
  18. sqlalchemy/dialects/__init__.py +62 -0
  19. sqlalchemy/dialects/_typing.py +30 -0
  20. sqlalchemy/dialects/mssql/__init__.py +88 -0
  21. sqlalchemy/dialects/mssql/aioodbc.py +63 -0
  22. sqlalchemy/dialects/mssql/base.py +4093 -0
  23. sqlalchemy/dialects/mssql/information_schema.py +285 -0
  24. sqlalchemy/dialects/mssql/json.py +129 -0
  25. sqlalchemy/dialects/mssql/provision.py +185 -0
  26. sqlalchemy/dialects/mssql/pymssql.py +126 -0
  27. sqlalchemy/dialects/mssql/pyodbc.py +760 -0
  28. sqlalchemy/dialects/mysql/__init__.py +104 -0
  29. sqlalchemy/dialects/mysql/aiomysql.py +250 -0
  30. sqlalchemy/dialects/mysql/asyncmy.py +231 -0
  31. sqlalchemy/dialects/mysql/base.py +3949 -0
  32. sqlalchemy/dialects/mysql/cymysql.py +106 -0
  33. sqlalchemy/dialects/mysql/dml.py +225 -0
  34. sqlalchemy/dialects/mysql/enumerated.py +282 -0
  35. sqlalchemy/dialects/mysql/expression.py +146 -0
  36. sqlalchemy/dialects/mysql/json.py +91 -0
  37. sqlalchemy/dialects/mysql/mariadb.py +72 -0
  38. sqlalchemy/dialects/mysql/mariadbconnector.py +322 -0
  39. sqlalchemy/dialects/mysql/mysqlconnector.py +302 -0
  40. sqlalchemy/dialects/mysql/mysqldb.py +314 -0
  41. sqlalchemy/dialects/mysql/provision.py +153 -0
  42. sqlalchemy/dialects/mysql/pymysql.py +158 -0
  43. sqlalchemy/dialects/mysql/pyodbc.py +157 -0
  44. sqlalchemy/dialects/mysql/reflection.py +727 -0
  45. sqlalchemy/dialects/mysql/reserved_words.py +570 -0
  46. sqlalchemy/dialects/mysql/types.py +835 -0
  47. sqlalchemy/dialects/oracle/__init__.py +81 -0
  48. sqlalchemy/dialects/oracle/base.py +3802 -0
  49. sqlalchemy/dialects/oracle/cx_oracle.py +1555 -0
  50. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  51. sqlalchemy/dialects/oracle/oracledb.py +941 -0
  52. sqlalchemy/dialects/oracle/provision.py +297 -0
  53. sqlalchemy/dialects/oracle/types.py +316 -0
  54. sqlalchemy/dialects/oracle/vector.py +365 -0
  55. sqlalchemy/dialects/postgresql/__init__.py +167 -0
  56. sqlalchemy/dialects/postgresql/_psycopg_common.py +189 -0
  57. sqlalchemy/dialects/postgresql/array.py +519 -0
  58. sqlalchemy/dialects/postgresql/asyncpg.py +1284 -0
  59. sqlalchemy/dialects/postgresql/base.py +5378 -0
  60. sqlalchemy/dialects/postgresql/dml.py +339 -0
  61. sqlalchemy/dialects/postgresql/ext.py +540 -0
  62. sqlalchemy/dialects/postgresql/hstore.py +406 -0
  63. sqlalchemy/dialects/postgresql/json.py +404 -0
  64. sqlalchemy/dialects/postgresql/named_types.py +524 -0
  65. sqlalchemy/dialects/postgresql/operators.py +129 -0
  66. sqlalchemy/dialects/postgresql/pg8000.py +669 -0
  67. sqlalchemy/dialects/postgresql/pg_catalog.py +326 -0
  68. sqlalchemy/dialects/postgresql/provision.py +183 -0
  69. sqlalchemy/dialects/postgresql/psycopg.py +862 -0
  70. sqlalchemy/dialects/postgresql/psycopg2.py +892 -0
  71. sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
  72. sqlalchemy/dialects/postgresql/ranges.py +1031 -0
  73. sqlalchemy/dialects/postgresql/types.py +313 -0
  74. sqlalchemy/dialects/sqlite/__init__.py +57 -0
  75. sqlalchemy/dialects/sqlite/aiosqlite.py +482 -0
  76. sqlalchemy/dialects/sqlite/base.py +3056 -0
  77. sqlalchemy/dialects/sqlite/dml.py +263 -0
  78. sqlalchemy/dialects/sqlite/json.py +92 -0
  79. sqlalchemy/dialects/sqlite/provision.py +229 -0
  80. sqlalchemy/dialects/sqlite/pysqlcipher.py +157 -0
  81. sqlalchemy/dialects/sqlite/pysqlite.py +756 -0
  82. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  83. sqlalchemy/engine/__init__.py +62 -0
  84. sqlalchemy/engine/_py_processors.py +136 -0
  85. sqlalchemy/engine/_py_row.py +128 -0
  86. sqlalchemy/engine/_py_util.py +74 -0
  87. sqlalchemy/engine/base.py +3390 -0
  88. sqlalchemy/engine/characteristics.py +155 -0
  89. sqlalchemy/engine/create.py +893 -0
  90. sqlalchemy/engine/cursor.py +2298 -0
  91. sqlalchemy/engine/default.py +2394 -0
  92. sqlalchemy/engine/events.py +965 -0
  93. sqlalchemy/engine/interfaces.py +3471 -0
  94. sqlalchemy/engine/mock.py +134 -0
  95. sqlalchemy/engine/processors.py +61 -0
  96. sqlalchemy/engine/reflection.py +2102 -0
  97. sqlalchemy/engine/result.py +2399 -0
  98. sqlalchemy/engine/row.py +400 -0
  99. sqlalchemy/engine/strategies.py +16 -0
  100. sqlalchemy/engine/url.py +924 -0
  101. sqlalchemy/engine/util.py +167 -0
  102. sqlalchemy/event/__init__.py +26 -0
  103. sqlalchemy/event/api.py +220 -0
  104. sqlalchemy/event/attr.py +676 -0
  105. sqlalchemy/event/base.py +472 -0
  106. sqlalchemy/event/legacy.py +258 -0
  107. sqlalchemy/event/registry.py +390 -0
  108. sqlalchemy/events.py +17 -0
  109. sqlalchemy/exc.py +832 -0
  110. sqlalchemy/ext/__init__.py +11 -0
  111. sqlalchemy/ext/associationproxy.py +2027 -0
  112. sqlalchemy/ext/asyncio/__init__.py +25 -0
  113. sqlalchemy/ext/asyncio/base.py +281 -0
  114. sqlalchemy/ext/asyncio/engine.py +1471 -0
  115. sqlalchemy/ext/asyncio/exc.py +21 -0
  116. sqlalchemy/ext/asyncio/result.py +965 -0
  117. sqlalchemy/ext/asyncio/scoping.py +1599 -0
  118. sqlalchemy/ext/asyncio/session.py +1947 -0
  119. sqlalchemy/ext/automap.py +1701 -0
  120. sqlalchemy/ext/baked.py +570 -0
  121. sqlalchemy/ext/compiler.py +600 -0
  122. sqlalchemy/ext/declarative/__init__.py +65 -0
  123. sqlalchemy/ext/declarative/extensions.py +564 -0
  124. sqlalchemy/ext/horizontal_shard.py +478 -0
  125. sqlalchemy/ext/hybrid.py +1535 -0
  126. sqlalchemy/ext/indexable.py +364 -0
  127. sqlalchemy/ext/instrumentation.py +450 -0
  128. sqlalchemy/ext/mutable.py +1085 -0
  129. sqlalchemy/ext/mypy/__init__.py +6 -0
  130. sqlalchemy/ext/mypy/apply.py +324 -0
  131. sqlalchemy/ext/mypy/decl_class.py +515 -0
  132. sqlalchemy/ext/mypy/infer.py +590 -0
  133. sqlalchemy/ext/mypy/names.py +335 -0
  134. sqlalchemy/ext/mypy/plugin.py +303 -0
  135. sqlalchemy/ext/mypy/util.py +357 -0
  136. sqlalchemy/ext/orderinglist.py +439 -0
  137. sqlalchemy/ext/serializer.py +185 -0
  138. sqlalchemy/future/__init__.py +16 -0
  139. sqlalchemy/future/engine.py +15 -0
  140. sqlalchemy/inspection.py +174 -0
  141. sqlalchemy/log.py +288 -0
  142. sqlalchemy/orm/__init__.py +171 -0
  143. sqlalchemy/orm/_orm_constructors.py +2661 -0
  144. sqlalchemy/orm/_typing.py +179 -0
  145. sqlalchemy/orm/attributes.py +2845 -0
  146. sqlalchemy/orm/base.py +971 -0
  147. sqlalchemy/orm/bulk_persistence.py +2135 -0
  148. sqlalchemy/orm/clsregistry.py +571 -0
  149. sqlalchemy/orm/collections.py +1627 -0
  150. sqlalchemy/orm/context.py +3334 -0
  151. sqlalchemy/orm/decl_api.py +2004 -0
  152. sqlalchemy/orm/decl_base.py +2192 -0
  153. sqlalchemy/orm/dependency.py +1302 -0
  154. sqlalchemy/orm/descriptor_props.py +1092 -0
  155. sqlalchemy/orm/dynamic.py +300 -0
  156. sqlalchemy/orm/evaluator.py +379 -0
  157. sqlalchemy/orm/events.py +3252 -0
  158. sqlalchemy/orm/exc.py +237 -0
  159. sqlalchemy/orm/identity.py +302 -0
  160. sqlalchemy/orm/instrumentation.py +754 -0
  161. sqlalchemy/orm/interfaces.py +1496 -0
  162. sqlalchemy/orm/loading.py +1686 -0
  163. sqlalchemy/orm/mapped_collection.py +557 -0
  164. sqlalchemy/orm/mapper.py +4444 -0
  165. sqlalchemy/orm/path_registry.py +809 -0
  166. sqlalchemy/orm/persistence.py +1788 -0
  167. sqlalchemy/orm/properties.py +935 -0
  168. sqlalchemy/orm/query.py +3459 -0
  169. sqlalchemy/orm/relationships.py +3508 -0
  170. sqlalchemy/orm/scoping.py +2148 -0
  171. sqlalchemy/orm/session.py +5280 -0
  172. sqlalchemy/orm/state.py +1168 -0
  173. sqlalchemy/orm/state_changes.py +196 -0
  174. sqlalchemy/orm/strategies.py +3470 -0
  175. sqlalchemy/orm/strategy_options.py +2568 -0
  176. sqlalchemy/orm/sync.py +164 -0
  177. sqlalchemy/orm/unitofwork.py +796 -0
  178. sqlalchemy/orm/util.py +2403 -0
  179. sqlalchemy/orm/writeonly.py +674 -0
  180. sqlalchemy/pool/__init__.py +44 -0
  181. sqlalchemy/pool/base.py +1524 -0
  182. sqlalchemy/pool/events.py +375 -0
  183. sqlalchemy/pool/impl.py +588 -0
  184. sqlalchemy/py.typed +0 -0
  185. sqlalchemy/schema.py +69 -0
  186. sqlalchemy/sql/__init__.py +145 -0
  187. sqlalchemy/sql/_dml_constructors.py +132 -0
  188. sqlalchemy/sql/_elements_constructors.py +1872 -0
  189. sqlalchemy/sql/_orm_types.py +20 -0
  190. sqlalchemy/sql/_py_util.py +75 -0
  191. sqlalchemy/sql/_selectable_constructors.py +763 -0
  192. sqlalchemy/sql/_typing.py +482 -0
  193. sqlalchemy/sql/annotation.py +587 -0
  194. sqlalchemy/sql/base.py +2293 -0
  195. sqlalchemy/sql/cache_key.py +1057 -0
  196. sqlalchemy/sql/coercions.py +1404 -0
  197. sqlalchemy/sql/compiler.py +8081 -0
  198. sqlalchemy/sql/crud.py +1752 -0
  199. sqlalchemy/sql/ddl.py +1444 -0
  200. sqlalchemy/sql/default_comparator.py +551 -0
  201. sqlalchemy/sql/dml.py +1850 -0
  202. sqlalchemy/sql/elements.py +5589 -0
  203. sqlalchemy/sql/events.py +458 -0
  204. sqlalchemy/sql/expression.py +159 -0
  205. sqlalchemy/sql/functions.py +2158 -0
  206. sqlalchemy/sql/lambdas.py +1442 -0
  207. sqlalchemy/sql/naming.py +209 -0
  208. sqlalchemy/sql/operators.py +2623 -0
  209. sqlalchemy/sql/roles.py +323 -0
  210. sqlalchemy/sql/schema.py +6222 -0
  211. sqlalchemy/sql/selectable.py +7265 -0
  212. sqlalchemy/sql/sqltypes.py +3930 -0
  213. sqlalchemy/sql/traversals.py +1024 -0
  214. sqlalchemy/sql/type_api.py +2368 -0
  215. sqlalchemy/sql/util.py +1485 -0
  216. sqlalchemy/sql/visitors.py +1164 -0
  217. sqlalchemy/testing/__init__.py +96 -0
  218. sqlalchemy/testing/assertions.py +994 -0
  219. sqlalchemy/testing/assertsql.py +520 -0
  220. sqlalchemy/testing/asyncio.py +135 -0
  221. sqlalchemy/testing/config.py +434 -0
  222. sqlalchemy/testing/engines.py +483 -0
  223. sqlalchemy/testing/entities.py +117 -0
  224. sqlalchemy/testing/exclusions.py +476 -0
  225. sqlalchemy/testing/fixtures/__init__.py +28 -0
  226. sqlalchemy/testing/fixtures/base.py +384 -0
  227. sqlalchemy/testing/fixtures/mypy.py +332 -0
  228. sqlalchemy/testing/fixtures/orm.py +227 -0
  229. sqlalchemy/testing/fixtures/sql.py +482 -0
  230. sqlalchemy/testing/pickleable.py +155 -0
  231. sqlalchemy/testing/plugin/__init__.py +6 -0
  232. sqlalchemy/testing/plugin/bootstrap.py +51 -0
  233. sqlalchemy/testing/plugin/plugin_base.py +828 -0
  234. sqlalchemy/testing/plugin/pytestplugin.py +892 -0
  235. sqlalchemy/testing/profiling.py +329 -0
  236. sqlalchemy/testing/provision.py +603 -0
  237. sqlalchemy/testing/requirements.py +1945 -0
  238. sqlalchemy/testing/schema.py +198 -0
  239. sqlalchemy/testing/suite/__init__.py +19 -0
  240. sqlalchemy/testing/suite/test_cte.py +237 -0
  241. sqlalchemy/testing/suite/test_ddl.py +389 -0
  242. sqlalchemy/testing/suite/test_deprecations.py +153 -0
  243. sqlalchemy/testing/suite/test_dialect.py +776 -0
  244. sqlalchemy/testing/suite/test_insert.py +630 -0
  245. sqlalchemy/testing/suite/test_reflection.py +3557 -0
  246. sqlalchemy/testing/suite/test_results.py +504 -0
  247. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  248. sqlalchemy/testing/suite/test_select.py +2010 -0
  249. sqlalchemy/testing/suite/test_sequence.py +317 -0
  250. sqlalchemy/testing/suite/test_types.py +2147 -0
  251. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  252. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  253. sqlalchemy/testing/util.py +535 -0
  254. sqlalchemy/testing/warnings.py +52 -0
  255. sqlalchemy/types.py +74 -0
  256. sqlalchemy/util/__init__.py +162 -0
  257. sqlalchemy/util/_collections.py +712 -0
  258. sqlalchemy/util/_concurrency_py3k.py +288 -0
  259. sqlalchemy/util/_has_cy.py +40 -0
  260. sqlalchemy/util/_py_collections.py +541 -0
  261. sqlalchemy/util/compat.py +421 -0
  262. sqlalchemy/util/concurrency.py +110 -0
  263. sqlalchemy/util/deprecations.py +401 -0
  264. sqlalchemy/util/langhelpers.py +2203 -0
  265. sqlalchemy/util/preloaded.py +150 -0
  266. sqlalchemy/util/queue.py +322 -0
  267. sqlalchemy/util/tool_support.py +201 -0
  268. sqlalchemy/util/topological.py +120 -0
  269. sqlalchemy/util/typing.py +734 -0
  270. sqlalchemy-2.0.47.dist-info/METADATA +243 -0
  271. sqlalchemy-2.0.47.dist-info/RECORD +274 -0
  272. sqlalchemy-2.0.47.dist-info/WHEEL +5 -0
  273. sqlalchemy-2.0.47.dist-info/licenses/LICENSE +19 -0
  274. 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