From 1c6ddeec31c69dbd734e291b78278217a026d030 Mon Sep 17 00:00:00 2001 From: Josh Markovic Date: Wed, 10 Jun 2026 15:43:50 +0000 Subject: [PATCH 1/8] fix: default port 1433 (not Postgres 5432) in dbt init profile template --- dbt/include/sqlserver/profile_template.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbt/include/sqlserver/profile_template.yml b/dbt/include/sqlserver/profile_template.yml index 32c807119..abe07dc40 100644 --- a/dbt/include/sqlserver/profile_template.yml +++ b/dbt/include/sqlserver/profile_template.yml @@ -4,7 +4,7 @@ prompts: host: hint: "your host name" port: - default: 5432 + default: 1433 type: "int" user: hint: "dev username" From 245726fc9bed8a72a086aba205ef5e3310a3b55d Mon Sep 17 00:00:00 2001 From: Josh Markovic Date: Wed, 10 Jun 2026 15:43:50 +0000 Subject: [PATCH 2/8] fix: map Python float to SQL Server float, not bigint --- dbt/adapters/sqlserver/sqlserver_constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbt/adapters/sqlserver/sqlserver_constants.py b/dbt/adapters/sqlserver/sqlserver_constants.py index ecae4e8c0..9ee5fdcb6 100644 --- a/dbt/adapters/sqlserver/sqlserver_constants.py +++ b/dbt/adapters/sqlserver/sqlserver_constants.py @@ -102,7 +102,7 @@ "str": "varchar", "uuid.UUID": "uniqueidentifier", "uuid": "uniqueidentifier", - "float": "bigint", + "float": "float", "int": "int", "bytes": "varbinary", "bytearray": "varbinary", From 0c06273f72da4301c717b7de7a5fa9ba4426c775 Mon Sep 17 00:00:00 2001 From: Josh Markovic Date: Wed, 10 Jun 2026 15:43:50 +0000 Subject: [PATCH 3/8] fix: escape single quotes in query_tag before building OPTION (LABEL) A query_tag containing a single quote broke every query the adapter emitted, and allowed injection into the OPTION clause. Escape via dbt's cross-adapter escape_single_quotes() macro (quote doubling on this adapter), the same helper the EXEC('...') wrappers here already use. --- dbt/include/sqlserver/macros/adapters/metadata.sql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dbt/include/sqlserver/macros/adapters/metadata.sql b/dbt/include/sqlserver/macros/adapters/metadata.sql index 062a0c4f5..a72377087 100644 --- a/dbt/include/sqlserver/macros/adapters/metadata.sql +++ b/dbt/include/sqlserver/macros/adapters/metadata.sql @@ -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', []) -%} @@ -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 %} From 63298fbc2057b323bf600fd59e34d76ccc619dd9 Mon Sep 17 00:00:00 2001 From: Josh Markovic Date: Fri, 12 Jun 2026 13:13:49 +0000 Subject: [PATCH 4/8] fix: columnstore IF EXISTS guard checked object_id('schema_table') The underscore-joined name never resolves, so the existence check was always false and the DROP never ran. Use the relation's own quoted rendering (relation.include(database=False)), which OBJECT_ID resolves. --- dbt/include/sqlserver/macros/adapters/indexes.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbt/include/sqlserver/macros/adapters/indexes.sql b/dbt/include/sqlserver/macros/adapters/indexes.sql index 2fd3733ae..278d93ac5 100644 --- a/dbt/include/sqlserver/macros/adapters/indexes.sql +++ b/dbt/include/sqlserver/macros/adapters/indexes.sql @@ -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 ( From 48d2aea010fe970965e5364de438f54a4b6d5b96 Mon Sep 17 00:00:00 2001 From: Josh Markovic Date: Fri, 12 Jun 2026 13:13:49 +0000 Subject: [PATCH 5/8] docs: correct incremental default-strategy comment to MERGE With a unique_key the default strategy emits a MERGE via get_incremental_merge_sql, not delete+insert as the comment claimed. --- .../models/incremental/incremental_strategies.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbt/include/sqlserver/macros/materializations/models/incremental/incremental_strategies.sql b/dbt/include/sqlserver/macros/materializations/models/incremental/incremental_strategies.sql index 393d70205..2adb1f343 100644 --- a/dbt/include/sqlserver/macros/materializations/models/incremental/incremental_strategies.sql +++ b/dbt/include/sqlserver/macros/materializations/models/incremental/incremental_strategies.sql @@ -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. From 9749d3051121c8b06259868400c85ab6b7b43d2b Mon Sep 17 00:00:00 2001 From: Josh Markovic Date: Fri, 12 Jun 2026 13:13:58 +0000 Subject: [PATCH 6/8] docs: de-dupe README schema-concat section README documented dbt_sqlserver_use_default_schema_concat twice with conflicting flags-vs-vars guidance; merged into one section matching the code (behavior flag primary, vars fallback). --- README.md | 49 ++++++++++++++----------------------------------- 1 file changed, 14 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 3c431ec0a..f3a9fe22f 100644 --- a/README.md +++ b/README.md @@ -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` From 2b8195ce0f8f730dc8be14135e92188e7e1b6198 Mon Sep 17 00:00:00 2001 From: Josh Markovic Date: Fri, 12 Jun 2026 13:13:58 +0000 Subject: [PATCH 7/8] chore: target py310 in black/isort pre-commit args black/isort pre-commit hooks targeted py39 while requires-python is >=3.10 and the manual black-check already used py310; aligned both. --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0015df9e1..b122e48b8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -43,7 +43,7 @@ repos: - id: black args: - '--line-length=99' - - '--target-version=py39' + - '--target-version=py310' - id: black alias: black-check stages: From b5e142b4adf6e259f63214f960cee7fccd16df10 Mon Sep 17 00:00:00 2001 From: Josh Markovic Date: Fri, 12 Jun 2026 13:13:58 +0000 Subject: [PATCH 8/8] fix: restore missing Makefile clean rule line The clean target had a .PHONY declaration and recipe lines but no 'clean:' rule line, so 'make clean' did nothing. --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index afa615764..54490324d 100644 --- a/Makefile +++ b/Makefile @@ -56,6 +56,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