adapters.sql 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. -- Copyright 2020 Josh Wills. All rights reserved.
  2. -- Copyright Materialize, Inc. and contributors. All rights reserved.
  3. --
  4. -- Licensed under the Apache License, Version 2.0 (the "License");
  5. -- you may not use this file except in compliance with the License.
  6. -- You may obtain a copy of the License in the LICENSE file at the
  7. -- root of this repository, or online at
  8. --
  9. -- http://www.apache.org/licenses/LICENSE-2.0
  10. --
  11. -- Unless required by applicable law or agreed to in writing, software
  12. -- distributed under the License is distributed on an "AS IS" BASIS,
  13. -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. -- See the License for the specific language governing permissions and
  15. -- limitations under the License.
  16. -- Most of these macros are direct copies of their PostgreSQL counterparts.
  17. -- See: https://github.com/dbt-labs/dbt-core/blob/13b18654f/plugins/postgres/dbt/include/postgres/macros/adapters.sql
  18. {% macro materialize__create_view_as(relation, sql) -%}
  19. create view {{ relation }}
  20. {% set contract_config = config.get('contract') %}
  21. {% if contract_config.enforced %}
  22. {{ get_assert_columns_equivalent(sql) }}
  23. {%- endif %}
  24. as (
  25. {{ sql }}
  26. );
  27. {%- endmacro %}
  28. {% macro materialize__create_materialized_view_as(relation, sql) -%}
  29. {%- set cluster = adapter.generate_final_cluster_name(config.get('cluster', target.cluster)) -%}
  30. create materialized view {{ relation }}
  31. {% if cluster %}
  32. in cluster {{ cluster }}
  33. {% endif %}
  34. {# Scheduled refreshes #}
  35. {%- set refresh_interval = config.get('refresh_interval') -%}
  36. {%- if refresh_interval -%}
  37. with (
  38. {{ materialize__get_refresh_interval_sql(relation, refresh_interval) }}
  39. )
  40. {%- endif %}
  41. {# History retention #}
  42. {%- set retain_history = config.get('retain_history') -%}
  43. {%- if retain_history -%}
  44. with (retain history for '{{ retain_history }}')
  45. {%- endif %}
  46. {# Contracts and constraints #}
  47. {% set contract_config = config.get('contract') %}
  48. {% if contract_config.enforced %}
  49. {{ get_assert_columns_equivalent(sql) }}
  50. {% set ns = namespace(c_constraints=False, m_constraints=False) %}
  51. {# Column-level constraints #}
  52. {% set raw_columns = model['columns'] %}
  53. {% for c_id, c_details in raw_columns.items() if c_details['constraints'] != [] %}
  54. {% set ns.c_constraints = True %}
  55. {%- endfor %}
  56. {# Model-level constraints #}
  57. -- NOTE(morsapaes): not_null constraints are not originally supported in
  58. -- dbt-core at model-level, since model-level constraints are intended for
  59. -- multi-columns constraints. Any model-level constraint is ignored in
  60. -- dbt-materialize, albeit silently.
  61. {% if model['constraints'] != [] %}
  62. {% set ns.m_constraints = True %}
  63. {%- endif %}
  64. {% if ns.c_constraints %}
  65. with
  66. {{ get_table_columns_and_constraints() }}
  67. {%- endif %}
  68. {%- endif %}
  69. as (
  70. {{ sql }}
  71. );
  72. {%- endmacro %}
  73. {% macro materialize__create_arbitrary_object(sql) -%}
  74. {% set contract_config = config.get('contract') %}
  75. {% if contract_config.enforced %}
  76. {{exceptions.warn("Model contracts cannot be enforced for custom materializations (see dbt-core #7213)")}}
  77. {%- endif %}
  78. {{ sql }}
  79. {%- endmacro %}
  80. {% macro materialize__create_source(relation, sql) -%}
  81. {% set contract_config = config.get('contract') %}
  82. {% if contract_config.enforced %}
  83. {{exceptions.warn("Model contracts cannot be enforced for custom materializations (see dbt-core #7213)")}}
  84. {%- endif %}
  85. {%- set cluster = adapter.generate_final_cluster_name(config.get('cluster', target.cluster)) -%}
  86. create source {{ relation }}
  87. {% if cluster %}
  88. in cluster {{ cluster }}
  89. {% endif %}
  90. {{ sql }}
  91. ;
  92. {%- endmacro %}
  93. {% macro materialize__create_source_table(relation, sql) %}
  94. {% set contract_config = config.get('contract') %}
  95. {% if contract_config.enforced %}
  96. {{exceptions.warn("Model contracts cannot be enforced for custom materializations (see dbt-core #7213)")}}
  97. {%- endif %}
  98. create table {{ relation }}
  99. {{ sql }}
  100. {% endmacro %}
  101. {% macro materialize__create_sink(relation, sql) -%}
  102. {% set contract_config = config.get('contract') %}
  103. {% if contract_config.enforced %}
  104. {{exceptions.warn("Model contracts cannot be enforced for custom materializations (see dbt-core #7213)")}}
  105. {%- endif %}
  106. {%- set cluster = adapter.generate_final_cluster_name(config.get('cluster', target.cluster)) -%}
  107. create sink {{ relation }}
  108. {% if cluster %}
  109. in cluster {{ cluster }}
  110. {% endif %}
  111. {{ sql }}
  112. ;
  113. {%- endmacro %}
  114. {% macro materialize__rename_relation(from_relation, to_relation) -%}
  115. {% set target_name = adapter.quote_as_configured(to_relation.identifier, 'identifier') %}
  116. {% call statement('rename_relation') -%}
  117. {% if relation.type == 'view' %}
  118. alter view {{ from_relation }} rename to {{ target_name }}
  119. {% else %}
  120. alter materialized view {{ from_relation }} rename to {{ target_name }}
  121. {% endif %}
  122. {%- endcall %}
  123. {% endmacro %}
  124. {% macro materialize__drop_relation(relation) -%}
  125. {% call statement('drop_relation') -%}
  126. {% if relation.type == 'view' %}
  127. drop view if exists {{ relation }} cascade
  128. {% elif relation.is_materialized_view %}
  129. drop materialized view if exists {{ relation }} cascade
  130. {% elif relation.type == 'sink' %}
  131. drop sink if exists {{ relation }}
  132. {% elif relation.type == 'source' %}
  133. drop source if exists {{ relation }} cascade
  134. {% elif relation.type == 'index' %}
  135. drop index if exists {{ relation }}
  136. -- Tables are not supported as a materialization type in dbt-materialize,
  137. -- but seeds and source tables are materialized as tables.
  138. {% elif relation.type == 'table' %}
  139. drop table if exists {{ relation }} cascade
  140. {% endif %}
  141. {%- endcall %}
  142. {% endmacro %}
  143. {% macro set_cluster(cluster) %}
  144. set cluster = {{ cluster }};
  145. {% endmacro %}
  146. {% macro materialize__truncate_relation(relation) -%}
  147. -- Materialize does not support the TRUNCATE command, so we work around that
  148. -- by using an unqualified DELETE.
  149. {% call statement('truncate_relation') -%}
  150. delete from {{ relation }}
  151. {%- endcall %}
  152. {% endmacro %}
  153. {% macro truncate_relation_sql(relation, cluster) -%}
  154. -- DELETE requires a scan of the relation, so it needs a valid cluster to run
  155. -- against. This is expected to fail if no cluster is specified for the
  156. -- target in the materialization configuration, `profiles.yml`, _and_ the
  157. -- default cluster for the user is invalid(or intentionally set to
  158. -- mz_catalog_server, which cannot query user data).
  159. {% if cluster -%}
  160. {%- set origin_cluster = adapter.generate_final_cluster_name(cluster) -%}
  161. {% do run_query(set_cluster(origin_cluster)) -%}
  162. {%- endif %}
  163. {{ truncate_relation(relation) }}
  164. {% endmacro %}
  165. {% macro materialize__get_create_index_sql(relation, index_dict) -%}
  166. {%- set index_config = adapter.parse_index(index_dict) -%}
  167. {%- set cluster = index_config.cluster or config.get('cluster', target.cluster) -%}
  168. {%- set cluster = adapter.generate_final_cluster_name(cluster) -%}
  169. create
  170. {% if index_config.default -%}
  171. default
  172. {%- endif %}
  173. index
  174. {% if index_config.name -%}
  175. "{{ index_config.name }}"
  176. {%- endif %}
  177. {% if cluster -%}
  178. in cluster {{ cluster }}
  179. {%- endif %}
  180. on {{ relation }}
  181. {% if index_config.columns -%}
  182. ({{ ", ".join(index_config.columns) }})
  183. {%- endif %};
  184. {%- endmacro %}
  185. {% macro materialize__persist_docs(relation, model, for_relation, for_columns) -%}
  186. {% if for_relation and config.persist_relation_docs() and model.description %}
  187. {% do run_query(alter_relation_comment(relation, model.description)) %}
  188. {% endif %}
  189. {% if for_columns and config.persist_column_docs() and model.columns %}
  190. {% set existing_columns = adapter.get_columns_in_relation(relation) | map(attribute="name") | list %}
  191. {% set column_dict = model.columns %}
  192. -- Materialize does not support running multiple COMMENT ON commands in a
  193. -- transaction, so we work around that by forcing a transaction per comment
  194. -- instead
  195. -- See: https://github.com/MaterializeInc/database-issues/issues/6759
  196. {% for column_name in column_dict if (column_name in existing_columns) %}
  197. {% set comment = column_dict[column_name]['description'] %}
  198. {% set quote = column_dict[column_name]['quote'] %}
  199. {% do run_query(materialize__alter_column_comment_single(relation, column_name, quote, comment)) %}
  200. {% endfor %}
  201. {% endif %}
  202. {% endmacro %}
  203. {% macro materialize__apply_grants(relation, grant_config, should_revoke) -%}
  204. {{ exceptions.raise_compiler_error(
  205. """
  206. dbt-materialize does not implement the grants configuration.
  207. If this feature is important to you, please reach out!
  208. """
  209. )}}
  210. {% endmacro %}
  211. {% macro materialize__get_refresh_interval_sql(relation, refresh_interval_dict) -%}
  212. {%- set refresh_interval = adapter.parse_refresh_interval(refresh_interval_dict) -%}
  213. {% if refresh_interval.at -%}
  214. refresh at '{{ refresh_interval.at }}'
  215. {%- endif %}
  216. {% if refresh_interval.at_creation -%}
  217. refresh at creation
  218. {%- endif %}
  219. {% if refresh_interval.every -%}
  220. {% if refresh_interval.at or refresh_interval.at_creation -%}
  221. ,
  222. {%- endif %}
  223. refresh every '{{ refresh_interval.every }}'
  224. {% if refresh_interval.aligned_to -%}
  225. aligned to '{{ refresh_interval.aligned_to }}'
  226. {%- endif %}
  227. {%- endif %}
  228. {% if refresh_interval.on_commit -%}
  229. refresh on commit
  230. {%- endif %}
  231. {%- endmacro %}
  232. {% macro materialize__alter_column_comment_single(relation, column_name, quote, comment) %}
  233. {% set escaped_comment = postgres_escape_comment(comment) %}
  234. comment on column {{ relation }}.{{ adapter.quote(column_name) if quote else column_name }} is {{ escaped_comment }};
  235. {% endmacro %}
  236. -- In the dbt-adapter we extend the Relation class to include sinks and indexes
  237. {% macro materialize__list_relations_without_caching(schema_relation) %}
  238. {% call statement('list_relations_without_caching', fetch_result=True) -%}
  239. select
  240. d.name as database,
  241. s.name as schema,
  242. o.name,
  243. case when o.type = 'materialized-view' then 'materialized_view'
  244. else o.type
  245. end as type
  246. from mz_objects o
  247. left join mz_sources so on o.id = so.id
  248. join mz_schemas s on o.schema_id = s.id and s.name = '{{ schema_relation.schema }}'
  249. join mz_databases d on s.database_id = d.id and d.name = '{{ schema_relation.database }}'
  250. where o.type in ('table', 'source', 'view', 'materialized-view', 'index', 'sink')
  251. -- Exclude subsources and progress subsources, which aren't relevant in this
  252. -- context and can bork the adapter (see database-issues#6162)
  253. and coalesce(so.type, '') not in ('subsource', 'progress')
  254. {% endcall %}
  255. {{ return(load_result('list_relations_without_caching').table) }}
  256. {% endmacro %}