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
9from ... import cast
10from ... import Column
11from ... import MetaData
12from ... import Table
13from ...ext.compiler import compiles
14from ...sql import expression
15from ...types import Boolean
16from ...types import Integer
17from ...types import Numeric
18from ...types import NVARCHAR
19from ...types import String
20from ...types import TypeDecorator
21from ...types import Unicode
22
23ischema = MetaData()
24
25
26class CoerceUnicode(TypeDecorator):
27 impl = Unicode
28 cache_ok = True
29
30 def bind_expression(self, bindvalue):
31 return _cast_on_2005(bindvalue)
32
33
34class _cast_on_2005(expression.ColumnElement):
35 def __init__(self, bindvalue):
36 self.bindvalue = bindvalue
37
38
39@compiles(_cast_on_2005)
40def _compile(element, compiler, **kw):
41 from . import base
42
43 if (
44 compiler.dialect.server_version_info is None
45 or compiler.dialect.server_version_info < base.MS_2005_VERSION
46 ):
47 return compiler.process(element.bindvalue, **kw)
48 else:
49 return compiler.process(cast(element.bindvalue, Unicode), **kw)
50
51
52schemata = Table(
53 "SCHEMATA",
54 ischema,
55 Column("CATALOG_NAME", CoerceUnicode, key="catalog_name"),
56 Column("SCHEMA_NAME", CoerceUnicode, key="schema_name"),
57 Column("SCHEMA_OWNER", CoerceUnicode, key="schema_owner"),
58 schema="INFORMATION_SCHEMA",
59)
60
61tables = Table(
62 "TABLES",
63 ischema,
64 Column("TABLE_CATALOG", CoerceUnicode, key="table_catalog"),
65 Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
66 Column("TABLE_NAME", CoerceUnicode, key="table_name"),
67 Column("TABLE_TYPE", CoerceUnicode, key="table_type"),
68 schema="INFORMATION_SCHEMA",
69)
70
71columns = Table(
72 "COLUMNS",
73 ischema,
74 Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
75 Column("TABLE_NAME", CoerceUnicode, key="table_name"),
76 Column("COLUMN_NAME", CoerceUnicode, key="column_name"),
77 Column("IS_NULLABLE", Integer, key="is_nullable"),
78 Column("DATA_TYPE", String, key="data_type"),
79 Column("ORDINAL_POSITION", Integer, key="ordinal_position"),
80 Column(
81 "CHARACTER_MAXIMUM_LENGTH", Integer, key="character_maximum_length"
82 ),
83 Column("NUMERIC_PRECISION", Integer, key="numeric_precision"),
84 Column("NUMERIC_SCALE", Integer, key="numeric_scale"),
85 Column("COLUMN_DEFAULT", Integer, key="column_default"),
86 Column("COLLATION_NAME", String, key="collation_name"),
87 schema="INFORMATION_SCHEMA",
88)
89
90sys_columns = Table(
91 "columns",
92 ischema,
93 Column("object_id", Integer),
94 Column("name", CoerceUnicode),
95 Column("column_id", Integer),
96 Column("default_object_id", Integer),
97 Column("user_type_id", Integer),
98 Column("is_nullable", Integer),
99 Column("ordinal_position", Integer),
100 Column("max_length", Integer),
101 Column("precision", Integer),
102 Column("scale", Integer),
103 Column("collation_name", String),
104 schema="sys",
105)
106
107sys_types = Table(
108 "types",
109 ischema,
110 Column("name", CoerceUnicode, key="name"),
111 Column("system_type_id", Integer, key="system_type_id"),
112 Column("user_type_id", Integer, key="user_type_id"),
113 Column("schema_id", Integer, key="schema_id"),
114 Column("max_length", Integer, key="max_length"),
115 Column("precision", Integer, key="precision"),
116 Column("scale", Integer, key="scale"),
117 Column("collation_name", CoerceUnicode, key="collation_name"),
118 Column("is_nullable", Boolean, key="is_nullable"),
119 Column("is_user_defined", Boolean, key="is_user_defined"),
120 Column("is_assembly_type", Boolean, key="is_assembly_type"),
121 Column("default_object_id", Integer, key="default_object_id"),
122 Column("rule_object_id", Integer, key="rule_object_id"),
123 Column("is_table_type", Boolean, key="is_table_type"),
124 schema="sys",
125)
126
127constraints = Table(
128 "TABLE_CONSTRAINTS",
129 ischema,
130 Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
131 Column("TABLE_NAME", CoerceUnicode, key="table_name"),
132 Column("CONSTRAINT_NAME", CoerceUnicode, key="constraint_name"),
133 Column("CONSTRAINT_TYPE", CoerceUnicode, key="constraint_type"),
134 schema="INFORMATION_SCHEMA",
135)
136
137sys_default_constraints = Table(
138 "default_constraints",
139 ischema,
140 Column("object_id", Integer),
141 Column("name", CoerceUnicode),
142 Column("schema_id", Integer),
143 Column("parent_column_id", Integer),
144 Column("definition", CoerceUnicode),
145 schema="sys",
146)
147
148column_constraints = Table(
149 "CONSTRAINT_COLUMN_USAGE",
150 ischema,
151 Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
152 Column("TABLE_NAME", CoerceUnicode, key="table_name"),
153 Column("COLUMN_NAME", CoerceUnicode, key="column_name"),
154 Column("CONSTRAINT_NAME", CoerceUnicode, key="constraint_name"),
155 schema="INFORMATION_SCHEMA",
156)
157
158key_constraints = Table(
159 "KEY_COLUMN_USAGE",
160 ischema,
161 Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
162 Column("TABLE_NAME", CoerceUnicode, key="table_name"),
163 Column("COLUMN_NAME", CoerceUnicode, key="column_name"),
164 Column("CONSTRAINT_NAME", CoerceUnicode, key="constraint_name"),
165 Column("CONSTRAINT_SCHEMA", CoerceUnicode, key="constraint_schema"),
166 Column("ORDINAL_POSITION", Integer, key="ordinal_position"),
167 schema="INFORMATION_SCHEMA",
168)
169
170ref_constraints = Table(
171 "REFERENTIAL_CONSTRAINTS",
172 ischema,
173 Column("CONSTRAINT_CATALOG", CoerceUnicode, key="constraint_catalog"),
174 Column("CONSTRAINT_SCHEMA", CoerceUnicode, key="constraint_schema"),
175 Column("CONSTRAINT_NAME", CoerceUnicode, key="constraint_name"),
176 # TODO: is CATLOG misspelled ?
177 Column(
178 "UNIQUE_CONSTRAINT_CATLOG",
179 CoerceUnicode,
180 key="unique_constraint_catalog",
181 ),
182 Column(
183 "UNIQUE_CONSTRAINT_SCHEMA",
184 CoerceUnicode,
185 key="unique_constraint_schema",
186 ),
187 Column(
188 "UNIQUE_CONSTRAINT_NAME", CoerceUnicode, key="unique_constraint_name"
189 ),
190 Column("MATCH_OPTION", String, key="match_option"),
191 Column("UPDATE_RULE", String, key="update_rule"),
192 Column("DELETE_RULE", String, key="delete_rule"),
193 schema="INFORMATION_SCHEMA",
194)
195
196views = Table(
197 "VIEWS",
198 ischema,
199 Column("TABLE_CATALOG", CoerceUnicode, key="table_catalog"),
200 Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
201 Column("TABLE_NAME", CoerceUnicode, key="table_name"),
202 Column("VIEW_DEFINITION", CoerceUnicode, key="view_definition"),
203 Column("CHECK_OPTION", String, key="check_option"),
204 Column("IS_UPDATABLE", String, key="is_updatable"),
205 schema="INFORMATION_SCHEMA",
206)
207
208computed_columns = Table(
209 "computed_columns",
210 ischema,
211 Column("object_id", Integer),
212 Column("name", CoerceUnicode),
213 Column("column_id", Integer),
214 Column("is_computed", Boolean),
215 Column("is_persisted", Boolean),
216 Column("definition", CoerceUnicode),
217 schema="sys",
218)
219
220sequences = Table(
221 "SEQUENCES",
222 ischema,
223 Column("SEQUENCE_CATALOG", CoerceUnicode, key="sequence_catalog"),
224 Column("SEQUENCE_SCHEMA", CoerceUnicode, key="sequence_schema"),
225 Column("SEQUENCE_NAME", CoerceUnicode, key="sequence_name"),
226 schema="INFORMATION_SCHEMA",
227)
228
229
230class NumericSqlVariant(TypeDecorator):
231 r"""This type casts sql_variant columns in the identity_columns view
232 to numeric. This is required because:
233
234 * pyodbc does not support sql_variant
235 * pymssql under python 2 return the byte representation of the number,
236 int 1 is returned as "\x01\x00\x00\x00". On python 3 it returns the
237 correct value as string.
238 """
239
240 impl = Unicode
241 cache_ok = True
242
243 def column_expression(self, colexpr):
244 return cast(colexpr, Numeric(38, 0))
245
246
247identity_columns = Table(
248 "identity_columns",
249 ischema,
250 Column("object_id", Integer),
251 Column("name", CoerceUnicode),
252 Column("column_id", Integer),
253 Column("is_identity", Boolean),
254 Column("seed_value", NumericSqlVariant),
255 Column("increment_value", NumericSqlVariant),
256 Column("last_value", NumericSqlVariant),
257 Column("is_not_for_replication", Boolean),
258 schema="sys",
259)
260
261
262class NVarcharSqlVariant(TypeDecorator):
263 """This type casts sql_variant columns in the extended_properties view
264 to nvarchar. This is required because pyodbc does not support sql_variant
265 """
266
267 impl = Unicode
268 cache_ok = True
269
270 def column_expression(self, colexpr):
271 return cast(colexpr, NVARCHAR)
272
273
274extended_properties = Table(
275 "extended_properties",
276 ischema,
277 Column("class", Integer), # TINYINT
278 Column("class_desc", CoerceUnicode),
279 Column("major_id", Integer),
280 Column("minor_id", Integer),
281 Column("name", CoerceUnicode),
282 Column("value", NVarcharSqlVariant),
283 schema="sys",
284)