dbt-sqlserver 1.11.0rc1__tar.gz → 1.12.0rc2__tar.gz
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.
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/PKG-INFO +34 -10
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/README.md +25 -3
- dbt_sqlserver-1.12.0rc2/dbt/adapters/sqlserver/__version__.py +1 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/sqlserver_adapter.py +120 -20
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/sqlserver_auth.py +8 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/sqlserver_backend.py +95 -1
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/sqlserver_connections.py +322 -6
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/sqlserver_constants.py +5 -1
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/sqlserver_credentials.py +2 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/sqlserver_helpers.py +36 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/sqlserver_relation.py +9 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/sqlserver_runtime.py +78 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/adapters/apply_grants.sql +3 -3
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/adapters/apply_masks.sql +3 -3
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/adapters/columns.sql +1 -1
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/adapters/indexes.sql +124 -58
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/adapters/metadata.sql +3 -3
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/adapters/relation.sql +12 -5
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/adapters/schema.sql +8 -3
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/hooks.sql +5 -1
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/models/incremental/incremental.sql +47 -6
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/models/table/table.sql +5 -3
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/models/unit_test/unit_test_create_table_as.sql +1 -1
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/tests.sql +4 -3
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/unit_tests.sql +6 -4
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/relations/table/create.sql +84 -26
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/relations/views/create.sql +9 -1
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt_sqlserver.egg-info/PKG-INFO +34 -10
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt_sqlserver.egg-info/requires.txt +6 -5
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/pyproject.toml +17 -7
- dbt_sqlserver-1.11.0rc1/dbt/adapters/sqlserver/__version__.py +0 -1
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/LICENSE +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/__init__.py +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/__init__.py +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/py.typed +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/relation_configs/__init__.py +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/relation_configs/index.py +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/relation_configs/policies.py +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/sqlserver_column.py +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/sqlserver_configs.py +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/sqlserver_mask.py +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/__init__.py +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/dbt_project.yml +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/adapters/catalog.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/adapters/persist_docs.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/adapters/show.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/adapters/validate_sql.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/functions/helpers.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/functions/scalar.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/models/incremental/incremental_strategies.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/models/incremental/merge.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/models/table/columns_spec_ddl.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/models/table/table_dml_refresh.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/models/unit_test/get_fixture_sql.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/models/view/create_view_as.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/models/view/view.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/snapshots/helpers.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/snapshots/snapshot.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/snapshots/snapshot_merge.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/materializations/snapshots/strategies.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/relations/seeds/helpers.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/relations/table/clone.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/utils/any_value.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/utils/array_construct.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/utils/cast_bool_to_text.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/utils/concat.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/utils/date_trunc.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/utils/dateadd.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/utils/get_tables_by_pattern.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/utils/hash.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/utils/last_day.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/utils/length.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/utils/listagg.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/utils/position.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/utils/safe_cast.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/utils/split_part.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/macros/utils/timestamps.sql +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/include/sqlserver/profile_template.yml +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt_sqlserver.egg-info/SOURCES.txt +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt_sqlserver.egg-info/dependency_links.txt +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt_sqlserver.egg-info/top_level.txt +0 -0
- {dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dbt-sqlserver
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.12.0rc2
|
|
4
4
|
Summary: A Microsoft SQL Server adapter plugin for dbt
|
|
5
5
|
Author: Mikael Ene, Anders Swanson, Sam Debruyn, Cor Zuurmond, Cody Scott
|
|
6
6
|
License: MIT
|
|
@@ -14,32 +14,45 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
14
14
|
Classifier: Operating System :: Microsoft :: Windows
|
|
15
15
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
16
16
|
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
20
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
-
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Requires-Python: >=3.10
|
|
21
23
|
Description-Content-Type: text/markdown
|
|
22
24
|
License-File: LICENSE
|
|
23
|
-
Requires-Dist: dbt-core<2.0,>=1.
|
|
25
|
+
Requires-Dist: dbt-core<2.0,>=1.12.0
|
|
24
26
|
Requires-Dist: dbt-common<2.0,>=1.22.0
|
|
25
|
-
Requires-Dist: dbt-adapters<2.0,>=1.24.
|
|
26
|
-
Requires-Dist: pyodbc>=5.2.0
|
|
27
|
+
Requires-Dist: dbt-adapters<2.0,>=1.24.5
|
|
27
28
|
Provides-Extra: azure
|
|
28
29
|
Requires-Dist: azure-identity>=1.12.0; extra == "azure"
|
|
29
30
|
Provides-Extra: pyodbc
|
|
30
31
|
Requires-Dist: pyodbc>=5.2.0; extra == "pyodbc"
|
|
31
32
|
Provides-Extra: mssql
|
|
32
33
|
Requires-Dist: mssql-python>=1.7.1; extra == "mssql"
|
|
33
|
-
|
|
34
|
-
Requires-Dist:
|
|
34
|
+
Provides-Extra: adbc
|
|
35
|
+
Requires-Dist: adbc-driver-manager>=1.0.0; extra == "adbc"
|
|
36
|
+
Requires-Dist: pyarrow>=14.0.0; extra == "adbc"
|
|
35
37
|
Dynamic: license-file
|
|
36
38
|
|
|
37
39
|
# dbt-sqlserver
|
|
38
40
|
|
|
39
41
|
[dbt](https://www.getdbt.com) adapter for Microsoft SQL Server and Azure SQL services.
|
|
40
42
|
|
|
41
|
-
The adapter supports dbt-core 1.
|
|
42
|
-
E.g. version 1.
|
|
43
|
+
The adapter supports dbt-core 1.11 or newer and follows the same versioning scheme.
|
|
44
|
+
E.g. version 1.11.x of the adapter is compatible with dbt-core 1.11.x.
|
|
45
|
+
|
|
46
|
+
## Supported Python versions
|
|
47
|
+
|
|
48
|
+
The adapter is tested against:
|
|
49
|
+
|
|
50
|
+
| Python version | Status |
|
|
51
|
+
|---|---|
|
|
52
|
+
| 3.10 | Installable (not tested in CI) |
|
|
53
|
+
| 3.11 | Officially supported |
|
|
54
|
+
| 3.12 | Officially supported |
|
|
55
|
+
| 3.13 | Officially supported |
|
|
43
56
|
|
|
44
57
|
## Supported SQL Server versions
|
|
45
58
|
|
|
@@ -79,6 +92,7 @@ Latest pre-release: * | `dbt-sqlserver[adbc]` | none (driver binary installed separately via the `dbc` CLI) |
|
|
82
96
|
|
|
83
97
|
|
|
84
98
|
### `pyodbc` backend
|
|
@@ -143,6 +157,16 @@ your_profile:
|
|
|
143
157
|
backend: mssql-python # <-- enables this backend
|
|
144
158
|
```
|
|
145
159
|
|
|
160
|
+
### `adbc` backend *(experimental)*
|
|
161
|
+
|
|
162
|
+
An Arrow-native backend built on [ADBC](https://arrow.apache.org/adbc/), avoiding the row-based ODBC/DB-API bridge entirely. SQL Server authentication only (no Azure AD / Windows auth yet).
|
|
163
|
+
|
|
164
|
+
```shell
|
|
165
|
+
pip install -U "dbt-sqlserver[adbc]"
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
The driver binary is not on PyPI and must be installed once via the `dbc` CLI. See [docs/adbc_backend.md](docs/adbc_backend.md) for the full setup, configuration, and known-differences guide.
|
|
169
|
+
|
|
146
170
|
## Changelog
|
|
147
171
|
|
|
148
172
|
See [the changelog](CHANGELOG.md)
|
|
@@ -176,7 +200,7 @@ The same setting is also honoured via `vars:` for backwards compatibility; the b
|
|
|
176
200
|
|
|
177
201
|
### `backend`
|
|
178
202
|
|
|
179
|
-
*(default: `pyodbc`)* Set to `mssql-python` in a profile target to use
|
|
203
|
+
*(default: `pyodbc`)* Set to `mssql-python` or `adbc` (experimental, see [docs/adbc_backend.md](docs/adbc_backend.md)) in a profile target to use that backend instead of `pyodbc`. The adapter fails if the required backend package (Python dependency), such as `pyodbc`, `mssql-python`, or `adbc-driver-manager`, is not installed.
|
|
180
204
|
|
|
181
205
|
### `dbt_sqlserver_enable_safe_type_expansion`
|
|
182
206
|
|
|
@@ -2,8 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
[dbt](https://www.getdbt.com) adapter for Microsoft SQL Server and Azure SQL services.
|
|
4
4
|
|
|
5
|
-
The adapter supports dbt-core 1.
|
|
6
|
-
E.g. version 1.
|
|
5
|
+
The adapter supports dbt-core 1.11 or newer and follows the same versioning scheme.
|
|
6
|
+
E.g. version 1.11.x of the adapter is compatible with dbt-core 1.11.x.
|
|
7
|
+
|
|
8
|
+
## Supported Python versions
|
|
9
|
+
|
|
10
|
+
The adapter is tested against:
|
|
11
|
+
|
|
12
|
+
| Python version | Status |
|
|
13
|
+
|---|---|
|
|
14
|
+
| 3.10 | Installable (not tested in CI) |
|
|
15
|
+
| 3.11 | Officially supported |
|
|
16
|
+
| 3.12 | Officially supported |
|
|
17
|
+
| 3.13 | Officially supported |
|
|
7
18
|
|
|
8
19
|
## Supported SQL Server versions
|
|
9
20
|
|
|
@@ -43,6 +54,7 @@ Latest pre-release: * | `dbt-sqlserver[adbc]` | none (driver binary installed separately via the `dbc` CLI) |
|
|
46
58
|
|
|
47
59
|
|
|
48
60
|
### `pyodbc` backend
|
|
@@ -107,6 +119,16 @@ your_profile:
|
|
|
107
119
|
backend: mssql-python # <-- enables this backend
|
|
108
120
|
```
|
|
109
121
|
|
|
122
|
+
### `adbc` backend *(experimental)*
|
|
123
|
+
|
|
124
|
+
An Arrow-native backend built on [ADBC](https://arrow.apache.org/adbc/), avoiding the row-based ODBC/DB-API bridge entirely. SQL Server authentication only (no Azure AD / Windows auth yet).
|
|
125
|
+
|
|
126
|
+
```shell
|
|
127
|
+
pip install -U "dbt-sqlserver[adbc]"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The driver binary is not on PyPI and must be installed once via the `dbc` CLI. See [docs/adbc_backend.md](docs/adbc_backend.md) for the full setup, configuration, and known-differences guide.
|
|
131
|
+
|
|
110
132
|
## Changelog
|
|
111
133
|
|
|
112
134
|
See [the changelog](CHANGELOG.md)
|
|
@@ -140,7 +162,7 @@ The same setting is also honoured via `vars:` for backwards compatibility; the b
|
|
|
140
162
|
|
|
141
163
|
### `backend`
|
|
142
164
|
|
|
143
|
-
*(default: `pyodbc`)* Set to `mssql-python` in a profile target to use
|
|
165
|
+
*(default: `pyodbc`)* Set to `mssql-python` or `adbc` (experimental, see [docs/adbc_backend.md](docs/adbc_backend.md)) in a profile target to use that backend instead of `pyodbc`. The adapter fails if the required backend package (Python dependency), such as `pyodbc`, `mssql-python`, or `adbc-driver-manager`, is not installed.
|
|
144
166
|
|
|
145
167
|
### `dbt_sqlserver_enable_safe_type_expansion`
|
|
146
168
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
version = "1.12.0rc2"
|
{dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/sqlserver_adapter.py
RENAMED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import datetime as _dt
|
|
2
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
2
3
|
|
|
3
4
|
import agate
|
|
4
5
|
import dbt_common.exceptions
|
|
@@ -37,6 +38,44 @@ from dbt.adapters.sqlserver.sqlserver_relation import SQLServerRelation
|
|
|
37
38
|
logger = AdapterLogger("SQLServer")
|
|
38
39
|
|
|
39
40
|
|
|
41
|
+
def _normalize_result_datetimes(
|
|
42
|
+
result: Union[Tuple, List[Tuple], None],
|
|
43
|
+
) -> Union[Tuple, List[Tuple], None]:
|
|
44
|
+
"""Strip spurious ``tzinfo=UTC`` that ADBC attaches to SQL Server
|
|
45
|
+
DATETIME2 / DATETIME values.
|
|
46
|
+
|
|
47
|
+
SQL Server does **not** store timezone offsets for these types, so the
|
|
48
|
+
correct Python representation is a naive ``datetime``. ADBC's Arrow
|
|
49
|
+
backend wraps every ``timestamp`` column as ``timestamp[us, tz=UTC]``
|
|
50
|
+
regardless of the source semantics, producing ``datetime(…, tzinfo=UTC)``.
|
|
51
|
+
We revert that to match SQL Server semantics and to stay compatible with
|
|
52
|
+
the existing pyodbc / mssql-python backends.
|
|
53
|
+
"""
|
|
54
|
+
if result is None:
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
if isinstance(result, tuple):
|
|
58
|
+
return tuple(
|
|
59
|
+
(v.replace(tzinfo=None) if isinstance(v, _dt.datetime) and v.tzinfo is not None else v)
|
|
60
|
+
for v in result
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
if isinstance(result, list):
|
|
64
|
+
return [
|
|
65
|
+
tuple(
|
|
66
|
+
(
|
|
67
|
+
v.replace(tzinfo=None)
|
|
68
|
+
if isinstance(v, _dt.datetime) and v.tzinfo is not None
|
|
69
|
+
else v
|
|
70
|
+
)
|
|
71
|
+
for v in row
|
|
72
|
+
)
|
|
73
|
+
for row in result
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
return result
|
|
77
|
+
|
|
78
|
+
|
|
40
79
|
class SQLServerAdapter(SQLAdapter):
|
|
41
80
|
"""
|
|
42
81
|
Controls actual implementation of adapter, and ability to override certain methods.
|
|
@@ -77,14 +116,6 @@ class SQLServerAdapter(SQLAdapter):
|
|
|
77
116
|
@property
|
|
78
117
|
def _behavior_flags(self) -> List[BehaviorFlag]:
|
|
79
118
|
return [
|
|
80
|
-
{
|
|
81
|
-
"name": "empty",
|
|
82
|
-
"default": False,
|
|
83
|
-
"description": (
|
|
84
|
-
"When enabled, table and view materializations will be created as empty "
|
|
85
|
-
"structures (no data)."
|
|
86
|
-
),
|
|
87
|
-
},
|
|
88
119
|
{
|
|
89
120
|
"name": "dbt_sqlserver_use_default_schema_concat",
|
|
90
121
|
"default": False,
|
|
@@ -108,13 +139,14 @@ class SQLServerAdapter(SQLAdapter):
|
|
|
108
139
|
},
|
|
109
140
|
{
|
|
110
141
|
"name": "dbt_sqlserver_use_native_string_types",
|
|
111
|
-
"default":
|
|
142
|
+
"default": True,
|
|
112
143
|
"description": (
|
|
113
|
-
"When True, uses SQL Server-native string type mappings: "
|
|
144
|
+
"When True (default), uses SQL Server-native string type mappings: "
|
|
114
145
|
"STRING -> VARCHAR(MAX), NCHAR -> NCHAR(1), NVARCHAR -> NVARCHAR(4000). "
|
|
115
|
-
"When False
|
|
146
|
+
"When False, preserves deprecated legacy mappings: "
|
|
116
147
|
"STRING and NVARCHAR -> VARCHAR(8000), NCHAR -> CHAR(1). "
|
|
117
|
-
"The
|
|
148
|
+
"The legacy False behavior is deprecated "
|
|
149
|
+
"and will be removed in a future release."
|
|
118
150
|
),
|
|
119
151
|
},
|
|
120
152
|
{
|
|
@@ -129,14 +161,15 @@ class SQLServerAdapter(SQLAdapter):
|
|
|
129
161
|
},
|
|
130
162
|
{
|
|
131
163
|
"name": "dbt_sqlserver_use_dbt_transactions",
|
|
132
|
-
"default":
|
|
164
|
+
"default": True,
|
|
133
165
|
"description": (
|
|
134
|
-
"When True, dbt transaction hooks (begin/commit) emit real T-SQL "
|
|
166
|
+
"When True (default), dbt transaction hooks (begin/commit) emit real T-SQL "
|
|
135
167
|
"BEGIN TRANSACTION / COMMIT TRANSACTION statements. "
|
|
136
|
-
"When False
|
|
137
|
-
"is auto-committed by the driver
|
|
168
|
+
"When False, begin/commit are no-ops and each statement "
|
|
169
|
+
"is auto-committed by the driver, meaning earlier successful statements "
|
|
138
170
|
"are not rolled back if a later statement fails. "
|
|
139
|
-
"
|
|
171
|
+
"The legacy False behavior is deprecated "
|
|
172
|
+
"and will be removed in a future release."
|
|
140
173
|
),
|
|
141
174
|
},
|
|
142
175
|
]
|
|
@@ -155,6 +188,22 @@ class SQLServerAdapter(SQLAdapter):
|
|
|
155
188
|
]
|
|
156
189
|
return columns
|
|
157
190
|
|
|
191
|
+
@classmethod
|
|
192
|
+
def quote(cls, identifier: str) -> str:
|
|
193
|
+
"""Double-quote an identifier, doubling any embedded double quote.
|
|
194
|
+
|
|
195
|
+
``SQLAdapter.quote`` interpolates the identifier verbatim, so a name
|
|
196
|
+
containing a ``"`` would close the quoted identifier early and the
|
|
197
|
+
remainder would parse as SQL. T-SQL escapes a delimiter by doubling
|
|
198
|
+
it -- the same rule ``QUOTENAME()`` applies to brackets -- so
|
|
199
|
+
``ab"cd`` must render as ``"ab""cd"``.
|
|
200
|
+
|
|
201
|
+
This is the quoting used by every macro that formats an identifier
|
|
202
|
+
(see #785). Relation rendering escapes nothing, since it goes through
|
|
203
|
+
``BaseRelation.quote_character`` upstream rather than this method.
|
|
204
|
+
"""
|
|
205
|
+
return '"{}"'.format(str(identifier).replace('"', '""'))
|
|
206
|
+
|
|
158
207
|
@classmethod
|
|
159
208
|
def convert_boolean_type(cls, agate_table, col_idx):
|
|
160
209
|
return "bit"
|
|
@@ -273,9 +322,9 @@ class SQLServerAdapter(SQLAdapter):
|
|
|
273
322
|
if not fetch:
|
|
274
323
|
conn.handle.commit()
|
|
275
324
|
if fetch == "one":
|
|
276
|
-
return cursor.fetchone()
|
|
325
|
+
return _normalize_result_datetimes(cursor.fetchone())
|
|
277
326
|
elif fetch == "all":
|
|
278
|
-
return cursor.fetchall()
|
|
327
|
+
return _normalize_result_datetimes(cursor.fetchall())
|
|
279
328
|
else:
|
|
280
329
|
return
|
|
281
330
|
except BaseException:
|
|
@@ -427,6 +476,57 @@ class SQLServerAdapter(SQLAdapter):
|
|
|
427
476
|
def parse_index(self, raw_index: Any) -> Optional[SQLServerIndexConfig]:
|
|
428
477
|
return SQLServerIndexConfig.parse(raw_index)
|
|
429
478
|
|
|
479
|
+
@available
|
|
480
|
+
def index_needs_own_batch(self, raw_index: Any) -> bool:
|
|
481
|
+
"""True when raw_index's build_options (ONLINE / RESUMABLE) force its
|
|
482
|
+
CREATE INDEX to run outside any transaction: SQL Server rejects
|
|
483
|
+
RESUMABLE inside a user transaction (error 574), and an ONLINE build
|
|
484
|
+
wrapped in one holds its locks until commit, negating the point."""
|
|
485
|
+
parsed = self.parse_index(raw_index)
|
|
486
|
+
if not parsed:
|
|
487
|
+
return False
|
|
488
|
+
return create_needs_own_batch(parsed.build_options)
|
|
489
|
+
|
|
490
|
+
@available
|
|
491
|
+
def commit_if_open(self) -> None:
|
|
492
|
+
"""Commit the current transaction if one is open - a no-op otherwise.
|
|
493
|
+
|
|
494
|
+
dbt_sqlserver_use_dbt_transactions on (default) wraps a
|
|
495
|
+
materialization's whole build, from its first statement through its
|
|
496
|
+
own trailing ``adapter.commit()``, in one continuous ambient
|
|
497
|
+
transaction. Some statements must not share that transaction with
|
|
498
|
+
whatever runs after them: an ONLINE/RESUMABLE index build (SQL Server
|
|
499
|
+
rejects RESUMABLE inside a user transaction outright, and ONLINE
|
|
500
|
+
holds its locks until commit either way), or a full-refresh-in-
|
|
501
|
+
progress marker, which exists specifically to survive a later
|
|
502
|
+
failure and so must not roll back with it. This makes the prior
|
|
503
|
+
statement durable on its own; pair with begin_if_closed once the
|
|
504
|
+
statement(s) that must run outside a transaction are done, to leave
|
|
505
|
+
later code (more such statements, or the materialization's own
|
|
506
|
+
trailing ``adapter.commit()``, which raises if it finds nothing open)
|
|
507
|
+
working as if this call had never happened.
|
|
508
|
+
|
|
509
|
+
A no-op when no transaction is open: the caller's statement already
|
|
510
|
+
ran autocommitted on its own (e.g. via ``run_query``'s
|
|
511
|
+
``auto_begin=false``, before anything else began one), so there is
|
|
512
|
+
nothing to flush. Also a no-op, at the SQL level, whenever
|
|
513
|
+
dbt_sqlserver_use_dbt_transactions is off: begin/commit still flip
|
|
514
|
+
dbt-core's bookkeeping (see
|
|
515
|
+
SQLServerConnectionManager.add_begin_query/add_commit_query), but
|
|
516
|
+
emit no real T-SQL, matching the driver's own autocommit.
|
|
517
|
+
"""
|
|
518
|
+
connection = self.connections.get_thread_connection()
|
|
519
|
+
if connection is not None and connection.transaction_open:
|
|
520
|
+
self.connections.commit()
|
|
521
|
+
|
|
522
|
+
@available
|
|
523
|
+
def begin_if_closed(self) -> None:
|
|
524
|
+
"""Begin a transaction if none is open - a no-op otherwise. See
|
|
525
|
+
commit_if_open, which this pairs with."""
|
|
526
|
+
connection = self.connections.get_thread_connection()
|
|
527
|
+
if connection is not None and not connection.transaction_open:
|
|
528
|
+
self.connections.begin()
|
|
529
|
+
|
|
430
530
|
@available
|
|
431
531
|
def validate_indexes(
|
|
432
532
|
self, raw_indexes: Any, as_columnstore: Any = False, drop_unmanaged: Any = False
|
{dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/sqlserver_auth.py
RENAMED
|
@@ -43,6 +43,14 @@ def is_mssql_python_backend(backend: "SQLServerBackend") -> bool:
|
|
|
43
43
|
return backend.value == SQLSERVER_BACKEND_MSSQL_PYTHON
|
|
44
44
|
|
|
45
45
|
|
|
46
|
+
def is_adbc_backend(backend: "SQLServerBackend") -> bool:
|
|
47
|
+
"""Return whether the coerced backend enum targets ``adbc``."""
|
|
48
|
+
|
|
49
|
+
from dbt.adapters.sqlserver.sqlserver_credentials import SQLServerBackend
|
|
50
|
+
|
|
51
|
+
return backend == SQLServerBackend.adbc
|
|
52
|
+
|
|
53
|
+
|
|
46
54
|
def normalize_authentication_key(value: Optional[str]) -> str:
|
|
47
55
|
"""Normalize a SQL Server auth or lookup key for cross-layer comparisons."""
|
|
48
56
|
|
{dbt_sqlserver-1.11.0rc1 → dbt_sqlserver-1.12.0rc2}/dbt/adapters/sqlserver/sqlserver_backend.py
RENAMED
|
@@ -8,6 +8,7 @@ lives in ``sqlserver_runtime.py`` and is orchestrated by
|
|
|
8
8
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
|
+
import urllib.parse
|
|
11
12
|
from contextlib import suppress
|
|
12
13
|
from typing import Any, Callable, Tuple
|
|
13
14
|
|
|
@@ -42,6 +43,7 @@ from dbt.adapters.sqlserver.sqlserver_runtime import (
|
|
|
42
43
|
_RUNTIME_STATE,
|
|
43
44
|
MssqlPythonModuleProtocol,
|
|
44
45
|
PyodbcModuleProtocol,
|
|
46
|
+
_get_adbc,
|
|
45
47
|
)
|
|
46
48
|
|
|
47
49
|
logger = AdapterLogger("sqlserver")
|
|
@@ -259,12 +261,19 @@ def log_connection_string(connection_string: str) -> None:
|
|
|
259
261
|
|
|
260
262
|
|
|
261
263
|
def is_pyodbc_handle(handle: Any) -> bool:
|
|
262
|
-
"""Detect a pyodbc handle without importing pyodbc from the caller.
|
|
264
|
+
"""Detect a pyodbc handle without importing pyodbc from the caller.
|
|
265
|
+
|
|
266
|
+
ADBC handles (from ``adbc_driver_manager``) must always return False,
|
|
267
|
+
even when the handle is a mock in test code.
|
|
268
|
+
"""
|
|
263
269
|
|
|
264
270
|
handle_type = type(handle)
|
|
265
271
|
module_name = getattr(handle_type, "__module__", "") or ""
|
|
266
272
|
class_name = getattr(handle_type, "__name__", "") or ""
|
|
267
273
|
|
|
274
|
+
if "adbc" in module_name.lower() or "adbc" in class_name.lower():
|
|
275
|
+
return False
|
|
276
|
+
|
|
268
277
|
if "pyodbc" in module_name or "pyodbc" in class_name:
|
|
269
278
|
return True
|
|
270
279
|
|
|
@@ -340,3 +349,88 @@ def _connect_pyodbc(
|
|
|
340
349
|
timeout=credentials.login_timeout,
|
|
341
350
|
)
|
|
342
351
|
return _finalize_connection_handle(handle, credentials)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def _sanitize_adbc_uri_for_logging(uri: str) -> str:
|
|
355
|
+
"""Redact the password component of an ADBC URI for safe logging."""
|
|
356
|
+
parsed = urllib.parse.urlparse(uri)
|
|
357
|
+
if parsed.password:
|
|
358
|
+
safe_netloc = parsed.netloc.replace(
|
|
359
|
+
f":{parsed.password}@",
|
|
360
|
+
":***@",
|
|
361
|
+
)
|
|
362
|
+
sanitized = parsed._replace(netloc=safe_netloc).geturl()
|
|
363
|
+
return sanitized
|
|
364
|
+
return uri
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def build_adbc_connection_uri(credentials: SQLServerCredentials) -> str:
|
|
368
|
+
"""Build a go-mssqldb URI for the ADBC backend.
|
|
369
|
+
|
|
370
|
+
Constructs URIs in the format:
|
|
371
|
+
``sqlserver://[user:password@]host[:port]?query_params``
|
|
372
|
+
|
|
373
|
+
- User and password are URL-encoded so special characters (``@``, ``:``,
|
|
374
|
+
``/``, etc.) are escaped per RFC 3986.
|
|
375
|
+
- Named instances (host containing ``\\``) omit the port.
|
|
376
|
+
- Query parameters: ``database``, ``encrypt``, ``TrustServerCertificate``,
|
|
377
|
+
and optional ``connection timeout``.
|
|
378
|
+
"""
|
|
379
|
+
|
|
380
|
+
host = (credentials.host or "").strip()
|
|
381
|
+
port = credentials.port or 1433
|
|
382
|
+
database = credentials.database or ""
|
|
383
|
+
uid = credentials.UID or ""
|
|
384
|
+
pwd = credentials.PWD or ""
|
|
385
|
+
|
|
386
|
+
userinfo = f"{urllib.parse.quote(uid, safe='')}:{urllib.parse.quote(pwd, safe='')}"
|
|
387
|
+
|
|
388
|
+
if "\\" in host:
|
|
389
|
+
authority = f"{userinfo}@{host}"
|
|
390
|
+
else:
|
|
391
|
+
authority = f"{userinfo}@{host}:{port}"
|
|
392
|
+
|
|
393
|
+
query_parts = [
|
|
394
|
+
f"database={urllib.parse.quote(database, safe='')}",
|
|
395
|
+
f"encrypt={str(credentials.encrypt).lower()}",
|
|
396
|
+
f"TrustServerCertificate={str(credentials.trust_cert).lower()}",
|
|
397
|
+
]
|
|
398
|
+
|
|
399
|
+
if credentials.login_timeout and credentials.login_timeout > 0:
|
|
400
|
+
query_parts.append(f"connection timeout={credentials.login_timeout}")
|
|
401
|
+
|
|
402
|
+
query_string = "&".join(query_parts)
|
|
403
|
+
return f"sqlserver://{authority}?{query_string}"
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def _connect_adbc(credentials: SQLServerCredentials, uri: str) -> Any:
|
|
407
|
+
"""Open an ADBC connection using the constructed go-mssqldb URI.
|
|
408
|
+
|
|
409
|
+
The ADBC mssql driver (``"mssql"``) is the only supported driver.
|
|
410
|
+
Connections are opened with ``autocommit=True`` so that DDL statements
|
|
411
|
+
(``CREATE SCHEMA``, ``CREATE TABLE``, …) auto-commit without extra
|
|
412
|
+
round-trips. When ``dbt_sqlserver_use_dbt_transactions: true``, dbt
|
|
413
|
+
emits explicit ``BEGIN TRANSACTION`` / ``COMMIT TRANSACTION`` SQL
|
|
414
|
+
that correctly nests on top of the autocommit session -- exactly the
|
|
415
|
+
same strategy used by the pyodbc backend.
|
|
416
|
+
"""
|
|
417
|
+
|
|
418
|
+
sanitized = _sanitize_adbc_uri_for_logging(uri)
|
|
419
|
+
logger.debug(f"Connecting to SQL Server with ADBC: {sanitized}")
|
|
420
|
+
|
|
421
|
+
adbc_module = _get_adbc()
|
|
422
|
+
return adbc_module.connect(
|
|
423
|
+
driver="mssql",
|
|
424
|
+
db_kwargs={"uri": uri},
|
|
425
|
+
autocommit=True,
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
def get_adbc_retryable_exceptions() -> Tuple[type[Exception], ...]:
|
|
430
|
+
"""Return the ADBC exception types that the connection manager may retry."""
|
|
431
|
+
|
|
432
|
+
adbc_module = _get_adbc()
|
|
433
|
+
return (
|
|
434
|
+
adbc_module.InternalError,
|
|
435
|
+
adbc_module.OperationalError,
|
|
436
|
+
)
|