|
| 1 | +{% macro get_query_options(parse_options=False) %} |
| 2 | + {{ log (config.get('query_tag','dbt-sqlserver'))}} |
| 3 | + {%- set query_label = config.get('query_tag','dbt-sqlserver') -%} |
| 4 | + {%- set query_options = config.get('query_options', {}) -%} |
| 5 | + {%- set query_options_raw = config.get('query_options_raw', []) -%} |
| 6 | + |
| 7 | + {%- set options_list = ["LABEL = '" ~ query_label ~ "'"] -%} |
| 8 | + |
| 9 | + {%- if parse_options -%} |
| 10 | + {%- set valid_options = [ |
| 11 | + 'HASH GROUP', 'ORDER GROUP', |
| 12 | + 'CONCAT UNION', 'HASH UNION', 'MERGE UNION', |
| 13 | + 'LOOP JOIN', 'MERGE JOIN', 'HASH JOIN', |
| 14 | + 'DISABLE_OPTIMIZED_PLAN_FORCING', |
| 15 | + 'EXPAND VIEWS', |
| 16 | + 'FAST', |
| 17 | + 'FORCE ORDER', |
| 18 | + 'FORCE EXTERNALPUSHDOWN', 'DISABLE EXTERNALPUSHDOWN', |
| 19 | + 'FORCE SCALEOUTEXECUTION', 'DISABLE SCALEOUTEXECUTION', |
| 20 | + 'IGNORE_NONCLUSTERED_COLUMNSTORE_INDEX', |
| 21 | + 'KEEP PLAN', |
| 22 | + 'KEEPFIXED PLAN', |
| 23 | + 'MAX_GRANT_PERCENT', |
| 24 | + 'MIN_GRANT_PERCENT', |
| 25 | + 'MAXDOP', |
| 26 | + 'MAXRECURSION', |
| 27 | + 'NO_PERFORMANCE_SPOOL', |
| 28 | + 'OPTIMIZE FOR UNKNOWN', |
| 29 | + 'QUERYTRACEON', |
| 30 | + 'RECOMPILE', |
| 31 | + 'ROBUST PLAN', |
| 32 | + ] -%} |
| 33 | + {#- SQL Server uses `OPTION (X = N)` for grant-percent hints, not `OPTION (X N)`. -#} |
| 34 | + {%- set equals_syntax_options = ['MAX_GRANT_PERCENT', 'MIN_GRANT_PERCENT'] -%} |
| 35 | + |
| 36 | + {%- for key, value in query_options.items() -%} |
| 37 | + {%- if key | upper not in valid_options -%} |
| 38 | + {{ exceptions.raise_compiler_error("Invalid query option: '" ~ key ~ "'. Use query_options_raw for non-standard hints. Allowed: " ~ valid_options | join(', ')) }} |
| 39 | + {%- endif -%} |
| 40 | + |
| 41 | + {%- if value is none -%} |
| 42 | + {%- do options_list.append(key | upper) -%} |
| 43 | + {%- else -%} |
| 44 | + {%- if value is not number -%} |
| 45 | + {{ exceptions.raise_compiler_error("Query option '" ~ key ~ "' value must be a number, got: '" ~ value ~ "'") }} |
| 46 | + {%- endif -%} |
| 47 | + {%- set separator = ' = ' if key | upper in equals_syntax_options else ' ' -%} |
| 48 | + {#- Render the value verbatim: ints become "1", floats become "12.5". |
| 49 | + MAX_GRANT_PERCENT / MIN_GRANT_PERCENT accept decimals 0.0–100.0; integer-only |
| 50 | + options will surface a clear SQL Server parse error on invalid decimals. -#} |
| 51 | + {%- do options_list.append(key | upper ~ separator ~ value) -%} |
| 52 | + {%- endif -%} |
| 53 | + {%- endfor -%} |
| 54 | + |
| 55 | + {#- query_options_raw bypasses the allowlist; users opt in to writing valid SQL Server syntax themselves. |
| 56 | + Shape-check only: a plain string would be iterated character-by-character into garbage. -#} |
| 57 | + {%- if query_options_raw is string or query_options_raw is mapping -%} |
| 58 | + {{ exceptions.raise_compiler_error("query_options_raw must be a list of strings, got: '" ~ query_options_raw ~ "'") }} |
| 59 | + {%- endif -%} |
| 60 | + {%- for raw in query_options_raw -%} |
| 61 | + {%- do options_list.append(raw) -%} |
| 62 | + {%- endfor -%} |
| 63 | + {%- endif -%} |
| 64 | + |
| 65 | + OPTION ({{ options_list | join(', ') }}); |
| 66 | +{% endmacro %} |
| 67 | + |
| 68 | +{#- DEPRECATED: backward-compat alias for the pre-1.10 macro. |
| 69 | + |
| 70 | + Calls to `{{ apply_label() }}` from user macros still resolve and emit |
| 71 | + a LABEL-only OPTION clause — but apply_label() is no longer the |
| 72 | + extension point. Adapter macros now call get_query_options() instead, |
| 73 | + so overriding apply_label() in a project's macros directory will have |
| 74 | + no effect on adapter-emitted SQL. |
| 75 | +
|
| 76 | + To customise the OPTION clause emitted by adapter macros (table, |
| 77 | + incremental, snapshot, unit_test), override get_query_options instead. -#} |
1 | 78 | {% macro apply_label() %} |
2 | 79 | {{ log (config.get('query_tag','dbt-sqlserver'))}} |
3 | 80 | {%- set query_label = config.get('query_tag','dbt-sqlserver') -%} |
4 | 81 | OPTION (LABEL = '{{query_label}}'); |
5 | 82 | {% endmacro %} |
6 | 83 |
|
| 84 | +{#- Guard for materializations and incremental strategies that cannot emit OPTION clauses. |
| 85 | + Raises a compiler error if the user has configured query_options/query_options_raw. -#} |
| 86 | +{% macro raise_if_query_options_set(context_label) %} |
| 87 | + {%- if config.get('query_options') or config.get('query_options_raw') -%} |
| 88 | + {{ exceptions.raise_compiler_error( |
| 89 | + "query_options/query_options_raw is not supported on " ~ context_label |
| 90 | + ~ ". Remove the config or switch to a supported materialization (table, incremental delete+insert, snapshot, unit_test)." |
| 91 | + ) }} |
| 92 | + {%- endif -%} |
| 93 | +{% endmacro %} |
| 94 | +
|
7 | 95 | {% macro default__information_schema_hints() %}{% endmacro %} |
8 | 96 | {% macro sqlserver__information_schema_hints() %}with (nolock){% endmacro %} |
9 | 97 |
|
|
27 | 115 | {% call statement('list_schemas', fetch_result=True, auto_begin=False) -%} |
28 | 116 | {{ get_use_database_sql(database) }} |
29 | 117 | select name as [schema] |
30 | | - from sys.schemas {{ information_schema_hints() }} {{ apply_label() }} |
| 118 | + from sys.schemas {{ information_schema_hints() }} {{ get_query_options() }} |
31 | 119 | {% endcall %} |
32 | 120 | {{ return(load_result('list_schemas').table) }} |
33 | 121 | {% endmacro %} |
34 | 122 |
|
35 | 123 | {% macro sqlserver__check_schema_exists(information_schema, schema) -%} |
36 | 124 | {% call statement('check_schema_exists', fetch_result=True, auto_begin=False) -%} |
37 | | - SELECT count(*) as schema_exist FROM sys.schemas WHERE name = '{{ schema }}' {{ apply_label() }} |
| 125 | + SELECT count(*) as schema_exist FROM sys.schemas WHERE name = '{{ schema }}' {{ get_query_options() }} |
38 | 126 | {%- endcall %} |
39 | 127 | {{ return(load_result('check_schema_exists').table) }} |
40 | 128 | {% endmacro %} |
|
58 | 146 | 'view' as table_type |
59 | 147 | from sys.views as v {{ information_schema_hints() }} |
60 | 148 | where v.schema_id = @schema_id |
61 | | - {{ apply_label() }} |
| 149 | + {{ get_query_options() }} |
62 | 150 | {% endcall %} |
63 | 151 | {{ return(load_result('list_relations_without_caching').table) }} |
64 | 152 | {% endmacro %} |
|
82 | 170 | 'view' as table_type |
83 | 171 | from sys.views as v {{ information_schema_hints() }} |
84 | 172 | where v.schema_id = @schema_id and v.name = '{{ schema_relation.identifier }}' |
85 | | - {{ apply_label() }} |
| 173 | + {{ get_query_options() }} |
86 | 174 | {% endcall %} |
87 | 175 | {{ return(load_result('get_relation_without_caching').table) }} |
88 | 176 | {% endmacro %} |
|
113 | 201 | upper(o.name) = upper('{{ relation.identifier }}')){%- if not loop.last %} or {% endif -%} |
114 | 202 | {%- endfor -%} |
115 | 203 | ) |
116 | | - {{ apply_label() }} |
| 204 | + {{ get_query_options() }} |
117 | 205 | {%- endcall -%} |
118 | 206 | {{ return(load_result('last_modified')) }} |
119 | 207 |
|
|
0 commit comments