@@ -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+
16131663func 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
20872147func 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