Skip to content

Commit

Permalink
Attach GPDB 7+ child tables to their root
Browse files Browse the repository at this point in the history
In GPDB 7+, we no longer have large DDL commands to create a partition
table and its leaf partitions. Each leaf partition must be created
individually (at the moment) and attached to the root or subroot
partition. To do this, we must query for some simple partition
information and construct the SQL command to attach the partition. This
SQL command should be printed immediately after the CREATE TABLE
statement of the leaf partition.

Authored-by: Kevin Yeap <kyeap@vmware.com>
  • Loading branch information
kyeap-vmware authored and AJR-VMware committed Nov 22, 2022
1 parent c90eadb commit 08fd7c5
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 5 deletions.
6 changes: 6 additions & 0 deletions backup/predata_relations.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,12 @@ func PrintPostCreateTableStatements(metadataFile *utils.FileWithByteCount, toc *
utils.MakeFQN(alteredPartitionRelation.OldSchema, alteredPartitionRelation.Name), alteredPartitionRelation.NewSchema))
}

attachInfo := table.AttachPartitionInfo
if (attachInfo != AttachPartitionInfo{}) {
statements = append(statements,
fmt.Sprintf("ALTER TABLE ONLY %s ATTACH PARTITION %s %s;", attachInfo.Parent, attachInfo.Relname, attachInfo.Expr))
}

PrintStatements(metadataFile, toc, table, statements)
}

Expand Down
47 changes: 42 additions & 5 deletions backup/queries_table_defs.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ type TableDefinition struct {
PartitionAlteredSchemas []AlteredPartitionRelation
AccessMethodName string
PartitionKeyDef string
AttachPartitionInfo AttachPartitionInfo
}

/*
Expand All @@ -99,6 +100,7 @@ func ConstructDefinitionsForTables(connectionPool *dbconn.DBConn, tableRelations
replicaIdentityMap := GetTableReplicaIdentity(connectionPool)
partitionAlteredSchemaMap := GetPartitionAlteredSchema(connectionPool)
partitionKeyDefs := GetPartitionKeyDefs(connectionPool)
attachPartitionInfo := GetAttachPartitionInfo(connectionPool)

gplog.Verbose("Constructing table definition map")
for _, tableRel := range tableRelations {
Expand All @@ -121,6 +123,7 @@ func ConstructDefinitionsForTables(connectionPool *dbconn.DBConn, tableRelations
PartitionAlteredSchemas: partitionAlteredSchemaMap[oid],
AccessMethodName: accessMethodMap[oid],
PartitionKeyDef: partitionKeyDefs[oid],
AttachPartitionInfo: attachPartitionInfo[oid],
}
if tableDef.Inherits == nil {
tableDef.Inherits = []string{}
Expand Down Expand Up @@ -565,11 +568,11 @@ func GetPartitionKeyDefs(connectionPool *dbconn.DBConn) map[uint32]string {
return make(map[uint32]string, 0)
}
query := `
SELECT
partrelid AS oid,
pg_get_partkeydef(partrelid) AS keydef
FROM
pg_partitioned_table;`
SELECT
partrelid AS oid,
pg_get_partkeydef(partrelid) AS keydef
FROM
pg_partitioned_table;`

var results []struct {
Oid uint32
Expand All @@ -584,6 +587,40 @@ FROM
return resultMap
}

type AttachPartitionInfo struct {
Oid uint32
Relname string
Parent string
Expr string
}

func GetAttachPartitionInfo(connectionPool *dbconn.DBConn) map[uint32]AttachPartitionInfo {
if connectionPool.Version.Before("7") {
return make(map[uint32]AttachPartitionInfo, 0)
}

query := fmt.Sprintf(`
SELECT
c.oid,
quote_ident(n.nspname) || '.' || quote_ident(c.relname) AS relname,
quote_ident(rn.nspname) || '.' || quote_ident(rc.relname) AS parent,
pg_get_expr(c.relpartbound, c.oid) AS expr
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
JOIN pg_class rc ON pg_partition_root(c.oid) = rc.oid
JOIN pg_namespace rn ON rc.relnamespace = rn.oid
WHERE c.relispartition = 't'`)

results := make([]AttachPartitionInfo, 0)
err := connectionPool.Select(&results, query)
gplog.FatalOnError(err)
resultMap := make(map[uint32]AttachPartitionInfo)
for _, result := range results {
resultMap[result.Oid] = result
}
return resultMap
}

func selectAsOidToStringMap(connectionPool *dbconn.DBConn, query string) map[uint32]string {
var results []struct {
Oid uint32
Expand Down
30 changes: 30 additions & 0 deletions integration/predata_relations_create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,36 @@ SET SUBPARTITION TEMPLATE ` + `
resultTable := backup.ConstructDefinitionsForTables(connectionPool, []backup.Relation{testTable.Relation})[0]
Expect(resultTable.ReplicaIdentity).To(Equal("f"))
})
It("prints a GPDB 7+ ALTER statement to ATTACH a child table to it's root", func() {
testutils.SkipIfBefore7(connectionPool)
testhelper.AssertQueryRuns(connectionPool, "CREATE TABLE public.testroottable(i int) PARTITION BY RANGE (i) DISTRIBUTED BY (i); ")
defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE public.testroottable;")
testhelper.AssertQueryRuns(connectionPool, "CREATE TABLE public.testchildtable(i int) DISTRIBUTED BY (i);")
defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE public.testchildtable;")
tableMetadata = backup.ObjectMetadata{Privileges: []backup.ACL{}, ObjectType: "RELATION"}
testChildTable := backup.Table{
Relation: backup.Relation{Schema: "public", Name: "testChildTable"},
TableDefinition: backup.TableDefinition{
DistPolicy: "DISTRIBUTED BY (i)",
ColumnDefs: []backup.ColumnDefinition{tableRow},
ExtTableDef: extTableEmpty,
Inherits: []string{},
AttachPartitionInfo: backup.AttachPartitionInfo{
Relname: "public.testchildtable",
Parent: "public.testroottable",
Expr: "FOR VALUES FROM (1) TO (2)",
},
},
}

backup.PrintPostCreateTableStatements(backupfile, tocfile, testChildTable, tableMetadata)
testhelper.AssertQueryRuns(connectionPool, buffer.String())

attachPartitionInfoMap := backup.GetAttachPartitionInfo(connectionPool)
childTableOid := testutils.OidFromObjectName(connectionPool, "public", "testchildtable", backup.TYPE_RELATION)
testChildTable.AttachPartitionInfo.Oid = childTableOid
structmatcher.ExpectStructsToMatch(&testChildTable.AttachPartitionInfo, attachPartitionInfoMap[childTableOid])
})
})
Describe("PrintCreateViewStatements", func() {
var viewDef sql.NullString
Expand Down
18 changes: 18 additions & 0 deletions integration/predata_table_defs_queries_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -878,4 +878,22 @@ SET SUBPARTITION TEMPLATE
Expect(result[oid]).To(ConsistOf(expectedAlteredPartitions))
})
})
Describe("GetAttachedPartitionInfo", func() {
It("Returns a map of table oid to attach partition info", func() {
testutils.SkipIfBefore7(connectionPool)
testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
testhelper.AssertQueryRuns(connectionPool, "CREATE TABLE testschema.foopart(a integer, b integer) PARTITION BY RANGE (b) DISTRIBUTED BY (a)")
testhelper.AssertQueryRuns(connectionPool, "CREATE TABLE testschema.foopart_1_prt_1 (a integer, b integer) DISTRIBUTED BY (a)")
testhelper.AssertQueryRuns(connectionPool, "ALTER TABLE ONLY testschema.foopart ATTACH PARTITION testschema.foopart_1_prt_1 FOR VALUES FROM (1) TO (2)")
defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE testschema.foopart")

oid := testutils.OidFromObjectName(connectionPool, "testschema", "foopart_1_prt_1", backup.TYPE_RELATION)
result := backup.GetAttachPartitionInfo(connectionPool)

expectedAttachPartitionInfo := backup.AttachPartitionInfo{Oid: oid, Relname: "testschema.foopart_1_prt_1", Parent: "testschema.foopart", Expr: "FOR VALUES FROM (1) TO (2)"}

structmatcher.ExpectStructsToMatch(result[oid], &expectedAttachPartitionInfo)
})
})
})

0 comments on commit 08fd7c5

Please sign in to comment.