Skip to content

Commit 4bebe6c

Browse files
Fixing hive partitioning diff (#14483) (#10366)
[upstream:43ca35a159e375c2668ddf5b45122fdeab748f89] Signed-off-by: Modular Magician <[email protected]>
1 parent d3cdce4 commit 4bebe6c

File tree

4 files changed

+259
-87
lines changed

4 files changed

+259
-87
lines changed

.changelog/14483.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
bigquery: added `ignore_auto_generated_schema` virtual field to `google_bigquery_table` resource to ignore server-added columns in the `schema` field
3+
```

google-beta/services/bigquery/resource_bigquery_table.go

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,6 +1361,13 @@ func ResourceBigQueryTable() *schema.Resource {
13611361
Description: `Whether Terraform will be prevented from destroying the instance. When the field is set to true or unset in Terraform state, a terraform apply or terraform destroy that would delete the table will fail. When the field is set to false, deleting the table is allowed.`,
13621362
},
13631363

1364+
"ignore_auto_generated_schema": {
1365+
Type: schema.TypeBool,
1366+
Optional: true,
1367+
Default: false,
1368+
Description: `Whether Terraform will prevent implicitly added columns in schema from showing diff.`,
1369+
},
1370+
13641371
// TableConstraints: [Optional] Defines the primary key and foreign keys.
13651372
"table_constraints": {
13661373
Type: schema.TypeList,
@@ -1610,6 +1617,49 @@ func ResourceBigQueryTable() *schema.Resource {
16101617
}
16111618
}
16121619

1620+
// filterLiveSchemaByConfig compares a live schema from the BQ API with a schema from
1621+
// the Terraform config. It returns a new schema containing only the fields
1622+
// that are defined in the config, effectively removing any columns that were
1623+
// auto-generated by the service (e.g., hive partitioning keys).
1624+
//
1625+
// Parameters:
1626+
// - liveSchema: The schema returned from a BigQuery API Read/Get call. This may contain extra columns.
1627+
// - configSchema: The schema built from the user's Terraform configuration (`d.Get("schema")`). This is the source of truth.
1628+
//
1629+
// Returns:
1630+
//
1631+
// A new *bigquery.TableSchema containing a filtered list of fields.
1632+
func filterLiveSchemaByConfig(liveSchema *bigquery.TableSchema, configSchema *bigquery.TableSchema) *bigquery.TableSchema {
1633+
if liveSchema == nil || configSchema == nil {
1634+
// If either schema is nil, there's nothing to compare, so return an empty schema.
1635+
return &bigquery.TableSchema{Fields: []*bigquery.TableFieldSchema{}}
1636+
}
1637+
1638+
// 1. Create a lookup map of all column names defined in the configuration.
1639+
// This provides fast O(1) average time complexity for lookups.
1640+
configFieldsMap := make(map[string]bool)
1641+
for _, field := range configSchema.Fields {
1642+
configFieldsMap[field.Name] = true
1643+
}
1644+
1645+
// 2. Iterate through the fields in the live schema and keep only the ones
1646+
// that exist in our configuration map.
1647+
var filteredFields []*bigquery.TableFieldSchema
1648+
for _, liveField := range liveSchema.Fields {
1649+
// If the live field's name is present in the map of configured fields...
1650+
if _, ok := configFieldsMap[liveField.Name]; ok {
1651+
// ...then it's a field we care about. Add it to our filtered list.
1652+
filteredFields = append(filteredFields, liveField)
1653+
} else {
1654+
log.Printf("[DEBUG] auto-generated column `%s` dropped during Table read.", liveField.Name)
1655+
}
1656+
}
1657+
1658+
return &bigquery.TableSchema{
1659+
Fields: filteredFields,
1660+
}
1661+
}
1662+
16131663
func resourceTable(d *schema.ResourceData, meta interface{}) (*bigquery.Table, error) {
16141664
config := meta.(*transport_tpg.Config)
16151665

@@ -1999,7 +2049,17 @@ func resourceBigQueryTableRead(d *schema.ResourceData, meta interface{}) error {
19992049
}
20002050

20012051
if res.Schema != nil {
2002-
schema, err := flattenSchema(res.Schema)
2052+
table, err := resourceTable(d, meta)
2053+
if err != nil {
2054+
return err
2055+
}
2056+
2057+
schemaFiltered := res.Schema
2058+
ignore, ok := d.Get("ignore_auto_generated_schema").(bool)
2059+
if ok && ignore {
2060+
schemaFiltered = filterLiveSchemaByConfig(res.Schema, table.Schema)
2061+
}
2062+
schema, err := flattenSchema(schemaFiltered)
20032063
if err != nil {
20042064
return err
20052065
}
@@ -2086,7 +2146,7 @@ type TableReference struct {
20862146

20872147
func resourceBigQueryTableUpdate(d *schema.ResourceData, meta interface{}) error {
20882148
// If only client-side fields were modified, short-circuit the Update function to avoid sending an update API request.
2089-
clientSideFields := map[string]bool{"deletion_protection": true, "ignore_schema_changes": true, "table_metadata_view": true}
2149+
clientSideFields := map[string]bool{"deletion_protection": true, "ignore_schema_changes": true, "ignore_auto_generated_schema": true, "table_metadata_view": true}
20902150
clientSideOnly := true
20912151
for field := range ResourceBigQueryTable().Schema {
20922152
if d.HasChange(field) && !clientSideFields[field] {
@@ -2134,8 +2194,11 @@ func resourceBigQueryTableUpdate(d *schema.ResourceData, meta interface{}) error
21342194
tableID: tableID,
21352195
}
21362196

2137-
if err = resourceBigQueryTableColumnDrop(config, userAgent, table, tableReference, tableMetadataView); err != nil {
2138-
return err
2197+
// If we are supposed to ignore server generated schema columns, we don't need to drop them
2198+
if !d.Get("ignore_auto_generated_schema").(bool) {
2199+
if err = resourceBigQueryTableColumnDrop(config, userAgent, table, tableReference, tableMetadataView); err != nil {
2200+
return err
2201+
}
21392202
}
21402203

21412204
if _, err = config.NewBigQueryClient(userAgent).Tables.Update(project, datasetID, tableID, table).Do(); err != nil {

0 commit comments

Comments
 (0)