|
1 |
| -{% macro declare_dbt_max_partition(relation, partition_by, complied_code, language='sql') %} |
2 |
| - |
3 |
| - {#-- TODO: revisit partitioning with python models --#} |
4 |
| - {%- if '_dbt_max_partition' in complied_code and language == 'sql' -%} |
5 |
| - |
6 |
| - declare _dbt_max_partition {{ partition_by.data_type }} default ( |
7 |
| - select max({{ partition_by.field }}) from {{ this }} |
8 |
| - where {{ partition_by.field }} is not null |
9 |
| - ); |
10 |
| - |
11 |
| - {%- endif -%} |
12 |
| - |
13 |
| -{% endmacro %} |
14 |
| - |
15 |
| - |
16 | 1 | {% macro dbt_bigquery_validate_get_incremental_strategy(config) %}
|
17 | 2 | {#-- Find and validate the incremental strategy #}
|
18 | 3 | {%- set strategy = config.get("incremental_strategy") or 'merge' -%}
|
|
28 | 13 | {% do return(strategy) %}
|
29 | 14 | {% endmacro %}
|
30 | 15 |
|
| 16 | +{% macro source_sql_with_partition(partition_by, source_sql) %} |
31 | 17 |
|
32 |
| -{% macro bq_insert_overwrite( |
33 |
| - tmp_relation, target_relation, sql, unique_key, partition_by, partitions, dest_columns, tmp_relation_exists |
34 |
| -) %} |
35 |
| - |
36 |
| - {% if partitions is not none and partitions != [] %} {# static #} |
37 |
| - |
38 |
| - {% set predicate -%} |
39 |
| - {{ partition_by.render(alias='DBT_INTERNAL_DEST') }} in ( |
40 |
| - {{ partitions | join (', ') }} |
41 |
| - ) |
42 |
| - {%- endset %} |
43 |
| - |
44 |
| - {%- set source_sql -%} |
45 |
| - ( |
46 |
| - {{sql}} |
47 |
| - ) |
48 |
| - {%- endset -%} |
49 |
| - |
50 |
| - {#-- Because we're putting the model SQL _directly_ into the MERGE statement, |
51 |
| - we need to prepend the MERGE statement with the user-configured sql_header, |
52 |
| - which may be needed to resolve that model SQL (e.g. referencing a variable or UDF in the header) |
53 |
| - in the "dynamic" case, we save the model SQL result as a temp table first, wherein the |
54 |
| - sql_header is included by the create_table_as macro. |
55 |
| - #} |
56 |
| - {{ get_insert_overwrite_merge_sql(target_relation, source_sql, dest_columns, [predicate], include_sql_header=true) }} |
57 |
| - |
58 |
| - {% else %} {# dynamic #} |
59 |
| - |
60 |
| - {% set predicate -%} |
61 |
| - {{ partition_by.render(alias='DBT_INTERNAL_DEST') }} in unnest(dbt_partitions_for_replacement) |
62 |
| - {%- endset %} |
63 |
| - |
64 |
| - {%- set source_sql -%} |
65 |
| - ( |
66 |
| - select * from {{ tmp_relation }} |
67 |
| - ) |
68 |
| - {%- endset -%} |
69 |
| - |
70 |
| - -- generated script to merge partitions into {{ target_relation }} |
71 |
| - declare dbt_partitions_for_replacement array<{{ partition_by.data_type }}>; |
72 |
| - |
73 |
| - {# have we already created the temp table to check for schema changes? #} |
74 |
| - {% if not tmp_relation_exists %} |
75 |
| - {{ declare_dbt_max_partition(this, partition_by, sql) }} |
76 |
| - |
77 |
| - -- 1. create a temp table |
78 |
| - {{ create_table_as(True, tmp_relation, compiled_code) }} |
79 |
| - {% else %} |
80 |
| - -- 1. temp table already exists, we used it to check for schema changes |
81 |
| - {% endif %} |
82 |
| - |
83 |
| - -- 2. define partitions to update |
84 |
| - set (dbt_partitions_for_replacement) = ( |
85 |
| - select as struct |
86 |
| - array_agg(distinct {{ partition_by.render() }}) |
87 |
| - from {{ tmp_relation }} |
88 |
| - ); |
89 |
| - |
90 |
| - -- 3. run the merge statement |
91 |
| - {{ get_insert_overwrite_merge_sql(target_relation, source_sql, dest_columns, [predicate]) }}; |
92 |
| - |
93 |
| - -- 4. clean up the temp table |
94 |
| - drop table if exists {{ tmp_relation }} |
| 18 | + {%- if partition_by.time_ingestion_partitioning %} |
| 19 | + {{ return(wrap_with_time_ingestion_partitioning(build_partition_time_exp(partition_by.field), source_sql, False)) }} |
| 20 | + {% else %} |
| 21 | + {{ return(source_sql) }} |
| 22 | + {%- endif -%} |
95 | 23 |
|
| 24 | +{% endmacro %} |
| 25 | +{% macro bq_create_table_as(is_time_ingestion_partitioning, temporary, relation, compiled_code, language='sql') %} |
| 26 | + {% if is_time_ingestion_partitioning %} |
| 27 | + {#-- Create the table before inserting data as ingestion time partitioned tables can't be created with the transformed data --#} |
| 28 | + {% do run_query(create_ingestion_time_partitioned_table_as(temporary, relation, sql)) %} |
| 29 | + {{ return(bq_insert_into_ingestion_time_partitioned_table(relation, sql)) }} |
| 30 | + {% else %} |
| 31 | + {{ return(create_table_as(temporary, relation, sql)) }} |
96 | 32 | {% endif %}
|
97 |
| - |
98 | 33 | {% endmacro %}
|
99 | 34 |
|
100 |
| - |
101 | 35 | {% macro bq_generate_incremental_build_sql(
|
102 | 36 | strategy, tmp_relation, target_relation, sql, unique_key, partition_by, partitions, dest_columns, tmp_relation_exists
|
103 | 37 | ) %}
|
104 | 38 | {#-- if partitioned, use BQ scripting to get the range of partition values to be updated --#}
|
105 | 39 | {% if strategy == 'insert_overwrite' %}
|
106 | 40 |
|
107 |
| - {% set missing_partition_msg -%} |
108 |
| - The 'insert_overwrite' strategy requires the `partition_by` config. |
109 |
| - {%- endset %} |
110 |
| - {% if partition_by is none %} |
111 |
| - {% do exceptions.raise_compiler_error(missing_partition_msg) %} |
112 |
| - {% endif %} |
113 |
| - |
114 |
| - {% set build_sql = bq_insert_overwrite( |
| 41 | + {% set build_sql = bq_generate_incremental_insert_overwrite_build_sql( |
115 | 42 | tmp_relation, target_relation, sql, unique_key, partition_by, partitions, dest_columns, tmp_relation_exists
|
116 | 43 | ) %}
|
117 | 44 |
|
118 | 45 | {% else %} {# strategy == 'merge' #}
|
119 |
| - {%- set source_sql -%} |
120 |
| - {%- if tmp_relation_exists -%} |
121 |
| - ( |
122 |
| - select * from {{ tmp_relation }} |
123 |
| - ) |
124 |
| - {%- else -%} {#-- wrap sql in parens to make it a subquery --#} |
125 |
| - ( |
126 |
| - {{sql}} |
127 |
| - ) |
128 |
| - {%- endif -%} |
129 |
| - {%- endset -%} |
130 |
| - |
131 |
| - {% set build_sql = get_merge_sql(target_relation, source_sql, unique_key, dest_columns) %} |
| 46 | + |
| 47 | + {% set build_sql = bq_generate_incremental_merge_build_sql( |
| 48 | + tmp_relation, target_relation, sql, unique_key, partition_by, dest_columns, tmp_relation_exists |
| 49 | + ) %} |
132 | 50 |
|
133 | 51 | {% endif %}
|
134 | 52 |
|
|
163 | 81 |
|
164 | 82 | {% if existing_relation is none %}
|
165 | 83 | {%- call statement('main', language=language) -%}
|
166 |
| - {{ create_table_as(False, target_relation, compiled_code, language) }} |
| 84 | + {{ bq_create_table_as(partition_by.time_ingestion_partitioning, False, target_relation, compiled_code, language) }} |
167 | 85 | {%- endcall -%}
|
168 | 86 |
|
169 | 87 | {% elif existing_relation.is_view %}
|
170 | 88 | {#-- There's no way to atomically replace a view with a table on BQ --#}
|
171 | 89 | {{ adapter.drop_relation(existing_relation) }}
|
172 | 90 | {%- call statement('main', language=language) -%}
|
173 |
| - {{ create_table_as(False, target_relation, compiled_code, language) }} |
| 91 | + {{ bq_create_table_as(partition_by.time_ingestion_partitioning, False, target_relation, compiled_code, language) }} |
174 | 92 | {%- endcall -%}
|
175 | 93 |
|
176 | 94 | {% elif full_refresh_mode %}
|
|
180 | 98 | {{ adapter.drop_relation(existing_relation) }}
|
181 | 99 | {% endif %}
|
182 | 100 | {%- call statement('main', language=language) -%}
|
183 |
| - {{ create_table_as(False, target_relation, compiled_code, language) }} |
| 101 | + {{ bq_create_table_as(partition_by.time_ingestion_partitioning, False, target_relation, compiled_code, language) }} |
184 | 102 | {%- endcall -%}
|
185 | 103 |
|
186 | 104 | {% else %}
|
|
198 | 116 | {#-- Python always needs to create a temp table --#}
|
199 | 117 | {%- call statement('create_tmp_relation', language=language) -%}
|
200 | 118 | {{ declare_dbt_max_partition(this, partition_by, compiled_code, language) +
|
201 |
| - create_table_as(True, tmp_relation, compiled_code, language) |
| 119 | + bq_create_table_as(partition_by.time_ingestion_partitioning, True, tmp_relation, compiled_code, language) |
202 | 120 | }}
|
203 | 121 | {%- endcall -%}
|
204 | 122 | {% set tmp_relation_exists = true %}
|
|
209 | 127 | {% if not dest_columns %}
|
210 | 128 | {% set dest_columns = adapter.get_columns_in_relation(existing_relation) %}
|
211 | 129 | {% endif %}
|
| 130 | + {% if partition_by.time_ingestion_partitioning %} |
| 131 | + {% set dest_columns = adapter.add_time_ingestion_partition_column(dest_columns) %} |
| 132 | + {% endif %} |
212 | 133 | {% set build_sql = bq_generate_incremental_build_sql(
|
213 | 134 | strategy, tmp_relation, target_relation, compiled_code, unique_key, partition_by, partitions, dest_columns, tmp_relation_exists
|
214 | 135 | ) %}
|
|
0 commit comments