diff --git a/README.md b/README.md index b110c35..66fc05e 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ vars: ## Installation 1. Add this package to your `packages.yml` following [these instructions](https://docs.getdbt.com/docs/building-a-dbt-project/package-management/). Please check [this link for the latest released version](https://github.com/Snowflake-Labs/dbt_constraints/releases/latest). + ```yml packages: - package: Snowflake-Labs/dbt_constraints @@ -56,6 +57,7 @@ packages: 2. Run `dbt deps`. 3. Optionally add `primary_key`, `unique_key`, or `foreign_key` tests to your model like the following examples. + ```yml - name: DIM_ORDER_LINES columns: @@ -106,7 +108,7 @@ packages: * The package currently only includes macros for creating constraints in Snowflake, PostgreSQL, and Oracle. To add support for other databases, it is necessary to implement the following seven macros with the appropriate DDL & SQL for your database. Pull requests to contribute support for other databases are welcome. See the __create_constraints.sql files as examples. -``` +```sql __create_primary_key(table_model, column_names, verify_permissions, quote_columns=false, constraint_name=none, lookup_cache=none) __create_unique_key(table_model, column_names, verify_permissions, quote_columns=false, constraint_name=none, lookup_cache=none) __create_foreign_key(pk_model, pk_column_names, fk_model, fk_column_names, verify_permissions, quote_columns=false, constraint_name=none, lookup_cache=none) @@ -121,33 +123,35 @@ packages: Generally, if you don't meet a requirement, tests are still executed but the constraint is skipped rather than producing an error. -- All models involved in a constraint must be materialized as table, incremental, snapshot, or seed. - -- If source constraints are enabled, the source must be a table. You must also have the `OWNERSHIP` table privilege to add a constraint. For foreign keys you also need the `REFERENCES` privilege on the parent table with the primary or unique key. The package will identify when you lack these privileges on Snowflake and PostgreSQL. Oracle does not provide an easy way to look up your effective privileges so it has an exception handler and will display Oracle's error messages. +* All models involved in a constraint must be materialized as table, incremental, snapshot, or seed. -- All columns on constraints must be individual column names, not expressions. You can reference columns on a model that come from an expression. +* If source constraints are enabled, the source must be a table. You must also have the `OWNERSHIP` table privilege to add a constraint. For foreign keys you also need the `REFERENCES` privilege on the parent table with the primary or unique key. The package will identify when you lack these privileges on Snowflake and PostgreSQL. Oracle does not provide an easy way to look up your effective privileges so it has an exception handler and will display Oracle's error messages. -- Constraints are not created for failed tests. See how to get around this using severity and `config: always_create_constraint: true` in the next section. +* All columns on constraints must be individual column names, not expressions. You can reference columns on a model that come from an expression. -- `primary_key`, `unique_key`, and `foreign_key` tests are considered first and duplicate constraints are skipped. One exception is that you will get an error if you add two different `primary_key` tests to the same model. +* Constraints are not created for failed tests. See how to get around this using severity and `config: always_create_constraint: true` in the next section. -- Foreign keys require that the parent table have a primary key or unique key on the referenced columns. Unique keys generated from standard `unique` tests are sufficient. +* `primary_key`, `unique_key`, and `foreign_key` tests are considered first and duplicate constraints are skipped. One exception is that you will get an error if you add two different `primary_key` tests to the same model. -- The order of columns on a foreign key test must match between the FK columns and PK columns +* Foreign keys require that the parent table have a primary key or unique key on the referenced columns. Unique keys generated from standard `unique` tests are sufficient. -- The `foreign_key` test will ignore any rows with a null column, even if only one of two columns in a compound key is null. If you also want to ensure FK columns are not null, you should add standard `not_null` tests to your model which will add not null constraints to the table. +* The order of columns on a foreign key test must match between the FK columns and PK columns -- Referential constraints must apply to all the rows in a table so any tests with a `config: where:` property will be skipped when creating constraints. See how to disable this rule using `config: always_create_constraint: true` in the next section. +* The `foreign_key` test will ignore any rows with a null column, even if only one of two columns in a compound key is null. If you also want to ensure FK columns are not null, you should add standard `not_null` tests to your model which will add not null constraints to the table. +* Referential constraints must apply to all the rows in a table so any tests with a `config: where:` property will be skipped when creating constraints. See how to disable this rule using `config: always_create_constraint: true` in the next section. ## Advanced: `config: always_create_constraint: true` property + There is an advanced option to force a constraint to be generated when there is a `config: where:` property or if the constraint has a threshold. The `config: always_create_constraint: true` property will override those exclusions. When this setting is in effect, you can create constraints even when you have excluded some records or have a number of failures below a threshold. If your test has a status of 'failed', it will still be skipped. Please see [dbt's documentation on how to set a threshold for failures](https://docs.getdbt.com/reference/resource-configs/severity). __Caveat Emptor:__ + * You will get an error if you try to force constraints to be generated that are enforced by your database. On Snowflake that is only a not_null constraint but on databases like Oracle, all the generated constraints are enforced. * This feature could cause unexpected query results on Snowflake due to [join elimination](https://docs.snowflake.com/en/user-guide/join-elimination). This is an example using the feature: + ```yml - name: dim_duplicate_orders description: "Test that we do not try to create PK/UK on failed tests" @@ -177,10 +181,9 @@ This is an example using the feature: always_create_constraint: true ``` - ## Primary Maintainers -- Dan Flippo ([@sfc-gh-dflippo](https://github.com/sfc-gh-dflippo)) +* Dan Flippo ([@sfc-gh-dflippo](https://github.com/sfc-gh-dflippo)) This is a community-developed package, not an official Snowflake offering. It comes with no support or warranty. However, feel free to raise a github issue if you find a bug or would like a new feature. diff --git a/dbt_project.yml b/dbt_project.yml index 3a2c3b4..c1bb8e3 100644 --- a/dbt_project.yml +++ b/dbt_project.yml @@ -1,6 +1,6 @@ name: 'dbt_constraints' -version: '0.6.1' +version: '0.6.2' config-version: 2 # These macros depend on the results and graph objects in dbt >=0.19.0 diff --git a/integration_tests/profiles.yml b/integration_tests/profiles.yml new file mode 100644 index 0000000..a6aa238 --- /dev/null +++ b/integration_tests/profiles.yml @@ -0,0 +1,36 @@ +dbt_constraints: + target: snowflake + outputs: + snowflake: + type: "snowflake" + client_session_keep_alive: False + account: "{{ env_var('SNOWFLAKE_ACCOUNT') }}" + user: "{{ env_var('SNOWFLAKE_USER') }}" + # The DBT_ENV_SECRET_ prefix prevents the variable being included in logs + private_key: "{{ env_var('DBT_ENV_SECRET_PRIVATE_KEY') }}" + role: "{{ env_var('SNOWFLAKE_ROLE') }}" + database: "{{ env_var('SNOWFLAKE_DATABASE') }}" + warehouse: "{{ env_var('SNOWFLAKE_WAREHOUSE') }}" + schema: "{{ env_var('SNOWFLAKE_SCHEMA') }}" + threads: "{{ env_var('SNOWFLAKE_THREADS', '8') | as_number }}" + query_tag: dbt_constraints + oracle: + database: XEPDB1 + host: localhost + pass: dbt_user2 + port: 1521 + protocol: tcp + schema: DBT_USER + service: XEPDB1 + threads: 4 + type: oracle + user: DBT_USER + postgres: + dbname: postgres + host: localhost + password: Snowflake + port: 5432 + schema: dbt_demo + threads: 1 + type: postgres + user: postgres diff --git a/macros/snowflake__create_constraints.sql b/macros/snowflake__create_constraints.sql index e71c775..b1822b9 100644 --- a/macros/snowflake__create_constraints.sql +++ b/macros/snowflake__create_constraints.sql @@ -1,15 +1,15 @@ {# Snowflake specific implementation to create a primary key #} {%- macro snowflake__create_primary_key(table_relation, column_names, verify_permissions, quote_columns=false, constraint_name=none, lookup_cache=none) -%} - {%- set constraint_name = (constraint_name or table_relation.identifier ~ "_" ~ column_names|join('_') ~ "_PK") | upper -%} - {%- set columns_csv = dbt_constraints.get_quoted_column_csv(column_names, quote_columns) -%} +{%- set constraint_name = (constraint_name or table_relation.identifier ~ "_" ~ column_names|join('_') ~ "_PK") | upper -%} +{%- set columns_csv = dbt_constraints.get_quoted_column_csv(column_names, quote_columns) -%} - {#- Check that the table does not already have this PK/UK -#} - {%- if not dbt_constraints.unique_constraint_exists(table_relation, column_names, lookup_cache) -%} +{#- Check that the table does not already have this PK/UK -#} +{%- if not dbt_constraints.unique_constraint_exists(table_relation, column_names, lookup_cache) -%} {%- if dbt_constraints.have_ownership_priv(table_relation, verify_permissions, lookup_cache) -%} {%- set query -%} - ALTER TABLE {{table_relation}} ADD CONSTRAINT {{constraint_name}} PRIMARY KEY ( {{columns_csv}} ) RELY + ALTER TABLE {{ table_relation }} ADD CONSTRAINT {{ constraint_name }} PRIMARY KEY ( {{ columns_csv }} ) RELY {%- endset -%} {%- do log("Creating primary key: " ~ constraint_name, info=true) -%} {%- do run_query(query) -%} @@ -31,16 +31,16 @@ {# Snowflake specific implementation to create a unique key #} {%- macro snowflake__create_unique_key(table_relation, column_names, verify_permissions, quote_columns=false, constraint_name=none, lookup_cache=none) -%} - {%- set constraint_name = (constraint_name or table_relation.identifier ~ "_" ~ column_names|join('_') ~ "_UK") | upper -%} - {%- set columns_csv = dbt_constraints.get_quoted_column_csv(column_names, quote_columns) -%} +{%- set constraint_name = (constraint_name or table_relation.identifier ~ "_" ~ column_names|join('_') ~ "_UK") | upper -%} +{%- set columns_csv = dbt_constraints.get_quoted_column_csv(column_names, quote_columns) -%} - {#- Check that the table does not already have this PK/UK -#} - {%- if not dbt_constraints.unique_constraint_exists(table_relation, column_names, lookup_cache) -%} +{#- Check that the table does not already have this PK/UK -#} +{%- if not dbt_constraints.unique_constraint_exists(table_relation, column_names, lookup_cache) -%} {%- if dbt_constraints.have_ownership_priv(table_relation, verify_permissions, lookup_cache) -%} {%- set query -%} - ALTER TABLE {{table_relation}} ADD CONSTRAINT {{constraint_name}} UNIQUE ( {{columns_csv}} ) RELY + ALTER TABLE {{ table_relation }} ADD CONSTRAINT {{ constraint_name }} UNIQUE ( {{ columns_csv }} ) RELY {%- endset -%} {%- do log("Creating unique key: " ~ constraint_name, info=true) -%} {%- do run_query(query) -%} @@ -61,18 +61,18 @@ {# Snowflake specific implementation to create a foreign key #} {%- macro snowflake__create_foreign_key(pk_table_relation, pk_column_names, fk_table_relation, fk_column_names, verify_permissions, quote_columns, constraint_name, lookup_cache) -%} - {%- set constraint_name = (constraint_name or fk_table_relation.identifier ~ "_" ~ fk_column_names|join('_') ~ "_FK") | upper -%} - {%- set fk_columns_csv = dbt_constraints.get_quoted_column_csv(fk_column_names, quote_columns) -%} - {%- set pk_columns_csv = dbt_constraints.get_quoted_column_csv(pk_column_names, quote_columns) -%} - {#- Check that the PK table has a PK or UK -#} - {%- if dbt_constraints.unique_constraint_exists(pk_table_relation, pk_column_names, lookup_cache) -%} +{%- set constraint_name = (constraint_name or fk_table_relation.identifier ~ "_" ~ fk_column_names|join('_') ~ "_FK") | upper -%} +{%- set fk_columns_csv = dbt_constraints.get_quoted_column_csv(fk_column_names, quote_columns) -%} +{%- set pk_columns_csv = dbt_constraints.get_quoted_column_csv(pk_column_names, quote_columns) -%} +{#- Check that the PK table has a PK or UK -#} +{%- if dbt_constraints.unique_constraint_exists(pk_table_relation, pk_column_names, lookup_cache) -%} {#- Check if the table already has this foreign key -#} {%- if not dbt_constraints.foreign_key_exists(fk_table_relation, fk_column_names, lookup_cache) -%} {%- if dbt_constraints.have_ownership_priv(fk_table_relation, verify_permissions, lookup_cache) and dbt_constraints.have_references_priv(pk_table_relation, verify_permissions, lookup_cache) -%} {%- set query -%} - ALTER TABLE {{fk_table_relation}} ADD CONSTRAINT {{constraint_name}} FOREIGN KEY ( {{fk_columns_csv}} ) REFERENCES {{pk_table_relation}} ( {{pk_columns_csv}} ) MATCH SIMPLE RELY + ALTER TABLE {{ fk_table_relation }} ADD CONSTRAINT {{ constraint_name }} FOREIGN KEY ( {{ fk_columns_csv }} ) REFERENCES {{ pk_table_relation }} ( {{ pk_columns_csv }} ) RELY {%- endset -%} {%- do log("Creating foreign key: " ~ constraint_name ~ " referencing " ~ pk_table_relation.identifier ~ " " ~ pk_column_names, info=true) -%} {%- do run_query(query) -%} @@ -97,17 +97,17 @@ {# Snowflake specific implementation to create a not null constraint #} {%- macro snowflake__create_not_null(table_relation, column_names, verify_permissions, quote_columns, lookup_cache) -%} - {%- set existing_not_null_col = lookup_cache.not_null_col[table_relation] -%} +{%- set existing_not_null_col = lookup_cache.not_null_col[table_relation] -%} - {%- set columns_to_change = [] -%} - {%- for column_name in column_names if column_name not in existing_not_null_col -%} - {%- do columns_to_change.append(column_name) -%} - {%- do existing_not_null_col.append(column_name) -%} - {%- endfor -%} - {%- if columns_to_change|count > 0 -%} - {%- set columns_list = dbt_constraints.get_quoted_column_list(columns_to_change, quote_columns) -%} +{%- set columns_to_change = [] -%} +{%- for column_name in column_names if column_name not in existing_not_null_col -%} +{%- do columns_to_change.append(column_name) -%} +{%- do existing_not_null_col.append(column_name) -%} +{%- endfor -%} +{%- if columns_to_change|count > 0 -%} +{%- set columns_list = dbt_constraints.get_quoted_column_list(columns_to_change, quote_columns) -%} - {%- if dbt_constraints.have_ownership_priv(table_relation, verify_permissions, lookup_cache) -%} +{%- if dbt_constraints.have_ownership_priv(table_relation, verify_permissions, lookup_cache) -%} {%- set modify_statements= [] -%} {%- for column in columns_list -%} @@ -115,7 +115,7 @@ {%- endfor -%} {%- set modify_statement_csv = modify_statements | join(", ") -%} {%- set query -%} - ALTER TABLE {{table_relation}} MODIFY {{ modify_statement_csv }}; + ALTER TABLE {{ table_relation }} MODIFY {{ modify_statement_csv }}; {%- endset -%} {%- do log("Creating not null constraint for: " ~ columns_to_change | join(", ") ~ " in " ~ table_relation, info=true) -%} {%- do run_query(query) -%} @@ -137,22 +137,22 @@ and to skip FK where no PK/UK constraint exists on the parent table -#} {%- macro snowflake__unique_constraint_exists(table_relation, column_names, lookup_cache) -%} - {#- Check if we can find this constraint in the lookup cache -#} - {%- if table_relation in lookup_cache.unique_keys -%} - {%- set cached_unique_keys = lookup_cache.unique_keys[table_relation] -%} - {%- for cached_columns in cached_unique_keys.values() -%} - {%- if dbt_constraints.column_list_matches(cached_columns, column_names ) -%} - {%- do log("Found UK key: " ~ table_relation ~ " " ~ column_names, info=false) -%} - {{ return(true) }} - {%- endif -%} - {% endfor %} - {%- endif -%} - - {%- set lookup_query -%} - SHOW UNIQUE KEYS IN TABLE {{table_relation}} - {%- endset -%} - {%- set constraint_list = run_query(lookup_query) -%} - {%- if constraint_list.columns["column_name"].values() | count > 0 -%} +{#- Check if we can find this constraint in the lookup cache -#} +{%- if table_relation in lookup_cache.unique_keys -%} +{%- set cached_unique_keys = lookup_cache.unique_keys[table_relation] -%} +{%- for cached_columns in cached_unique_keys.values() -%} +{%- if dbt_constraints.column_list_matches(cached_columns, column_names ) -%} +{%- do log("Found UK key: " ~ table_relation ~ " " ~ column_names, info=false) -%} +{{ return(true) }} +{%- endif -%} +{% endfor %} +{%- endif -%} + +{%- set lookup_query -%} +SHOW UNIQUE KEYS IN TABLE {{ table_relation }} +{%- endset -%} +{%- set constraint_list = run_query(lookup_query) -%} +{%- if constraint_list.columns["column_name"].values() | count > 0 -%} {%- for constraint in constraint_list.group_by("constraint_name") -%} {#- Add this constraint to the lookup cache -#} {%- do lookup_cache.unique_keys.update({table_relation: {constraint.key_name: constraint.columns["column_name"].values()} }) -%} @@ -165,11 +165,11 @@ {% endfor %} {%- endif -%} - {%- set lookup_query -%} - SHOW PRIMARY KEYS IN TABLE {{table_relation}} - {%- endset -%} - {%- set constraint_list = run_query(lookup_query) -%} - {%- if constraint_list.columns["column_name"].values() | count > 0 -%} +{%- set lookup_query -%} +SHOW PRIMARY KEYS IN TABLE {{ table_relation }} +{%- endset -%} +{%- set constraint_list = run_query(lookup_query) -%} +{%- if constraint_list.columns["column_name"].values() | count > 0 -%} {%- for constraint in constraint_list.group_by("constraint_name") -%} {#- Add this constraint to the lookup cache -#} {%- do lookup_cache.unique_keys.update({table_relation: {constraint.key_name: constraint.columns["column_name"].values()} }) -%} @@ -182,9 +182,9 @@ {% endfor %} {%- endif -%} - {#- If we get this far then the table does not have either constraint -#} - {%- do log("No PK/UK key: " ~ table_relation ~ " " ~ column_names, info=false) -%} - {{ return(false) }} +{#- If we get this far then the table does not have either constraint -#} +{%- do log("No PK/UK key: " ~ table_relation ~ " " ~ column_names, info=false) -%} +{{ return(false) }} {%- endmacro -%} @@ -192,22 +192,22 @@ {#- This macro is used in create macros to avoid duplicate FK constraints -#} {%- macro snowflake__foreign_key_exists(table_relation, column_names, lookup_cache) -%} - {#- Check if we can find this constraint in the lookup cache -#} - {%- if table_relation in lookup_cache.foreign_keys -%} - {%- set cached_foreign_keys = lookup_cache.foreign_keys[table_relation] -%} - {%- for cached_columns in cached_foreign_keys.values() -%} - {%- if dbt_constraints.column_list_matches(cached_columns, column_names ) -%} - {%- do log("Found FK key: " ~ table_relation ~ " " ~ column_names, info=false) -%} - {{ return(true) }} - {%- endif -%} - {% endfor %} - {%- endif -%} - - {%- set lookup_query -%} - SHOW IMPORTED KEYS IN TABLE {{table_relation}} - {%- endset -%} - {%- set constraint_list = run_query(lookup_query) -%} - {%- if constraint_list.columns["fk_column_name"].values() | count > 0 -%} +{#- Check if we can find this constraint in the lookup cache -#} +{%- if table_relation in lookup_cache.foreign_keys -%} +{%- set cached_foreign_keys = lookup_cache.foreign_keys[table_relation] -%} +{%- for cached_columns in cached_foreign_keys.values() -%} +{%- if dbt_constraints.column_list_matches(cached_columns, column_names ) -%} +{%- do log("Found FK key: " ~ table_relation ~ " " ~ column_names, info=false) -%} +{{ return(true) }} +{%- endif -%} +{% endfor %} +{%- endif -%} + +{%- set lookup_query -%} +SHOW IMPORTED KEYS IN TABLE {{ table_relation }} +{%- endset -%} +{%- set constraint_list = run_query(lookup_query) -%} +{%- if constraint_list.columns["fk_column_name"].values() | count > 0 -%} {%- for constraint in constraint_list.group_by("fk_name") -%} {#- Add this constraint to the lookup cache -#} {%- do lookup_cache.foreign_keys.update({table_relation: {constraint.key_name: constraint.columns["fk_column_name"].values()} }) -%} @@ -220,73 +220,87 @@ {% endfor %} {%- endif -%} - {#- If we get this far then the table does not have this constraint -#} - {%- do log("No FK key: " ~ table_relation ~ " " ~ column_names, info=false) -%} - {{ return(false) }} +{#- If we get this far then the table does not have this constraint -#} +{%- do log("No FK key: " ~ table_relation ~ " " ~ column_names, info=false) -%} +{{ return(false) }} {%- endmacro -%} {%- macro snowflake__have_references_priv(table_relation, verify_permissions, lookup_cache) -%} - {%- if verify_permissions is sameas true -%} +{%- if verify_permissions is sameas true -%} - {%- set table_privileges = snowflake__lookup_table_privileges(table_relation, lookup_cache) -%} - {%- if "REFERENCES" in table_privileges or "OWNERSHIP" in table_privileges -%} +{%- set table_privileges = snowflake__lookup_table_privileges(table_relation, lookup_cache) -%} +{%- if "REFERENCES" in table_privileges or "OWNERSHIP" in table_privileges -%} {{ return(true) }} {%- else -%} {{ return(false) }} {%- endif -%} {%- else -%} - {{ return(true) }} - {%- endif -%} +{{ return(true) }} +{%- endif -%} {%- endmacro -%} {%- macro snowflake__have_ownership_priv(table_relation, verify_permissions, lookup_cache) -%} - {%- if verify_permissions is sameas true -%} +{%- if verify_permissions is sameas true -%} - {%- set table_privileges = snowflake__lookup_table_privileges(table_relation, lookup_cache) -%} - {%- if "OWNERSHIP" in table_privileges -%} +{%- set table_privileges = snowflake__lookup_table_privileges(table_relation, lookup_cache) -%} +{%- if "OWNERSHIP" in table_privileges -%} {{ return(true) }} {%- else -%} {{ return(false) }} {%- endif -%} {%- else -%} - {{ return(true) }} - {%- endif -%} +{{ return(true) }} +{%- endif -%} {%- endmacro -%} {%- macro snowflake__lookup_table_privileges(table_relation, lookup_cache) -%} - {%- if table_relation.database not in lookup_cache.table_privileges -%} +{%- if table_relation.database not in lookup_cache.table_privileges -%} + {%- do log("Caching privileges for database: " ~ table_relation.database, info=false) -%} + {%- set lookup_query -%} select distinct upper(tp.table_schema) as "table_schema", upper(tp.table_name) as "table_name", tp.privilege_type as "privilege_type" - from {{table_relation.database}}.information_schema.table_privileges tp + from {{ table_relation.database }}.information_schema.table_privileges tp where is_role_in_session(tp.grantee) and tp.privilege_type in ('OWNERSHIP', 'REFERENCES') {%- endset -%} - {%- do log("Caching privileges for database: " ~ table_relation.database, info=false) -%} - {%- set privilege_list = run_query(lookup_query) -%} + {%- set role_privilege_list = run_query(lookup_query) -%} + + {%- set lookup_query -%} + select distinct + upper(tp.table_schema) as "table_schema", + upper(tp.table_name) as "table_name", + tp.privilege_type as "privilege_type" + from {{ table_relation.database }}.information_schema.table_privileges tp + where is_database_role_in_session(tp.grantee) + and tp.privilege_type in ('OWNERSHIP', 'REFERENCES') + {%- endset -%} + {%- set db_role_privilege_list = run_query(lookup_query) -%} + + {%- set privilege_list = role_privilege_list.merge([role_privilege_list, db_role_privilege_list]).distinct() -%} {%- do lookup_cache.table_privileges.update({ table_relation.database: privilege_list }) -%} {%- endif -%} - {%- set tab_priv_list = [] -%} - {%- set schema_name = table_relation.schema|upper -%} - {%- set table_name = table_relation.identifier|upper -%} - {%- for row in lookup_cache.table_privileges[table_relation.database].rows -%} +{%- set tab_priv_list = [] -%} +{%- set schema_name = table_relation.schema|upper -%} +{%- set table_name = table_relation.identifier|upper -%} +{%- for row in lookup_cache.table_privileges[table_relation.database].rows -%} {%- if row["table_schema"] == schema_name and row["table_name"] == table_name -%} {%- do tab_priv_list.append(row["privilege_type"]) -%} {%- endif -%} {%- endfor -%} - {{ return(tab_priv_list) }} +{{ return(tab_priv_list) }} {%- endmacro -%} @@ -294,9 +308,9 @@ {%- macro snowflake__lookup_table_columns(table_relation, lookup_cache) -%} - {%- if table_relation not in lookup_cache.table_columns -%} +{%- if table_relation not in lookup_cache.table_columns -%} {%- set lookup_query -%} - SHOW COLUMNS IN TABLE {{table_relation}} + SHOW COLUMNS IN TABLE {{ table_relation }} {%- endset -%} {%- set results = run_query(lookup_query) -%} @@ -311,6 +325,6 @@ {%- do lookup_cache.table_columns.update({ table_relation: upper_column_list }) -%} {%- do lookup_cache.not_null_col.update({ table_relation: not_null_col }) -%} {%- endif -%} - {{ return(lookup_cache.table_columns[table_relation]) }} +{{ return(lookup_cache.table_columns[table_relation]) }} {%- endmacro -%}