|
27 | 27 | {% do return(strategy) %}
|
28 | 28 | {% endmacro %}
|
29 | 29 |
|
| 30 | +{% macro get_columns_with_types_in_query(select_sql) %} |
| 31 | + {% call statement('get_columns_with_types_in_query', fetch_result=True, auto_begin=False) -%} |
| 32 | + select * from ( |
| 33 | + {{ select_sql }} |
| 34 | + ) as __dbt_sbq |
| 35 | + where false |
| 36 | + limit 0 |
| 37 | + {% endcall %} |
| 38 | + {%- set result = load_result('get_columns_with_types_in_query') -%} |
| 39 | + {{ return(load_result('get_columns_with_types_in_query').response.fields) }} |
| 40 | +{% endmacro %} |
| 41 | + |
| 42 | +{% macro create_ingestion_time_partitioned_table_as(temporary, relation, sql) -%} |
| 43 | + {%- set raw_partition_by = config.get('partition_by', none) -%} |
| 44 | + {%- set raw_cluster_by = config.get('cluster_by', none) -%} |
| 45 | + {%- set sql_header = config.get('sql_header', none) -%} |
| 46 | + |
| 47 | + {%- set partition_config = adapter.parse_partition_by(raw_partition_by) -%} |
| 48 | + |
| 49 | + {%- set columns = get_columns_with_types_in_query(sql) -%} |
| 50 | + {%- set table_dest_columns_csv = columns_without_partition_fields_csv(partition_config, columns) -%} |
| 51 | + |
| 52 | + {{ sql_header if sql_header is not none }} |
| 53 | + |
| 54 | + {% set ingestion_time_partition_config_raw = fromjson(tojson(raw_partition_by)) %} |
| 55 | + {% do ingestion_time_partition_config_raw.update({'field':'_PARTITIONTIME'}) %} |
| 56 | + |
| 57 | + {%- set ingestion_time_partition_config = adapter.parse_partition_by(ingestion_time_partition_config_raw) -%} |
| 58 | + |
| 59 | + create or replace table {{ relation }} ({{table_dest_columns_csv}}) |
| 60 | + {{ partition_by(ingestion_time_partition_config) }} |
| 61 | + {{ cluster_by(raw_cluster_by) }} |
| 62 | + {{ bigquery_table_options(config, model, temporary) }} |
| 63 | + |
| 64 | +{%- endmacro -%} |
| 65 | + |
| 66 | +{% macro get_quoted_with_types_csv(columns) %} |
| 67 | + {% set quoted = [] %} |
| 68 | + {% for col in columns -%} |
| 69 | + {%- do quoted.append(adapter.quote(col.name) ~ " " ~ col.field_type) -%} |
| 70 | + {%- endfor %} |
| 71 | + {%- set dest_cols_csv = quoted | join(', ') -%} |
| 72 | + {{ return(dest_cols_csv) }} |
| 73 | + |
| 74 | +{% endmacro %} |
| 75 | + |
| 76 | +{% macro columns_without_partition_fields_csv(partition_config, columns) -%} |
| 77 | + {%- set columns_no_partition = partition_config.reject_partition_field_column(columns) -%} |
| 78 | + {% set columns_names = get_quoted_with_types_csv(columns_no_partition) %} |
| 79 | + {{ return(columns_names) }} |
| 80 | + |
| 81 | +{%- endmacro -%} |
| 82 | + |
| 83 | +{% macro bq_insert_into_ingestion_time_partitioned_table(target_relation, sql) -%} |
| 84 | + {%- set partition_by = config.get('partition_by', none) -%} |
| 85 | + {% set dest_columns = adapter.get_columns_in_relation(target_relation) %} |
| 86 | + {%- set dest_columns_csv = get_quoted_csv(dest_columns | map(attribute="name")) -%} |
| 87 | + |
| 88 | + insert into {{ target_relation }} (_partitiontime, {{ dest_columns_csv }}) |
| 89 | + {{ wrap_with_time_ingestion_partitioning(build_partition_time_exp(partition_by), sql) }} |
| 90 | + |
| 91 | +{%- endmacro -%} |
| 92 | + |
| 93 | +{% macro build_partition_time_exp(partition_by) %} |
| 94 | + {% if partition_by.data_type == 'timestamp' %} |
| 95 | + {{ return(partition_by.field) }} |
| 96 | + {% else %} |
| 97 | + {{ return('timestamp(' + partition_by.field + ')') }} |
| 98 | + {% endif %} |
| 99 | +{% endmacro %} |
| 100 | + |
| 101 | +{% macro wrap_with_time_ingestion_partitioning(partition_time_exp, sql) %} |
| 102 | + |
| 103 | + select {{ partition_time_exp }} as _partitiontime, * EXCEPT({{ partition_time_exp }}) from ( |
| 104 | + {{ sql }} |
| 105 | + ); |
| 106 | + |
| 107 | +{% endmacro %} |
| 108 | + |
| 109 | +{% macro source_sql_with_partition(partition_by, source_sql) %} |
| 110 | + |
| 111 | + {%- if partition_by.time_ingestion_partitioning %} |
| 112 | + {{ return(wrap_with_time_ingestion_partitioning(build_partition_time_exp(partition_by), source_sql)) }} |
| 113 | + {% else %} |
| 114 | + {{ return(source_sql) }} |
| 115 | + {%- endif -%} |
| 116 | + |
| 117 | +{% endmacro %} |
30 | 118 |
|
31 | 119 | {% macro bq_insert_overwrite(
|
32 | 120 | tmp_relation, target_relation, sql, unique_key, partition_by, partitions, dest_columns, tmp_relation_exists
|
|
60 | 148 | )
|
61 | 149 | {%- endset -%}
|
62 | 150 |
|
63 |
| - -- generated script to merge partitions into {{ target_relation }} |
64 | 151 | declare dbt_partitions_for_replacement array<{{ partition_by.data_type }}>;
|
65 | 152 |
|
66 | 153 | {# have we already created the temp table to check for schema changes? #}
|
67 | 154 | {% if not tmp_relation_exists %}
|
68 | 155 | {{ declare_dbt_max_partition(this, partition_by, sql) }}
|
69 | 156 |
|
70 | 157 | -- 1. create a temp table
|
71 |
| - {{ create_table_as(True, tmp_relation, sql) }} |
| 158 | + {% set create_table_sql = bq_create_table_as(partition_by.time_ingestion_partitioning, False, target_relation, sql) %} |
| 159 | + {{ create_table_sql }} |
72 | 160 | {% else %}
|
73 | 161 | -- 1. temp table already exists, we used it to check for schema changes
|
74 | 162 | {% endif %}
|
|
94 | 182 |
|
95 | 183 | {% endmacro %}
|
96 | 184 |
|
| 185 | +{% macro bq_create_table_as(is_time_ingestion_partitioning, temporary, relation, sql) %} |
| 186 | + {% if is_time_ingestion_partitioning %} |
| 187 | + {#-- Create the table before inserting data as ingestion time partitioned tables can't be created with the transformed data --#} |
| 188 | + {% do run_query(create_ingestion_time_partitioned_table_as(temporary, relation, sql)) %} |
| 189 | + {{ return(bq_insert_into_ingestion_time_partitioned_table(relation, sql)) }} |
| 190 | + {% else %} |
| 191 | + {{ return(create_table_as(temporary, relation, sql)) }} |
| 192 | + {% endif %} |
| 193 | +{% endmacro %} |
97 | 194 |
|
98 | 195 | {% macro bq_generate_incremental_build_sql(
|
99 | 196 | strategy, tmp_relation, target_relation, sql, unique_key, partition_by, partitions, dest_columns, tmp_relation_exists
|
|
155 | 252 | {{ run_hooks(pre_hooks) }}
|
156 | 253 |
|
157 | 254 | {% if existing_relation is none %}
|
158 |
| - {% set build_sql = create_table_as(False, target_relation, sql) %} |
| 255 | + {% set build_sql = bq_create_table_as(partition_by.time_ingestion_partitioning, False, target_relation, sql) %} |
159 | 256 |
|
160 | 257 | {% elif existing_relation.is_view %}
|
161 | 258 | {#-- There's no way to atomically replace a view with a table on BQ --#}
|
162 | 259 | {{ adapter.drop_relation(existing_relation) }}
|
163 |
| - {% set build_sql = create_table_as(False, target_relation, sql) %} |
| 260 | + {% set build_sql = bq_create_table_as(partition_by.time_ingestion_partitioning, False, target_relation, sql) %} |
164 | 261 |
|
165 | 262 | {% elif full_refresh_mode %}
|
166 | 263 | {#-- If the partition/cluster config has changed, then we must drop and recreate --#}
|
167 | 264 | {% if not adapter.is_replaceable(existing_relation, partition_by, cluster_by) %}
|
168 | 265 | {% do log("Hard refreshing " ~ existing_relation ~ " because it is not replaceable") %}
|
169 | 266 | {{ adapter.drop_relation(existing_relation) }}
|
170 | 267 | {% endif %}
|
171 |
| - {% set build_sql = create_table_as(False, target_relation, sql) %} |
| 268 | + {% set build_sql = bq_create_table_as(partition_by.time_ingestion_partitioning, False, target_relation, sql) %} |
172 | 269 |
|
173 | 270 | {% else %}
|
174 | 271 | {% set tmp_relation_exists = false %}
|
175 | 272 | {% if on_schema_change != 'ignore' %} {# Check first, since otherwise we may not build a temp table #}
|
176 | 273 | {% do run_query(
|
177 |
| - declare_dbt_max_partition(this, partition_by, sql) + create_table_as(True, tmp_relation, sql) |
| 274 | + declare_dbt_max_partition(this, partition_by, sql) + bq_create_table_as(partition_by.time_ingestion_partitioning, True, tmp_relation, sql) |
178 | 275 | ) %}
|
179 | 276 | {% set tmp_relation_exists = true %}
|
180 | 277 | {#-- Process schema changes. Returns dict of changes if successful. Use source columns for upserting/merging --#}
|
|
0 commit comments