-
Notifications
You must be signed in to change notification settings - Fork 29
fix: materialized view drop order that depends on table #188
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -79,36 +79,53 @@ func generateCreateViewsSQL(views []*ir.View, targetSchema string, collector *di | |
| } | ||
|
|
||
| // generateModifyViewsSQL generates CREATE OR REPLACE VIEW statements or comment changes | ||
| func generateModifyViewsSQL(diffs []*viewDiff, targetSchema string, collector *diffCollector) { | ||
| // preDroppedViews contains views that were already dropped in the pre-drop phase | ||
| func generateModifyViewsSQL(diffs []*viewDiff, targetSchema string, collector *diffCollector, preDroppedViews map[string]bool) { | ||
| for _, diff := range diffs { | ||
| // Handle materialized views that require recreation (DROP + CREATE) | ||
| if diff.RequiresRecreate { | ||
| viewKey := diff.New.Schema + "." + diff.New.Name | ||
| viewName := qualifyEntityName(diff.New.Schema, diff.New.Name, targetSchema) | ||
|
|
||
| // DROP the old materialized view | ||
| dropSQL := fmt.Sprintf("DROP MATERIALIZED VIEW %s RESTRICT;", viewName) | ||
| createSQL := generateViewSQL(diff.New, targetSchema) | ||
| // Check if already pre-dropped | ||
| if preDroppedViews != nil && preDroppedViews[viewKey] { | ||
| // Skip DROP, only CREATE since view was already dropped in pre-drop phase | ||
| createSQL := generateViewSQL(diff.New, targetSchema) | ||
|
|
||
| statements := []SQLStatement{ | ||
| { | ||
| SQL: dropSQL, | ||
| CanRunInTransaction: true, | ||
| }, | ||
| { | ||
| SQL: createSQL, | ||
| context := &diffContext{ | ||
| Type: DiffTypeMaterializedView, | ||
| Operation: DiffOperationCreate, | ||
| Path: fmt.Sprintf("%s.%s", diff.New.Schema, diff.New.Name), | ||
| Source: diff, | ||
| CanRunInTransaction: true, | ||
| }, | ||
| } | ||
| } | ||
| collector.collect(context, createSQL) | ||
| } else { | ||
| // DROP the old materialized view | ||
| dropSQL := fmt.Sprintf("DROP MATERIALIZED VIEW %s RESTRICT;", viewName) | ||
| createSQL := generateViewSQL(diff.New, targetSchema) | ||
|
|
||
| statements := []SQLStatement{ | ||
| { | ||
| SQL: dropSQL, | ||
| CanRunInTransaction: true, | ||
| }, | ||
| { | ||
| SQL: createSQL, | ||
| CanRunInTransaction: true, | ||
| }, | ||
| } | ||
|
|
||
| // Use DiffOperationAlter to categorize as a modification | ||
| context := &diffContext{ | ||
| Type: DiffTypeMaterializedView, | ||
| Operation: DiffOperationAlter, | ||
| Path: fmt.Sprintf("%s.%s", diff.New.Schema, diff.New.Name), | ||
| Source: diff, | ||
| CanRunInTransaction: true, | ||
| // Use DiffOperationAlter to categorize as a modification | ||
| context := &diffContext{ | ||
| Type: DiffTypeMaterializedView, | ||
| Operation: DiffOperationAlter, | ||
| Path: fmt.Sprintf("%s.%s", diff.New.Schema, diff.New.Name), | ||
| Source: diff, | ||
| CanRunInTransaction: true, | ||
| } | ||
| collector.collectStatements(context, statements) | ||
| } | ||
| collector.collectStatements(context, statements) | ||
|
|
||
| // Add view comment if present | ||
| if diff.New.Comment != "" { | ||
|
|
@@ -330,3 +347,27 @@ func viewDependsOnView(viewA *ir.View, viewBName string) bool { | |
| // This can be enhanced with proper dependency parsing later | ||
| return strings.Contains(strings.ToLower(viewA.Definition), strings.ToLower(viewBName)) | ||
| } | ||
|
|
||
| // viewDependsOnTable checks if a view depends on a specific table | ||
| // by checking if the table name appears in the view definition | ||
| func viewDependsOnTable(view *ir.View, tableSchema, tableName string) bool { | ||
| if view == nil || view.Definition == "" { | ||
| return false | ||
| } | ||
|
|
||
| def := strings.ToLower(view.Definition) | ||
| tableNameLower := strings.ToLower(tableName) | ||
|
|
||
| // Check for unqualified table name | ||
| if strings.Contains(def, tableNameLower) { | ||
| return true | ||
|
Comment on lines
+361
to
+363
|
||
| } | ||
|
|
||
| // Check for qualified table name (schema.table) | ||
| qualifiedName := strings.ToLower(tableSchema + "." + tableName) | ||
| if strings.Contains(def, qualifiedName) { | ||
| return true | ||
| } | ||
|
|
||
| return false | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| DROP MATERIALIZED VIEW expensive_products RESTRICT; | ||
|
|
||
| ALTER TABLE products ADD COLUMN category text; | ||
|
|
||
| CREATE MATERIALIZED VIEW IF NOT EXISTS expensive_products AS | ||
| SELECT id, | ||
| name, | ||
| price, | ||
| category | ||
| FROM products | ||
| WHERE price > 100::numeric; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| -- Table structure changed (added column), materialized view updated to use it | ||
| CREATE TABLE products ( | ||
| id integer PRIMARY KEY, | ||
| name text NOT NULL, | ||
| price numeric(10,2), | ||
| category text | ||
| ); | ||
|
|
||
| -- Materialized view now includes category | ||
| CREATE MATERIALIZED VIEW expensive_products AS | ||
| SELECT id, name, price, category FROM products WHERE price > 100; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| -- Base table referenced by a materialized view | ||
| CREATE TABLE products ( | ||
| id integer PRIMARY KEY, | ||
| name text NOT NULL, | ||
| price numeric(10,2) | ||
| ); | ||
|
|
||
| -- Materialized view that depends on the products table | ||
| CREATE MATERIALIZED VIEW expensive_products AS | ||
| SELECT id, name, price FROM products WHERE price > 100; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| { | ||
| "version": "1.0.0", | ||
| "pgschema_version": "1.4.3", | ||
| "created_at": "1970-01-01T00:00:00Z", | ||
| "source_fingerprint": { | ||
| "hash": "55a7680d1ce73c3b56fbc34065ad9197a57668cc1cdcd0854bce421c2fa33d4b" | ||
| }, | ||
| "groups": [ | ||
| { | ||
| "steps": [ | ||
| { | ||
| "sql": "DROP MATERIALIZED VIEW expensive_products RESTRICT;", | ||
| "type": "materialized_view", | ||
| "operation": "drop", | ||
| "path": "public.expensive_products" | ||
| }, | ||
| { | ||
| "sql": "ALTER TABLE products ADD COLUMN category text;", | ||
| "type": "table.column", | ||
| "operation": "create", | ||
| "path": "public.products.category" | ||
| }, | ||
| { | ||
| "sql": "CREATE MATERIALIZED VIEW IF NOT EXISTS expensive_products AS\n SELECT id,\n name,\n price,\n category\n FROM products\n WHERE price > 100::numeric;", | ||
| "type": "materialized_view", | ||
| "operation": "create", | ||
| "path": "public.expensive_products" | ||
| } | ||
| ] | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| DROP MATERIALIZED VIEW expensive_products RESTRICT; | ||
|
|
||
| ALTER TABLE products ADD COLUMN category text; | ||
|
|
||
| CREATE MATERIALIZED VIEW IF NOT EXISTS expensive_products AS | ||
| SELECT id, | ||
| name, | ||
| price, | ||
| category | ||
| FROM products | ||
| WHERE price > 100::numeric; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| Plan: 1 to add, 1 to modify. | ||
|
|
||
| Summary by type: | ||
| tables: 1 to modify | ||
| materialized views: 1 to add | ||
|
|
||
| Tables: | ||
| ~ products | ||
| + category (column) | ||
|
|
||
| Materialized views: | ||
| + expensive_products | ||
|
|
||
| DDL to be executed: | ||
| -------------------------------------------------- | ||
|
|
||
| DROP MATERIALIZED VIEW expensive_products RESTRICT; | ||
|
|
||
| ALTER TABLE products ADD COLUMN category text; | ||
|
|
||
| CREATE MATERIALIZED VIEW IF NOT EXISTS expensive_products AS | ||
| SELECT id, | ||
| name, | ||
| price, | ||
| category | ||
| FROM products | ||
| WHERE price > 100::numeric; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| ALTER TABLE products ADD COLUMN category text; | ||
|
|
||
| CREATE OR REPLACE VIEW expensive_products AS | ||
| SELECT id, | ||
| name, | ||
| price, | ||
| category | ||
| FROM products | ||
| WHERE price > 100::numeric; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The view key is constructed using
diff.New.Schema + "." + diff.New.Name, but ingeneratePreDropMaterializedViewsSQL(line 952 of diff.go), the key is constructed usingviewDiff.Old.Schema + "." + viewDiff.Old.Name. This inconsistency could cause the pre-dropped view check to fail if the view is renamed or moved to a different schema. Consider using the Old view's schema and name for both key construction and lookup to ensure consistency.