blob: a56492f96b76ea3bd12b27efdef08079e2849f23 [file] [log] [blame]
package backup
/*
* This file contains structs and functions related to executing specific
* queries to gather metadata for the objects handled in predata_general.go.
*/
import (
"fmt"
"github.com/greenplum-db/gp-common-go-libs/dbconn"
"github.com/greenplum-db/gp-common-go-libs/gplog"
"github.com/greenplum-db/gpbackup/toc"
"github.com/greenplum-db/gpbackup/utils"
)
type Operator struct {
Oid uint32
Schema string
Name string
Procedure string
LeftArgType string
RightArgType string
CommutatorOp string
NegatorOp string
RestrictFunction string
JoinFunction string
CanHash bool
CanMerge bool
}
func (o Operator) GetMetadataEntry() (string, toc.MetadataEntry) {
return "predata",
toc.MetadataEntry{
Schema: o.Schema,
Name: o.Name,
ObjectType: "OPERATOR",
ReferenceObject: "",
StartByte: 0,
EndByte: 0,
}
}
func (o Operator) GetUniqueID() UniqueID {
return UniqueID{ClassID: PG_OPERATOR_OID, Oid: o.Oid}
}
func (o Operator) FQN() string {
leftArg := "NONE"
rightArg := "NONE"
if o.LeftArgType != "-" {
leftArg = o.LeftArgType
}
if o.RightArgType != "-" {
rightArg = o.RightArgType
}
return fmt.Sprintf("%s.%s (%s, %s)", o.Schema, o.Name, leftArg, rightArg)
}
func GetOperators(connectionPool *dbconn.DBConn) []Operator {
results := make([]Operator, 0)
atLeast5Query := fmt.Sprintf(`
SELECT o.oid AS oid,
quote_ident(n.nspname) AS schema,
oprname AS name,
oprcode::regproc AS procedure,
oprleft::regtype AS leftargtype,
oprright::regtype AS rightargtype,
oprcom::regoper AS commutatorop,
oprnegate::regoper AS negatorop,
oprrest AS restrictfunction,
oprjoin AS joinfunction,
oprcanmerge AS canmerge,
oprcanhash AS canhash
FROM pg_operator o
JOIN pg_namespace n on n.oid = o.oprnamespace
WHERE %s AND oprcode != 0
AND %s`, SchemaFilterClause("n"), ExtensionFilterClause("o"))
query := atLeast5Query
err := connectionPool.Select(&results, query)
gplog.FatalOnError(err)
return results
}
/*
* Operator families are not supported in GPDB 4.3, so OperatorFamily
* and GetOperatorFamilies are not used in a 4.3 backup.
*/
type OperatorFamily struct {
Oid uint32
Schema string
Name string
IndexMethod string
}
func (opf OperatorFamily) GetMetadataEntry() (string, toc.MetadataEntry) {
return "predata",
toc.MetadataEntry{
Schema: opf.Schema,
Name: opf.Name,
ObjectType: "OPERATOR FAMILY",
ReferenceObject: "",
StartByte: 0,
EndByte: 0,
}
}
func (opf OperatorFamily) GetUniqueID() UniqueID {
return UniqueID{ClassID: PG_OPFAMILY_OID, Oid: opf.Oid}
}
func (opf OperatorFamily) FQN() string {
return fmt.Sprintf("%s USING %s", utils.MakeFQN(opf.Schema, opf.Name), opf.IndexMethod)
}
func GetOperatorFamilies(connectionPool *dbconn.DBConn) []OperatorFamily {
results := make([]OperatorFamily, 0)
query := fmt.Sprintf(`
SELECT o.oid AS oid,
quote_ident(n.nspname) AS schema,
quote_ident(opfname) AS name,
(SELECT quote_ident(amname) FROM pg_am WHERE oid = opfmethod) AS indexMethod
FROM pg_opfamily o
JOIN pg_namespace n on n.oid = o.opfnamespace
WHERE %s
AND %s`,
SchemaFilterClause("n"), ExtensionFilterClause("o"))
err := connectionPool.Select(&results, query)
gplog.FatalOnError(err)
return results
}
type OperatorClass struct {
Oid uint32
Schema string
Name string
FamilySchema string
FamilyName string
IndexMethod string
Type string
Default bool
StorageType string
Operators []OperatorClassOperator
Functions []OperatorClassFunction
}
func (opc OperatorClass) GetMetadataEntry() (string, toc.MetadataEntry) {
return "predata",
toc.MetadataEntry{
Schema: opc.Schema,
Name: opc.Name,
ObjectType: "OPERATOR CLASS",
ReferenceObject: "",
StartByte: 0,
EndByte: 0,
}
}
func (opc OperatorClass) GetUniqueID() UniqueID {
return UniqueID{ClassID: PG_OPCLASS_OID, Oid: opc.Oid}
}
func (opc OperatorClass) FQN() string {
return fmt.Sprintf("%s USING %s", utils.MakeFQN(opc.Schema, opc.Name), opc.IndexMethod)
}
func GetOperatorClasses(connectionPool *dbconn.DBConn) []OperatorClass {
results := make([]OperatorClass, 0)
/*
* In the GPDB 4.3 query, we assign the class schema and name to both the
* class schema/name and family schema/name fields, so that the logic in
* PrintCreateOperatorClassStatement to not print FAMILY if the class and
* family have the same schema and name will work for both versions.
*/
atLeast5Query := fmt.Sprintf(`
SELECT c.oid AS oid,
quote_ident(cls_ns.nspname) AS schema,
quote_ident(opcname) AS name,
quote_ident(fam_ns.nspname) AS familyschema,
quote_ident(opfname) AS familyname,
(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS indexmethod,
opcintype::pg_catalog.regtype AS type,
opcdefault AS default,
opckeytype::pg_catalog.regtype AS storagetype
FROM pg_catalog.pg_opclass c
LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily
JOIN pg_catalog.pg_namespace cls_ns ON cls_ns.oid = opcnamespace
JOIN pg_catalog.pg_namespace fam_ns ON fam_ns.oid = opfnamespace
WHERE %s
AND %s`,
SchemaFilterClause("cls_ns"), ExtensionFilterClause("c"))
query := atLeast5Query
err := connectionPool.Select(&results, query)
gplog.FatalOnError(err)
operators := GetOperatorClassOperators(connectionPool)
for i := range results {
results[i].Operators = operators[results[i].Oid]
}
functions := GetOperatorClassFunctions(connectionPool)
for i := range results {
results[i].Functions = functions[results[i].Oid]
}
return results
}
type OperatorClassOperator struct {
ClassOid uint32
StrategyNumber int
Operator string
Recheck bool
OrderByFamily string
}
func GetOperatorClassOperators(connectionPool *dbconn.DBConn) map[uint32][]OperatorClassOperator {
results := make([]OperatorClassOperator, 0)
atLeast6Query := `
SELECT refobjid AS classoid,
amopstrategy AS strategynumber,
amopopr::pg_catalog.regoperator AS operator,
coalesce(quote_ident(ns.nspname) || '.' || quote_ident(opf.opfname), '') AS orderbyfamily
FROM pg_catalog.pg_amop ao
JOIN pg_catalog.pg_depend d ON d.objid = ao.oid
LEFT JOIN pg_opfamily opf ON opf.oid = ao.amopsortfamily
LEFT JOIN pg_namespace ns ON ns.oid = opf.opfnamespace
WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass
AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass
ORDER BY amopstrategy`
query := atLeast6Query
err := connectionPool.Select(&results, query)
gplog.FatalOnError(err)
operators := make(map[uint32][]OperatorClassOperator)
for _, result := range results {
operators[result.ClassOid] = append(operators[result.ClassOid], result)
}
return operators
}
type OperatorClassFunction struct {
ClassOid uint32
SupportNumber int
FunctionName string
LeftType string `db:"amproclefttype"`
RightType string `db:"amprocrighttype"`
}
func GetOperatorClassFunctions(connectionPool *dbconn.DBConn) map[uint32][]OperatorClassFunction {
results := make([]OperatorClassFunction, 0)
atLeast5Query := `
SELECT refobjid AS classoid,
amprocnum AS supportnumber,
amproclefttype::regtype,
amprocrighttype::regtype,
amproc::regprocedure::text AS functionname
FROM pg_catalog.pg_amproc ap
JOIN pg_catalog.pg_depend d ON d.objid = ap.oid
WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass
AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass
ORDER BY amprocnum`
query := atLeast5Query
err := connectionPool.Select(&results, query)
gplog.FatalOnError(err)
functions := make(map[uint32][]OperatorClassFunction)
for _, result := range results {
functions[result.ClassOid] = append(functions[result.ClassOid], result)
}
return functions
}