@@ -50,6 +50,8 @@ static List *GetDataFileMetadataOperations(const TableMetadataOperationTracker *
5050 List * allTransforms );
5151static List * GetDDLMetadataOperations (const TableMetadataOperationTracker * opTracker );
5252static void DeleteInProgressAddedFiles (Oid relationId , List * addedFiles );
53+ static bool AreSchemasEqual (IcebergTableSchema * existingSchema , DataFileSchema * newSchema );
54+ static int32_t GetSchemaIdForIcebergTableIfExists (const TableMetadataOperationTracker * opTracker , DataFileSchema * schema );
5355static int ComparePartitionSpecsById (const ListCell * a , const ListCell * b );
5456
5557
@@ -596,7 +598,7 @@ GetDDLMetadataOperations(const TableMetadataOperationTracker * opTracker)
596598 TableMetadataOperation * createOp = palloc0 (sizeof (TableMetadataOperation ));
597599
598600 createOp -> type = TABLE_CREATE ;
599- createOp -> schema = schema ;
601+ createOp -> newSchema = schema ;
600602 createOp -> partitionSpecs = newPartitionSpecs ;
601603 createOp -> defaultSpecId = defaultSpecId ;
602604
@@ -611,10 +613,30 @@ GetDDLMetadataOperations(const TableMetadataOperationTracker * opTracker)
611613
612614 if (opTracker -> relationAltered )
613615 {
616+ /*
617+ * When a table is altered, its schema has changed. However, it might
618+ * have been set to an existing schema in the iceberg metadata, if so,
619+ * use that schemaId.
620+ */
614621 TableMetadataOperation * ddlOp = palloc0 (sizeof (TableMetadataOperation ));
615622
616623 ddlOp -> type = TABLE_DDL ;
617- ddlOp -> schema = schema ;
624+
625+ int32_t existingSchemaId =
626+ GetSchemaIdForIcebergTableIfExists (opTracker , schema );
627+
628+ if (existingSchemaId != -1 )
629+ {
630+ ddlOp -> ddlSchemaEffect = DDL_EFFECT_SET_EXISTING_SCHEMA ;
631+ ddlOp -> existingSchemaId = existingSchemaId ;
632+ ddlOp -> newSchema = NULL ;
633+ }
634+ else
635+ {
636+ ddlOp -> ddlSchemaEffect = DDL_EFFECT_ADD_SCHEMA ;
637+ ddlOp -> newSchema = schema ;
638+ ddlOp -> existingSchemaId = -1 ;
639+ }
618640
619641 operations = lappend (operations , ddlOp );
620642 }
@@ -645,3 +667,52 @@ ComparePartitionSpecsById(const ListCell *a, const ListCell *b)
645667
646668 return pg_cmp_s32 (specA -> spec_id , specB -> spec_id );
647669}
670+
671+
672+ /*
673+ * GetSchemaIdForIcebergTableIfExists checks if the given schema already exists
674+ * in the iceberg table metadata. If it exists, it returns the schema ID, otherwise -1.
675+ */
676+ static int32_t
677+ GetSchemaIdForIcebergTableIfExists (const TableMetadataOperationTracker * opTracker , DataFileSchema * schema )
678+ {
679+ IcebergTableMetadata * metadata = GetLastPushedIcebergMetadata (opTracker );
680+
681+ if (metadata == NULL )
682+ return -1 ;
683+
684+ IcebergTableSchema * schemas = metadata -> schemas ;
685+
686+ for (int schemaIndex = 0 ; schemaIndex < metadata -> schemas_length ; schemaIndex ++ )
687+ {
688+ IcebergTableSchema * existingSchema = & schemas [schemaIndex ];
689+
690+ if (AreSchemasEqual (existingSchema , schema ))
691+ return schemas [schemaIndex ].schema_id ;
692+
693+ }
694+
695+ return -1 ;
696+ }
697+
698+
699+ /*
700+ * AreSchemasEqual compares two schemas for equality.
701+ */
702+ static bool
703+ AreSchemasEqual (IcebergTableSchema * existingSchema , DataFileSchema * newSchema )
704+ {
705+ if (existingSchema -> fields_length != newSchema -> nfields )
706+ return false;
707+
708+ for (size_t i = 0 ; i < existingSchema -> fields_length ; i ++ )
709+ {
710+ DataFileSchemaField * existingField = & existingSchema -> fields [i ];
711+ DataFileSchemaField * newField = & newSchema -> fields [i ];
712+
713+ if (!SchemaFieldsEquivalent (existingField , newField ))
714+ return false;
715+ }
716+
717+ return true;
718+ }
0 commit comments