dbt-sqlserver 1.11.2rc1__tar.gz → 1.12.0__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.2rc1/dbt_sqlserver.egg-info → dbt_sqlserver-1.12.0}/PKG-INFO +91 -30
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/README.md +84 -24
- dbt_sqlserver-1.12.0/dbt/adapters/sqlserver/__version__.py +1 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/relation_configs/index.py +8 -2
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/sqlserver_adapter.py +317 -96
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/sqlserver_auth.py +8 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/sqlserver_backend.py +95 -1
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/sqlserver_configs.py +10 -1
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/sqlserver_connections.py +345 -8
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/sqlserver_constants.py +5 -1
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/sqlserver_credentials.py +2 -0
- dbt_sqlserver-1.12.0/dbt/adapters/sqlserver/sqlserver_deny.py +141 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/sqlserver_helpers.py +36 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/sqlserver_relation.py +10 -1
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/sqlserver_runtime.py +78 -0
- dbt_sqlserver-1.12.0/dbt/include/sqlserver/macros/adapters/apply_denies.sql +118 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/adapters/apply_grants.sql +3 -3
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/adapters/apply_masks.sql +13 -5
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/adapters/columns.sql +23 -4
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/adapters/indexes.sql +49 -24
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/adapters/metadata.sql +50 -1
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/adapters/relation.sql +2 -1
- dbt_sqlserver-1.12.0/dbt/include/sqlserver/macros/adapters/schema.sql +104 -0
- dbt_sqlserver-1.12.0/dbt/include/sqlserver/macros/materializations/hooks.sql +58 -0
- dbt_sqlserver-1.12.0/dbt/include/sqlserver/macros/materializations/models/incremental/incremental.sql +271 -0
- dbt_sqlserver-1.12.0/dbt/include/sqlserver/macros/materializations/models/table/table.sql +259 -0
- dbt_sqlserver-1.12.0/dbt/include/sqlserver/macros/materializations/models/table/table_dml_refresh.sql +200 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/materializations/models/unit_test/unit_test_create_table_as.sql +1 -1
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/materializations/models/view/view.sql +15 -15
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/materializations/snapshots/helpers.sql +31 -16
- dbt_sqlserver-1.12.0/dbt/include/sqlserver/macros/materializations/snapshots/snapshot.sql +207 -0
- dbt_sqlserver-1.12.0/dbt/include/sqlserver/macros/materializations/snapshots/strategies.sql +65 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/materializations/tests.sql +5 -7
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/materializations/unit_tests.sql +16 -7
- dbt_sqlserver-1.12.0/dbt/include/sqlserver/macros/relations/table/create.sql +395 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/relations/views/create.sql +9 -1
- dbt_sqlserver-1.12.0/dbt/include/sqlserver/macros/utils/array_append.sql +3 -0
- dbt_sqlserver-1.12.0/dbt/include/sqlserver/macros/utils/openquery.sql +21 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0/dbt_sqlserver.egg-info}/PKG-INFO +91 -30
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt_sqlserver.egg-info/SOURCES.txt +4 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt_sqlserver.egg-info/requires.txt +6 -5
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/pyproject.toml +56 -12
- dbt_sqlserver-1.11.2rc1/dbt/adapters/sqlserver/__version__.py +0 -1
- dbt_sqlserver-1.11.2rc1/dbt/include/sqlserver/macros/adapters/schema.sql +0 -73
- dbt_sqlserver-1.11.2rc1/dbt/include/sqlserver/macros/materializations/hooks.sql +0 -23
- dbt_sqlserver-1.11.2rc1/dbt/include/sqlserver/macros/materializations/models/incremental/incremental.sql +0 -200
- dbt_sqlserver-1.11.2rc1/dbt/include/sqlserver/macros/materializations/models/table/table.sql +0 -136
- dbt_sqlserver-1.11.2rc1/dbt/include/sqlserver/macros/materializations/models/table/table_dml_refresh.sql +0 -167
- dbt_sqlserver-1.11.2rc1/dbt/include/sqlserver/macros/materializations/snapshots/snapshot.sql +0 -135
- dbt_sqlserver-1.11.2rc1/dbt/include/sqlserver/macros/materializations/snapshots/strategies.sql +0 -5
- dbt_sqlserver-1.11.2rc1/dbt/include/sqlserver/macros/relations/table/create.sql +0 -264
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/LICENSE +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/__init__.py +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/__init__.py +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/py.typed +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/relation_configs/__init__.py +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/relation_configs/policies.py +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/sqlserver_column.py +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/sqlserver_mask.py +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/__init__.py +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/dbt_project.yml +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/adapters/catalog.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/adapters/persist_docs.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/adapters/show.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/adapters/validate_sql.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/materializations/functions/helpers.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/materializations/functions/scalar.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/materializations/models/incremental/incremental_strategies.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/materializations/models/incremental/merge.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/materializations/models/table/columns_spec_ddl.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/materializations/models/unit_test/get_fixture_sql.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/materializations/models/view/create_view_as.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/materializations/snapshots/snapshot_merge.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/relations/seeds/helpers.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/relations/table/clone.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/utils/any_value.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/utils/array_construct.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/utils/cast_bool_to_text.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/utils/concat.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/utils/date_trunc.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/utils/dateadd.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/utils/get_tables_by_pattern.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/utils/hash.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/utils/last_day.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/utils/length.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/utils/listagg.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/utils/position.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/utils/safe_cast.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/utils/split_part.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/macros/utils/timestamps.sql +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/include/sqlserver/profile_template.yml +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt_sqlserver.egg-info/dependency_links.txt +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt_sqlserver.egg-info/top_level.txt +0 -0
- {dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/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.0
|
|
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
|
|
@@ -18,29 +18,30 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
22
|
Requires-Python: >=3.10
|
|
22
23
|
Description-Content-Type: text/markdown
|
|
23
24
|
License-File: LICENSE
|
|
24
|
-
Requires-Dist: dbt-core<2.0,>=1.
|
|
25
|
+
Requires-Dist: dbt-core<2.0,>=1.12.0
|
|
25
26
|
Requires-Dist: dbt-common<2.0,>=1.22.0
|
|
26
|
-
Requires-Dist: dbt-adapters<2.0,>=1.24.
|
|
27
|
-
Requires-Dist: pyodbc>=5.2.0
|
|
27
|
+
Requires-Dist: dbt-adapters<2.0,>=1.24.5
|
|
28
28
|
Provides-Extra: azure
|
|
29
29
|
Requires-Dist: azure-identity>=1.12.0; extra == "azure"
|
|
30
30
|
Provides-Extra: pyodbc
|
|
31
31
|
Requires-Dist: pyodbc>=5.2.0; extra == "pyodbc"
|
|
32
32
|
Provides-Extra: mssql
|
|
33
33
|
Requires-Dist: mssql-python>=1.7.1; extra == "mssql"
|
|
34
|
-
|
|
35
|
-
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"
|
|
36
37
|
Dynamic: license-file
|
|
37
38
|
|
|
38
39
|
# dbt-sqlserver
|
|
39
40
|
|
|
40
41
|
[dbt](https://www.getdbt.com) adapter for Microsoft SQL Server and Azure SQL services.
|
|
41
42
|
|
|
42
|
-
The adapter supports dbt-core 1.
|
|
43
|
-
E.g. version 1.
|
|
43
|
+
The adapter supports dbt-core 1.12 or newer and follows the same versioning scheme.
|
|
44
|
+
E.g. version 1.12.x of the adapter is compatible with dbt-core 1.12.x.
|
|
44
45
|
|
|
45
46
|
## Supported Python versions
|
|
46
47
|
|
|
@@ -52,6 +53,7 @@ The adapter is tested against:
|
|
|
52
53
|
| 3.11 | Officially supported |
|
|
53
54
|
| 3.12 | Officially supported |
|
|
54
55
|
| 3.13 | Officially supported |
|
|
56
|
+
| 3.14 | Officially supported |
|
|
55
57
|
|
|
56
58
|
## Supported SQL Server versions
|
|
57
59
|
|
|
@@ -75,7 +77,7 @@ We've bundled all documentation on the dbt docs site:
|
|
|
75
77
|
- [Profile setup & authentication](https://docs.getdbt.com/reference/warehouse-profiles/mssql-profile)
|
|
76
78
|
- [Adapter documentation, usage and important notes](https://docs.getdbt.com/reference/resource-configs/mssql-configs)
|
|
77
79
|
|
|
78
|
-
|
|
80
|
+
Ask questions and get help in [GitHub Discussions](https://github.com/dbt-msft/dbt-sqlserver/discussions/categories/q-a). The [dbt Slack](https://getdbt.slack.com/archives/CMRMDDQ9W) channel is there for chatting with the community.
|
|
79
81
|
|
|
80
82
|
## Installation
|
|
81
83
|
|
|
@@ -91,6 +93,7 @@ Latest pre-release: * | `dbt-sqlserver[adbc]` | none (driver binary installed separately via the `dbc` CLI) |
|
|
94
97
|
|
|
95
98
|
|
|
96
99
|
### `pyodbc` backend
|
|
@@ -155,31 +158,41 @@ your_profile:
|
|
|
155
158
|
backend: mssql-python # <-- enables this backend
|
|
156
159
|
```
|
|
157
160
|
|
|
161
|
+
### `adbc` backend *(experimental)*
|
|
162
|
+
|
|
163
|
+
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).
|
|
164
|
+
|
|
165
|
+
```shell
|
|
166
|
+
pip install -U "dbt-sqlserver[adbc]"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
The driver binary is not on PyPI and must be installed once via the `dbc` CLI. See [docs/adbc_backend.md](https://github.com/dbt-msft/dbt-sqlserver/blob/master/docs/adbc_backend.md) for the full setup, configuration, and known-differences guide.
|
|
170
|
+
|
|
158
171
|
## Changelog
|
|
159
172
|
|
|
160
|
-
See [the changelog](CHANGELOG.md)
|
|
173
|
+
See [the changelog](https://github.com/dbt-msft/dbt-sqlserver/blob/master/CHANGELOG.md)
|
|
161
174
|
|
|
162
175
|
## Configuration
|
|
163
176
|
|
|
164
177
|
### `dbt_sqlserver_use_default_schema_concat`
|
|
165
178
|
|
|
166
|
-
*(default: `
|
|
179
|
+
*(default: `true`)* Controls schema name generation when a [custom schema](https://docs.getdbt.com/docs/build/custom-schemas) is set on a model.
|
|
167
180
|
|
|
168
181
|
| Flag value | `custom_schema_name` | Result |
|
|
169
182
|
|---|---|---|
|
|
170
|
-
| `
|
|
171
|
-
| `
|
|
172
|
-
| `
|
|
173
|
-
| `
|
|
183
|
+
| `true` (default, dbt-core standard) | *(none)* | `target.schema` |
|
|
184
|
+
| `true` (default, dbt-core standard) | `"reporting"` | `target.schema_reporting` |
|
|
185
|
+
| `false` (legacy, deprecated) | *(none)* | `target.schema` |
|
|
186
|
+
| `false` (legacy, deprecated) | `"reporting"` | `reporting` |
|
|
174
187
|
|
|
175
|
-
When `
|
|
176
|
-
When `
|
|
188
|
+
When `true` (the default), the adapter delegates to dbt-core's `default__generate_schema_name`, which concatenates `target.schema` + `_` + `custom_schema_name`. This also matches the behavior dbt-core v2 (Fusion) ships unconditionally.
|
|
189
|
+
When `false`, the adapter uses its legacy behaviour: `custom_schema_name` is used **as-is** without being prefixed by `target.schema`. This legacy behavior is deprecated and will be removed in a future release.
|
|
177
190
|
|
|
178
191
|
**Example usage in `dbt_project.yml`:**
|
|
179
192
|
|
|
180
193
|
```yaml
|
|
181
194
|
flags:
|
|
182
|
-
dbt_sqlserver_use_default_schema_concat:
|
|
195
|
+
dbt_sqlserver_use_default_schema_concat: false # Opt back into the deprecated legacy behavior
|
|
183
196
|
```
|
|
184
197
|
|
|
185
198
|
The same setting is also honoured via `vars:` for backwards compatibility; the behavior flag under `flags:` takes precedence when both are set.
|
|
@@ -188,7 +201,7 @@ The same setting is also honoured via `vars:` for backwards compatibility; the b
|
|
|
188
201
|
|
|
189
202
|
### `backend`
|
|
190
203
|
|
|
191
|
-
*(default: `pyodbc`)* Set to `mssql-python` in a profile target to use
|
|
204
|
+
*(default: `pyodbc`)* Set to `mssql-python` or `adbc` (experimental, see [docs/adbc_backend.md](https://github.com/dbt-msft/dbt-sqlserver/blob/master/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.
|
|
192
205
|
|
|
193
206
|
### `dbt_sqlserver_enable_safe_type_expansion`
|
|
194
207
|
|
|
@@ -202,21 +215,46 @@ The same setting is also honoured via `vars:` for backwards compatibility; the b
|
|
|
202
215
|
|
|
203
216
|
Safe expansions are further gated by `column_type_expansion_max_rows` (default 1,000,000 rows) to avoid long-running operations on large tables.
|
|
204
217
|
|
|
218
|
+
### `pre_hook_transaction_scope`
|
|
219
|
+
|
|
220
|
+
_(default: `load`)_ Where a `table`, `incremental` or `snapshot` build resolves its schema
|
|
221
|
+
(the tmp view and the empty `CREATE`) relative to its in-transaction pre-hooks.
|
|
222
|
+
`load` stages it before them, so the new table's `Sch-M` lock is released in an
|
|
223
|
+
instant and the load blocks no metadata reader in other sessions; a
|
|
224
|
+
`transaction: true` pre-hook still rolls back with a failed load, except on the
|
|
225
|
+
two paths that commit a full-refresh marker before the load
|
|
226
|
+
(`full_refresh_build: prebuilt`, and an incremental `--full-refresh` of an
|
|
227
|
+
existing table), where neither scope can roll it back. `build` stages
|
|
228
|
+
it inside the hook's transaction, for the one case `load` cannot serve: a
|
|
229
|
+
`transaction: true` pre-hook that creates an object the model reads. See
|
|
230
|
+
[docs/transaction_scope.md](https://github.com/dbt-msft/dbt-sqlserver/blob/master/docs/transaction_scope.md) for the full flow and
|
|
231
|
+
the post-hook ordering change.
|
|
232
|
+
|
|
205
233
|
### `dbt_sqlserver_use_dbt_transactions`
|
|
206
234
|
|
|
207
|
-
_(default: `
|
|
235
|
+
_(default: `true`)_ Makes dbt's transaction hooks real at the SQL Server level by emitting `BEGIN TRANSACTION` / `COMMIT TRANSACTION` through the adapter's `add_begin_query` and `add_commit_query` methods.
|
|
208
236
|
|
|
209
|
-
The default is `
|
|
237
|
+
The default is `true`, so dbt-managed transaction hooks emit real T-SQL transaction statements and rollback uses `IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION`. Set it to `false` to opt back into the deprecated legacy behavior where `begin`/`commit` hooks are logical no-ops and the driver auto-commits each statement.
|
|
210
238
|
|
|
211
239
|
The driver connection remains in autocommit mode (`autocommit=true`) in both modes.
|
|
212
240
|
|
|
213
|
-
This
|
|
241
|
+
This is now the default and should be tested carefully with project-specific materializations and hooks. Projects that depend on autocommit-only behavior should set the flag to `false` during migration.
|
|
242
|
+
|
|
243
|
+
**Compatibility notes:** Enabling `dbt_sqlserver_use_dbt_transactions: true` may expose transaction-state assumptions hidden by autocommit-only mode. Explicit transaction macros may interact with dbt-managed transactions, and cleanup after failed DDL/DML may differ. Review pre/post hooks for in-transaction vs out-of-transaction semantics.
|
|
214
244
|
|
|
215
245
|
```yaml
|
|
216
246
|
# dbt_project.yml
|
|
217
247
|
flags:
|
|
218
|
-
|
|
219
|
-
|
|
248
|
+
dbt_sqlserver_use_dbt_transactions: false # legacy autocommit; deprecated
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### `dbt_sqlserver_use_native_string_types`
|
|
252
|
+
|
|
253
|
+
*(default: `true`)* Controls the SQL Server-native mappings used for dbt string types. With the default enabled, `STRING` maps to `VARCHAR(MAX)`, `NCHAR` maps to `NCHAR(1)`, and `NVARCHAR` maps to `NVARCHAR(4000)`. Set it to `false` to opt back into the deprecated legacy mappings: `STRING` and `NVARCHAR` map to `VARCHAR(8000)`, while `NCHAR` maps to `CHAR(1)`.
|
|
254
|
+
|
|
255
|
+
```yaml
|
|
256
|
+
flags:
|
|
257
|
+
dbt_sqlserver_use_native_string_types: false # deprecated legacy behavior
|
|
220
258
|
```
|
|
221
259
|
|
|
222
260
|
### `xact_abort`
|
|
@@ -250,7 +288,11 @@ your_profile:
|
|
|
250
288
|
|
|
251
289
|
### `prefer_single_alter_column`
|
|
252
290
|
|
|
253
|
-
*(default:
|
|
291
|
+
*(default: unset)* Model-level config that controls how `alter_column_type` changes column types on tables:
|
|
292
|
+
|
|
293
|
+
* `true`: a single `ALTER COLUMN` statement. It is atomic, instant for a longer `varchar`/`nvarchar`, and keeps the column's indexes, default constraint and position. It fails for types that cannot be implicitly converted, and changing `varchar` to `nvarchar` on a large clustered columnstore table can fail with Msg 35357 (dictionary size limit).
|
|
294
|
+
* `false`: add a temporary column, copy the data, drop the original and rename. It fails when an index, default constraint or statistics object depends on the column, and it moves the column to the end of the table. A failed attempt no longer blocks the next run.
|
|
295
|
+
* unset (default): `true` when column type expansion widens a column within its type (a longer `varchar`, or `varchar(max)`), `false` for every other change.
|
|
254
296
|
|
|
255
297
|
```sql
|
|
256
298
|
-- In an incremental model
|
|
@@ -258,8 +300,6 @@ your_profile:
|
|
|
258
300
|
prefer_single_alter_column=true) }}
|
|
259
301
|
```
|
|
260
302
|
|
|
261
|
-
**Compatibility notes:** Enabling `dbt_sqlserver_use_dbt_transactions: true` may expose transaction-state assumptions hidden by autocommit-only mode. Explicit transaction macros may interact with dbt-managed transactions, and cleanup after failed DDL/DML may differ. Review pre/post hooks for in-transaction vs out-of-transaction semantics.
|
|
262
|
-
|
|
263
303
|
### `as_columnstore`
|
|
264
304
|
|
|
265
305
|
*(default: `true`)* When building a table, the adapter creates a [clustered columnstore index](https://learn.microsoft.com/en-us/sql/relational-databases/indexes/columnstore-indexes-overview) (CCI) on it. Set `as_columnstore: false` to build a plain rowstore table instead.
|
|
@@ -285,6 +325,10 @@ You can also set it per model:
|
|
|
285
325
|
|
|
286
326
|
With `table_refresh_method: dml`, a schema change makes the refresh fall back to a rename-swap. On that run — and only that run — the scratch table is rebuilt the way this adapter builds every other table, so it carries the model's columnstore index, and under an enforced contract its `NOT NULL`s and inline constraints, into the swap. That run therefore executes the model's SQL twice — once for the `SELECT … INTO` that probes for the schema change, once for the rebuild — and builds the columnstore index once. Steady-state refreshes are unaffected and keep the single `SELECT … INTO`. A table that lost its columnstore index to this bug before you upgraded is not repaired automatically: its schema still matches, so it stays on the cheap path. To rebuild it, temporarily set `full_refresh_build: prebuilt` and run with `--full-refresh`.
|
|
287
327
|
|
|
328
|
+
### Ephemeral models
|
|
329
|
+
|
|
330
|
+
Ephemeral models are supported, with one limit: an ephemeral model can't start with its own `WITH`. dbt inlines it as a CTE, and T-SQL can't nest a `WITH` inside one (still true on SQL Server 2025). Write it with derived tables instead, or materialize it as a `view`, which SQL Server expands into the calling query the same way.
|
|
331
|
+
|
|
288
332
|
### Constraints
|
|
289
333
|
|
|
290
334
|
Constraints declared in a model's yaml are applied when — and only when — the model's [contract](https://docs.getdbt.com/reference/resource-configs/contract) is enforced, which is what every dbt adapter does and keeps their cost opt-in. (dbt-core does not raise if you declare constraints with the contract off — they are simply never emitted.) `not_null`, `check`, `unique`, `primary_key` and `foreign_key` are all supported.
|
|
@@ -297,7 +341,7 @@ A *model-level* constraint carrying `name:` is applied by `ALTER TABLE … ADD C
|
|
|
297
341
|
|
|
298
342
|
Name a constraint when you want it stable across environments (schema-comparison tools report the generated names as differences) or need to reference it later. A `name:` on a *column-level* constraint is ignored with a warning — declare it under the model's `constraints:` key instead.
|
|
299
343
|
|
|
300
|
-
The full set of rules, with the test that verifies each, is in [docs/constraints.md](docs/constraints.md).
|
|
344
|
+
The full set of rules, with the test that verifies each, is in [docs/constraints.md](https://github.com/dbt-msft/dbt-sqlserver/blob/master/docs/constraints.md).
|
|
301
345
|
|
|
302
346
|
```yaml
|
|
303
347
|
models:
|
|
@@ -432,14 +476,31 @@ Behaviour:
|
|
|
432
476
|
|
|
433
477
|
**Version notes.** All masking DDL the adapter emits (`ADD MASKED`, `MASKED WITH`, `DROP MASKED`) and the functions `default()`, `email()`, `random(a,b)` and `partial(...)` work on 2016+. The `datetime()` partial-date function and granular column/schema/table-scoped `UNMASK` are SQL Server 2022+ only; the adapter never emits them, but mask-function strings are passed through verbatim, so using a 2022-only function on an older server will be rejected by SQL Server.
|
|
434
478
|
|
|
479
|
+
### Object-level DENY (`denies`)
|
|
480
|
+
|
|
481
|
+
In SQL Server, an object-level `DENY` is the only way to carve an exception out of a schema-level `GRANT` — grant a principal `SELECT` on a whole schema, then `DENY SELECT` on the individual PII-bearing models. But a `DENY` is stored against the object's `object_id`, so dbt destroys it every time it drops and recreates the relation (which is *every* run for a view). The schema grant survives; its exceptions silently evaporate, leaving a **fail-open** posture that no run reports.
|
|
482
|
+
|
|
483
|
+
The `denies` config re-applies object-level DENYs after each build, diffed against `sys.database_permissions`, the same way `masks` re-applies Dynamic Data Masking. Its shape mirrors `grants` — a `{privilege: [principals]}` map — and it is settable in the in-file `{{ config() }}`, the model's `.yml` `config:` block, or a directory-wide default in `dbt_project.yml` (merging key-wise across those levels, like `masks`):
|
|
484
|
+
|
|
485
|
+
```sql
|
|
486
|
+
{{ config(denies={'select': ['Restricted_Read_Only']}) }}
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
- **Survives rebuilds:** the DENY is present after `dbt run` and *still present after the next run*, for `table`, `view`, `incremental` (append and full-refresh) and `snapshot`. Unlike masks, this **includes views** — a view is a valid securable and is recreated on every run, which is where a DENY is lost most often.
|
|
490
|
+
- **Reconciled:** the adapter diffs the config against the live DENY state and emits only what changed — `DENY` for configured-not-present, `REVOKE` for present-not-configured (a `REVOKE` removes a `DENY`). Removing a principal from `denies` revokes its DENY on the next run; a converged, persisted relation issues no DDL.
|
|
491
|
+
- **Scope:** object-level DENY for the table privileges `select`, `insert`, `update`, `delete`, `references`. An unsupported privilege is warned and skipped (the warning surfaces the likely typo without taking down the build). Column-, database- and server-scoped permissions are out of scope (the latter survive a rebuild already).
|
|
492
|
+
- **Absent principal:** a `DENY` to a non-existent database principal is warned-and-skipped (the run still succeeds), so one config runs unchanged across dev, CI and prod where the principal set differs.
|
|
493
|
+
- **Ordering vs `grants`:** grants are applied first, then denies, so the final state is unambiguous. A `(privilege, principal)` pair appearing in both `grants` and `denies` is warned as a likely mistake (a DENY overrides a GRANT in SQL Server).
|
|
494
|
+
- **Other adapters:** `denies` is a no-op on non-SQL-Server adapters, not an error. This is SQL-Server-specific by design — `DENY` is absent from the SQL standard and does not port.
|
|
495
|
+
|
|
435
496
|
## Contributing
|
|
436
497
|
|
|
437
498
|
[](https://github.com/dbt-msft/dbt-sqlserver/actions/workflows/unit-tests.yml)
|
|
438
499
|
[](https://github.com/dbt-msft/dbt-sqlserver/actions/workflows/integration-tests-sqlserver.yml)
|
|
439
500
|
|
|
440
501
|
This adapter is community-maintained.
|
|
441
|
-
You are welcome to contribute by creating issues, opening or reviewing pull requests, or helping other users in the Slack
|
|
442
|
-
If you're unsure how to get started, check out our [contributing guide](CONTRIBUTING.md).
|
|
502
|
+
You are welcome to contribute by creating issues, opening or reviewing pull requests, or helping other users in [Discussions](https://github.com/dbt-msft/dbt-sqlserver/discussions) and on the [dbt Slack](https://getdbt.slack.com/archives/CMRMDDQ9W).
|
|
503
|
+
If you're unsure how to get started, check out our [contributing guide](https://github.com/dbt-msft/dbt-sqlserver/blob/master/CONTRIBUTING.md).
|
|
443
504
|
|
|
444
505
|
## License
|
|
445
506
|
|
|
@@ -2,8 +2,8 @@
|
|
|
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.12 or newer and follows the same versioning scheme.
|
|
6
|
+
E.g. version 1.12.x of the adapter is compatible with dbt-core 1.12.x.
|
|
7
7
|
|
|
8
8
|
## Supported Python versions
|
|
9
9
|
|
|
@@ -15,6 +15,7 @@ The adapter is tested against:
|
|
|
15
15
|
| 3.11 | Officially supported |
|
|
16
16
|
| 3.12 | Officially supported |
|
|
17
17
|
| 3.13 | Officially supported |
|
|
18
|
+
| 3.14 | Officially supported |
|
|
18
19
|
|
|
19
20
|
## Supported SQL Server versions
|
|
20
21
|
|
|
@@ -38,7 +39,7 @@ We've bundled all documentation on the dbt docs site:
|
|
|
38
39
|
- [Profile setup & authentication](https://docs.getdbt.com/reference/warehouse-profiles/mssql-profile)
|
|
39
40
|
- [Adapter documentation, usage and important notes](https://docs.getdbt.com/reference/resource-configs/mssql-configs)
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
Ask questions and get help in [GitHub Discussions](https://github.com/dbt-msft/dbt-sqlserver/discussions/categories/q-a). The [dbt Slack](https://getdbt.slack.com/archives/CMRMDDQ9W) channel is there for chatting with the community.
|
|
42
43
|
|
|
43
44
|
## Installation
|
|
44
45
|
|
|
@@ -54,6 +55,7 @@ Latest pre-release: * | `dbt-sqlserver[adbc]` | none (driver binary installed separately via the `dbc` CLI) |
|
|
57
59
|
|
|
58
60
|
|
|
59
61
|
### `pyodbc` backend
|
|
@@ -118,31 +120,41 @@ your_profile:
|
|
|
118
120
|
backend: mssql-python # <-- enables this backend
|
|
119
121
|
```
|
|
120
122
|
|
|
123
|
+
### `adbc` backend *(experimental)*
|
|
124
|
+
|
|
125
|
+
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).
|
|
126
|
+
|
|
127
|
+
```shell
|
|
128
|
+
pip install -U "dbt-sqlserver[adbc]"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The driver binary is not on PyPI and must be installed once via the `dbc` CLI. See [docs/adbc_backend.md](https://github.com/dbt-msft/dbt-sqlserver/blob/master/docs/adbc_backend.md) for the full setup, configuration, and known-differences guide.
|
|
132
|
+
|
|
121
133
|
## Changelog
|
|
122
134
|
|
|
123
|
-
See [the changelog](CHANGELOG.md)
|
|
135
|
+
See [the changelog](https://github.com/dbt-msft/dbt-sqlserver/blob/master/CHANGELOG.md)
|
|
124
136
|
|
|
125
137
|
## Configuration
|
|
126
138
|
|
|
127
139
|
### `dbt_sqlserver_use_default_schema_concat`
|
|
128
140
|
|
|
129
|
-
*(default: `
|
|
141
|
+
*(default: `true`)* Controls schema name generation when a [custom schema](https://docs.getdbt.com/docs/build/custom-schemas) is set on a model.
|
|
130
142
|
|
|
131
143
|
| Flag value | `custom_schema_name` | Result |
|
|
132
144
|
|---|---|---|
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
145
|
+
| `true` (default, dbt-core standard) | *(none)* | `target.schema` |
|
|
146
|
+
| `true` (default, dbt-core standard) | `"reporting"` | `target.schema_reporting` |
|
|
147
|
+
| `false` (legacy, deprecated) | *(none)* | `target.schema` |
|
|
148
|
+
| `false` (legacy, deprecated) | `"reporting"` | `reporting` |
|
|
137
149
|
|
|
138
|
-
When `
|
|
139
|
-
When `
|
|
150
|
+
When `true` (the default), the adapter delegates to dbt-core's `default__generate_schema_name`, which concatenates `target.schema` + `_` + `custom_schema_name`. This also matches the behavior dbt-core v2 (Fusion) ships unconditionally.
|
|
151
|
+
When `false`, the adapter uses its legacy behaviour: `custom_schema_name` is used **as-is** without being prefixed by `target.schema`. This legacy behavior is deprecated and will be removed in a future release.
|
|
140
152
|
|
|
141
153
|
**Example usage in `dbt_project.yml`:**
|
|
142
154
|
|
|
143
155
|
```yaml
|
|
144
156
|
flags:
|
|
145
|
-
dbt_sqlserver_use_default_schema_concat:
|
|
157
|
+
dbt_sqlserver_use_default_schema_concat: false # Opt back into the deprecated legacy behavior
|
|
146
158
|
```
|
|
147
159
|
|
|
148
160
|
The same setting is also honoured via `vars:` for backwards compatibility; the behavior flag under `flags:` takes precedence when both are set.
|
|
@@ -151,7 +163,7 @@ The same setting is also honoured via `vars:` for backwards compatibility; the b
|
|
|
151
163
|
|
|
152
164
|
### `backend`
|
|
153
165
|
|
|
154
|
-
*(default: `pyodbc`)* Set to `mssql-python` in a profile target to use
|
|
166
|
+
*(default: `pyodbc`)* Set to `mssql-python` or `adbc` (experimental, see [docs/adbc_backend.md](https://github.com/dbt-msft/dbt-sqlserver/blob/master/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.
|
|
155
167
|
|
|
156
168
|
### `dbt_sqlserver_enable_safe_type_expansion`
|
|
157
169
|
|
|
@@ -165,21 +177,46 @@ The same setting is also honoured via `vars:` for backwards compatibility; the b
|
|
|
165
177
|
|
|
166
178
|
Safe expansions are further gated by `column_type_expansion_max_rows` (default 1,000,000 rows) to avoid long-running operations on large tables.
|
|
167
179
|
|
|
180
|
+
### `pre_hook_transaction_scope`
|
|
181
|
+
|
|
182
|
+
_(default: `load`)_ Where a `table`, `incremental` or `snapshot` build resolves its schema
|
|
183
|
+
(the tmp view and the empty `CREATE`) relative to its in-transaction pre-hooks.
|
|
184
|
+
`load` stages it before them, so the new table's `Sch-M` lock is released in an
|
|
185
|
+
instant and the load blocks no metadata reader in other sessions; a
|
|
186
|
+
`transaction: true` pre-hook still rolls back with a failed load, except on the
|
|
187
|
+
two paths that commit a full-refresh marker before the load
|
|
188
|
+
(`full_refresh_build: prebuilt`, and an incremental `--full-refresh` of an
|
|
189
|
+
existing table), where neither scope can roll it back. `build` stages
|
|
190
|
+
it inside the hook's transaction, for the one case `load` cannot serve: a
|
|
191
|
+
`transaction: true` pre-hook that creates an object the model reads. See
|
|
192
|
+
[docs/transaction_scope.md](https://github.com/dbt-msft/dbt-sqlserver/blob/master/docs/transaction_scope.md) for the full flow and
|
|
193
|
+
the post-hook ordering change.
|
|
194
|
+
|
|
168
195
|
### `dbt_sqlserver_use_dbt_transactions`
|
|
169
196
|
|
|
170
|
-
_(default: `
|
|
197
|
+
_(default: `true`)_ Makes dbt's transaction hooks real at the SQL Server level by emitting `BEGIN TRANSACTION` / `COMMIT TRANSACTION` through the adapter's `add_begin_query` and `add_commit_query` methods.
|
|
171
198
|
|
|
172
|
-
The default is `
|
|
199
|
+
The default is `true`, so dbt-managed transaction hooks emit real T-SQL transaction statements and rollback uses `IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION`. Set it to `false` to opt back into the deprecated legacy behavior where `begin`/`commit` hooks are logical no-ops and the driver auto-commits each statement.
|
|
173
200
|
|
|
174
201
|
The driver connection remains in autocommit mode (`autocommit=true`) in both modes.
|
|
175
202
|
|
|
176
|
-
This
|
|
203
|
+
This is now the default and should be tested carefully with project-specific materializations and hooks. Projects that depend on autocommit-only behavior should set the flag to `false` during migration.
|
|
204
|
+
|
|
205
|
+
**Compatibility notes:** Enabling `dbt_sqlserver_use_dbt_transactions: true` may expose transaction-state assumptions hidden by autocommit-only mode. Explicit transaction macros may interact with dbt-managed transactions, and cleanup after failed DDL/DML may differ. Review pre/post hooks for in-transaction vs out-of-transaction semantics.
|
|
177
206
|
|
|
178
207
|
```yaml
|
|
179
208
|
# dbt_project.yml
|
|
180
209
|
flags:
|
|
181
|
-
|
|
182
|
-
|
|
210
|
+
dbt_sqlserver_use_dbt_transactions: false # legacy autocommit; deprecated
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### `dbt_sqlserver_use_native_string_types`
|
|
214
|
+
|
|
215
|
+
*(default: `true`)* Controls the SQL Server-native mappings used for dbt string types. With the default enabled, `STRING` maps to `VARCHAR(MAX)`, `NCHAR` maps to `NCHAR(1)`, and `NVARCHAR` maps to `NVARCHAR(4000)`. Set it to `false` to opt back into the deprecated legacy mappings: `STRING` and `NVARCHAR` map to `VARCHAR(8000)`, while `NCHAR` maps to `CHAR(1)`.
|
|
216
|
+
|
|
217
|
+
```yaml
|
|
218
|
+
flags:
|
|
219
|
+
dbt_sqlserver_use_native_string_types: false # deprecated legacy behavior
|
|
183
220
|
```
|
|
184
221
|
|
|
185
222
|
### `xact_abort`
|
|
@@ -213,7 +250,11 @@ your_profile:
|
|
|
213
250
|
|
|
214
251
|
### `prefer_single_alter_column`
|
|
215
252
|
|
|
216
|
-
*(default:
|
|
253
|
+
*(default: unset)* Model-level config that controls how `alter_column_type` changes column types on tables:
|
|
254
|
+
|
|
255
|
+
* `true`: a single `ALTER COLUMN` statement. It is atomic, instant for a longer `varchar`/`nvarchar`, and keeps the column's indexes, default constraint and position. It fails for types that cannot be implicitly converted, and changing `varchar` to `nvarchar` on a large clustered columnstore table can fail with Msg 35357 (dictionary size limit).
|
|
256
|
+
* `false`: add a temporary column, copy the data, drop the original and rename. It fails when an index, default constraint or statistics object depends on the column, and it moves the column to the end of the table. A failed attempt no longer blocks the next run.
|
|
257
|
+
* unset (default): `true` when column type expansion widens a column within its type (a longer `varchar`, or `varchar(max)`), `false` for every other change.
|
|
217
258
|
|
|
218
259
|
```sql
|
|
219
260
|
-- In an incremental model
|
|
@@ -221,8 +262,6 @@ your_profile:
|
|
|
221
262
|
prefer_single_alter_column=true) }}
|
|
222
263
|
```
|
|
223
264
|
|
|
224
|
-
**Compatibility notes:** Enabling `dbt_sqlserver_use_dbt_transactions: true` may expose transaction-state assumptions hidden by autocommit-only mode. Explicit transaction macros may interact with dbt-managed transactions, and cleanup after failed DDL/DML may differ. Review pre/post hooks for in-transaction vs out-of-transaction semantics.
|
|
225
|
-
|
|
226
265
|
### `as_columnstore`
|
|
227
266
|
|
|
228
267
|
*(default: `true`)* When building a table, the adapter creates a [clustered columnstore index](https://learn.microsoft.com/en-us/sql/relational-databases/indexes/columnstore-indexes-overview) (CCI) on it. Set `as_columnstore: false` to build a plain rowstore table instead.
|
|
@@ -248,6 +287,10 @@ You can also set it per model:
|
|
|
248
287
|
|
|
249
288
|
With `table_refresh_method: dml`, a schema change makes the refresh fall back to a rename-swap. On that run — and only that run — the scratch table is rebuilt the way this adapter builds every other table, so it carries the model's columnstore index, and under an enforced contract its `NOT NULL`s and inline constraints, into the swap. That run therefore executes the model's SQL twice — once for the `SELECT … INTO` that probes for the schema change, once for the rebuild — and builds the columnstore index once. Steady-state refreshes are unaffected and keep the single `SELECT … INTO`. A table that lost its columnstore index to this bug before you upgraded is not repaired automatically: its schema still matches, so it stays on the cheap path. To rebuild it, temporarily set `full_refresh_build: prebuilt` and run with `--full-refresh`.
|
|
250
289
|
|
|
290
|
+
### Ephemeral models
|
|
291
|
+
|
|
292
|
+
Ephemeral models are supported, with one limit: an ephemeral model can't start with its own `WITH`. dbt inlines it as a CTE, and T-SQL can't nest a `WITH` inside one (still true on SQL Server 2025). Write it with derived tables instead, or materialize it as a `view`, which SQL Server expands into the calling query the same way.
|
|
293
|
+
|
|
251
294
|
### Constraints
|
|
252
295
|
|
|
253
296
|
Constraints declared in a model's yaml are applied when — and only when — the model's [contract](https://docs.getdbt.com/reference/resource-configs/contract) is enforced, which is what every dbt adapter does and keeps their cost opt-in. (dbt-core does not raise if you declare constraints with the contract off — they are simply never emitted.) `not_null`, `check`, `unique`, `primary_key` and `foreign_key` are all supported.
|
|
@@ -260,7 +303,7 @@ A *model-level* constraint carrying `name:` is applied by `ALTER TABLE … ADD C
|
|
|
260
303
|
|
|
261
304
|
Name a constraint when you want it stable across environments (schema-comparison tools report the generated names as differences) or need to reference it later. A `name:` on a *column-level* constraint is ignored with a warning — declare it under the model's `constraints:` key instead.
|
|
262
305
|
|
|
263
|
-
The full set of rules, with the test that verifies each, is in [docs/constraints.md](docs/constraints.md).
|
|
306
|
+
The full set of rules, with the test that verifies each, is in [docs/constraints.md](https://github.com/dbt-msft/dbt-sqlserver/blob/master/docs/constraints.md).
|
|
264
307
|
|
|
265
308
|
```yaml
|
|
266
309
|
models:
|
|
@@ -395,14 +438,31 @@ Behaviour:
|
|
|
395
438
|
|
|
396
439
|
**Version notes.** All masking DDL the adapter emits (`ADD MASKED`, `MASKED WITH`, `DROP MASKED`) and the functions `default()`, `email()`, `random(a,b)` and `partial(...)` work on 2016+. The `datetime()` partial-date function and granular column/schema/table-scoped `UNMASK` are SQL Server 2022+ only; the adapter never emits them, but mask-function strings are passed through verbatim, so using a 2022-only function on an older server will be rejected by SQL Server.
|
|
397
440
|
|
|
441
|
+
### Object-level DENY (`denies`)
|
|
442
|
+
|
|
443
|
+
In SQL Server, an object-level `DENY` is the only way to carve an exception out of a schema-level `GRANT` — grant a principal `SELECT` on a whole schema, then `DENY SELECT` on the individual PII-bearing models. But a `DENY` is stored against the object's `object_id`, so dbt destroys it every time it drops and recreates the relation (which is *every* run for a view). The schema grant survives; its exceptions silently evaporate, leaving a **fail-open** posture that no run reports.
|
|
444
|
+
|
|
445
|
+
The `denies` config re-applies object-level DENYs after each build, diffed against `sys.database_permissions`, the same way `masks` re-applies Dynamic Data Masking. Its shape mirrors `grants` — a `{privilege: [principals]}` map — and it is settable in the in-file `{{ config() }}`, the model's `.yml` `config:` block, or a directory-wide default in `dbt_project.yml` (merging key-wise across those levels, like `masks`):
|
|
446
|
+
|
|
447
|
+
```sql
|
|
448
|
+
{{ config(denies={'select': ['Restricted_Read_Only']}) }}
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
- **Survives rebuilds:** the DENY is present after `dbt run` and *still present after the next run*, for `table`, `view`, `incremental` (append and full-refresh) and `snapshot`. Unlike masks, this **includes views** — a view is a valid securable and is recreated on every run, which is where a DENY is lost most often.
|
|
452
|
+
- **Reconciled:** the adapter diffs the config against the live DENY state and emits only what changed — `DENY` for configured-not-present, `REVOKE` for present-not-configured (a `REVOKE` removes a `DENY`). Removing a principal from `denies` revokes its DENY on the next run; a converged, persisted relation issues no DDL.
|
|
453
|
+
- **Scope:** object-level DENY for the table privileges `select`, `insert`, `update`, `delete`, `references`. An unsupported privilege is warned and skipped (the warning surfaces the likely typo without taking down the build). Column-, database- and server-scoped permissions are out of scope (the latter survive a rebuild already).
|
|
454
|
+
- **Absent principal:** a `DENY` to a non-existent database principal is warned-and-skipped (the run still succeeds), so one config runs unchanged across dev, CI and prod where the principal set differs.
|
|
455
|
+
- **Ordering vs `grants`:** grants are applied first, then denies, so the final state is unambiguous. A `(privilege, principal)` pair appearing in both `grants` and `denies` is warned as a likely mistake (a DENY overrides a GRANT in SQL Server).
|
|
456
|
+
- **Other adapters:** `denies` is a no-op on non-SQL-Server adapters, not an error. This is SQL-Server-specific by design — `DENY` is absent from the SQL standard and does not port.
|
|
457
|
+
|
|
398
458
|
## Contributing
|
|
399
459
|
|
|
400
460
|
[](https://github.com/dbt-msft/dbt-sqlserver/actions/workflows/unit-tests.yml)
|
|
401
461
|
[](https://github.com/dbt-msft/dbt-sqlserver/actions/workflows/integration-tests-sqlserver.yml)
|
|
402
462
|
|
|
403
463
|
This adapter is community-maintained.
|
|
404
|
-
You are welcome to contribute by creating issues, opening or reviewing pull requests, or helping other users in the Slack
|
|
405
|
-
If you're unsure how to get started, check out our [contributing guide](CONTRIBUTING.md).
|
|
464
|
+
You are welcome to contribute by creating issues, opening or reviewing pull requests, or helping other users in [Discussions](https://github.com/dbt-msft/dbt-sqlserver/discussions) and on the [dbt Slack](https://getdbt.slack.com/archives/CMRMDDQ9W).
|
|
465
|
+
If you're unsure how to get started, check out our [contributing guide](https://github.com/dbt-msft/dbt-sqlserver/blob/master/CONTRIBUTING.md).
|
|
406
466
|
|
|
407
467
|
## License
|
|
408
468
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
version = "1.12.0"
|
{dbt_sqlserver-1.11.2rc1 → dbt_sqlserver-1.12.0}/dbt/adapters/sqlserver/relation_configs/index.py
RENAMED
|
@@ -593,13 +593,19 @@ def index_config_changes(
|
|
|
593
593
|
SQLServerIndexConfig.parse_relation_results(rows_by_name[name])
|
|
594
594
|
)
|
|
595
595
|
changes.append(
|
|
596
|
-
SQLServerIndexConfigChange(
|
|
596
|
+
SQLServerIndexConfigChange(
|
|
597
|
+
# `action` is inherited from RelationConfigChange, a dataclass a
|
|
598
|
+
# type checker cannot see; see [tool.ty.rules] in pyproject.toml.
|
|
599
|
+
action=RelationConfigChangeAction.drop, # ty: ignore[unknown-argument]
|
|
600
|
+
context=context,
|
|
601
|
+
)
|
|
597
602
|
)
|
|
598
603
|
for name, config in expected_by_name.items():
|
|
599
604
|
if name not in existing_names:
|
|
600
605
|
changes.append(
|
|
601
606
|
SQLServerIndexConfigChange(
|
|
602
|
-
action=RelationConfigChangeAction.create,
|
|
607
|
+
action=RelationConfigChangeAction.create, # ty: ignore[unknown-argument]
|
|
608
|
+
context=config,
|
|
603
609
|
)
|
|
604
610
|
)
|
|
605
611
|
return changes, warnings
|