Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ repos:
- '--line-length'
- '99'
- '--python-version'
- '39'
- '310'
- repo: 'https://github.com/psf/black'
rev: 26.5.1
hooks:
- id: black
args:
- '--line-length=99'
- '--target-version=py39'
- '--target-version=py310'
- id: black
alias: black-check
stages:
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ server: ## Spins up a local MS SQL Server instance for development. Docker-compo
docker compose up -d

.PHONY: clean
clean: ## Removes ignored files and build artifacts from the repo.
@echo "cleaning repo"
@git clean -f -X

Expand Down
49 changes: 14 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,51 +98,30 @@ See [the changelog](CHANGELOG.md)

## Configuration

- `dbt_sqlserver_use_default_schema_concat`: *(default: `false`)* Controls schema name generation when a [custom schema](https://docs.getdbt.com/docs/build/custom-schemas) is set on a model.

| Flag value | `custom_schema_name` | Result |
|---|---|---|
| `false` (default, legacy) | *(none)* | `target.schema` |
| `false` (default, legacy) | `"reporting"` | `reporting` |
| `true` (dbt-core standard) | *(none)* | `target.schema` |
| `true` (dbt-core standard) | `"reporting"` | `target.schema_reporting` |

When `false` (the default), the adapter uses its legacy behaviour: `custom_schema_name` is used **as-is** without being prefixed by `target.schema`.
When `true`, the adapter delegates to dbt-core's `default__generate_schema_name`, which concatenates `target.schema` + `_` + `custom_schema_name`.

**Example usage in `dbt_project.yml`:**

```yaml
flags:
dbt_sqlserver_use_default_schema_concat: true # Enable standard schema concatenation
```

This adapter also supports the same setting via `vars:` for backwards compatibility, so either method works in the current release.

> **Note:** If you want to permanently customise schema generation and avoid any future changes, override the `sqlserver__generate_schema_name` macro directly in your project instead.


### `dbt_sqlserver_use_default_schema_concat`

*(default: `false`)* Controls schema name generation when a [custom schema](https://docs.getdbt.com/docs/build/custom-schemas) is set on a model.

| Value | `custom_schema_name` | Result |
| Flag value | `custom_schema_name` | Result |
|---|---|---|
| `false` (default) | *(none)* | `target.schema` |
| `false` (default) | `"reporting"` | `reporting` |
| `true` | *(none)* | `target.schema` |
| `true` | `"reporting"` | `target.schema_reporting` |
| `false` (default, legacy) | *(none)* | `target.schema` |
| `false` (default, legacy) | `"reporting"` | `reporting` |
| `true` (dbt-core standard) | *(none)* | `target.schema` |
| `true` (dbt-core standard) | `"reporting"` | `target.schema_reporting` |

When `false`, `custom_schema_name` is used as-is without being prefixed by `target.schema`.
When `true`, the adapter delegates to dbt-core's `default__generate_schema_name`.
When `false` (the default), the adapter uses its legacy behaviour: `custom_schema_name` is used **as-is** without being prefixed by `target.schema`.
When `true`, the adapter delegates to dbt-core's `default__generate_schema_name`, which concatenates `target.schema` + `_` + `custom_schema_name`.

**Example usage in `dbt_project.yml`:**

```yaml
# dbt_project.yml
vars:
dbt_sqlserver_use_default_schema_concat: true
flags:
dbt_sqlserver_use_default_schema_concat: true # Enable standard schema concatenation
```

> **Note:** To permanently customise schema generation without a flag dependency, override the `sqlserver__generate_schema_name` macro directly in your project.
The same setting is also honoured via `vars:` for backwards compatibility; the behavior flag under `flags:` takes precedence when both are set.

> **Note:** If you want to permanently customise schema generation and avoid any future changes, override the `sqlserver__generate_schema_name` macro directly in your project instead.

### `backend`

Expand Down
2 changes: 1 addition & 1 deletion dbt/adapters/sqlserver/sqlserver_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
"str": "varchar",
"uuid.UUID": "uniqueidentifier",
"uuid": "uniqueidentifier",
"float": "bigint",
"float": "float",
"int": "int",
"bytes": "varbinary",
"bytearray": "varbinary",
Expand Down
2 changes: 1 addition & 1 deletion dbt/include/sqlserver/macros/adapters/indexes.sql
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% macro sqlserver__create_clustered_columnstore_index(relation) -%}
{%- set cci_name = (relation.schema ~ '_' ~ relation.identifier ~ '_cci') | replace(".", "") | replace(" ", "") -%}
{%- set relation_name = relation.schema ~ '_' ~ relation.identifier -%}
{%- set relation_name = relation.include(database=False) -%}
{%- set full_relation = '"' ~ relation.schema ~ '"."' ~ relation.identifier ~ '"' -%}
use [{{ relation.database }}];
if EXISTS (
Expand Down
5 changes: 3 additions & 2 deletions dbt/include/sqlserver/macros/adapters/metadata.sql
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{% macro get_query_options(parse_options=False) %}
{{ log (config.get('query_tag','dbt-sqlserver'))}}
{%- set query_label = config.get('query_tag','dbt-sqlserver') -%}
{#- Escape single quotes so a query_tag like "it's" can't break out of the LABEL literal. -#}
{%- set query_label = escape_single_quotes(config.get('query_tag','dbt-sqlserver')) -%}
{%- set query_options = config.get('query_options', {}) -%}
{%- set query_options_raw = config.get('query_options_raw', []) -%}

Expand Down Expand Up @@ -77,7 +78,7 @@
incremental, snapshot, unit_test), override get_query_options instead. -#}
{% macro apply_label() %}
{{ log (config.get('query_tag','dbt-sqlserver'))}}
{%- set query_label = config.get('query_tag','dbt-sqlserver') -%}
{%- set query_label = escape_single_quotes(config.get('query_tag','dbt-sqlserver')) -%}
OPTION (LABEL = '{{query_label}}');
{% endmacro %}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{% macro sqlserver__get_incremental_default_sql(arg_dict) %}

{% if arg_dict["unique_key"] %}
-- Delete + Insert Strategy, calls get_delete_insert_merge_sql
-- Merge strategy: emits a MERGE statement via get_incremental_merge_sql
{% do return(get_incremental_merge_sql(arg_dict)) %}
{% else %}
-- Incremental Append will insert data into target table.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,13 @@
{# Atomic DML swap — RCSI protects concurrent readers #}
{# dbt-sqlserver uses autocommit=True and add_begin_query/add_commit_query #}
{# are no-ops, so this creates a simple (non-nested) transaction. #}
{# SET XACT_ABORT ON makes the whole transaction roll back if any statement #}
{# fails. Without it, statement-aborting errors on the INSERT (e.g. NULL or #}
{# constraint violations) do not stop the batch: the DELETE stands and the #}
{# trailing COMMIT still executes, leaving the target committed-empty — #}
{# silent data loss. (Verified against SQL Server 2022.) #}
{% call statement('dml_refresh_swap') -%}
SET XACT_ABORT ON;
BEGIN TRANSACTION;
DELETE FROM {{ target_relation }};
INSERT INTO {{ target_relation }} ({{ column_list }})
Expand Down
2 changes: 1 addition & 1 deletion dbt/include/sqlserver/profile_template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ prompts:
host:
hint: "your host name"
port:
default: 5432
default: 1433
type: "int"
user:
hint: "dev username"
Expand Down