github.com/greenplum-db/gpbackup@v0.0.0-20240517212602-89daab1885b3/backup/wrappers.go (about) 1 package backup 2 3 import ( 4 "fmt" 5 "os" 6 "path" 7 "reflect" 8 9 "github.com/greenplum-db/gp-common-go-libs/cluster" 10 "github.com/greenplum-db/gp-common-go-libs/dbconn" 11 "github.com/greenplum-db/gp-common-go-libs/gplog" 12 "github.com/greenplum-db/gpbackup/history" 13 "github.com/greenplum-db/gpbackup/options" 14 "github.com/greenplum-db/gpbackup/report" 15 "github.com/greenplum-db/gpbackup/toc" 16 "github.com/greenplum-db/gpbackup/utils" 17 "github.com/nightlyone/lockfile" 18 "github.com/pkg/errors" 19 ) 20 21 /* 22 * This file contains wrapper functions that group together functions relating 23 * to querying and printing metadata, so that the logic for each object type 24 * can all be in one place and backup.go can serve as a high-level look at the 25 * overall backup flow. 26 */ 27 28 /* 29 * Setup and validation wrapper functions 30 */ 31 32 func SetLoggerVerbosity() { 33 gplog.SetLogFileVerbosity(gplog.LOGINFO) 34 if MustGetFlagBool(options.QUIET) { 35 gplog.SetVerbosity(gplog.LOGERROR) 36 gplog.SetLogFileVerbosity(gplog.LOGERROR) 37 } else if MustGetFlagBool(options.DEBUG) { 38 gplog.SetVerbosity(gplog.LOGDEBUG) 39 gplog.SetLogFileVerbosity(gplog.LOGDEBUG) 40 } else if MustGetFlagBool(options.VERBOSE) { 41 gplog.SetVerbosity(gplog.LOGVERBOSE) 42 gplog.SetLogFileVerbosity(gplog.LOGVERBOSE) 43 } 44 } 45 46 func initializeConnectionPool(timestamp string) { 47 var numConns int 48 var err error 49 connectionPool = dbconn.NewDBConnFromEnvironment(MustGetFlagString(options.DBNAME)) 50 /* 51 * The additional connection is used to hold the locks and process any deferred 52 * tables while not being assigned any tables up front. The benefit is that the 53 * connection holding the locks won't be overburdened by processing an assigned 54 * set of tables and any extra deferred tables, at the cost of making one 55 * additional connection to the database. 56 */ 57 switch true { 58 case FlagChanged(options.COPY_QUEUE_SIZE): 59 numConns = MustGetFlagInt(options.COPY_QUEUE_SIZE) + 1 60 case FlagChanged(options.JOBS): 61 numConns = MustGetFlagInt(options.JOBS) + 1 62 default: 63 numConns = 2 64 } 65 66 gplog.Verbose(fmt.Sprintf("Initializing %d database connections", numConns)) 67 connectionPool.MustConnect(numConns) 68 69 utils.ValidateGPDBVersionCompatibility(connectionPool) 70 InitializeMetadataParams(connectionPool) 71 // Begin transactions, initialize the synchronized snapshot, and set session GUCs 72 for connNum := 0; connNum < connectionPool.NumConns; connNum++ { 73 connectionPool.MustExec(fmt.Sprintf("SET application_name TO 'gpbackup_%s'", timestamp), connNum) 74 // Begins transaction in repeatable read 75 connectionPool.MustBegin(connNum) 76 if connectionPool.Version.AtLeast(SNAPSHOT_GPDB_MIN_VERSION) && backupSnapshot == "" { 77 backupSnapshot, err = GetSynchronizedSnapshot(connectionPool) 78 if err != nil { 79 gplog.FatalOnError(err) 80 } 81 } 82 83 SetSessionGUCs(connNum) 84 } 85 } 86 87 func SetSessionGUCs(connNum int) { 88 // These GUCs ensure the dumps portability accross systems 89 connectionPool.MustExec("SET search_path TO pg_catalog", connNum) 90 connectionPool.MustExec("SET statement_timeout = 0", connNum) 91 connectionPool.MustExec("SET DATESTYLE = ISO", connNum) 92 connectionPool.MustExec("SET enable_mergejoin TO off", connNum) 93 94 // To avoid any complicated version diffs of setting this GUC, 95 // we use set_config() with a subquery getting the max value. 96 connectionPool.MustExec("SELECT set_config('extra_float_digits', (SELECT max_val FROM pg_settings WHERE name = 'extra_float_digits'), false)", connNum) 97 98 connectionPool.MustExec("SET synchronize_seqscans TO off", connNum) 99 100 if connectionPool.Version.AtLeast("6") { 101 connectionPool.MustExec("SET INTERVALSTYLE = POSTGRES", connNum) 102 connectionPool.MustExec("SET lock_timeout = 0", connNum) 103 } 104 105 if connectionPool.Version.AtLeast("7") { 106 // This is a GPDB7+ GUC that can terminate sessions with open transactions that have been idle for too long, so we disable it. 107 connectionPool.MustExec("SET idle_in_transaction_session_timeout = 0", connNum) 108 } 109 } 110 111 func NewBackupConfig(dbName string, dbVersion string, backupVersion string, plugin string, timestamp string, opts options.Options) *history.BackupConfig { 112 backupConfig := history.BackupConfig{ 113 BackupDir: MustGetFlagString(options.BACKUP_DIR), 114 BackupVersion: backupVersion, 115 Compressed: !MustGetFlagBool(options.NO_COMPRESSION), 116 CompressionType: MustGetFlagString(options.COMPRESSION_TYPE), 117 DatabaseName: dbName, 118 DatabaseVersion: dbVersion, 119 DataOnly: MustGetFlagBool(options.DATA_ONLY), 120 ExcludeRelations: MustGetFlagStringArray(options.EXCLUDE_RELATION), 121 ExcludeSchemaFiltered: len(MustGetFlagStringArray(options.EXCLUDE_SCHEMA)) > 0, 122 ExcludeSchemas: MustGetFlagStringArray(options.EXCLUDE_SCHEMA), 123 ExcludeTableFiltered: len(MustGetFlagStringArray(options.EXCLUDE_RELATION)) > 0, 124 IncludeRelations: opts.GetOriginalIncludedTables(), 125 IncludeSchemaFiltered: len(MustGetFlagStringArray(options.INCLUDE_SCHEMA)) > 0, 126 IncludeSchemas: MustGetFlagStringArray(options.INCLUDE_SCHEMA), 127 IncludeTableFiltered: len(opts.GetOriginalIncludedTables()) > 0, 128 Incremental: MustGetFlagBool(options.INCREMENTAL), 129 LeafPartitionData: MustGetFlagBool(options.LEAF_PARTITION_DATA), 130 MetadataOnly: MustGetFlagBool(options.METADATA_ONLY), 131 Plugin: plugin, 132 SingleDataFile: MustGetFlagBool(options.SINGLE_DATA_FILE), 133 Timestamp: timestamp, 134 WithoutGlobals: MustGetFlagBool(options.WITHOUT_GLOBALS), 135 WithStatistics: MustGetFlagBool(options.WITH_STATS), 136 Status: history.BackupStatusInProgress, 137 } 138 139 return &backupConfig 140 } 141 142 func initializeBackupReport(opts options.Options) { 143 escapedDBName := dbconn.MustSelectString(connectionPool, fmt.Sprintf("select quote_ident(datname) AS string FROM pg_database where datname='%s'", utils.EscapeSingleQuotes(connectionPool.DBName))) 144 plugin := "" 145 if pluginConfig != nil { 146 _, plugin = path.Split(pluginConfig.ExecutablePath) 147 } 148 config := NewBackupConfig(escapedDBName, connectionPool.Version.VersionString, version, 149 plugin, globalFPInfo.Timestamp, opts) 150 151 isFilteredBackup := config.IncludeTableFiltered || config.IncludeSchemaFiltered || 152 config.ExcludeTableFiltered || config.ExcludeSchemaFiltered 153 dbSize := "" 154 if !MustGetFlagBool(options.METADATA_ONLY) && !isFilteredBackup { 155 gplog.Verbose("Getting database size") 156 //Potentially expensive query 157 dbSize = GetDBSize(connectionPool) 158 } 159 160 config.SegmentCount = len(globalCluster.ContentIDs) - 1 161 162 backupReport = &report.Report{ 163 DatabaseSize: dbSize, 164 BackupConfig: *config, 165 } 166 backupReport.ConstructBackupParamsString() 167 } 168 169 func createBackupLockFile(timestamp string) { 170 var err error 171 var timestampLockFile string 172 metadataOnly := MustGetFlagBool(options.METADATA_ONLY) 173 backupDir := MustGetFlagString(options.BACKUP_DIR) 174 noHistory := MustGetFlagBool(options.NO_HISTORY) 175 if metadataOnly && noHistory && backupDir != "" { 176 err = os.MkdirAll(backupDir, 0777) 177 gplog.FatalOnError(err) 178 timestampLockFile = fmt.Sprintf("%s/%s.lck", backupDir, timestamp) 179 } else { 180 timestampLockFile = fmt.Sprintf("/tmp/%s.lck", timestamp) 181 } 182 backupLockFile, err = lockfile.New(timestampLockFile) 183 gplog.FatalOnError(err) 184 err = backupLockFile.TryLock() 185 if err != nil { 186 gplog.Error(err.Error()) 187 gplog.Fatal(errors.Errorf("A backup with timestamp %s is already in progress. Wait 1 second and try the backup again.", timestamp), "") 188 } 189 } 190 191 func createBackupDirectoriesOnAllHosts() { 192 remoteOutput := globalCluster.GenerateAndExecuteCommand("Creating backup directories", 193 cluster.ON_SEGMENTS|cluster.INCLUDE_COORDINATOR, 194 func(contentID int) string { 195 return fmt.Sprintf("mkdir -p %s", globalFPInfo.GetDirForContent(contentID)) 196 }) 197 globalCluster.CheckClusterError(remoteOutput, "Unable to create backup directories", func(contentID int) string { 198 return fmt.Sprintf("Unable to create backup directory %s", globalFPInfo.GetDirForContent(contentID)) 199 }) 200 } 201 202 /* 203 * Metadata retrieval wrapper functions 204 */ 205 206 func RetrieveAndProcessTables() ([]Table, []Table) { 207 includedRelations := GetIncludedUserTableRelations(connectionPool, IncludedRelationFqns) 208 tableRelations := ConvertRelationsOptionsToBackup(includedRelations) 209 210 LockTables(connectionPool, tableRelations) 211 212 if connectionPool.Version.AtLeast("6") { 213 tableRelations = append(tableRelations, GetForeignTableRelations(connectionPool)...) 214 } 215 216 tables := ConstructDefinitionsForTables(connectionPool, tableRelations) 217 218 metadataTables, dataTables := SplitTablesByPartitionType(tables, IncludedRelationFqns) 219 objectCounts["Tables"] = len(metadataTables) 220 221 return metadataTables, dataTables 222 } 223 224 func retrieveFunctions(sortables *[]Sortable, metadataMap MetadataMap) ([]Function, map[uint32]FunctionInfo) { 225 gplog.Verbose("Retrieving function information") 226 functionMetadata := GetMetadataForObjectType(connectionPool, TYPE_FUNCTION) 227 addToMetadataMap(functionMetadata, metadataMap) 228 functions := GetFunctions(connectionPool) 229 funcInfoMap := GetFunctionOidToInfoMap(connectionPool) 230 objectCounts["Functions"] = len(functions) 231 *sortables = append(*sortables, convertToSortableSlice(functions)...) 232 233 return functions, funcInfoMap 234 } 235 236 func retrieveTransforms(sortables *[]Sortable) { 237 if connectionPool.Version.Before("7") { 238 return 239 } 240 gplog.Verbose("Retrieving transform information") 241 transforms := GetTransforms(connectionPool) 242 objectCounts["Transforms"] = len(transforms) 243 *sortables = append(*sortables, convertToSortableSlice(transforms)...) 244 } 245 246 func retrieveAndBackupTypes(metadataFile *utils.FileWithByteCount, sortables *[]Sortable, metadataMap MetadataMap) { 247 gplog.Verbose("Retrieving type information") 248 shells := GetShellTypes(connectionPool) 249 bases := GetBaseTypes(connectionPool) 250 composites := GetCompositeTypes(connectionPool) 251 domains := GetDomainTypes(connectionPool) 252 rangeTypes := make([]RangeType, 0) 253 if connectionPool.Version.AtLeast("6") { 254 rangeTypes = GetRangeTypes(connectionPool) 255 } 256 typeMetadata := GetMetadataForObjectType(connectionPool, TYPE_TYPE) 257 258 backupShellTypes(metadataFile, shells, bases, rangeTypes) 259 backupEnumTypes(metadataFile, typeMetadata) 260 261 objectCounts["Types"] += len(shells) 262 objectCounts["Types"] += len(bases) 263 objectCounts["Types"] += len(composites) 264 objectCounts["Types"] += len(domains) 265 objectCounts["Types"] += len(rangeTypes) 266 *sortables = append(*sortables, convertToSortableSlice(bases)...) 267 *sortables = append(*sortables, convertToSortableSlice(composites)...) 268 *sortables = append(*sortables, convertToSortableSlice(domains)...) 269 *sortables = append(*sortables, convertToSortableSlice(rangeTypes)...) 270 addToMetadataMap(typeMetadata, metadataMap) 271 } 272 273 func retrieveConstraints(sortables *[]Sortable, metadataMap MetadataMap, tables ...Relation) ([]Constraint, []Constraint, MetadataMap) { 274 gplog.Verbose("Retrieving constraints") 275 constraints := GetConstraints(connectionPool, tables...) 276 if len(constraints) > 0 && connectionPool.Version.AtLeast("7") { 277 RenameExchangedPartitionConstraints(connectionPool, &constraints) 278 } 279 280 //split into domain constraints and all others, as they are handled differently downstream 281 domainConstraints := make([]Constraint, 0) 282 nonDomainConstraints := make([]Constraint, 0) 283 for _, con := range constraints { 284 if con.IsDomainConstraint { 285 domainConstraints = append(domainConstraints, con) 286 } else { 287 nonDomainConstraints = append(nonDomainConstraints, con) 288 } 289 } 290 objectCounts["Constraints"] = len(nonDomainConstraints) 291 conMetadata := GetCommentsForObjectType(connectionPool, TYPE_CONSTRAINT) 292 *sortables = append(*sortables, convertToSortableSlice(nonDomainConstraints)...) 293 addToMetadataMap(conMetadata, metadataMap) 294 return domainConstraints, nonDomainConstraints, conMetadata 295 } 296 297 func retrieveAndBackupSequences(metadataFile *utils.FileWithByteCount, 298 relationMetadata MetadataMap) []Sequence { 299 gplog.Verbose("Writing CREATE SEQUENCE statements to metadata file") 300 sequences := GetAllSequences(connectionPool) 301 objectCounts["Sequences"] = len(sequences) 302 PrintCreateSequenceStatements(metadataFile, globalTOC, sequences, relationMetadata) 303 return sequences 304 } 305 306 func retrieveProtocols(sortables *[]Sortable, metadataMap MetadataMap) []ExternalProtocol { 307 gplog.Verbose("Retrieving protocols") 308 protocols := GetExternalProtocols(connectionPool) 309 objectCounts["Protocols"] = len(protocols) 310 protoMetadata := GetMetadataForObjectType(connectionPool, TYPE_PROTOCOL) 311 312 *sortables = append(*sortables, convertToSortableSlice(protocols)...) 313 addToMetadataMap(protoMetadata, metadataMap) 314 315 return protocols 316 } 317 318 func retrieveViews(sortables *[]Sortable) { 319 gplog.Verbose("Retrieving views") 320 views := GetAllViews(connectionPool) 321 objectCounts["Views"] = len(views) 322 323 *sortables = append(*sortables, convertToSortableSlice(views)...) 324 } 325 326 func retrieveTSObjects(sortables *[]Sortable, metadataMap MetadataMap) { 327 gplog.Verbose("Retrieving Text Search Parsers") 328 retrieveTSParsers(sortables, metadataMap) 329 retrieveTSConfigurations(sortables, metadataMap) 330 retrieveTSTemplates(sortables, metadataMap) 331 retrieveTSDictionaries(sortables, metadataMap) 332 } 333 334 func retrieveTSParsers(sortables *[]Sortable, metadataMap MetadataMap) { 335 gplog.Verbose("Retrieving Text Search Parsers") 336 parsers := GetTextSearchParsers(connectionPool) 337 objectCounts["Text Search Parsers"] = len(parsers) 338 parserMetadata := GetCommentsForObjectType(connectionPool, TYPE_TS_PARSER) 339 340 *sortables = append(*sortables, convertToSortableSlice(parsers)...) 341 addToMetadataMap(parserMetadata, metadataMap) 342 } 343 344 func retrieveTSTemplates(sortables *[]Sortable, metadataMap MetadataMap) { 345 gplog.Verbose("Retrieving TEXT SEARCH TEMPLATE information") 346 templates := GetTextSearchTemplates(connectionPool) 347 objectCounts["Text Search Templates"] = len(templates) 348 templateMetadata := GetCommentsForObjectType(connectionPool, TYPE_TS_TEMPLATE) 349 350 *sortables = append(*sortables, convertToSortableSlice(templates)...) 351 addToMetadataMap(templateMetadata, metadataMap) 352 } 353 354 func retrieveTSDictionaries(sortables *[]Sortable, metadataMap MetadataMap) { 355 gplog.Verbose("Retrieving TEXT SEARCH DICTIONARY information") 356 dictionaries := GetTextSearchDictionaries(connectionPool) 357 objectCounts["Text Search Dictionaries"] = len(dictionaries) 358 dictionaryMetadata := GetMetadataForObjectType(connectionPool, TYPE_TS_DICTIONARY) 359 360 *sortables = append(*sortables, convertToSortableSlice(dictionaries)...) 361 addToMetadataMap(dictionaryMetadata, metadataMap) 362 } 363 364 func retrieveTSConfigurations(sortables *[]Sortable, metadataMap MetadataMap) { 365 gplog.Verbose("Retrieving TEXT SEARCH CONFIGURATION information") 366 configurations := GetTextSearchConfigurations(connectionPool) 367 objectCounts["Text Search Configurations"] = len(configurations) 368 configurationMetadata := GetMetadataForObjectType(connectionPool, TYPE_TS_CONFIGURATION) 369 370 *sortables = append(*sortables, convertToSortableSlice(configurations)...) 371 addToMetadataMap(configurationMetadata, metadataMap) 372 } 373 374 func retrieveOperatorObjects(sortables *[]Sortable, metadataMap MetadataMap) { 375 retrieveOperators(sortables, metadataMap) 376 retrieveOperatorClasses(sortables, metadataMap) 377 } 378 379 func retrieveOperators(sortables *[]Sortable, metadataMap MetadataMap) { 380 gplog.Verbose("Retrieving OPERATOR information") 381 operators := GetOperators(connectionPool) 382 objectCounts["Operators"] = len(operators) 383 operatorMetadata := GetMetadataForObjectType(connectionPool, TYPE_OPERATOR) 384 385 *sortables = append(*sortables, convertToSortableSlice(operators)...) 386 addToMetadataMap(operatorMetadata, metadataMap) 387 } 388 389 func retrieveOperatorClasses(sortables *[]Sortable, metadataMap MetadataMap) { 390 gplog.Verbose("Retrieving OPERATOR CLASS information") 391 operatorClasses := GetOperatorClasses(connectionPool) 392 objectCounts["Operator Classes"] = len(operatorClasses) 393 operatorClassMetadata := GetMetadataForObjectType(connectionPool, TYPE_OPERATOR_CLASS) 394 395 *sortables = append(*sortables, convertToSortableSlice(operatorClasses)...) 396 addToMetadataMap(operatorClassMetadata, metadataMap) 397 } 398 399 func retrieveAggregates(sortables *[]Sortable, metadataMap MetadataMap) { 400 gplog.Verbose("Retrieving AGGREGATE information") 401 aggregates := GetAggregates(connectionPool) 402 objectCounts["Aggregates"] = len(aggregates) 403 aggMetadata := GetMetadataForObjectType(connectionPool, TYPE_AGGREGATE) 404 405 *sortables = append(*sortables, convertToSortableSlice(aggregates)...) 406 addToMetadataMap(aggMetadata, metadataMap) 407 } 408 409 func retrieveCasts(sortables *[]Sortable, metadataMap MetadataMap) { 410 gplog.Verbose("Retrieving CAST information") 411 casts := GetCasts(connectionPool) 412 objectCounts["Casts"] = len(casts) 413 castMetadata := GetCommentsForObjectType(connectionPool, TYPE_CAST) 414 415 *sortables = append(*sortables, convertToSortableSlice(casts)...) 416 addToMetadataMap(castMetadata, metadataMap) 417 } 418 419 func retrieveFDWObjects(sortables *[]Sortable, metadataMap MetadataMap) { 420 if !connectionPool.Version.AtLeast("6") { 421 return 422 } 423 retrieveForeignDataWrappers(sortables, metadataMap) 424 retrieveForeignServers(sortables, metadataMap) 425 retrieveUserMappings(sortables) 426 } 427 428 func retrieveForeignDataWrappers(sortables *[]Sortable, metadataMap MetadataMap) { 429 gplog.Verbose("Writing CREATE FOREIGN DATA WRAPPER statements to metadata file") 430 wrappers := GetForeignDataWrappers(connectionPool) 431 objectCounts["Foreign Data Wrappers"] = len(wrappers) 432 fdwMetadata := GetMetadataForObjectType(connectionPool, TYPE_FOREIGN_DATA_WRAPPER) 433 434 *sortables = append(*sortables, convertToSortableSlice(wrappers)...) 435 addToMetadataMap(fdwMetadata, metadataMap) 436 } 437 438 func retrieveForeignServers(sortables *[]Sortable, metadataMap MetadataMap) { 439 gplog.Verbose("Writing CREATE SERVER statements to metadata file") 440 servers := GetForeignServers(connectionPool) 441 objectCounts["Foreign Servers"] = len(servers) 442 serverMetadata := GetMetadataForObjectType(connectionPool, TYPE_FOREIGN_SERVER) 443 444 *sortables = append(*sortables, convertToSortableSlice(servers)...) 445 addToMetadataMap(serverMetadata, metadataMap) 446 } 447 448 func retrieveUserMappings(sortables *[]Sortable) { 449 gplog.Verbose("Writing CREATE USER MAPPING statements to metadata file") 450 mappings := GetUserMappings(connectionPool) 451 objectCounts["User Mappings"] = len(mappings) 452 // No comments, owners, or ACLs on UserMappings so no need to get metadata 453 454 *sortables = append(*sortables, convertToSortableSlice(mappings)...) 455 } 456 457 func backupSessionGUC(metadataFile *utils.FileWithByteCount) { 458 gplog.Verbose("Writing Session Configuration Parameters to metadata file") 459 gucs := GetSessionGUCs(connectionPool) 460 PrintSessionGUCs(metadataFile, globalTOC, gucs) 461 } 462 463 /* 464 * Global metadata wrapper functions 465 */ 466 467 func backupTablespaces(metadataFile *utils.FileWithByteCount) { 468 gplog.Verbose("Writing CREATE TABLESPACE statements to metadata file") 469 tablespaces := GetTablespaces(connectionPool) 470 objectCounts["Tablespaces"] = len(tablespaces) 471 tablespaceMetadata := GetMetadataForObjectType(connectionPool, TYPE_TABLESPACE) 472 PrintCreateTablespaceStatements(metadataFile, globalTOC, tablespaces, tablespaceMetadata) 473 } 474 475 func backupCreateDatabase(metadataFile *utils.FileWithByteCount) { 476 gplog.Verbose("Writing CREATE DATABASE statement to metadata file") 477 defaultDB := GetDefaultDatabaseEncodingInfo(connectionPool) 478 db := GetDatabaseInfo(connectionPool) 479 dbMetadata := GetMetadataForObjectType(connectionPool, TYPE_DATABASE) 480 PrintCreateDatabaseStatement(metadataFile, globalTOC, defaultDB, db, dbMetadata) 481 } 482 483 func backupDatabaseGUCs(metadataFile *utils.FileWithByteCount) { 484 gplog.Verbose("Writing Database Configuration Parameters to metadata file") 485 databaseGucs := GetDatabaseGUCs(connectionPool) 486 objectCounts["Database GUCs"] = len(databaseGucs) 487 PrintDatabaseGUCs(metadataFile, globalTOC, databaseGucs, connectionPool.DBName) 488 } 489 490 func backupResourceQueues(metadataFile *utils.FileWithByteCount) { 491 gplog.Verbose("Writing CREATE RESOURCE QUEUE statements to metadata file") 492 resQueues := GetResourceQueues(connectionPool) 493 objectCounts["Resource Queues"] = len(resQueues) 494 resQueueMetadata := GetCommentsForObjectType(connectionPool, TYPE_RESOURCE_QUEUE) 495 PrintCreateResourceQueueStatements(metadataFile, globalTOC, resQueues, resQueueMetadata) 496 } 497 498 func backupResourceGroups(metadataFile *utils.FileWithByteCount) { 499 gplog.Verbose("Writing CREATE RESOURCE GROUP statements to metadata file") 500 if connectionPool.Version.Before("7") { 501 resGroups := GetResourceGroups[ResourceGroupBefore7](connectionPool) 502 objectCounts["Resource Groups"] = len(resGroups) 503 resGroupMetadata := GetCommentsForObjectType(connectionPool, TYPE_RESOURCE_GROUP) 504 PrintResetResourceGroupStatements(metadataFile, globalTOC) 505 PrintCreateResourceGroupStatementsBefore7(metadataFile, globalTOC, resGroups, resGroupMetadata) 506 } else { // GPDB7+ 507 resGroups := GetResourceGroups[ResourceGroupAtLeast7](connectionPool) 508 objectCounts["Resource Groups"] = len(resGroups) 509 resGroupMetadata := GetCommentsForObjectType(connectionPool, TYPE_RESOURCE_GROUP) 510 PrintResetResourceGroupStatements(metadataFile, globalTOC) 511 PrintCreateResourceGroupStatementsAtLeast7(metadataFile, globalTOC, resGroups, resGroupMetadata) 512 } 513 } 514 515 func backupRoles(metadataFile *utils.FileWithByteCount) { 516 gplog.Verbose("Writing CREATE ROLE statements to metadata file") 517 roles := GetRoles(connectionPool) 518 objectCounts["Roles"] = len(roles) 519 roleMetadata := GetMetadataForObjectType(connectionPool, TYPE_ROLE) 520 PrintCreateRoleStatements(metadataFile, globalTOC, roles, roleMetadata) 521 } 522 523 func backupRoleGUCs(metadataFile *utils.FileWithByteCount) { 524 gplog.Verbose("Writing ROLE Configuration Parameter to meadata file") 525 roleGUCs := GetRoleGUCs(connectionPool) 526 PrintRoleGUCStatements(metadataFile, globalTOC, roleGUCs) 527 } 528 529 func backupRoleGrants(metadataFile *utils.FileWithByteCount) { 530 gplog.Verbose("Writing GRANT ROLE statements to metadata file") 531 roleMembers := GetRoleMembers(connectionPool) 532 PrintRoleMembershipStatements(metadataFile, globalTOC, roleMembers) 533 } 534 535 /* 536 * Predata wrapper functions 537 */ 538 539 func backupSchemas(metadataFile *utils.FileWithByteCount, partitionAlteredSchemas map[string]bool) { 540 gplog.Verbose("Writing CREATE SCHEMA statements to metadata file") 541 schemas := GetAllUserSchemas(connectionPool, partitionAlteredSchemas) 542 objectCounts["Schemas"] = len(schemas) 543 schemaMetadata := GetMetadataForObjectType(connectionPool, TYPE_SCHEMA) 544 PrintCreateSchemaStatements(metadataFile, globalTOC, schemas, schemaMetadata) 545 } 546 547 func backupProceduralLanguages(metadataFile *utils.FileWithByteCount, 548 functions []Function, funcInfoMap map[uint32]FunctionInfo, functionMetadata MetadataMap) { 549 gplog.Verbose("Writing CREATE PROCEDURAL LANGUAGE statements to metadata file") 550 procLangs := GetProceduralLanguages(connectionPool) 551 objectCounts["Procedural Languages"] = len(procLangs) 552 langFuncs, _ := ExtractLanguageFunctions(functions, procLangs) 553 for _, langFunc := range langFuncs { 554 PrintCreateFunctionStatement(metadataFile, globalTOC, langFunc, functionMetadata[langFunc.GetUniqueID()]) 555 } 556 procLangMetadata := GetMetadataForObjectType(connectionPool, TYPE_PROC_LANGUAGE) 557 PrintCreateLanguageStatements(metadataFile, globalTOC, procLangs, funcInfoMap, procLangMetadata) 558 } 559 560 func backupShellTypes(metadataFile *utils.FileWithByteCount, shellTypes []ShellType, baseTypes []BaseType, rangeTypes []RangeType) { 561 gplog.Verbose("Writing CREATE TYPE statements for shell types to metadata file") 562 PrintCreateShellTypeStatements(metadataFile, globalTOC, shellTypes, baseTypes, rangeTypes) 563 } 564 565 func backupEnumTypes(metadataFile *utils.FileWithByteCount, typeMetadata MetadataMap) { 566 gplog.Verbose("Writing CREATE TYPE statements for enum types to metadata file") 567 enums := GetEnumTypes(connectionPool) 568 objectCounts["Types"] += len(enums) 569 PrintCreateEnumTypeStatements(metadataFile, globalTOC, enums, typeMetadata) 570 } 571 572 func backupAccessMethods(metadataFile *utils.FileWithByteCount) { 573 if connectionPool.Version.Before("7") { 574 return 575 } 576 gplog.Verbose("Writing CREATE ACCESS METHOD statements to metadata file") 577 accessMethods := GetAccessMethods(connectionPool) 578 objectCounts["Access Methods"] = len(accessMethods) 579 accessMethodsMetadata := GetMetadataForObjectType(connectionPool, TYPE_ACCESS_METHOD) 580 PrintAccessMethodStatements(metadataFile, globalTOC, accessMethods, accessMethodsMetadata) 581 } 582 583 func createBackupSet(objSlice []Sortable) (backupSet map[UniqueID]bool) { 584 backupSet = make(map[UniqueID]bool) 585 for _, obj := range objSlice { 586 backupSet[obj.GetUniqueID()] = true 587 } 588 589 return backupSet 590 } 591 592 func convertToSortableSlice(objSlice interface{}) []Sortable { 593 sortableSlice := make([]Sortable, 0) 594 s := reflect.ValueOf(objSlice) 595 596 ret := make([]interface{}, s.Len()) 597 598 for i := 0; i < s.Len(); i++ { 599 ret[i] = s.Index(i).Interface() 600 } 601 602 for _, obj := range ret { 603 newObj := obj.(Sortable) 604 sortableSlice = append(sortableSlice, newObj) 605 } 606 607 return sortableSlice 608 } 609 610 func addToMetadataMap(newMetadata MetadataMap, metadataMap MetadataMap) { 611 for k, v := range newMetadata { 612 metadataMap[k] = v 613 } 614 } 615 616 // This function is fairly unwieldy, but there's not really a good way to break it down 617 func backupDependentObjects(metadataFile *utils.FileWithByteCount, tables []Table, 618 protocols []ExternalProtocol, filteredMetadata MetadataMap, domainConstraints []Constraint, 619 sortables []Sortable, sequences []Sequence, funcInfoMap map[uint32]FunctionInfo, tableOnly bool) []View { 620 var sortedSlice []Sortable 621 gplog.Verbose("Writing CREATE statements for dependent objects to metadata file") 622 623 backupSet := createBackupSet(sortables) 624 relevantDeps := GetDependencies(connectionPool, backupSet, tables) 625 viewsDependingOnConstraints := MarkViewsDependingOnConstraints(sortables, relevantDeps) 626 sortedSlice, globalTierMap = TopologicalSort(sortables, relevantDeps) 627 628 PrintDependentObjectStatements(metadataFile, globalTOC, sortedSlice, filteredMetadata, domainConstraints, funcInfoMap) 629 PrintIdentityColumns(metadataFile, globalTOC, sequences) 630 PrintAlterSequenceStatements(metadataFile, globalTOC, sequences) 631 extPartInfo, partInfoMap := GetExternalPartitionInfo(connectionPool) 632 if connectionPool.Version.Before("7") && len(extPartInfo) > 0 { 633 gplog.Verbose("Writing EXCHANGE PARTITION statements to metadata file") 634 PrintExchangeExternalPartitionStatements(metadataFile, globalTOC, extPartInfo, partInfoMap, tables) 635 } 636 return viewsDependingOnConstraints 637 } 638 639 func backupConversions(metadataFile *utils.FileWithByteCount) { 640 gplog.Verbose("Writing CREATE CONVERSION statements to metadata file") 641 conversions := GetConversions(connectionPool) 642 objectCounts["Conversions"] = len(conversions) 643 convMetadata := GetMetadataForObjectType(connectionPool, TYPE_CONVERSION) 644 PrintCreateConversionStatements(metadataFile, globalTOC, conversions, convMetadata) 645 } 646 647 func backupOperatorFamilies(metadataFile *utils.FileWithByteCount) { 648 gplog.Verbose("Writing CREATE OPERATOR FAMILY statements to metadata file") 649 operatorFamilies := GetOperatorFamilies(connectionPool) 650 objectCounts["Operator Families"] = len(operatorFamilies) 651 operatorFamilyMetadata := GetMetadataForObjectType(connectionPool, TYPE_OPERATOR_FAMILY) 652 PrintCreateOperatorFamilyStatements(metadataFile, globalTOC, operatorFamilies, operatorFamilyMetadata) 653 } 654 655 func backupCollations(metadataFile *utils.FileWithByteCount) { 656 if !connectionPool.Version.AtLeast("6") { 657 return 658 } 659 gplog.Verbose("Writing CREATE COLLATION statements to metadata file") 660 collations := GetCollations(connectionPool) 661 objectCounts["Collations"] = len(collations) 662 collationMetadata := GetMetadataForObjectType(connectionPool, TYPE_COLLATION) 663 PrintCreateCollationStatements(metadataFile, globalTOC, collations, collationMetadata) 664 } 665 666 func backupExtensions(metadataFile *utils.FileWithByteCount) { 667 gplog.Verbose("Writing CREATE EXTENSION statements to metadata file") 668 extensions := GetExtensions(connectionPool) 669 objectCounts["Extensions"] = len(extensions) 670 extensionMetadata := GetCommentsForObjectType(connectionPool, TYPE_EXTENSION) 671 PrintCreateExtensionStatements(metadataFile, globalTOC, extensions, extensionMetadata) 672 } 673 674 func backupConstraints(metadataFile *utils.FileWithByteCount, constraints []Constraint, conMetadata MetadataMap) { 675 gplog.Verbose("Writing ADD CONSTRAINT statements to metadata file") 676 objectCounts["Constraints"] = len(constraints) 677 PrintConstraintStatements(metadataFile, globalTOC, constraints, conMetadata) 678 } 679 680 func backupViewsDependingOnConstraints(metadataFile *utils.FileWithByteCount, views []View) { 681 gplog.Verbose("Writing CREATE VIEW statements for views that depend on constraints to metadata file") 682 PrintCreatePostdataViewStatements(metadataFile, globalTOC, views) 683 } 684 685 /* 686 * Postdata wrapper functions 687 */ 688 689 func backupIndexes(metadataFile *utils.FileWithByteCount) { 690 gplog.Verbose("Writing CREATE INDEX statements to metadata file") 691 indexes := GetIndexes(connectionPool) 692 objectCounts["Indexes"] = len(indexes) 693 if objectCounts["Indexes"] > 0 && connectionPool.Version.Is("6") { 694 // This bug is not addressed in versions prior to GPDB6 695 // New partition exchange syntax in GPDB7+ obviates the need for this renaming 696 RenameExchangedPartitionIndexes(connectionPool, &indexes) 697 } 698 indexMetadata := GetCommentsForObjectType(connectionPool, TYPE_INDEX) 699 PrintCreateIndexStatements(metadataFile, globalTOC, indexes, indexMetadata) 700 } 701 702 func backupRules(metadataFile *utils.FileWithByteCount) { 703 gplog.Verbose("Writing CREATE RULE statements to metadata file") 704 rules := GetRules(connectionPool) 705 objectCounts["Rules"] = len(rules) 706 ruleMetadata := GetCommentsForObjectType(connectionPool, TYPE_RULE) 707 PrintCreateRuleStatements(metadataFile, globalTOC, rules, ruleMetadata) 708 } 709 710 func backupTriggers(metadataFile *utils.FileWithByteCount) { 711 gplog.Verbose("Writing CREATE TRIGGER statements to metadata file") 712 triggers := GetTriggers(connectionPool) 713 objectCounts["Triggers"] = len(triggers) 714 triggerMetadata := GetCommentsForObjectType(connectionPool, TYPE_TRIGGER) 715 PrintCreateTriggerStatements(metadataFile, globalTOC, triggers, triggerMetadata) 716 } 717 718 func backupEventTriggers(metadataFile *utils.FileWithByteCount) { 719 gplog.Verbose("Writing CREATE EVENT TRIGGER statements to metadata file") 720 eventTriggers := GetEventTriggers(connectionPool) 721 objectCounts["Event Triggers"] = len(eventTriggers) 722 eventTriggerMetadata := GetMetadataForObjectType(connectionPool, TYPE_EVENT_TRIGGER) 723 PrintCreateEventTriggerStatements(metadataFile, globalTOC, eventTriggers, eventTriggerMetadata) 724 } 725 726 func backupRowLevelSecurityPolicies(metadataFile *utils.FileWithByteCount) { 727 gplog.Verbose("Writing CREATE POLICY statements to metadata file") 728 policies := GetPolicies(connectionPool) 729 objectCounts["Policies"] = len(policies) 730 ruleMetadata := GetCommentsForObjectType(connectionPool, TYPE_RULE) 731 PrintCreatePolicyStatements(metadataFile, globalTOC, policies, ruleMetadata) 732 } 733 734 func backupDefaultPrivileges(metadataFile *utils.FileWithByteCount) { 735 gplog.Verbose("Writing ALTER DEFAULT PRIVILEGES statements to metadata file") 736 defaultPrivileges := GetDefaultPrivileges(connectionPool) 737 objectCounts["DEFAULT PRIVILEGES"] = len(defaultPrivileges) 738 PrintDefaultPrivilegesStatements(metadataFile, globalTOC, defaultPrivileges) 739 } 740 741 func backupExtendedStatistic(metadataFile *utils.FileWithByteCount) { 742 gplog.Verbose("Writing CREATE STATISTICS statements to metadata file (for extended statistics)") 743 statisticsExt := GetExtendedStatistics(connectionPool) 744 objectCounts[toc.OBJ_STATISTICS_EXT] = len(statisticsExt) 745 statisticExtMetadata := GetMetadataForObjectType(connectionPool, TYPE_STATISTIC_EXT) 746 PrintCreateExtendedStatistics(metadataFile, globalTOC, statisticsExt, statisticExtMetadata) 747 } 748 749 /* 750 * Data wrapper functions 751 */ 752 753 func backupTableStatistics(statisticsFile *utils.FileWithByteCount, tables []Table) { 754 attStats := GetAttributeStatistics(connectionPool, tables) 755 tupleStats := GetTupleStatistics(connectionPool, tables) 756 757 backupSessionGUC(statisticsFile) 758 PrintStatisticsStatements(statisticsFile, globalTOC, tables, attStats, tupleStats) 759 } 760 761 func backupIncrementalMetadata() { 762 aoTableEntries := GetAOIncrementalMetadata(connectionPool) 763 globalTOC.IncrementalMetadata.AO = aoTableEntries 764 }