@@ -42,6 +42,7 @@ const (
4242 DiffTypePrivilege
4343 DiffTypeRevokedDefaultPrivilege
4444 DiffTypeColumnPrivilege
45+ DiffTypeExtension
4546)
4647
4748// String returns the string representation of DiffType
@@ -103,6 +104,8 @@ func (d DiffType) String() string {
103104 return "revoked_default_privilege"
104105 case DiffTypeColumnPrivilege :
105106 return "column_privilege"
107+ case DiffTypeExtension :
108+ return "extension"
106109 default :
107110 return "unknown"
108111 }
@@ -177,6 +180,8 @@ func (d *DiffType) UnmarshalJSON(data []byte) error {
177180 * d = DiffTypeRevokedDefaultPrivilege
178181 case "column_privilege" :
179182 * d = DiffTypeColumnPrivilege
183+ case "extension" :
184+ * d = DiffTypeExtension
180185 default :
181186 return fmt .Errorf ("unknown diff type: %s" , s )
182187 }
@@ -260,6 +265,8 @@ type Diff struct {
260265}
261266
262267type ddlDiff struct {
268+ addedExtensions []string
269+ droppedExtensions []string
263270 addedSchemas []* ir.Schema
264271 droppedSchemas []* ir.Schema
265272 modifiedSchemas []* schemaDiff
@@ -462,6 +469,26 @@ func GenerateMigration(oldIR, newIR *ir.IR, targetSchema string) []Diff {
462469 modifiedColumnPrivileges : []* columnPrivilegeDiff {},
463470 }
464471
472+ // Compare extensions
473+ oldExtSet := make (map [string ]bool )
474+ for _ , ext := range oldIR .Extensions {
475+ oldExtSet [ext ] = true
476+ }
477+ for _ , ext := range newIR .Extensions {
478+ if ! oldExtSet [ext ] {
479+ diff .addedExtensions = append (diff .addedExtensions , ext )
480+ }
481+ }
482+ newExtSet := make (map [string ]bool )
483+ for _ , ext := range newIR .Extensions {
484+ newExtSet [ext ] = true
485+ }
486+ for _ , ext := range oldIR .Extensions {
487+ if ! newExtSet [ext ] {
488+ diff .droppedExtensions = append (diff .droppedExtensions , ext )
489+ }
490+ }
491+
465492 // Compare schemas first in deterministic order
466493 schemaNames := sortedKeys (newIR .Schemas )
467494 for _ , name := range schemaNames {
@@ -1497,6 +1524,18 @@ func (d *ddlDiff) generatePreDropMaterializedViewsSQL(targetSchema string, colle
14971524
14981525// generateCreateSQL generates CREATE statements in dependency order
14991526func (d * ddlDiff ) generateCreateSQL (targetSchema string , collector * diffCollector ) {
1527+ // Create extensions first - must be installed before any schema objects that depend on them
1528+ for _ , ext := range d .addedExtensions {
1529+ context := & diffContext {
1530+ Type : DiffTypeExtension ,
1531+ Operation : DiffOperationCreate ,
1532+ Path : ext ,
1533+ Source : & ir.Extension {Name : ext },
1534+ CanRunInTransaction : true ,
1535+ }
1536+ collector .collect (context , fmt .Sprintf ("CREATE EXTENSION IF NOT EXISTS %s;" , ir .QuoteIdentifier (ext )))
1537+ }
1538+
15001539 // Note: Schema creation is out of scope for schema-level comparisons
15011540
15021541 // Build function lookup early - needed for both domain and table dependency checks
0 commit comments