From efdcb52d094a64a1457903b09a030bcec873d8fe Mon Sep 17 00:00:00 2001 From: Sam Debruyn Date: Tue, 19 May 2026 10:53:24 +0200 Subject: [PATCH] Escape closing brackets in T-SQL identifier quoting Bracket-quoted T-SQL identifiers require a literal ] to be doubled (]]) to avoid prematurely closing the bracket. Without escaping, any identifier containing ] either generates invalid T-SQL (silent breakage for reserved-word column names that happen to contain ]) or, more importantly, lets a crafted identifier terminate the bracket and inject arbitrary T-SQL. Apply the escape to every bracket-quoting site: - FabricAdapter.quote() - FabricColumn.quoted - FabricRelation.quoted - fabric__alter_column_type (columns.sql) - fabric__alter_relation_add_remove_columns (columns.sql) - fabric__create_table_as listColumns block (create_table_as.sql) - fabric__create_columns (snapshots/helpers.sql) --- dbt/adapters/fabric/fabric_adapter.py | 2 +- dbt/adapters/fabric/fabric_column.py | 2 +- dbt/adapters/fabric/fabric_relation.py | 2 +- dbt/include/fabric/macros/adapters/columns.sql | 6 +++--- .../materializations/models/table/create_table_as.sql | 2 +- .../fabric/macros/materializations/snapshots/helpers.sql | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dbt/adapters/fabric/fabric_adapter.py b/dbt/adapters/fabric/fabric_adapter.py index 8baa02bd..ae591397 100644 --- a/dbt/adapters/fabric/fabric_adapter.py +++ b/dbt/adapters/fabric/fabric_adapter.py @@ -35,7 +35,7 @@ class FabricAdapter(SQLAdapter): @classmethod def quote(cls, identifier): - return "[{}]".format(identifier) + return "[{}]".format(identifier.replace("]", "]]")) AdapterSpecificConfigs = FabricConfigs Relation = FabricRelation diff --git a/dbt/adapters/fabric/fabric_column.py b/dbt/adapters/fabric/fabric_column.py index 22718768..1e9f22e3 100644 --- a/dbt/adapters/fabric/fabric_column.py +++ b/dbt/adapters/fabric/fabric_column.py @@ -7,7 +7,7 @@ class FabricColumn(Column): @property def quoted(self) -> str: - return "[{}]".format(self.column) + return "[{}]".format(self.column.replace("]", "]]")) TYPE_LABELS: ClassVar[Dict[str, str]] = { "STRING": "VARCHAR(8000)", diff --git a/dbt/adapters/fabric/fabric_relation.py b/dbt/adapters/fabric/fabric_relation.py index 7819fbd3..85863b16 100644 --- a/dbt/adapters/fabric/fabric_relation.py +++ b/dbt/adapters/fabric/fabric_relation.py @@ -17,7 +17,7 @@ class FabricRelation(BaseRelation): require_alias: bool = True def quoted(self, identifier): - return "[{}]".format(identifier) + return "[{}]".format(identifier.replace("]", "]]")) @classproperty def get_relation_type(cls) -> Type[FabricRelationType]: diff --git a/dbt/include/fabric/macros/adapters/columns.sql b/dbt/include/fabric/macros/adapters/columns.sql index 8f7b057a..3c7a1d14 100644 --- a/dbt/include/fabric/macros/adapters/columns.sql +++ b/dbt/include/fabric/macros/adapters/columns.sql @@ -90,7 +90,7 @@ {% set tempTable %} CREATE TABLE {{tempTableName}} - AS SELECT {{query_result_text}}, CAST([{{ column_name }}] AS {{new_column_type}}) AS [{{column_name}}] FROM {{ relation.schema }}.{{ relation.identifier }} + AS SELECT {{query_result_text}}, CAST([{{ column_name | replace(']', ']]') }}] AS {{new_column_type}}) AS [{{ column_name | replace(']', ']]') }}] FROM {{ relation.schema }}.{{ relation.identifier }} {{ apply_label() }} {% endset %} @@ -129,12 +129,12 @@ {% call statement('add_drop_columns') -%} {% if add_columns %} alter {{ relation.type }} {{ relation }} - add {% for column in add_columns %}[{{ column.name }}] {{ column.data_type }}{{ ', ' if not loop.last }}{% endfor %}; + add {% for column in add_columns %}[{{ column.name | replace(']', ']]') }}] {{ column.data_type }}{{ ', ' if not loop.last }}{% endfor %}; {% endif %} {% if remove_columns %} alter {{ relation.type }} {{ relation }} - drop column {% for column in remove_columns %}[{{ column.name }}]{{ ',' if not loop.last }}{% endfor %}; + drop column {% for column in remove_columns %}[{{ column.name | replace(']', ']]') }}]{{ ',' if not loop.last }}{% endfor %}; {% endif %} {%- endcall -%} {% endmacro %} diff --git a/dbt/include/fabric/macros/materializations/models/table/create_table_as.sql b/dbt/include/fabric/macros/materializations/models/table/create_table_as.sql index e8ace8fa..69872672 100644 --- a/dbt/include/fabric/macros/materializations/models/table/create_table_as.sql +++ b/dbt/include/fabric/macros/materializations/models/table/create_table_as.sql @@ -16,7 +16,7 @@ {{ get_assert_columns_equivalent(sql) }} {% set listColumns %} {% for column in model['columns'] %} - {{ "["~column~"]" }}{{ ", " if not loop.last }} + {{ "["~column|replace(']', ']]')~"]" }}{{ ", " if not loop.last }} {% endfor %} {%endset%} diff --git a/dbt/include/fabric/macros/materializations/snapshots/helpers.sql b/dbt/include/fabric/macros/materializations/snapshots/helpers.sql index 4bcd14fb..847d5c49 100644 --- a/dbt/include/fabric/macros/materializations/snapshots/helpers.sql +++ b/dbt/include/fabric/macros/materializations/snapshots/helpers.sql @@ -6,7 +6,7 @@ {% macro fabric__create_columns(relation, columns) %} {% for column in columns %} {% call statement() %} - alter table {{ relation.render() }} add [{{ column.name }}] {{ column.data_type }} NULL; + alter table {{ relation.render() }} add [{{ column.name | replace(']', ']]') }}] {{ column.data_type }} NULL; {% endcall %} {% endfor %} {% endmacro %}