Skip to content

Commit cab172f

Browse files
committed
fix(relations): Ensure materialized view access method is restored
On Cloudberry, Greenplum 7+, materialized views must be created with a specific access method (e.g., 'heap', 'ao_row') and associated storage options in the 'WITH' clause (e.g., 'compresstype=zstd'). The prior implementation did not back up the 'USING' clause. During restore, the database would default to another access method (e.g., 'heap') which might not support the view's storage options. This incompatibility caused the 'CREATE MATERIALIZED VIEW' command to fail validation. This commit corrects the failure by: - Updating the view query for Cloudberry, GPDB 7+ to fetch the access method. - Modifying DDL generation to include the 'USING' clause. - Updating integration tests to verify the fix.
1 parent 1051c58 commit cab172f

File tree

4 files changed

+45
-6
lines changed

4 files changed

+45
-6
lines changed

integration/predata_relations_create_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,9 @@ SET SUBPARTITION TEMPLATE ` + `
550550
})
551551
It("creates a view with privileges, owner, security label, and comment", func() {
552552
view := builtin.View{Oid: 1, Schema: "public", Name: "simplemview", Definition: sql.NullString{String: " SELECT 1 AS a;", Valid: true}, IsMaterialized: true, DistPolicy: "DISTRIBUTED BY (a)"}
553+
if (connectionPool.Version.IsGPDB() && connectionPool.Version.AtLeast("7")) || connectionPool.Version.IsCBDBFamily() {
554+
view.AccessMethodName = "heap"
555+
}
553556
viewMetadata := testutils.DefaultMetadata("MATERIALIZED VIEW", true, true, true, includeSecurityLabels)
554557

555558
builtin.PrintCreateViewStatement(backupfile, tocfile, view, viewMetadata)
@@ -568,7 +571,9 @@ SET SUBPARTITION TEMPLATE ` + `
568571
})
569572
It("creates a materialized view with options", func() {
570573
view := builtin.View{Oid: 1, Schema: "public", Name: "simplemview", Options: " WITH (fillfactor=10)", Definition: sql.NullString{String: " SELECT 1 AS a;", Valid: true}, IsMaterialized: true, DistPolicy: "DISTRIBUTED BY (a)"}
571-
574+
if (connectionPool.Version.IsGPDB() && connectionPool.Version.AtLeast("7")) || connectionPool.Version.IsCBDBFamily() {
575+
view.AccessMethodName = "heap"
576+
}
572577
builtin.PrintCreateViewStatement(backupfile, tocfile, view, builtin.ObjectMetadata{})
573578

574579
testhelper.AssertQueryRuns(connectionPool, buffer.String())

integration/predata_relations_queries_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,9 @@ var _ = Describe("cbcopy integration tests", func() {
501501

502502
results := builtin.GetAllViews(connectionPool)
503503
materialView := builtin.View{Oid: 1, Schema: "public", Name: "simplematerialview", Definition: sql.NullString{String: " SELECT 1 AS a;", Valid: true}, IsMaterialized: true, DistPolicy: "DISTRIBUTED BY (a)"}
504+
if (connectionPool.Version.IsGPDB() && connectionPool.Version.AtLeast("7")) || connectionPool.Version.IsCBDBFamily() {
505+
materialView.AccessMethodName = "heap"
506+
}
504507

505508
Expect(results).To(HaveLen(1))
506509
structmatcher.ExpectStructsToMatchExcluding(&materialView, &results[0], "Oid")
@@ -514,6 +517,9 @@ var _ = Describe("cbcopy integration tests", func() {
514517

515518
results := builtin.GetAllViews(connectionPool)
516519
materialView := builtin.View{Oid: 1, Schema: "public", Name: "simplematerialview", Definition: sql.NullString{String: " SELECT 1 AS a;", Valid: true}, Options: " WITH (fillfactor=50, autovacuum_enabled=false)", IsMaterialized: true, DistPolicy: "DISTRIBUTED BY (a)"}
520+
if (connectionPool.Version.IsGPDB() && connectionPool.Version.AtLeast("7")) || connectionPool.Version.IsCBDBFamily() {
521+
materialView.AccessMethodName = "heap"
522+
}
517523

518524
Expect(results).To(HaveLen(1))
519525
structmatcher.ExpectStructsToMatchExcluding(&materialView, &results[0], "Oid")
@@ -529,6 +535,9 @@ var _ = Describe("cbcopy integration tests", func() {
529535

530536
results := builtin.GetAllViews(connectionPool)
531537
materialView := builtin.View{Oid: 1, Schema: "public", Name: "simplematerialview", Definition: sql.NullString{String: " SELECT 1 AS a;", Valid: true}, Tablespace: "test_tablespace", IsMaterialized: true, DistPolicy: "DISTRIBUTED BY (a)"}
538+
if (connectionPool.Version.IsGPDB() && connectionPool.Version.AtLeast("7")) || connectionPool.Version.IsCBDBFamily() {
539+
materialView.AccessMethodName = "heap"
540+
}
532541

533542
Expect(results).To(HaveLen(1))
534543
structmatcher.ExpectStructsToMatchExcluding(&materialView, &results[0], "Oid")

meta/builtin/predata_relations.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -682,8 +682,12 @@ func PrintCreateViewStatement(metadataFile *utils.FileWithByteCount, toc *toc.TO
682682
viewOptions = transformViewOptions(viewOptions)
683683
}
684684

685-
metadataFile.MustPrintf("\n\nCREATE MATERIALIZED VIEW %s%s%s AS %s\nWITH NO DATA\n%s;\n",
686-
view.FQN(), viewOptions, tablespaceClause, view.Definition.String[:len(view.Definition.String)-1], view.DistPolicy)
685+
accessMethodClause := ""
686+
if view.AccessMethodName != "" {
687+
accessMethodClause = fmt.Sprintf(" USING %s", view.AccessMethodName)
688+
}
689+
metadataFile.MustPrintf("\n\nCREATE MATERIALIZED VIEW %s%s%s%s AS %s\nWITH NO DATA\n%s;\n",
690+
view.FQN(), accessMethodClause, viewOptions, tablespaceClause, view.Definition.String[:len(view.Definition.String)-1], view.DistPolicy)
687691
}
688692
section, entry := view.GetMetadataEntry()
689693
toc.AddMetadataEntry(section, entry, start, metadataFile.ByteCount)

meta/builtin/queries_relations.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,8 @@ type View struct {
458458
Tablespace string
459459
IsMaterialized bool
460460
// https://github.com/greenplum-db/gpbackup/commit/ea5977fc892735fbb9f41e1e0a4944e20e260077
461-
DistPolicy string
461+
DistPolicy string
462+
AccessMethodName string
462463
}
463464

464465
func (v View) GetMetadataEntry() (string, toc.MetadataEntry) {
@@ -519,7 +520,7 @@ func GetAllViews(connectionPool *dbconn.DBConn) []View {
519520

520521
// Materialized views were introduced in GPDB 7 and backported to GPDB 6.2.
521522
// Reloptions and tablespace added to pg_class in GPDB 6
522-
atLeast6Query := fmt.Sprintf(`
523+
version6Query := fmt.Sprintf(`
523524
SELECT
524525
c.oid AS oid,
525526
quote_ident(n.nspname) AS schema,
@@ -535,11 +536,31 @@ func GetAllViews(connectionPool *dbconn.DBConn) []View {
535536
AND %s
536537
AND %s`, relationAndSchemaFilterClause(connectionPool), ExtensionFilterClause("c"))
537538

539+
atLeast7Query := fmt.Sprintf(`
540+
SELECT
541+
c.oid AS oid,
542+
quote_ident(n.nspname) AS schema,
543+
quote_ident(c.relname) AS name,
544+
pg_get_viewdef(c.oid) AS definition,
545+
coalesce(' WITH (' || array_to_string(c.reloptions, ', ') || ')', '') AS options,
546+
coalesce(quote_ident(t.spcname), '') AS tablespace,
547+
c.relkind='m' AS ismaterialized,
548+
coalesce(quote_ident(am.amname), '') AS accessmethodname
549+
FROM pg_class c
550+
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
551+
LEFT JOIN pg_tablespace t ON t.oid = c.reltablespace
552+
LEFT JOIN pg_am am ON am.oid = c.relam
553+
WHERE c.relkind IN ('m', 'v')
554+
AND %s
555+
AND %s`, relationAndSchemaFilterClause(connectionPool), ExtensionFilterClause("c"))
556+
538557
query := ""
539558
if connectionPool.Version.IsGPDB() && connectionPool.Version.Before("6") {
540559
query = before6Query
560+
} else if connectionPool.Version.IsGPDB() && connectionPool.Version.Is("6") {
561+
query = version6Query
541562
} else {
542-
query = atLeast6Query
563+
query = atLeast7Query
543564
}
544565

545566
gplog.Debug("GetAllViews, query is %v", query)

0 commit comments

Comments
 (0)