1# dialects/mssql/information_schema.py
2# Copyright (C) 2005-2025 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
23
24ischema = MetaData()
25
26
27class CoerceUnicode(TypeDecorator):
28 impl = Unicode
29 cache_ok = True
30
31 def bind_expression(self, bindvalue):
32 return _cast_on_2005(bindvalue)
33
34
35class _cast_on_2005(expression.ColumnElement):
36 def __init__(self, bindvalue):
37 self.bindvalue = bindvalue
38
39
40@compiles(_cast_on_2005)
41def _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
53schemata = 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
62tables = 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
72columns = 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
91mssql_temp_table_columns = Table(
92 "COLUMNS",
93 ischema,
94 Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
95 Column("TABLE_NAME", CoerceUnicode, key="table_name"),
96 Column("COLUMN_NAME", CoerceUnicode, key="column_name"),
97 Column("IS_NULLABLE", Integer, key="is_nullable"),
98 Column("DATA_TYPE", String, key="data_type"),
99 Column("ORDINAL_POSITION", Integer, key="ordinal_position"),
100 Column(
101 "CHARACTER_MAXIMUM_LENGTH", Integer, key="character_maximum_length"
102 ),
103 Column("NUMERIC_PRECISION", Integer, key="numeric_precision"),
104 Column("NUMERIC_SCALE", Integer, key="numeric_scale"),
105 Column("COLUMN_DEFAULT", Integer, key="column_default"),
106 Column("COLLATION_NAME", String, key="collation_name"),
107 schema="tempdb.INFORMATION_SCHEMA",
108)
109
110constraints = Table(
111 "TABLE_CONSTRAINTS",
112 ischema,
113 Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
114 Column("TABLE_NAME", CoerceUnicode, key="table_name"),
115 Column("CONSTRAINT_NAME", CoerceUnicode, key="constraint_name"),
116 Column("CONSTRAINT_TYPE", CoerceUnicode, key="constraint_type"),
117 schema="INFORMATION_SCHEMA",
118)
119
120column_constraints = Table(
121 "CONSTRAINT_COLUMN_USAGE",
122 ischema,
123 Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
124 Column("TABLE_NAME", CoerceUnicode, key="table_name"),
125 Column("COLUMN_NAME", CoerceUnicode, key="column_name"),
126 Column("CONSTRAINT_NAME", CoerceUnicode, key="constraint_name"),
127 schema="INFORMATION_SCHEMA",
128)
129
130key_constraints = Table(
131 "KEY_COLUMN_USAGE",
132 ischema,
133 Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
134 Column("TABLE_NAME", CoerceUnicode, key="table_name"),
135 Column("COLUMN_NAME", CoerceUnicode, key="column_name"),
136 Column("CONSTRAINT_NAME", CoerceUnicode, key="constraint_name"),
137 Column("CONSTRAINT_SCHEMA", CoerceUnicode, key="constraint_schema"),
138 Column("ORDINAL_POSITION", Integer, key="ordinal_position"),
139 schema="INFORMATION_SCHEMA",
140)
141
142ref_constraints = Table(
143 "REFERENTIAL_CONSTRAINTS",
144 ischema,
145 Column("CONSTRAINT_CATALOG", CoerceUnicode, key="constraint_catalog"),
146 Column("CONSTRAINT_SCHEMA", CoerceUnicode, key="constraint_schema"),
147 Column("CONSTRAINT_NAME", CoerceUnicode, key="constraint_name"),
148 # TODO: is CATLOG misspelled ?
149 Column(
150 "UNIQUE_CONSTRAINT_CATLOG",
151 CoerceUnicode,
152 key="unique_constraint_catalog",
153 ),
154 Column(
155 "UNIQUE_CONSTRAINT_SCHEMA",
156 CoerceUnicode,
157 key="unique_constraint_schema",
158 ),
159 Column(
160 "UNIQUE_CONSTRAINT_NAME", CoerceUnicode, key="unique_constraint_name"
161 ),
162 Column("MATCH_OPTION", String, key="match_option"),
163 Column("UPDATE_RULE", String, key="update_rule"),
164 Column("DELETE_RULE", String, key="delete_rule"),
165 schema="INFORMATION_SCHEMA",
166)
167
168views = Table(
169 "VIEWS",
170 ischema,
171 Column("TABLE_CATALOG", CoerceUnicode, key="table_catalog"),
172 Column("TABLE_SCHEMA", CoerceUnicode, key="table_schema"),
173 Column("TABLE_NAME", CoerceUnicode, key="table_name"),
174 Column("VIEW_DEFINITION", CoerceUnicode, key="view_definition"),
175 Column("CHECK_OPTION", String, key="check_option"),
176 Column("IS_UPDATABLE", String, key="is_updatable"),
177 schema="INFORMATION_SCHEMA",
178)
179
180computed_columns = Table(
181 "computed_columns",
182 ischema,
183 Column("object_id", Integer),
184 Column("name", CoerceUnicode),
185 Column("is_computed", Boolean),
186 Column("is_persisted", Boolean),
187 Column("definition", CoerceUnicode),
188 schema="sys",
189)
190
191sequences = Table(
192 "SEQUENCES",
193 ischema,
194 Column("SEQUENCE_CATALOG", CoerceUnicode, key="sequence_catalog"),
195 Column("SEQUENCE_SCHEMA", CoerceUnicode, key="sequence_schema"),
196 Column("SEQUENCE_NAME", CoerceUnicode, key="sequence_name"),
197 schema="INFORMATION_SCHEMA",
198)
199
200
201class NumericSqlVariant(TypeDecorator):
202 r"""This type casts sql_variant columns in the identity_columns view
203 to numeric. This is required because:
204
205 * pyodbc does not support sql_variant
206 * pymssql under python 2 return the byte representation of the number,
207 int 1 is returned as "\x01\x00\x00\x00". On python 3 it returns the
208 correct value as string.
209 """
210
211 impl = Unicode
212 cache_ok = True
213
214 def column_expression(self, colexpr):
215 return cast(colexpr, Numeric(38, 0))
216
217
218identity_columns = Table(
219 "identity_columns",
220 ischema,
221 Column("object_id", Integer),
222 Column("name", CoerceUnicode),
223 Column("is_identity", Boolean),
224 Column("seed_value", NumericSqlVariant),
225 Column("increment_value", NumericSqlVariant),
226 Column("last_value", NumericSqlVariant),
227 Column("is_not_for_replication", Boolean),
228 schema="sys",
229)
230
231
232class NVarcharSqlVariant(TypeDecorator):
233 """This type casts sql_variant columns in the extended_properties view
234 to nvarchar. This is required because pyodbc does not support sql_variant
235 """
236
237 impl = Unicode
238 cache_ok = True
239
240 def column_expression(self, colexpr):
241 return cast(colexpr, NVARCHAR)
242
243
244extended_properties = Table(
245 "extended_properties",
246 ischema,
247 Column("class", Integer), # TINYINT
248 Column("class_desc", CoerceUnicode),
249 Column("major_id", Integer),
250 Column("minor_id", Integer),
251 Column("name", CoerceUnicode),
252 Column("value", NVarcharSqlVariant),
253 schema="sys",
254)