blob: 284348cd6aecd1cfcdba22d6a9a1c2812a1e0104 [file]
package backup
import (
"fmt"
"os"
"path"
"reflect"
"github.com/apache/cloudberry-backup/history"
"github.com/apache/cloudberry-backup/options"
"github.com/apache/cloudberry-backup/report"
"github.com/apache/cloudberry-backup/toc"
"github.com/apache/cloudberry-backup/utils"
"github.com/apache/cloudberry-go-libs/cluster"
"github.com/apache/cloudberry-go-libs/dbconn"
"github.com/apache/cloudberry-go-libs/gplog"
"github.com/nightlyone/lockfile"
"github.com/pkg/errors"
)
/*
* This file contains wrapper functions that group together functions relating
* to querying and printing metadata, so that the logic for each object type
* can all be in one place and backup.go can serve as a high-level look at the
* overall backup flow.
*/
/*
* Setup and validation wrapper functions
*/
func SetLoggerVerbosity() {
gplog.SetLogFileVerbosity(gplog.LOGINFO)
if MustGetFlagBool(options.QUIET) {
gplog.SetVerbosity(gplog.LOGERROR)
gplog.SetLogFileVerbosity(gplog.LOGERROR)
} else if MustGetFlagBool(options.DEBUG) {
gplog.SetVerbosity(gplog.LOGDEBUG)
gplog.SetLogFileVerbosity(gplog.LOGDEBUG)
} else if MustGetFlagBool(options.VERBOSE) {
gplog.SetVerbosity(gplog.LOGVERBOSE)
gplog.SetLogFileVerbosity(gplog.LOGVERBOSE)
}
}
func initializeConnectionPool(timestamp string) {
var numConns int
var err error
connectionPool = dbconn.NewDBConnFromEnvironment(MustGetFlagString(options.DBNAME))
/*
* The additional connection is used to hold the locks and process any deferred
* tables while not being assigned any tables up front. The benefit is that the
* connection holding the locks won't be overburdened by processing an assigned
* set of tables and any extra deferred tables, at the cost of making one
* additional connection to the database.
*/
switch true {
case FlagChanged(options.COPY_QUEUE_SIZE):
numConns = MustGetFlagInt(options.COPY_QUEUE_SIZE) + 1
case FlagChanged(options.JOBS):
numConns = MustGetFlagInt(options.JOBS) + 1
default:
numConns = 2
}
gplog.Verbose("Initializing %d database connections", numConns)
connectionPool.MustConnect(numConns)
utils.ValidateGPDBVersionCompatibility(connectionPool)
InitializeMetadataParams(connectionPool)
// Begin transactions, initialize the synchronized snapshot, and set session GUCs
for connNum := 0; connNum < connectionPool.NumConns; connNum++ {
connectionPool.MustExec(fmt.Sprintf("SET application_name TO 'gpbackup_%s'", timestamp), connNum)
// Begins transaction in repeatable read
connectionPool.MustBegin(connNum)
if ((connectionPool.Version.IsGPDB() && connectionPool.Version.AtLeast(SNAPSHOT_GPDB_MIN_VERSION)) || connectionPool.Version.IsCBDB()) && backupSnapshot == "" {
backupSnapshot, err = GetSynchronizedSnapshot(connectionPool)
if err != nil {
gplog.FatalOnError(err)
}
}
SetSessionGUCs(connNum)
}
}
func SetSessionGUCs(connNum int) {
// These GUCs ensure the dumps portability accross systems
connectionPool.MustExec("SET search_path TO pg_catalog", connNum)
connectionPool.MustExec("SET statement_timeout = 0", connNum)
connectionPool.MustExec("SET DATESTYLE = ISO", connNum)
connectionPool.MustExec("SET enable_mergejoin TO off", connNum)
// To avoid any complicated version diffs of setting this GUC,
// we use set_config() with a subquery getting the max value.
connectionPool.MustExec("SELECT set_config('extra_float_digits', (SELECT max_val FROM pg_settings WHERE name = 'extra_float_digits'), false)", connNum)
connectionPool.MustExec("SET synchronize_seqscans TO off", connNum)
if (connectionPool.Version.IsGPDB() && connectionPool.Version.AtLeast("6")) || connectionPool.Version.IsCBDB() {
connectionPool.MustExec("SET INTERVALSTYLE = POSTGRES", connNum)
connectionPool.MustExec("SET lock_timeout = 0", connNum)
}
if (connectionPool.Version.IsGPDB() && connectionPool.Version.AtLeast("7")) || connectionPool.Version.IsCBDB() {
// This is a GPDB7+ GUC that can terminate sessions with open transactions that have been idle for too long, so we disable it.
connectionPool.MustExec("SET idle_in_transaction_session_timeout = 0", connNum)
}
}
func NewBackupConfig(dbName string, dbVersion string, backupVersion string, plugin string, timestamp string, opts options.Options) *history.BackupConfig {
backupConfig := history.BackupConfig{
BackupDir: MustGetFlagString(options.BACKUP_DIR),
BackupVersion: backupVersion,
Compressed: !MustGetFlagBool(options.NO_COMPRESSION),
CompressionType: MustGetFlagString(options.COMPRESSION_TYPE),
DatabaseName: dbName,
DatabaseVersion: dbVersion,
DataOnly: MustGetFlagBool(options.DATA_ONLY),
ExcludeRelations: MustGetFlagStringArray(options.EXCLUDE_RELATION),
ExcludeSchemaFiltered: len(MustGetFlagStringArray(options.EXCLUDE_SCHEMA)) > 0,
ExcludeSchemas: MustGetFlagStringArray(options.EXCLUDE_SCHEMA),
ExcludeTableFiltered: len(MustGetFlagStringArray(options.EXCLUDE_RELATION)) > 0,
IncludeRelations: opts.GetOriginalIncludedTables(),
IncludeSchemaFiltered: len(MustGetFlagStringArray(options.INCLUDE_SCHEMA)) > 0,
IncludeSchemas: MustGetFlagStringArray(options.INCLUDE_SCHEMA),
IncludeTableFiltered: len(opts.GetOriginalIncludedTables()) > 0,
Incremental: MustGetFlagBool(options.INCREMENTAL),
LeafPartitionData: MustGetFlagBool(options.LEAF_PARTITION_DATA),
MetadataOnly: MustGetFlagBool(options.METADATA_ONLY),
Plugin: plugin,
SingleDataFile: MustGetFlagBool(options.SINGLE_DATA_FILE),
Timestamp: timestamp,
WithoutGlobals: MustGetFlagBool(options.WITHOUT_GLOBALS),
WithStatistics: MustGetFlagBool(options.WITH_STATS),
Status: history.BackupStatusInProgress,
}
return &backupConfig
}
func initializeBackupReport(opts options.Options) {
escapedDBName := dbconn.MustSelectString(connectionPool, fmt.Sprintf("select quote_ident(datname) AS string FROM pg_database where datname='%s'", utils.EscapeSingleQuotes(connectionPool.DBName)))
plugin := ""
if pluginConfig != nil {
_, plugin = path.Split(pluginConfig.ExecutablePath)
}
config := NewBackupConfig(escapedDBName, connectionPool.Version.VersionString, version,
plugin, globalFPInfo.Timestamp, opts)
isFilteredBackup := config.IncludeTableFiltered || config.IncludeSchemaFiltered ||
config.ExcludeTableFiltered || config.ExcludeSchemaFiltered
dbSize := ""
if !MustGetFlagBool(options.METADATA_ONLY) && !isFilteredBackup {
gplog.Verbose("Getting database size")
//Potentially expensive query
dbSize = GetDBSize(connectionPool)
}
config.SegmentCount = len(globalCluster.ContentIDs) - 1
backupReport = &report.Report{
DatabaseSize: dbSize,
BackupConfig: *config,
}
backupReport.ConstructBackupParamsString()
}
func createBackupLockFile(timestamp string) {
var err error
var timestampLockFile string
metadataOnly := MustGetFlagBool(options.METADATA_ONLY)
backupDir := MustGetFlagString(options.BACKUP_DIR)
noHistory := MustGetFlagBool(options.NO_HISTORY)
if metadataOnly && noHistory && backupDir != "" {
err = os.MkdirAll(backupDir, 0777)
gplog.FatalOnError(err)
timestampLockFile = fmt.Sprintf("%s/%s.lck", backupDir, timestamp)
} else {
timestampLockFile = fmt.Sprintf("/tmp/%s.lck", timestamp)
}
backupLockFile, err = lockfile.New(timestampLockFile)
gplog.FatalOnError(err)
err = backupLockFile.TryLock()
if err != nil {
gplog.Error("%s", err.Error())
gplog.Fatal(errors.Errorf("A backup with timestamp %s is already in progress. Wait 1 second and try the backup again.", timestamp), "")
}
}
func createBackupDirectoriesOnAllHosts() {
remoteOutput := globalCluster.GenerateAndExecuteCommand("Creating backup directories",
cluster.ON_SEGMENTS|cluster.INCLUDE_COORDINATOR,
func(contentID int) string {
return fmt.Sprintf("mkdir -p %s", globalFPInfo.GetDirForContent(contentID))
})
globalCluster.CheckClusterError(remoteOutput, "Unable to create backup directories", func(contentID int) string {
return fmt.Sprintf("Unable to create backup directory %s", globalFPInfo.GetDirForContent(contentID))
})
}
/*
* Metadata retrieval wrapper functions
*/
func RetrieveAndProcessTables() ([]Table, []Table) {
includedRelations := GetIncludedUserTableRelations(connectionPool, IncludedRelationFqns)
tableRelations := ConvertRelationsOptionsToBackup(includedRelations)
LockTables(connectionPool, tableRelations)
if (connectionPool.Version.IsGPDB() && connectionPool.Version.AtLeast("6")) || connectionPool.Version.IsCBDB() {
tableRelations = append(tableRelations, GetForeignTableRelations(connectionPool)...)
}
tables := ConstructDefinitionsForTables(connectionPool, tableRelations)
metadataTables, dataTables := SplitTablesByPartitionType(tables, IncludedRelationFqns)
objectCounts["Tables"] = len(metadataTables)
return metadataTables, dataTables
}
func retrieveFunctions(sortables *[]Sortable, metadataMap MetadataMap) ([]Function, map[uint32]FunctionInfo) {
gplog.Verbose("Retrieving function information")
functionMetadata := GetMetadataForObjectType(connectionPool, TYPE_FUNCTION)
addToMetadataMap(functionMetadata, metadataMap)
functions := GetFunctions(connectionPool)
funcInfoMap := GetFunctionOidToInfoMap(connectionPool)
objectCounts["Functions"] = len(functions)
*sortables = append(*sortables, convertToSortableSlice(functions)...)
return functions, funcInfoMap
}
func retrieveTransforms(sortables *[]Sortable) {
if connectionPool.Version.IsGPDB() && connectionPool.Version.Before("7") {
return
}
gplog.Verbose("Retrieving transform information")
transforms := GetTransforms(connectionPool)
objectCounts["Transforms"] = len(transforms)
*sortables = append(*sortables, convertToSortableSlice(transforms)...)
}
func retrieveAndBackupTypes(metadataFile *utils.FileWithByteCount, sortables *[]Sortable, metadataMap MetadataMap) {
gplog.Verbose("Retrieving type information")
shells := GetShellTypes(connectionPool)
bases := GetBaseTypes(connectionPool)
composites := GetCompositeTypes(connectionPool)
domains := GetDomainTypes(connectionPool)
rangeTypes := make([]RangeType, 0)
if (connectionPool.Version.IsGPDB() && connectionPool.Version.AtLeast("6")) || connectionPool.Version.IsCBDB() {
rangeTypes = GetRangeTypes(connectionPool)
}
typeMetadata := GetMetadataForObjectType(connectionPool, TYPE_TYPE)
backupShellTypes(metadataFile, shells, bases, rangeTypes)
backupEnumTypes(metadataFile, typeMetadata)
objectCounts["Types"] += len(shells)
objectCounts["Types"] += len(bases)
objectCounts["Types"] += len(composites)
objectCounts["Types"] += len(domains)
objectCounts["Types"] += len(rangeTypes)
*sortables = append(*sortables, convertToSortableSlice(bases)...)
*sortables = append(*sortables, convertToSortableSlice(composites)...)
*sortables = append(*sortables, convertToSortableSlice(domains)...)
*sortables = append(*sortables, convertToSortableSlice(rangeTypes)...)
addToMetadataMap(typeMetadata, metadataMap)
}
func retrieveConstraints(sortables *[]Sortable, metadataMap MetadataMap, tables ...Relation) ([]Constraint, []Constraint, MetadataMap) {
gplog.Verbose("Retrieving constraints")
constraints := GetConstraints(connectionPool, tables...)
if len(constraints) > 0 && ((connectionPool.Version.IsGPDB() && connectionPool.Version.AtLeast("7")) ||
connectionPool.Version.IsCBDB()) {
RenameExchangedPartitionConstraints(connectionPool, &constraints)
}
//split into domain constraints and all others, as they are handled differently downstream
domainConstraints := make([]Constraint, 0)
nonDomainConstraints := make([]Constraint, 0)
for _, con := range constraints {
if con.IsDomainConstraint {
domainConstraints = append(domainConstraints, con)
} else {
nonDomainConstraints = append(nonDomainConstraints, con)
}
}
objectCounts["Constraints"] = len(nonDomainConstraints)
conMetadata := GetCommentsForObjectType(connectionPool, TYPE_CONSTRAINT)
*sortables = append(*sortables, convertToSortableSlice(nonDomainConstraints)...)
addToMetadataMap(conMetadata, metadataMap)
return domainConstraints, nonDomainConstraints, conMetadata
}
func retrieveAndBackupSequences(metadataFile *utils.FileWithByteCount,
relationMetadata MetadataMap) []Sequence {
gplog.Verbose("Writing CREATE SEQUENCE statements to metadata file")
sequences := GetAllSequences(connectionPool)
objectCounts["Sequences"] = len(sequences)
PrintCreateSequenceStatements(metadataFile, globalTOC, sequences, relationMetadata)
return sequences
}
func retrieveProtocols(sortables *[]Sortable, metadataMap MetadataMap) []ExternalProtocol {
gplog.Verbose("Retrieving protocols")
protocols := GetExternalProtocols(connectionPool)
objectCounts["Protocols"] = len(protocols)
protoMetadata := GetMetadataForObjectType(connectionPool, TYPE_PROTOCOL)
*sortables = append(*sortables, convertToSortableSlice(protocols)...)
addToMetadataMap(protoMetadata, metadataMap)
return protocols
}
func retrieveViews(sortables *[]Sortable) {
gplog.Verbose("Retrieving views")
views := GetAllViews(connectionPool)
objectCounts["Views"] = len(views)
*sortables = append(*sortables, convertToSortableSlice(views)...)
}
func retrieveTSObjects(sortables *[]Sortable, metadataMap MetadataMap) {
gplog.Verbose("Retrieving Text Search Parsers")
retrieveTSParsers(sortables, metadataMap)
retrieveTSConfigurations(sortables, metadataMap)
retrieveTSTemplates(sortables, metadataMap)
retrieveTSDictionaries(sortables, metadataMap)
}
func retrieveTSParsers(sortables *[]Sortable, metadataMap MetadataMap) {
gplog.Verbose("Retrieving Text Search Parsers")
parsers := GetTextSearchParsers(connectionPool)
objectCounts["Text Search Parsers"] = len(parsers)
parserMetadata := GetCommentsForObjectType(connectionPool, TYPE_TS_PARSER)
*sortables = append(*sortables, convertToSortableSlice(parsers)...)
addToMetadataMap(parserMetadata, metadataMap)
}
func retrieveTSTemplates(sortables *[]Sortable, metadataMap MetadataMap) {
gplog.Verbose("Retrieving TEXT SEARCH TEMPLATE information")
templates := GetTextSearchTemplates(connectionPool)
objectCounts["Text Search Templates"] = len(templates)
templateMetadata := GetCommentsForObjectType(connectionPool, TYPE_TS_TEMPLATE)
*sortables = append(*sortables, convertToSortableSlice(templates)...)
addToMetadataMap(templateMetadata, metadataMap)
}
func retrieveTSDictionaries(sortables *[]Sortable, metadataMap MetadataMap) {
gplog.Verbose("Retrieving TEXT SEARCH DICTIONARY information")
dictionaries := GetTextSearchDictionaries(connectionPool)
objectCounts["Text Search Dictionaries"] = len(dictionaries)
dictionaryMetadata := GetMetadataForObjectType(connectionPool, TYPE_TS_DICTIONARY)
*sortables = append(*sortables, convertToSortableSlice(dictionaries)...)
addToMetadataMap(dictionaryMetadata, metadataMap)
}
func retrieveTSConfigurations(sortables *[]Sortable, metadataMap MetadataMap) {
gplog.Verbose("Retrieving TEXT SEARCH CONFIGURATION information")
configurations := GetTextSearchConfigurations(connectionPool)
objectCounts["Text Search Configurations"] = len(configurations)
configurationMetadata := GetMetadataForObjectType(connectionPool, TYPE_TS_CONFIGURATION)
*sortables = append(*sortables, convertToSortableSlice(configurations)...)
addToMetadataMap(configurationMetadata, metadataMap)
}
func retrieveOperatorObjects(sortables *[]Sortable, metadataMap MetadataMap) {
retrieveOperators(sortables, metadataMap)
retrieveOperatorClasses(sortables, metadataMap)
}
func retrieveOperators(sortables *[]Sortable, metadataMap MetadataMap) {
gplog.Verbose("Retrieving OPERATOR information")
operators := GetOperators(connectionPool)
objectCounts["Operators"] = len(operators)
operatorMetadata := GetMetadataForObjectType(connectionPool, TYPE_OPERATOR)
*sortables = append(*sortables, convertToSortableSlice(operators)...)
addToMetadataMap(operatorMetadata, metadataMap)
}
func retrieveOperatorClasses(sortables *[]Sortable, metadataMap MetadataMap) {
gplog.Verbose("Retrieving OPERATOR CLASS information")
operatorClasses := GetOperatorClasses(connectionPool)
objectCounts["Operator Classes"] = len(operatorClasses)
operatorClassMetadata := GetMetadataForObjectType(connectionPool, TYPE_OPERATOR_CLASS)
*sortables = append(*sortables, convertToSortableSlice(operatorClasses)...)
addToMetadataMap(operatorClassMetadata, metadataMap)
}
func retrieveAggregates(sortables *[]Sortable, metadataMap MetadataMap) {
gplog.Verbose("Retrieving AGGREGATE information")
aggregates := GetAggregates(connectionPool)
objectCounts["Aggregates"] = len(aggregates)
aggMetadata := GetMetadataForObjectType(connectionPool, TYPE_AGGREGATE)
*sortables = append(*sortables, convertToSortableSlice(aggregates)...)
addToMetadataMap(aggMetadata, metadataMap)
}
func retrieveCasts(sortables *[]Sortable, metadataMap MetadataMap) {
gplog.Verbose("Retrieving CAST information")
casts := GetCasts(connectionPool)
objectCounts["Casts"] = len(casts)
castMetadata := GetCommentsForObjectType(connectionPool, TYPE_CAST)
*sortables = append(*sortables, convertToSortableSlice(casts)...)
addToMetadataMap(castMetadata, metadataMap)
}
func retrieveFDWObjects(sortables *[]Sortable, metadataMap MetadataMap) {
if !(connectionPool.Version.IsGPDB() && connectionPool.Version.AtLeast("6")) || connectionPool.Version.IsCBDB() {
return
}
retrieveForeignDataWrappers(sortables, metadataMap)
retrieveForeignServers(sortables, metadataMap)
retrieveUserMappings(sortables)
}
func retrieveForeignDataWrappers(sortables *[]Sortable, metadataMap MetadataMap) {
gplog.Verbose("Writing CREATE FOREIGN DATA WRAPPER statements to metadata file")
wrappers := GetForeignDataWrappers(connectionPool)
objectCounts["Foreign Data Wrappers"] = len(wrappers)
fdwMetadata := GetMetadataForObjectType(connectionPool, TYPE_FOREIGN_DATA_WRAPPER)
*sortables = append(*sortables, convertToSortableSlice(wrappers)...)
addToMetadataMap(fdwMetadata, metadataMap)
}
func retrieveForeignServers(sortables *[]Sortable, metadataMap MetadataMap) {
gplog.Verbose("Writing CREATE SERVER statements to metadata file")
servers := GetForeignServers(connectionPool)
objectCounts["Foreign Servers"] = len(servers)
serverMetadata := GetMetadataForObjectType(connectionPool, TYPE_FOREIGN_SERVER)
*sortables = append(*sortables, convertToSortableSlice(servers)...)
addToMetadataMap(serverMetadata, metadataMap)
}
func retrieveUserMappings(sortables *[]Sortable) {
gplog.Verbose("Writing CREATE USER MAPPING statements to metadata file")
mappings := GetUserMappings(connectionPool)
objectCounts["User Mappings"] = len(mappings)
// No comments, owners, or ACLs on UserMappings so no need to get metadata
*sortables = append(*sortables, convertToSortableSlice(mappings)...)
}
func backupSessionGUC(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing Session Configuration Parameters to metadata file")
gucs := GetSessionGUCs(connectionPool)
PrintSessionGUCs(metadataFile, globalTOC, gucs)
}
/*
* Global metadata wrapper functions
*/
func backupTablespaces(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing CREATE TABLESPACE statements to metadata file")
tablespaces := GetTablespaces(connectionPool)
objectCounts["Tablespaces"] = len(tablespaces)
tablespaceMetadata := GetMetadataForObjectType(connectionPool, TYPE_TABLESPACE)
PrintCreateTablespaceStatements(metadataFile, globalTOC, tablespaces, tablespaceMetadata)
}
func backupCreateDatabase(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing CREATE DATABASE statement to metadata file")
defaultDB := GetDefaultDatabaseEncodingInfo(connectionPool)
db := GetDatabaseInfo(connectionPool)
dbMetadata := GetMetadataForObjectType(connectionPool, TYPE_DATABASE)
PrintCreateDatabaseStatement(metadataFile, globalTOC, defaultDB, db, dbMetadata)
}
func backupDatabaseGUCs(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing Database Configuration Parameters to metadata file")
databaseGucs := GetDatabaseGUCs(connectionPool)
objectCounts["Database GUCs"] = len(databaseGucs)
PrintDatabaseGUCs(metadataFile, globalTOC, databaseGucs, connectionPool.DBName)
}
func backupResourceQueues(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing CREATE RESOURCE QUEUE statements to metadata file")
resQueues := GetResourceQueues(connectionPool)
objectCounts["Resource Queues"] = len(resQueues)
resQueueMetadata := GetCommentsForObjectType(connectionPool, TYPE_RESOURCE_QUEUE)
PrintCreateResourceQueueStatements(metadataFile, globalTOC, resQueues, resQueueMetadata)
}
func backupResourceGroups(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing CREATE RESOURCE GROUP statements to metadata file")
if connectionPool.Version.IsGPDB() && connectionPool.Version.Before("7") {
resGroups := GetResourceGroups[ResourceGroupBefore7](connectionPool)
objectCounts["Resource Groups"] = len(resGroups)
resGroupMetadata := GetCommentsForObjectType(connectionPool, TYPE_RESOURCE_GROUP)
PrintResetResourceGroupStatements(metadataFile, globalTOC)
PrintCreateResourceGroupStatementsBefore7(metadataFile, globalTOC, resGroups, resGroupMetadata)
} else { // GPDB7+
resGroups := GetResourceGroups[ResourceGroupAtLeast7](connectionPool)
objectCounts["Resource Groups"] = len(resGroups)
resGroupMetadata := GetCommentsForObjectType(connectionPool, TYPE_RESOURCE_GROUP)
PrintResetResourceGroupStatements(metadataFile, globalTOC)
PrintCreateResourceGroupStatementsAtLeast7(metadataFile, globalTOC, resGroups, resGroupMetadata)
}
}
func backupRoles(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing CREATE ROLE statements to metadata file")
roles := GetRoles(connectionPool)
objectCounts["Roles"] = len(roles)
roleMetadata := GetMetadataForObjectType(connectionPool, TYPE_ROLE)
PrintCreateRoleStatements(metadataFile, globalTOC, roles, roleMetadata)
}
func backupRoleGUCs(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing ROLE Configuration Parameter to meadata file")
roleGUCs := GetRoleGUCs(connectionPool)
PrintRoleGUCStatements(metadataFile, globalTOC, roleGUCs)
}
func backupRoleGrants(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing GRANT ROLE statements to metadata file")
roleMembers := GetRoleMembers(connectionPool)
PrintRoleMembershipStatements(metadataFile, globalTOC, roleMembers)
}
/*
* Predata wrapper functions
*/
func backupSchemas(metadataFile *utils.FileWithByteCount, partitionAlteredSchemas map[string]bool) {
gplog.Verbose("Writing CREATE SCHEMA statements to metadata file")
schemas := GetAllUserSchemas(connectionPool, partitionAlteredSchemas)
objectCounts["Schemas"] = len(schemas)
schemaMetadata := GetMetadataForObjectType(connectionPool, TYPE_SCHEMA)
PrintCreateSchemaStatements(metadataFile, globalTOC, schemas, schemaMetadata)
}
func backupProceduralLanguages(metadataFile *utils.FileWithByteCount,
functions []Function, funcInfoMap map[uint32]FunctionInfo, functionMetadata MetadataMap) {
gplog.Verbose("Writing CREATE PROCEDURAL LANGUAGE statements to metadata file")
procLangs := GetProceduralLanguages(connectionPool)
objectCounts["Procedural Languages"] = len(procLangs)
langFuncs, _ := ExtractLanguageFunctions(functions, procLangs)
for _, langFunc := range langFuncs {
PrintCreateFunctionStatement(metadataFile, globalTOC, langFunc, functionMetadata[langFunc.GetUniqueID()])
}
procLangMetadata := GetMetadataForObjectType(connectionPool, TYPE_PROC_LANGUAGE)
PrintCreateLanguageStatements(metadataFile, globalTOC, procLangs, funcInfoMap, procLangMetadata)
}
func backupShellTypes(metadataFile *utils.FileWithByteCount, shellTypes []ShellType, baseTypes []BaseType, rangeTypes []RangeType) {
gplog.Verbose("Writing CREATE TYPE statements for shell types to metadata file")
PrintCreateShellTypeStatements(metadataFile, globalTOC, shellTypes, baseTypes, rangeTypes)
}
func backupEnumTypes(metadataFile *utils.FileWithByteCount, typeMetadata MetadataMap) {
gplog.Verbose("Writing CREATE TYPE statements for enum types to metadata file")
enums := GetEnumTypes(connectionPool)
objectCounts["Types"] += len(enums)
PrintCreateEnumTypeStatements(metadataFile, globalTOC, enums, typeMetadata)
}
func backupAccessMethods(metadataFile *utils.FileWithByteCount) {
if connectionPool.Version.IsGPDB() && connectionPool.Version.Before("7") {
return
}
gplog.Verbose("Writing CREATE ACCESS METHOD statements to metadata file")
accessMethods := GetAccessMethods(connectionPool)
objectCounts["Access Methods"] = len(accessMethods)
accessMethodsMetadata := GetMetadataForObjectType(connectionPool, TYPE_ACCESS_METHOD)
PrintAccessMethodStatements(metadataFile, globalTOC, accessMethods, accessMethodsMetadata)
}
func createBackupSet(objSlice []Sortable) (backupSet map[UniqueID]bool) {
backupSet = make(map[UniqueID]bool)
for _, obj := range objSlice {
backupSet[obj.GetUniqueID()] = true
}
return backupSet
}
func convertToSortableSlice(objSlice interface{}) []Sortable {
sortableSlice := make([]Sortable, 0)
s := reflect.ValueOf(objSlice)
ret := make([]interface{}, s.Len())
for i := 0; i < s.Len(); i++ {
ret[i] = s.Index(i).Interface()
}
for _, obj := range ret {
newObj := obj.(Sortable)
sortableSlice = append(sortableSlice, newObj)
}
return sortableSlice
}
func addToMetadataMap(newMetadata MetadataMap, metadataMap MetadataMap) {
for k, v := range newMetadata {
metadataMap[k] = v
}
}
// This function is fairly unwieldy, but there's not really a good way to break it down
func backupDependentObjects(metadataFile *utils.FileWithByteCount, tables []Table,
protocols []ExternalProtocol, filteredMetadata MetadataMap, domainConstraints []Constraint,
sortables []Sortable, sequences []Sequence, funcInfoMap map[uint32]FunctionInfo, tableOnly bool) []View {
var sortedSlice []Sortable
gplog.Verbose("Writing CREATE statements for dependent objects to metadata file")
backupSet := createBackupSet(sortables)
relevantDeps := GetDependencies(connectionPool, backupSet, tables)
viewsDependingOnConstraints := MarkViewsDependingOnConstraints(sortables, relevantDeps)
sortedSlice, globalTierMap = TopologicalSort(sortables, relevantDeps)
PrintDependentObjectStatements(metadataFile, globalTOC, sortedSlice, filteredMetadata, domainConstraints, funcInfoMap)
PrintIdentityColumns(metadataFile, globalTOC, sequences)
PrintAlterSequenceStatements(metadataFile, globalTOC, sequences)
extPartInfo, partInfoMap := GetExternalPartitionInfo(connectionPool)
if connectionPool.Version.Before("7") && len(extPartInfo) > 0 {
gplog.Verbose("Writing EXCHANGE PARTITION statements to metadata file")
PrintExchangeExternalPartitionStatements(metadataFile, globalTOC, extPartInfo, partInfoMap, tables)
}
return viewsDependingOnConstraints
}
func backupConversions(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing CREATE CONVERSION statements to metadata file")
conversions := GetConversions(connectionPool)
objectCounts["Conversions"] = len(conversions)
convMetadata := GetMetadataForObjectType(connectionPool, TYPE_CONVERSION)
PrintCreateConversionStatements(metadataFile, globalTOC, conversions, convMetadata)
}
func backupOperatorFamilies(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing CREATE OPERATOR FAMILY statements to metadata file")
operatorFamilies := GetOperatorFamilies(connectionPool)
objectCounts["Operator Families"] = len(operatorFamilies)
operatorFamilyMetadata := GetMetadataForObjectType(connectionPool, TYPE_OPERATOR_FAMILY)
PrintCreateOperatorFamilyStatements(metadataFile, globalTOC, operatorFamilies, operatorFamilyMetadata)
}
func backupCollations(metadataFile *utils.FileWithByteCount) {
if !((connectionPool.Version.IsGPDB() && connectionPool.Version.AtLeast("6")) || connectionPool.Version.IsCBDB()) {
return
}
gplog.Verbose("Writing CREATE COLLATION statements to metadata file")
collations := GetCollations(connectionPool)
objectCounts["Collations"] = len(collations)
collationMetadata := GetMetadataForObjectType(connectionPool, TYPE_COLLATION)
PrintCreateCollationStatements(metadataFile, globalTOC, collations, collationMetadata)
}
func backupExtensions(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing CREATE EXTENSION statements to metadata file")
extensions := GetExtensions(connectionPool)
objectCounts["Extensions"] = len(extensions)
extensionMetadata := GetCommentsForObjectType(connectionPool, TYPE_EXTENSION)
PrintCreateExtensionStatements(metadataFile, globalTOC, extensions, extensionMetadata)
}
func backupConstraints(metadataFile *utils.FileWithByteCount, constraints []Constraint, conMetadata MetadataMap) {
gplog.Verbose("Writing ADD CONSTRAINT statements to metadata file")
objectCounts["Constraints"] = len(constraints)
PrintConstraintStatements(metadataFile, globalTOC, constraints, conMetadata)
}
func backupViewsDependingOnConstraints(metadataFile *utils.FileWithByteCount, views []View) {
gplog.Verbose("Writing CREATE VIEW statements for views that depend on constraints to metadata file")
PrintCreatePostdataViewStatements(metadataFile, globalTOC, views)
}
/*
* Postdata wrapper functions
*/
func backupIndexes(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing CREATE INDEX statements to metadata file")
indexes := GetIndexes(connectionPool)
objectCounts["Indexes"] = len(indexes)
if objectCounts["Indexes"] > 0 && (connectionPool.Version.IsGPDB() && connectionPool.Version.Is("6")) {
// This bug is not addressed in versions prior to GPDB6
// New partition exchange syntax in GPDB7+ obviates the need for this renaming
RenameExchangedPartitionIndexes(connectionPool, &indexes)
}
indexMetadata := GetCommentsForObjectType(connectionPool, TYPE_INDEX)
PrintCreateIndexStatements(metadataFile, globalTOC, indexes, indexMetadata)
}
func backupRules(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing CREATE RULE statements to metadata file")
rules := GetRules(connectionPool)
objectCounts["Rules"] = len(rules)
ruleMetadata := GetCommentsForObjectType(connectionPool, TYPE_RULE)
PrintCreateRuleStatements(metadataFile, globalTOC, rules, ruleMetadata)
}
func backupTriggers(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing CREATE TRIGGER statements to metadata file")
triggers := GetTriggers(connectionPool)
objectCounts["Triggers"] = len(triggers)
triggerMetadata := GetCommentsForObjectType(connectionPool, TYPE_TRIGGER)
PrintCreateTriggerStatements(metadataFile, globalTOC, triggers, triggerMetadata)
}
func backupEventTriggers(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing CREATE EVENT TRIGGER statements to metadata file")
eventTriggers := GetEventTriggers(connectionPool)
objectCounts["Event Triggers"] = len(eventTriggers)
eventTriggerMetadata := GetMetadataForObjectType(connectionPool, TYPE_EVENT_TRIGGER)
PrintCreateEventTriggerStatements(metadataFile, globalTOC, eventTriggers, eventTriggerMetadata)
}
func backupRowLevelSecurityPolicies(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing CREATE POLICY statements to metadata file")
policies := GetPolicies(connectionPool)
objectCounts["Policies"] = len(policies)
ruleMetadata := GetCommentsForObjectType(connectionPool, TYPE_RULE)
PrintCreatePolicyStatements(metadataFile, globalTOC, policies, ruleMetadata)
}
func backupDefaultPrivileges(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing ALTER DEFAULT PRIVILEGES statements to metadata file")
defaultPrivileges := GetDefaultPrivileges(connectionPool)
objectCounts["DEFAULT PRIVILEGES"] = len(defaultPrivileges)
PrintDefaultPrivilegesStatements(metadataFile, globalTOC, defaultPrivileges)
}
func backupExtendedStatistic(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing CREATE STATISTICS statements to metadata file (for extended statistics)")
statisticsExt := GetExtendedStatistics(connectionPool)
objectCounts[toc.OBJ_STATISTICS_EXT] = len(statisticsExt)
statisticExtMetadata := GetMetadataForObjectType(connectionPool, TYPE_STATISTIC_EXT)
PrintCreateExtendedStatistics(metadataFile, globalTOC, statisticsExt, statisticExtMetadata)
}
/*
* Data wrapper functions
*/
func backupTableStatistics(statisticsFile *utils.FileWithByteCount, tables []Table) {
attStats := GetAttributeStatistics(connectionPool, tables)
tupleStats := GetTupleStatistics(connectionPool, tables)
backupSessionGUC(statisticsFile)
PrintStatisticsStatements(statisticsFile, globalTOC, tables, attStats, tupleStats)
}
func backupIncrementalMetadata() {
aoTableEntries := GetAOIncrementalMetadata(connectionPool)
globalTOC.IncrementalMetadata.AO = aoTableEntries
}
func backupStorageServers(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing CREATE SERVER statements to metadata file")
servers := GetStorageServers(connectionPool)
objectCounts[toc.OBJ_STORAGE_SERVER] = len(servers)
serverMetadata := GetMetadataForObjectType(connectionPool, TYPE_STORAGE_SERVER)
PrintCreateStorageServerStatements(metadataFile, globalTOC, servers, serverMetadata)
}
func backupStorageUserMappings(metadataFile *utils.FileWithByteCount) {
gplog.Verbose("Writing CREATE STORAGE USER MAPPING statements to metadata file")
users := GetStorageUserMapping(connectionPool)
objectCounts[toc.OBJ_STORAGE_USER_MAPPING] = len(users)
PrintCreateStorageUserMappingStatements(metadataFile, globalTOC, users)
}