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  }