123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- -- Copyright 2020 Josh Wills. All rights reserved.
- -- Copyright Materialize, Inc. and contributors. All rights reserved.
- --
- -- Licensed under the Apache License, Version 2.0 (the "License");
- -- you may not use this file except in compliance with the License.
- -- You may obtain a copy of the License in the LICENSE file at the
- -- root of this repository, or online at
- --
- -- http://www.apache.org/licenses/LICENSE-2.0
- --
- -- Unless required by applicable law or agreed to in writing, software
- -- distributed under the License is distributed on an "AS IS" BASIS,
- -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- -- See the License for the specific language governing permissions and
- -- limitations under the License.
- -- Most of these macros are direct copies of their PostgreSQL counterparts.
- -- See: https://github.com/dbt-labs/dbt-core/blob/13b18654f/plugins/postgres/dbt/include/postgres/macros/adapters.sql
- {% macro materialize__create_view_as(relation, sql) -%}
- create view {{ relation }}
- {% set contract_config = config.get('contract') %}
- {% if contract_config.enforced %}
- {{ get_assert_columns_equivalent(sql) }}
- {%- endif %}
- as (
- {{ sql }}
- );
- {%- endmacro %}
- {% macro materialize__create_materialized_view_as(relation, sql) -%}
- {%- set cluster = adapter.generate_final_cluster_name(config.get('cluster', target.cluster)) -%}
- create materialized view {{ relation }}
- {% if cluster %}
- in cluster {{ cluster }}
- {% endif %}
- {# Scheduled refreshes #}
- {%- set refresh_interval = config.get('refresh_interval') -%}
- {%- if refresh_interval -%}
- with (
- {{ materialize__get_refresh_interval_sql(relation, refresh_interval) }}
- )
- {%- endif %}
- {# History retention #}
- {%- set retain_history = config.get('retain_history') -%}
- {%- if retain_history -%}
- with (retain history for '{{ retain_history }}')
- {%- endif %}
- {# Contracts and constraints #}
- {% set contract_config = config.get('contract') %}
- {% if contract_config.enforced %}
- {{ get_assert_columns_equivalent(sql) }}
- {% set ns = namespace(c_constraints=False, m_constraints=False) %}
- {# Column-level constraints #}
- {% set raw_columns = model['columns'] %}
- {% for c_id, c_details in raw_columns.items() if c_details['constraints'] != [] %}
- {% set ns.c_constraints = True %}
- {%- endfor %}
- {# Model-level constraints #}
- -- NOTE(morsapaes): not_null constraints are not originally supported in
- -- dbt-core at model-level, since model-level constraints are intended for
- -- multi-columns constraints. Any model-level constraint is ignored in
- -- dbt-materialize, albeit silently.
- {% if model['constraints'] != [] %}
- {% set ns.m_constraints = True %}
- {%- endif %}
- {% if ns.c_constraints %}
- with
- {{ get_table_columns_and_constraints() }}
- {%- endif %}
- {%- endif %}
- as (
- {{ sql }}
- );
- {%- endmacro %}
- {% macro materialize__create_arbitrary_object(sql) -%}
- {% set contract_config = config.get('contract') %}
- {% if contract_config.enforced %}
- {{exceptions.warn("Model contracts cannot be enforced for custom materializations (see dbt-core #7213)")}}
- {%- endif %}
- {{ sql }}
- {%- endmacro %}
- {% macro materialize__create_source(relation, sql) -%}
- {% set contract_config = config.get('contract') %}
- {% if contract_config.enforced %}
- {{exceptions.warn("Model contracts cannot be enforced for custom materializations (see dbt-core #7213)")}}
- {%- endif %}
- {%- set cluster = adapter.generate_final_cluster_name(config.get('cluster', target.cluster)) -%}
- create source {{ relation }}
- {% if cluster %}
- in cluster {{ cluster }}
- {% endif %}
- {{ sql }}
- ;
- {%- endmacro %}
- {% macro materialize__create_source_table(relation, sql) %}
- {% set contract_config = config.get('contract') %}
- {% if contract_config.enforced %}
- {{exceptions.warn("Model contracts cannot be enforced for custom materializations (see dbt-core #7213)")}}
- {%- endif %}
- create table {{ relation }}
- {{ sql }}
- {% endmacro %}
- {% macro materialize__create_sink(relation, sql) -%}
- {% set contract_config = config.get('contract') %}
- {% if contract_config.enforced %}
- {{exceptions.warn("Model contracts cannot be enforced for custom materializations (see dbt-core #7213)")}}
- {%- endif %}
- {%- set cluster = adapter.generate_final_cluster_name(config.get('cluster', target.cluster)) -%}
- create sink {{ relation }}
- {% if cluster %}
- in cluster {{ cluster }}
- {% endif %}
- {{ sql }}
- ;
- {%- endmacro %}
- {% macro materialize__rename_relation(from_relation, to_relation) -%}
- {% set target_name = adapter.quote_as_configured(to_relation.identifier, 'identifier') %}
- {% call statement('rename_relation') -%}
- {% if relation.type == 'view' %}
- alter view {{ from_relation }} rename to {{ target_name }}
- {% else %}
- alter materialized view {{ from_relation }} rename to {{ target_name }}
- {% endif %}
- {%- endcall %}
- {% endmacro %}
- {% macro materialize__drop_relation(relation) -%}
- {% call statement('drop_relation') -%}
- {% if relation.type == 'view' %}
- drop view if exists {{ relation }} cascade
- {% elif relation.is_materialized_view %}
- drop materialized view if exists {{ relation }} cascade
- {% elif relation.type == 'sink' %}
- drop sink if exists {{ relation }}
- {% elif relation.type == 'source' %}
- drop source if exists {{ relation }} cascade
- {% elif relation.type == 'index' %}
- drop index if exists {{ relation }}
- -- Tables are not supported as a materialization type in dbt-materialize,
- -- but seeds and source tables are materialized as tables.
- {% elif relation.type == 'table' %}
- drop table if exists {{ relation }} cascade
- {% endif %}
- {%- endcall %}
- {% endmacro %}
- {% macro set_cluster(cluster) %}
- set cluster = {{ cluster }};
- {% endmacro %}
- {% macro materialize__truncate_relation(relation) -%}
- -- Materialize does not support the TRUNCATE command, so we work around that
- -- by using an unqualified DELETE.
- {% call statement('truncate_relation') -%}
- delete from {{ relation }}
- {%- endcall %}
- {% endmacro %}
- {% macro truncate_relation_sql(relation, cluster) -%}
- -- DELETE requires a scan of the relation, so it needs a valid cluster to run
- -- against. This is expected to fail if no cluster is specified for the
- -- target in the materialization configuration, `profiles.yml`, _and_ the
- -- default cluster for the user is invalid(or intentionally set to
- -- mz_catalog_server, which cannot query user data).
- {% if cluster -%}
- {%- set origin_cluster = adapter.generate_final_cluster_name(cluster) -%}
- {% do run_query(set_cluster(origin_cluster)) -%}
- {%- endif %}
- {{ truncate_relation(relation) }}
- {% endmacro %}
- {% macro materialize__get_create_index_sql(relation, index_dict) -%}
- {%- set index_config = adapter.parse_index(index_dict) -%}
- {%- set cluster = index_config.cluster or config.get('cluster', target.cluster) -%}
- {%- set cluster = adapter.generate_final_cluster_name(cluster) -%}
- create
- {% if index_config.default -%}
- default
- {%- endif %}
- index
- {% if index_config.name -%}
- "{{ index_config.name }}"
- {%- endif %}
- {% if cluster -%}
- in cluster {{ cluster }}
- {%- endif %}
- on {{ relation }}
- {% if index_config.columns -%}
- ({{ ", ".join(index_config.columns) }})
- {%- endif %};
- {%- endmacro %}
- {% macro materialize__persist_docs(relation, model, for_relation, for_columns) -%}
- {% if for_relation and config.persist_relation_docs() and model.description %}
- {% do run_query(alter_relation_comment(relation, model.description)) %}
- {% endif %}
- {% if for_columns and config.persist_column_docs() and model.columns %}
- {% set existing_columns = adapter.get_columns_in_relation(relation) | map(attribute="name") | list %}
- {% set column_dict = model.columns %}
- -- Materialize does not support running multiple COMMENT ON commands in a
- -- transaction, so we work around that by forcing a transaction per comment
- -- instead
- -- See: https://github.com/MaterializeInc/database-issues/issues/6759
- {% for column_name in column_dict if (column_name in existing_columns) %}
- {% set comment = column_dict[column_name]['description'] %}
- {% set quote = column_dict[column_name]['quote'] %}
- {% do run_query(materialize__alter_column_comment_single(relation, column_name, quote, comment)) %}
- {% endfor %}
- {% endif %}
- {% endmacro %}
- {% macro materialize__apply_grants(relation, grant_config, should_revoke) -%}
- {{ exceptions.raise_compiler_error(
- """
- dbt-materialize does not implement the grants configuration.
- If this feature is important to you, please reach out!
- """
- )}}
- {% endmacro %}
- {% macro materialize__get_refresh_interval_sql(relation, refresh_interval_dict) -%}
- {%- set refresh_interval = adapter.parse_refresh_interval(refresh_interval_dict) -%}
- {% if refresh_interval.at -%}
- refresh at '{{ refresh_interval.at }}'
- {%- endif %}
- {% if refresh_interval.at_creation -%}
- refresh at creation
- {%- endif %}
- {% if refresh_interval.every -%}
- {% if refresh_interval.at or refresh_interval.at_creation -%}
- ,
- {%- endif %}
- refresh every '{{ refresh_interval.every }}'
- {% if refresh_interval.aligned_to -%}
- aligned to '{{ refresh_interval.aligned_to }}'
- {%- endif %}
- {%- endif %}
- {% if refresh_interval.on_commit -%}
- refresh on commit
- {%- endif %}
- {%- endmacro %}
- {% macro materialize__alter_column_comment_single(relation, column_name, quote, comment) %}
- {% set escaped_comment = postgres_escape_comment(comment) %}
- comment on column {{ relation }}.{{ adapter.quote(column_name) if quote else column_name }} is {{ escaped_comment }};
- {% endmacro %}
- -- In the dbt-adapter we extend the Relation class to include sinks and indexes
- {% macro materialize__list_relations_without_caching(schema_relation) %}
- {% call statement('list_relations_without_caching', fetch_result=True) -%}
- select
- d.name as database,
- s.name as schema,
- o.name,
- case when o.type = 'materialized-view' then 'materialized_view'
- else o.type
- end as type
- from mz_objects o
- left join mz_sources so on o.id = so.id
- join mz_schemas s on o.schema_id = s.id and s.name = '{{ schema_relation.schema }}'
- join mz_databases d on s.database_id = d.id and d.name = '{{ schema_relation.database }}'
- where o.type in ('table', 'source', 'view', 'materialized-view', 'index', 'sink')
- -- Exclude subsources and progress subsources, which aren't relevant in this
- -- context and can bork the adapter (see database-issues#6162)
- and coalesce(so.type, '') not in ('subsource', 'progress')
- {% endcall %}
- {{ return(load_result('list_relations_without_caching').table) }}
- {% endmacro %}
|