github.com/tuhaihe/gpbackup@v1.0.3/integration/predata_acl_queries_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/tuhaihe/gp-common-go-libs/structmatcher"
     7  	"github.com/tuhaihe/gp-common-go-libs/testhelper"
     8  	"github.com/tuhaihe/gpbackup/backup"
     9  	"github.com/tuhaihe/gpbackup/options"
    10  	"github.com/tuhaihe/gpbackup/testutils"
    11  
    12  	. "github.com/onsi/ginkgo/v2"
    13  	. "github.com/onsi/gomega"
    14  )
    15  
    16  var _ = Describe("backup integration tests", func() {
    17  	Describe("GetMetadataForObjectType", func() {
    18  		Context("default metadata for all objects of one type", func() {
    19  			It("returns a slice of metadata with modified privileges", func() {
    20  				testhelper.AssertQueryRuns(connectionPool, "CREATE TABLE public.foo(i int)")
    21  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE public.foo")
    22  				testhelper.AssertQueryRuns(connectionPool, "REVOKE DELETE ON TABLE public.foo FROM testrole")
    23  				testhelper.AssertQueryRuns(connectionPool, "CREATE TABLE public.bar(i int)")
    24  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE public.bar")
    25  				testhelper.AssertQueryRuns(connectionPool, "REVOKE ALL ON TABLE public.bar FROM testrole")
    26  				testhelper.AssertQueryRuns(connectionPool, "CREATE TABLE public.baz(i int)")
    27  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE public.baz")
    28  				testhelper.AssertQueryRuns(connectionPool, "GRANT ALL ON TABLE public.baz TO anothertestrole")
    29  
    30  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_RELATION)
    31  
    32  				fooUniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "foo", backup.TYPE_RELATION)
    33  				barUniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "bar", backup.TYPE_RELATION)
    34  				bazUniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "baz", backup.TYPE_RELATION)
    35  				expectedFoo := backup.ObjectMetadata{ObjectType: "RELATION", Privileges: []backup.ACL{testutils.DefaultACLWithout("testrole", "TABLE", "DELETE")}, Owner: "testrole"}
    36  				expectedBar := backup.ObjectMetadata{ObjectType: "RELATION", Privileges: []backup.ACL{{Grantee: "GRANTEE"}}, Owner: "testrole"}
    37  				expectedBaz := backup.ObjectMetadata{ObjectType: "RELATION", Privileges: []backup.ACL{testutils.DefaultACLForType("anothertestrole", "TABLE"), testutils.DefaultACLForType("testrole", "TABLE")}, Owner: "testrole"}
    38  				Expect(resultMetadataMap).To(HaveLen(3))
    39  				resultFoo := resultMetadataMap[fooUniqueID]
    40  				resultBar := resultMetadataMap[barUniqueID]
    41  				resultBaz := resultMetadataMap[bazUniqueID]
    42  				structmatcher.ExpectStructsToMatch(&resultFoo, &expectedFoo)
    43  				structmatcher.ExpectStructsToMatch(&resultBar, &expectedBar)
    44  				structmatcher.ExpectStructsToMatch(&resultBaz, &expectedBaz)
    45  			})
    46  			It("returns a slice of default metadata for a database", func() {
    47  				testhelper.AssertQueryRuns(connectionPool, "GRANT ALL ON DATABASE testdb TO anothertestrole")
    48  				defer testhelper.AssertQueryRuns(connectionPool, "REVOKE ALL ON DATABASE testdb FROM anothertestRole")
    49  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON DATABASE testdb IS 'This is a database comment.'")
    50  				testutils.CreateSecurityLabelIfGPDB6(connectionPool, "DATABASE", "testdb")
    51  				expectedMetadata := backup.ObjectMetadata{
    52  					ObjectType: "DATABASE", Privileges: []backup.ACL{
    53  						{Grantee: "", Temporary: true, Connect: true},
    54  						{Grantee: "anothertestrole", Create: true, Temporary: true, Connect: true},
    55  					}, Owner: "anothertestrole", Comment: "This is a database comment."}
    56  				if includeSecurityLabels {
    57  					expectedMetadata.SecurityLabelProvider = "dummy"
    58  					expectedMetadata.SecurityLabel = "unclassified"
    59  				}
    60  
    61  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_DATABASE)
    62  
    63  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "testdb", backup.TYPE_DATABASE)
    64  				resultMetadata := resultMetadataMap[uniqueID]
    65  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid", "schema")
    66  			})
    67  			It("returns a slice of default metadata for a role", func() {
    68  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_ROLE)
    69  				numRoles := len(resultMetadataMap)
    70  
    71  				testhelper.AssertQueryRuns(connectionPool, `CREATE ROLE testuser`)
    72  				defer testhelper.AssertQueryRuns(connectionPool, "DROP ROLE testuser")
    73  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON ROLE testuser IS 'This is a role comment.'")
    74  				testutils.CreateSecurityLabelIfGPDB6(connectionPool, "ROLE", "testuser")
    75  
    76  				resultMetadataMap = backup.GetMetadataForObjectType(connectionPool, backup.TYPE_ROLE)
    77  
    78  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "testuser", backup.TYPE_ROLE)
    79  				expectedMetadata := testutils.DefaultMetadata("ROLE", false, false, true, includeSecurityLabels)
    80  
    81  				Expect(resultMetadataMap).To(HaveLen(numRoles + 1))
    82  				resultMetadata := resultMetadataMap[uniqueID]
    83  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
    84  			})
    85  			It("returns a slice of metadata with the owner in quotes", func() {
    86  				testhelper.AssertQueryRuns(connectionPool, `CREATE ROLE "Role1"`)
    87  				defer testhelper.AssertQueryRuns(connectionPool, `DROP ROLE "Role1"`)
    88  				testhelper.AssertQueryRuns(connectionPool, "CREATE TABLE public.testtable(i int)")
    89  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE public.testtable")
    90  				testhelper.AssertQueryRuns(connectionPool, `ALTER TABLE public.testtable OWNER TO "Role1"`)
    91  
    92  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_RELATION)
    93  
    94  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "testtable", backup.TYPE_RELATION)
    95  				expectedMetadata := backup.ObjectMetadata{ObjectType: "RELATION", Privileges: []backup.ACL{}, Owner: `"Role1"`}
    96  				Expect(resultMetadataMap).To(HaveLen(1))
    97  				resultMetadata := resultMetadataMap[uniqueID]
    98  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
    99  			})
   100  			It("returns a slice of default metadata for a table", func() {
   101  				testhelper.AssertQueryRuns(connectionPool, "CREATE TABLE public.testtable(i int)")
   102  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE public.testtable")
   103  				testhelper.AssertQueryRuns(connectionPool, "GRANT ALL ON TABLE public.testtable TO testrole")
   104  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON TABLE public.testtable IS 'This is a table comment.'")
   105  				testutils.CreateSecurityLabelIfGPDB6(connectionPool, "TABLE", "public.testtable")
   106  
   107  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_RELATION)
   108  
   109  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "testtable", backup.TYPE_RELATION)
   110  				expectedMetadata := testutils.DefaultMetadata("TABLE", true, true, true, includeSecurityLabels)
   111  				Expect(resultMetadataMap).To(HaveLen(1))
   112  				resultMetadata := resultMetadataMap[uniqueID]
   113  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   114  			})
   115  			It("returns a slice of default metadata for a sequence", func() {
   116  				testhelper.AssertQueryRuns(connectionPool, "CREATE SEQUENCE public.testsequence")
   117  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SEQUENCE public.testsequence")
   118  				testhelper.AssertQueryRuns(connectionPool, "GRANT ALL ON SEQUENCE public.testsequence TO testrole")
   119  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON SEQUENCE public.testsequence IS 'This is a sequence comment.'")
   120  				testutils.CreateSecurityLabelIfGPDB6(connectionPool, "SEQUENCE", "public.testsequence")
   121  
   122  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_RELATION)
   123  
   124  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "testsequence", backup.TYPE_RELATION)
   125  				expectedMetadata := testutils.DefaultMetadata("SEQUENCE", true, true, true, includeSecurityLabels)
   126  				Expect(resultMetadataMap).To(HaveLen(1))
   127  				resultMetadata := resultMetadataMap[uniqueID]
   128  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   129  			})
   130  			It("returns a slice of default metadata for a procedural language", func() {
   131  				plpythonString := "plpythonu"
   132  				if true {
   133  					plpythonString = "plpython3u"
   134  				}
   135  				testhelper.AssertQueryRuns(connectionPool, fmt.Sprintf("CREATE LANGUAGE %s", plpythonString))
   136  				defer testhelper.AssertQueryRuns(connectionPool, fmt.Sprintf("DROP LANGUAGE %s", plpythonString))
   137  				testhelper.AssertQueryRuns(connectionPool, fmt.Sprintf("COMMENT ON LANGUAGE %s IS 'This is a language comment.'", plpythonString))
   138  				testutils.CreateSecurityLabelIfGPDB6(connectionPool, "LANGUAGE", plpythonString)
   139  
   140  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_PROCLANGUAGE)
   141  
   142  				var expectedMetadata backup.ObjectMetadata
   143  				if false {
   144  					langOwner := testutils.GetUserByID(connectionPool, 10)
   145  					expectedMetadata = backup.ObjectMetadata{ObjectType: "LANGUAGE", Privileges: []backup.ACL{}, Owner: langOwner, Comment: "This is a language comment."}
   146  				} else {
   147  					expectedMetadata = testutils.DefaultMetadata("LANGUAGE", false, true, true, includeSecurityLabels)
   148  				}
   149  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", plpythonString, backup.TYPE_PROCLANGUAGE)
   150  				resultMetadata := resultMetadataMap[uniqueID]
   151  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   152  			})
   153  			It("returns metadata for an empty {} ACL (not NULL)", func() {
   154  				testhelper.AssertQueryRuns(connectionPool, `CREATE FUNCTION public.add(integer, integer) RETURNS integer
   155  AS 'SELECT $1 + $2'
   156  LANGUAGE SQL`)
   157  				defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.add(integer, integer)")
   158  				testhelper.AssertQueryRuns(connectionPool, "REVOKE ALL ON FUNCTION public.add(integer, integer) FROM public")
   159  				testhelper.AssertQueryRuns(connectionPool, "REVOKE ALL ON FUNCTION public.add(integer, integer) FROM testrole")
   160  				testutils.CreateSecurityLabelIfGPDB6(connectionPool, "FUNCTION", "public.add(integer, integer)")
   161  
   162  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_FUNCTION)
   163  				Expect(resultMetadataMap).To(HaveLen(1))
   164  
   165  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "add", backup.TYPE_FUNCTION)
   166  				resultMetadata := resultMetadataMap[uniqueID]
   167  
   168  				// important: in the case where SQL reports ACL list = {}, and not null,
   169  				// we expect there to be a default ACL with ALL BOOLEANS FALSE, which prints as
   170  				// just the 2 default "REVOKE" and no additional grant because all booleans false.
   171  				Expect(resultMetadata.Privileges).To(HaveLen(1))
   172  
   173  				slabel := ""
   174  				slabelProvider := ""
   175  				if true {
   176  					slabel = "unclassified"
   177  					slabelProvider = "dummy"
   178  				}
   179  				expectedMetadata := backup.ObjectMetadata{ObjectType: "FUNCTION", Privileges: []backup.ACL{{Grantee: "GRANTEE"}}, Owner: "testrole", SecurityLabel: slabel, SecurityLabelProvider: slabelProvider}
   180  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   181  			})
   182  			It("returns metadata for a function with a grant and revoke", func() {
   183  				testhelper.AssertQueryRuns(connectionPool, `CREATE FUNCTION public.add(integer, integer) RETURNS integer
   184  AS 'SELECT $1 + $2'
   185  LANGUAGE SQL`)
   186  				defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.add(integer, integer)")
   187  				// for Function objects:
   188  				// `public` and the user that created the function (`testrole`) exist in the ACL by default. However, the ACL is not explicitly represented unless these defaults are modified.
   189  				testhelper.AssertQueryRuns(connectionPool, "GRANT ALL ON FUNCTION public.add(integer, integer) TO testrole")
   190  				testhelper.AssertQueryRuns(connectionPool, "REVOKE ALL ON FUNCTION public.add(integer, integer) FROM PUBLIC")
   191  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON FUNCTION public.add(integer, integer) IS 'This is a function comment.'")
   192  				testutils.CreateSecurityLabelIfGPDB6(connectionPool, "FUNCTION", "public.add(integer, integer)")
   193  
   194  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_FUNCTION)
   195  				Expect(resultMetadataMap).To(HaveLen(1))
   196  
   197  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "add", backup.TYPE_FUNCTION)
   198  				resultMetadata := resultMetadataMap[uniqueID]
   199  				Expect(resultMetadata.Privileges).To(HaveLen(1))
   200  
   201  				expectedMetadata := testutils.DefaultMetadata("FUNCTION", true, true, true, includeSecurityLabels)
   202  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   203  			})
   204  			It("returns a slice of default metadata for a view", func() {
   205  				testhelper.AssertQueryRuns(connectionPool, `CREATE VIEW public.testview AS SELECT * FROM pg_class`)
   206  				defer testhelper.AssertQueryRuns(connectionPool, "DROP VIEW public.testview")
   207  				testhelper.AssertQueryRuns(connectionPool, "GRANT ALL ON public.testview TO testrole")
   208  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON VIEW public.testview IS 'This is a view comment.'")
   209  				testutils.CreateSecurityLabelIfGPDB6(connectionPool, "VIEW", "public.testview")
   210  
   211  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_RELATION)
   212  
   213  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "testview", backup.TYPE_RELATION)
   214  				expectedMetadata := testutils.DefaultMetadata("VIEW", true, true, true, includeSecurityLabels)
   215  				Expect(resultMetadataMap).To(HaveLen(1))
   216  				resultMetadata := resultMetadataMap[uniqueID]
   217  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   218  			})
   219  			It("returns a slice of default metadata for a materialized view", func() {
   220  				testhelper.AssertQueryRuns(connectionPool, `CREATE MATERIALIZED VIEW public.testmview AS SELECT * FROM pg_class`)
   221  				defer testhelper.AssertQueryRuns(connectionPool, "DROP MATERIALIZED VIEW public.testmview")
   222  				testhelper.AssertQueryRuns(connectionPool, "GRANT ALL ON public.testmview TO testrole")
   223  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON MATERIALIZED VIEW public.testmview IS 'This is a materialized view comment.'")
   224  				testutils.CreateSecurityLabelIfGPDB6(connectionPool, "MATERIALIZED VIEW", "public.testmview")
   225  
   226  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_RELATION)
   227  
   228  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "testmview", backup.TYPE_RELATION)
   229  				expectedMetadata := testutils.DefaultMetadata("MATERIALIZED VIEW", true, true, true, includeSecurityLabels)
   230  				Expect(resultMetadataMap).To(HaveLen(1))
   231  				resultMetadata := resultMetadataMap[uniqueID]
   232  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   233  			})
   234  			It("returns a slice of default metadata for a schema", func() {
   235  				testhelper.AssertQueryRuns(connectionPool, `CREATE SCHEMA testschema`)
   236  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
   237  				testhelper.AssertQueryRuns(connectionPool, "GRANT ALL ON SCHEMA testschema TO testrole")
   238  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON SCHEMA testschema IS 'This is a schema comment.'")
   239  				testutils.CreateSecurityLabelIfGPDB6(connectionPool, "SCHEMA", "testschema")
   240  
   241  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_SCHEMA)
   242  
   243  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "testschema", backup.TYPE_SCHEMA)
   244  				expectedMetadata := testutils.DefaultMetadata("SCHEMA", true, true, true, includeSecurityLabels)
   245  				resultMetadata := resultMetadataMap[uniqueID]
   246  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   247  			})
   248  			It("returns a slice of default metadata for an aggregate", func() {
   249  				testhelper.AssertQueryRuns(connectionPool, `
   250  			CREATE FUNCTION public.mysfunc_accum(numeric, numeric, numeric)
   251  			   RETURNS numeric
   252  			   AS 'select $1 + $2 + $3'
   253  			   LANGUAGE SQL
   254  			   IMMUTABLE
   255  			   RETURNS NULL ON NULL INPUT;
   256  			`)
   257  				defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.mysfunc_accum(numeric, numeric, numeric)")
   258  				testhelper.AssertQueryRuns(connectionPool, `
   259  			CREATE FUNCTION public.mypre_accum(numeric, numeric)
   260  			   RETURNS numeric
   261  			   AS 'select $1 + $2'
   262  			   LANGUAGE SQL
   263  			   IMMUTABLE
   264  			   RETURNS NULL ON NULL INPUT;
   265  			`)
   266  				defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.mypre_accum(numeric, numeric)")
   267  				testhelper.AssertQueryRuns(connectionPool, `CREATE AGGREGATE public.agg_prefunc(numeric, numeric) (
   268  	SFUNC = public.mysfunc_accum,
   269  	STYPE = numeric,
   270  	PREFUNC = public.mypre_accum,
   271  	INITCOND = '0'
   272  );`)
   273  				defer testhelper.AssertQueryRuns(connectionPool, "DROP AGGREGATE public.agg_prefunc(numeric, numeric)")
   274  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON AGGREGATE public.agg_prefunc(numeric, numeric) IS 'This is an aggregate comment.'")
   275  				testutils.CreateSecurityLabelIfGPDB6(connectionPool, "AGGREGATE", "public.agg_prefunc(numeric, numeric)")
   276  
   277  				testhelper.AssertQueryRuns(connectionPool, `
   278  				GRANT ALL ON FUNCTION public.agg_prefunc(numeric, numeric)
   279  				  to testrole`)
   280  				testhelper.AssertQueryRuns(connectionPool, `
   281  				REVOKE ALL ON FUNCTION public.agg_prefunc(numeric, numeric) FROM public`)
   282  
   283  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_AGGREGATE)
   284  
   285  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "agg_prefunc", backup.TYPE_AGGREGATE)
   286  				expectedMetadata := testutils.DefaultMetadata("AGGREGATE", true, true, true, includeSecurityLabels)
   287  				resultMetadata := resultMetadataMap[uniqueID]
   288  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   289  			})
   290  			It("returns a slice of default metadata for a type", func() {
   291  				testhelper.AssertQueryRuns(connectionPool, `CREATE TYPE public.testtype AS (name text, num numeric)`)
   292  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TYPE public.testtype")
   293  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON TYPE public.testtype IS 'This is a type comment.'")
   294  				testutils.CreateSecurityLabelIfGPDB6(connectionPool, "TYPE", "public.testtype")
   295  
   296  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_TYPE)
   297  
   298  				typeUniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "testtype", backup.TYPE_TYPE)
   299  				expectedMetadata := testutils.DefaultMetadata("TYPE", false, true, true, includeSecurityLabels)
   300  				resultMetadata := resultMetadataMap[typeUniqueID]
   301  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   302  			})
   303  			It("returns a slice of default metadata for a domain", func() {
   304  				testhelper.AssertQueryRuns(connectionPool, `CREATE DOMAIN public.domain_type AS numeric`)
   305  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TYPE public.domain_type")
   306  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON DOMAIN public.domain_type IS 'This is a domain comment.'")
   307  				testutils.CreateSecurityLabelIfGPDB6(connectionPool, "DOMAIN", "public.domain_type")
   308  
   309  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_TYPE)
   310  
   311  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "domain_type", backup.TYPE_TYPE)
   312  				expectedMetadata := testutils.DefaultMetadata("DOMAIN", false, true, true, includeSecurityLabels)
   313  				resultMetadata := resultMetadataMap[uniqueID]
   314  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   315  			})
   316  			It("returns a slice of default metadata for an external protocol", func() {
   317  				testhelper.AssertQueryRuns(connectionPool, `CREATE OR REPLACE FUNCTION public.read_from_s3() RETURNS integer AS '$libdir/gps3ext.so', 's3_import' LANGUAGE C STABLE;`)
   318  				defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.read_from_s3()")
   319  				testhelper.AssertQueryRuns(connectionPool, `CREATE TRUSTED PROTOCOL s3_read (readfunc = public.read_from_s3);`)
   320  				defer testhelper.AssertQueryRuns(connectionPool, "DROP PROTOCOL s3_read")
   321  				testhelper.AssertQueryRuns(connectionPool, "GRANT ALL ON PROTOCOL s3_read TO testrole")
   322  
   323  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_PROTOCOL)
   324  
   325  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "s3_read", backup.TYPE_PROTOCOL)
   326  				expectedMetadata := testutils.DefaultMetadata("PROTOCOL", true, true, false, false)
   327  				resultMetadata := resultMetadataMap[uniqueID]
   328  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   329  			})
   330  			It("returns a slice of default metadata for a tablespace", func() {
   331  				if false {
   332  					testhelper.AssertQueryRuns(connectionPool, "CREATE TABLESPACE test_tablespace FILESPACE test_dir")
   333  				} else {
   334  					testhelper.AssertQueryRuns(connectionPool, "CREATE TABLESPACE test_tablespace LOCATION '/tmp/test_dir'")
   335  				}
   336  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLESPACE test_tablespace")
   337  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON TABLESPACE test_tablespace IS 'This is a tablespace comment.'")
   338  				testhelper.AssertQueryRuns(connectionPool, "GRANT ALL ON TABLESPACE test_tablespace TO testrole")
   339  				testutils.CreateSecurityLabelIfGPDB6(connectionPool, "TABLESPACE", "test_tablespace")
   340  
   341  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_TABLESPACE)
   342  
   343  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "test_tablespace", backup.TYPE_TABLESPACE)
   344  				expectedMetadata := testutils.DefaultMetadata("TABLESPACE", true, true, true, includeSecurityLabels)
   345  				resultMetadata := resultMetadataMap[uniqueID]
   346  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   347  			})
   348  			It("returns a slice of default metadata for an operator", func() {
   349  				testhelper.AssertQueryRuns(connectionPool, "CREATE OPERATOR public.#### (LEFTARG = bigint, PROCEDURE = numeric_fac)")
   350  				defer testhelper.AssertQueryRuns(connectionPool, "DROP OPERATOR public.#### (bigint, NONE)")
   351  
   352  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON OPERATOR public.#### (bigint, NONE) IS 'This is an operator comment.'")
   353  
   354  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_OPERATOR)
   355  
   356  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "####", backup.TYPE_OPERATOR)
   357  				expectedMetadata := testutils.DefaultMetadata("OPERATOR", false, true, true, false)
   358  				resultMetadata := resultMetadataMap[uniqueID]
   359  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   360  			})
   361  			It("returns a slice of default metadata for an operator family", func() {
   362  				testutils.SkipIfBefore5(connectionPool)
   363  				testhelper.AssertQueryRuns(connectionPool, "CREATE OPERATOR FAMILY public.testfam USING hash")
   364  				defer testhelper.AssertQueryRuns(connectionPool, "DROP OPERATOR FAMILY public.testfam USING hash")
   365  
   366  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON OPERATOR FAMILY public.testfam USING hash IS 'This is an operator family comment.'")
   367  
   368  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_OPERATORFAMILY)
   369  
   370  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "testfam", backup.TYPE_OPERATORFAMILY)
   371  				expectedMetadata := testutils.DefaultMetadata("OPERATOR FAMILY", false, true, true, false)
   372  				resultMetadata := resultMetadataMap[uniqueID]
   373  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   374  			})
   375  			It("returns a slice of default metadata for an operator class", func() {
   376  				testhelper.AssertQueryRuns(connectionPool, "CREATE OPERATOR CLASS public.testclass FOR TYPE int USING hash AS STORAGE int")
   377  				if false {
   378  					defer testhelper.AssertQueryRuns(connectionPool, "DROP OPERATOR CLASS public.testclass USING hash")
   379  				} else {
   380  					defer testhelper.AssertQueryRuns(connectionPool, "DROP OPERATOR FAMILY public.testclass USING hash")
   381  				}
   382  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON OPERATOR CLASS public.testclass USING hash IS 'This is an operator class comment.'")
   383  
   384  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_OPERATORCLASS)
   385  
   386  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "testclass", backup.TYPE_OPERATORCLASS)
   387  				expectedMetadata := testutils.DefaultMetadata("OPERATOR CLASS", false, true, true, false)
   388  				resultMetadata := resultMetadataMap[uniqueID]
   389  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   390  			})
   391  			It("returns a slice of default metadata for a text search dictionary", func() {
   392  				testutils.SkipIfBefore5(connectionPool)
   393  				testhelper.AssertQueryRuns(connectionPool, "CREATE TEXT SEARCH DICTIONARY public.testdictionary(TEMPLATE = snowball, LANGUAGE = 'russian', STOPWORDS = 'russian');")
   394  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TEXT SEARCH DICTIONARY public.testdictionary")
   395  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON TEXT SEARCH DICTIONARY public.testdictionary IS 'This is a text search dictionary comment.'")
   396  
   397  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_TSDICTIONARY)
   398  
   399  				Expect(resultMetadataMap).To(HaveLen(1))
   400  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "testdictionary", backup.TYPE_TSDICTIONARY)
   401  				dictionaryMetadata := testutils.DefaultMetadata("TEXT SEARCH DICTIONARY", false, true, true, false)
   402  				resultMetadata := resultMetadataMap[uniqueID]
   403  				structmatcher.ExpectStructsToMatch(&dictionaryMetadata, &resultMetadata)
   404  			})
   405  			It("returns a slice of default metadata for a text search configuration", func() {
   406  				testutils.SkipIfBefore5(connectionPool)
   407  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_TSCONFIGURATION)
   408  				configurationMetadata := testutils.DefaultMetadata("TEXT SEARCH CONFIGURATION", false, true, true, false)
   409  
   410  				testhelper.AssertQueryRuns(connectionPool, `CREATE TEXT SEARCH CONFIGURATION public.testconfiguration (PARSER = pg_catalog."default");`)
   411  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TEXT SEARCH CONFIGURATION public.testconfiguration")
   412  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON TEXT SEARCH CONFIGURATION public.testconfiguration IS 'This is a text search configuration comment.'")
   413  
   414  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "testconfiguration", backup.TYPE_TSCONFIGURATION)
   415  				resultMetadataMap = backup.GetMetadataForObjectType(connectionPool, backup.TYPE_TSCONFIGURATION)
   416  
   417  				Expect(resultMetadataMap).To(HaveLen(1))
   418  				resultMetadata := resultMetadataMap[uniqueID]
   419  				structmatcher.ExpectStructsToMatch(&configurationMetadata, &resultMetadata)
   420  			})
   421  			It("returns a slice of default metadata for a foreign data wrapper", func() {
   422  				testutils.SkipIfBefore6(connectionPool)
   423  				testhelper.AssertQueryRuns(connectionPool, "CREATE FOREIGN DATA WRAPPER foreignwrapper")
   424  				defer testhelper.AssertQueryRuns(connectionPool, "DROP FOREIGN DATA WRAPPER foreignwrapper")
   425  
   426  				testhelper.AssertQueryRuns(connectionPool, "GRANT ALL ON FOREIGN DATA WRAPPER foreignwrapper TO testrole")
   427  
   428  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_FOREIGNDATAWRAPPER)
   429  
   430  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "foreignwrapper", backup.TYPE_FOREIGNDATAWRAPPER)
   431  				expectedMetadata := testutils.DefaultMetadata("FOREIGN DATA WRAPPER", true, true, false, false)
   432  				resultMetadata := resultMetadataMap[uniqueID]
   433  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   434  			})
   435  			It("returns a slice of default metadata for a foreign server", func() {
   436  				testutils.SkipIfBefore6(connectionPool)
   437  				testhelper.AssertQueryRuns(connectionPool, "CREATE FOREIGN DATA WRAPPER foreignwrapper")
   438  				defer testhelper.AssertQueryRuns(connectionPool, "DROP FOREIGN DATA WRAPPER foreignwrapper CASCADE")
   439  				testhelper.AssertQueryRuns(connectionPool, "CREATE SERVER foreignserver FOREIGN DATA WRAPPER foreignwrapper")
   440  
   441  				testhelper.AssertQueryRuns(connectionPool, "GRANT ALL ON FOREIGN SERVER foreignserver TO testrole")
   442  
   443  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_FOREIGNSERVER)
   444  
   445  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "foreignserver", backup.TYPE_FOREIGNSERVER)
   446  				expectedMetadata := testutils.DefaultMetadata("FOREIGN SERVER", true, true, false, false)
   447  				resultMetadata := resultMetadataMap[uniqueID]
   448  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   449  			})
   450  			It("returns a slice of default metadata for a collation", func() {
   451  				testutils.SkipIfBefore6(connectionPool)
   452  				testhelper.AssertQueryRuns(connectionPool, `CREATE COLLATION public.some_coll (lc_collate = 'POSIX', lc_ctype = 'POSIX');`)
   453  				defer testhelper.AssertQueryRuns(connectionPool, "DROP COLLATION public.some_coll")
   454  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON COLLATION public.some_coll IS 'This is a collation comment.'")
   455  
   456  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_COLLATION)
   457  
   458  				Expect(resultMetadataMap).To(HaveLen(1))
   459  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "some_coll", backup.TYPE_COLLATION)
   460  				collationMetadata := testutils.DefaultMetadata("COLLATION", false, true, true, false)
   461  				resultMetadata := resultMetadataMap[uniqueID]
   462  				structmatcher.ExpectStructsToMatch(&collationMetadata, &resultMetadata)
   463  			})
   464  			It("returns a slice of default metadata for an event trigger", func() {
   465  				testutils.SkipIfBefore6(connectionPool)
   466  				testhelper.AssertQueryRuns(connectionPool, `CREATE FUNCTION abort_any_command()
   467  RETURNS event_trigger LANGUAGE plpgsql
   468  AS $$ BEGIN RAISE EXCEPTION 'exception'; END; $$;`)
   469  				defer testhelper.AssertQueryRuns(connectionPool, `DROP FUNCTION abort_any_command()`)
   470  				testhelper.AssertQueryRuns(connectionPool, "CREATE EVENT TRIGGER test_event_trigger ON ddl_command_start EXECUTE PROCEDURE abort_any_command();")
   471  				defer testhelper.AssertQueryRuns(connectionPool, "DROP EVENT TRIGGER test_event_trigger")
   472  				testutils.CreateSecurityLabelIfGPDB6(connectionPool, "EVENT TRIGGER", "test_event_trigger")
   473  
   474  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON EVENT TRIGGER test_event_trigger IS 'This is an event trigger comment.'")
   475  
   476  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_EVENTTRIGGER)
   477  
   478  				Expect(resultMetadataMap).To(HaveLen(1))
   479  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "test_event_trigger", backup.TYPE_EVENTTRIGGER)
   480  				eventTriggerMetadata := testutils.DefaultMetadata("EVENT TRIGGER", false, true, true, true)
   481  				resultMetadata := resultMetadataMap[uniqueID]
   482  				structmatcher.ExpectStructsToMatch(&eventTriggerMetadata, &resultMetadata)
   483  			})
   484  			It("returns ACL information for a newly declared TYPE_TYPE object", func() {
   485  				testutils.SkipIfBefore6(connectionPool)
   486  				testhelper.AssertQueryRuns(connectionPool, `CREATE TYPE public.my_type AS (i int)`)
   487  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TYPE public.my_type")
   488  				testhelper.AssertQueryRuns(connectionPool, `GRANT USAGE ON TYPE public.my_type TO testrole`)
   489  				defer testhelper.AssertQueryRuns(connectionPool, "REVOKE usage on type public.my_type from testrole")
   490  				// public usage creates an entry in the ACL with GRANTEE="" . We revoke this for ease of testing.
   491  				testhelper.AssertQueryRuns(connectionPool, "REVOKE usage on type public.my_type from public")
   492  
   493  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_TYPE)
   494  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "my_type", backup.TYPE_TYPE)
   495  				resultMetadata := resultMetadataMap[uniqueID]
   496  
   497  				// (1) the 'my_type' obj   ...  (2) the implicit 'i INT' type, created when instantiating 'my_type'
   498  				Expect(resultMetadataMap).To(HaveLen(2))
   499  
   500  				expectedMetadata := testutils.DefaultMetadata("TYPE", true, true, false, false)
   501  				expectedMetadata.Privileges[0].Usage = true
   502  				Expect(&resultMetadata).To(Equal(&expectedMetadata))
   503  			})
   504  		})
   505  		Context("metadata for objects in a specific schema", func() {
   506  			It("returns a slice of default metadata for a table in a specific schema", func() {
   507  				testhelper.AssertQueryRuns(connectionPool, "CREATE TABLE public.testtable(i int)")
   508  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE public.testtable")
   509  				testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
   510  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
   511  				testhelper.AssertQueryRuns(connectionPool, "CREATE TABLE testschema.testtable(i int)")
   512  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE testschema.testtable")
   513  				testhelper.AssertQueryRuns(connectionPool, "GRANT ALL ON TABLE testschema.testtable TO testrole")
   514  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON TABLE testschema.testtable IS 'This is a table comment.'")
   515  				_ = backupCmdFlags.Set(options.INCLUDE_SCHEMA, "testschema")
   516  
   517  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_RELATION)
   518  
   519  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "testschema", "testtable", backup.TYPE_RELATION)
   520  				expectedMetadata := testutils.DefaultMetadata("TABLE", true, true, true, false)
   521  				Expect(resultMetadataMap).To(HaveLen(1))
   522  				resultMetadata := resultMetadataMap[uniqueID]
   523  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   524  			})
   525  			It("returns a slice of default metadata for a table not in a specific schema", func() {
   526  				testhelper.AssertQueryRuns(connectionPool, "CREATE TABLE public.testtable(i int)")
   527  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE public.testtable")
   528  				testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
   529  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
   530  				testhelper.AssertQueryRuns(connectionPool, "CREATE TABLE testschema.testtable(i int)")
   531  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE testschema.testtable")
   532  				testhelper.AssertQueryRuns(connectionPool, "GRANT ALL ON TABLE testschema.testtable TO testrole")
   533  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON TABLE testschema.testtable IS 'This is a table comment.'")
   534  				_ = backupCmdFlags.Set(options.EXCLUDE_SCHEMA, "public")
   535  
   536  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_RELATION)
   537  
   538  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "testschema", "testtable", backup.TYPE_RELATION)
   539  				expectedMetadata := testutils.DefaultMetadata("TABLE", true, true, true, false)
   540  				Expect(resultMetadataMap).To(HaveLen(1))
   541  				resultMetadata := resultMetadataMap[uniqueID]
   542  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   543  			})
   544  			It("returns a slice of default metadata for a function in a specific schema", func() {
   545  				testhelper.AssertQueryRuns(connectionPool, `CREATE FUNCTION public.add(integer, integer) RETURNS integer
   546  AS 'SELECT $1 + $2'
   547  LANGUAGE SQL`)
   548  				defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.add(integer, integer)")
   549  				testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
   550  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
   551  				testhelper.AssertQueryRuns(connectionPool, `CREATE FUNCTION testschema.add(integer, integer) RETURNS integer
   552  AS 'SELECT $1 + $2'
   553  LANGUAGE SQL`)
   554  				defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION testschema.add(integer, integer)")
   555  				testhelper.AssertQueryRuns(connectionPool, "GRANT ALL ON FUNCTION testschema.add(integer, integer) TO testrole")
   556  				testhelper.AssertQueryRuns(connectionPool, "REVOKE ALL ON FUNCTION testschema.add(integer, integer) FROM PUBLIC")
   557  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON FUNCTION testschema.add(integer, integer) IS 'This is a function comment.'")
   558  
   559  				_ = backupCmdFlags.Set(options.INCLUDE_SCHEMA, "testschema")
   560  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_FUNCTION)
   561  
   562  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "testschema", "add", backup.TYPE_FUNCTION)
   563  				expectedMetadata := testutils.DefaultMetadata("FUNCTION", true, true, true, false)
   564  				Expect(resultMetadataMap).To(HaveLen(1))
   565  				resultMetadata := resultMetadataMap[uniqueID]
   566  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   567  			})
   568  			It("returns a slice of default metadata for a view in a specific schema", func() {
   569  				testhelper.AssertQueryRuns(connectionPool, `CREATE VIEW public.testview AS SELECT * FROM pg_class`)
   570  				defer testhelper.AssertQueryRuns(connectionPool, "DROP VIEW public.testview")
   571  				testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
   572  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
   573  				testhelper.AssertQueryRuns(connectionPool, `CREATE VIEW testschema.testview AS SELECT * FROM pg_class`)
   574  				defer testhelper.AssertQueryRuns(connectionPool, "DROP VIEW testschema.testview")
   575  				testhelper.AssertQueryRuns(connectionPool, "GRANT ALL ON testschema.testview TO testrole")
   576  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON VIEW testschema.testview IS 'This is a view comment.'")
   577  
   578  				_ = backupCmdFlags.Set(options.INCLUDE_SCHEMA, "testschema")
   579  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_RELATION)
   580  
   581  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "testschema", "testview", backup.TYPE_RELATION)
   582  				expectedMetadata := testutils.DefaultMetadata("VIEW", true, true, true, false)
   583  				Expect(resultMetadataMap).To(HaveLen(1))
   584  				resultMetadata := resultMetadataMap[uniqueID]
   585  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   586  			})
   587  			It("returns a slice of default metadata for a materialized view in a specific schema", func() {
   588  				if false {
   589  					Skip("Test only applicable to GPDB 6.2 and above")
   590  				}
   591  				testhelper.AssertQueryRuns(connectionPool, `CREATE MATERIALIZED VIEW public.testmview AS SELECT * FROM pg_class`)
   592  				defer testhelper.AssertQueryRuns(connectionPool, "DROP MATERIALIZED VIEW public.testmview")
   593  				testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
   594  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
   595  				testhelper.AssertQueryRuns(connectionPool, `CREATE MATERIALIZED VIEW testschema.testmview AS SELECT * FROM pg_class`)
   596  				defer testhelper.AssertQueryRuns(connectionPool, "DROP MATERIALIZED VIEW testschema.testmview")
   597  				testhelper.AssertQueryRuns(connectionPool, "GRANT ALL ON testschema.testmview TO testrole")
   598  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON MATERIALIZED VIEW testschema.testmview IS 'This is a materialized view comment.'")
   599  
   600  				_ = backupCmdFlags.Set(options.INCLUDE_SCHEMA, "testschema")
   601  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_RELATION)
   602  
   603  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "testschema", "testmview", backup.TYPE_RELATION)
   604  				expectedMetadata := testutils.DefaultMetadata("MATERIALIZED VIEW", true, true, true, false)
   605  				Expect(resultMetadataMap).To(HaveLen(1))
   606  				resultMetadata := resultMetadataMap[uniqueID]
   607  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   608  			})
   609  			It("returns a slice of default metadata for an aggregate in a specific schema", func() {
   610  				testhelper.AssertQueryRuns(connectionPool, `
   611  			CREATE FUNCTION public.mysfunc_accum(numeric, numeric, numeric)
   612  			   RETURNS numeric
   613  			   AS 'select $1 + $2 + $3'
   614  			   LANGUAGE SQL
   615  			   IMMUTABLE
   616  			   RETURNS NULL ON NULL INPUT;
   617  			`)
   618  				defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.mysfunc_accum(numeric, numeric, numeric)")
   619  				testhelper.AssertQueryRuns(connectionPool, `
   620  			CREATE FUNCTION public.mypre_accum(numeric, numeric)
   621  			   RETURNS numeric
   622  			   AS 'select $1 + $2'
   623  			   LANGUAGE SQL
   624  			   IMMUTABLE
   625  			   RETURNS NULL ON NULL INPUT;
   626  			`)
   627  				defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.mypre_accum(numeric, numeric)")
   628  				testhelper.AssertQueryRuns(connectionPool, `CREATE AGGREGATE public.agg_prefunc(numeric, numeric) (
   629  	SFUNC = public.mysfunc_accum,
   630  	STYPE = numeric,
   631  	PREFUNC = public.mypre_accum,
   632  	INITCOND = '0'
   633  );`)
   634  				defer testhelper.AssertQueryRuns(connectionPool, "DROP AGGREGATE public.agg_prefunc(numeric, numeric)")
   635  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON AGGREGATE public.agg_prefunc(numeric, numeric) IS 'This is an aggregate comment.'")
   636  				testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
   637  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
   638  				testhelper.AssertQueryRuns(connectionPool, `CREATE AGGREGATE testschema.agg_prefunc(numeric, numeric) (
   639  	SFUNC = public.mysfunc_accum,
   640  	STYPE = numeric,
   641  	PREFUNC = public.mypre_accum,
   642  	INITCOND = '0'
   643  );`)
   644  				defer testhelper.AssertQueryRuns(connectionPool, "DROP AGGREGATE testschema.agg_prefunc(numeric, numeric)")
   645  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON AGGREGATE testschema.agg_prefunc(numeric, numeric) IS 'This is an aggregate comment.'")
   646  
   647  				_ = backupCmdFlags.Set(options.INCLUDE_SCHEMA, "testschema")
   648  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_AGGREGATE)
   649  
   650  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "testschema", "agg_prefunc", backup.TYPE_AGGREGATE)
   651  				expectedMetadata := testutils.DefaultMetadata("AGGREGATE", false, true, true, false)
   652  				Expect(resultMetadataMap).To(HaveLen(1))
   653  				resultMetadata := resultMetadataMap[uniqueID]
   654  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   655  			})
   656  			It("returns a slice of default metadata for a type in a specific schema", func() {
   657  				testhelper.AssertQueryRuns(connectionPool, `CREATE TYPE public.testtype`)
   658  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TYPE public.testtype")
   659  				testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
   660  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
   661  				testhelper.AssertQueryRuns(connectionPool, `CREATE TYPE testschema.testtype AS (name text)`)
   662  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TYPE testschema.testtype")
   663  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON TYPE testschema.testtype IS 'This is a type comment.'")
   664  
   665  				_ = backupCmdFlags.Set(options.INCLUDE_SCHEMA, "testschema")
   666  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_TYPE)
   667  
   668  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "testschema", "testtype", backup.TYPE_TYPE)
   669  				expectedMetadata := testutils.DefaultMetadata("TYPE", false, true, true, false)
   670  				resultMetadata := resultMetadataMap[uniqueID]
   671  				if false {
   672  					// In 4.3, creating testtype does not generate a "_testtype" entry in pg_type
   673  					Expect(resultMetadataMap).To(HaveLen(1))
   674  				} else {
   675  					// In 5, creating testtype generates 2 entries in pg_type, "testtype" and "_testtype"
   676  					Expect(resultMetadataMap).To(HaveLen(2))
   677  				}
   678  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   679  			})
   680  			It("returns a slice of default metadata for an operator in a specific schema", func() {
   681  				testhelper.AssertQueryRuns(connectionPool, "CREATE OPERATOR public.#### (LEFTARG = bigint, PROCEDURE = numeric_fac)")
   682  				defer testhelper.AssertQueryRuns(connectionPool, "DROP OPERATOR public.#### (bigint, NONE)")
   683  				testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
   684  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
   685  				testhelper.AssertQueryRuns(connectionPool, "CREATE OPERATOR testschema.#### (LEFTARG = bigint, PROCEDURE = numeric_fac)")
   686  				defer testhelper.AssertQueryRuns(connectionPool, "DROP OPERATOR testschema.#### (bigint, NONE)")
   687  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON OPERATOR testschema.#### (bigint, NONE) IS 'This is an operator comment.'")
   688  
   689  				_ = backupCmdFlags.Set(options.INCLUDE_SCHEMA, "testschema")
   690  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_OPERATOR)
   691  
   692  				Expect(resultMetadataMap).To(HaveLen(1))
   693  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "testschema", "####", backup.TYPE_OPERATOR)
   694  				expectedMetadata := testutils.DefaultMetadata("OPERATOR", false, true, true, false)
   695  				resultMetadata := resultMetadataMap[uniqueID]
   696  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   697  			})
   698  			It("returns a slice of default metadata for an operator family in a specific schema", func() {
   699  				testutils.SkipIfBefore5(connectionPool)
   700  				testhelper.AssertQueryRuns(connectionPool, "CREATE OPERATOR FAMILY public.testfam USING hash")
   701  				defer testhelper.AssertQueryRuns(connectionPool, "DROP OPERATOR FAMILY public.testfam USING hash")
   702  				testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
   703  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
   704  				testhelper.AssertQueryRuns(connectionPool, "CREATE OPERATOR FAMILY testschema.testfam USING hash")
   705  				defer testhelper.AssertQueryRuns(connectionPool, "DROP OPERATOR FAMILY testschema.testfam USING hash")
   706  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON OPERATOR FAMILY testschema.testfam USING hash IS 'This is an operator family comment.'")
   707  
   708  				_ = backupCmdFlags.Set(options.INCLUDE_SCHEMA, "testschema")
   709  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_OPERATORFAMILY)
   710  
   711  				Expect(resultMetadataMap).To(HaveLen(1))
   712  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "testschema", "testfam", backup.TYPE_OPERATORFAMILY)
   713  				expectedMetadata := testutils.DefaultMetadata("OPERATOR FAMILY", false, true, true, false)
   714  				resultMetadata := resultMetadataMap[uniqueID]
   715  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   716  			})
   717  			It("returns a slice of default metadata for an operator class in a specific schema", func() {
   718  				testhelper.AssertQueryRuns(connectionPool, "CREATE OPERATOR CLASS public.testclass FOR TYPE int4 USING hash AS STORAGE int4")
   719  				if false {
   720  					defer testhelper.AssertQueryRuns(connectionPool, "DROP OPERATOR CLASS public.testclass USING hash CASCADE")
   721  				} else {
   722  					defer testhelper.AssertQueryRuns(connectionPool, "DROP OPERATOR FAMILY public.testclass USING hash CASCADE")
   723  				}
   724  				testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
   725  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
   726  				testhelper.AssertQueryRuns(connectionPool, "CREATE OPERATOR CLASS testschema.testclass FOR TYPE int4 USING hash AS STORAGE int4")
   727  				if false {
   728  					defer testhelper.AssertQueryRuns(connectionPool, "DROP OPERATOR CLASS testschema.testclass USING hash CASCADE")
   729  				} else {
   730  					defer testhelper.AssertQueryRuns(connectionPool, "DROP OPERATOR FAMILY testschema.testclass USING hash CASCADE")
   731  				}
   732  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON OPERATOR CLASS testschema.testclass USING hash IS 'This is an operator class comment.'")
   733  
   734  				_ = backupCmdFlags.Set(options.INCLUDE_SCHEMA, "testschema")
   735  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_OPERATORCLASS)
   736  
   737  				Expect(resultMetadataMap).To(HaveLen(1))
   738  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "testschema", "testclass", backup.TYPE_OPERATORCLASS)
   739  				expectedMetadata := testutils.DefaultMetadata("OPERATOR CLASS", false, true, true, false)
   740  				resultMetadata := resultMetadataMap[uniqueID]
   741  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   742  			})
   743  			It("returns a slice of default metadata for a text search dictionary in a specific schema", func() {
   744  				testutils.SkipIfBefore5(connectionPool)
   745  				testhelper.AssertQueryRuns(connectionPool, "CREATE TEXT SEARCH DICTIONARY public.testdictionary(TEMPLATE = snowball, LANGUAGE = 'russian', STOPWORDS = 'russian');")
   746  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TEXT SEARCH DICTIONARY public.testdictionary")
   747  				testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
   748  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
   749  				testhelper.AssertQueryRuns(connectionPool, "CREATE TEXT SEARCH DICTIONARY testschema.testdictionary(TEMPLATE = snowball, LANGUAGE = 'russian', STOPWORDS = 'russian');")
   750  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TEXT SEARCH DICTIONARY testschema.testdictionary")
   751  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON TEXT SEARCH DICTIONARY testschema.testdictionary IS 'This is a text search dictionary comment.'")
   752  
   753  				_ = backupCmdFlags.Set(options.INCLUDE_SCHEMA, "testschema")
   754  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_TSDICTIONARY)
   755  
   756  				Expect(resultMetadataMap).To(HaveLen(1))
   757  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "testschema", "testdictionary", backup.TYPE_TSDICTIONARY)
   758  				dictionaryMetadata := testutils.DefaultMetadata("TEXT SEARCH DICTIONARY", false, true, true, false)
   759  				resultMetadata := resultMetadataMap[uniqueID]
   760  				structmatcher.ExpectStructsToMatch(&dictionaryMetadata, &resultMetadata)
   761  			})
   762  			It("returns a slice of default metadata for a text search configuration in a specific schema", func() {
   763  				testutils.SkipIfBefore5(connectionPool)
   764  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_TSCONFIGURATION)
   765  				configurationMetadata := testutils.DefaultMetadata("TEXT SEARCH CONFIGURATION", false, true, true, false)
   766  
   767  				testhelper.AssertQueryRuns(connectionPool, `CREATE TEXT SEARCH CONFIGURATION public.testconfiguration (PARSER = pg_catalog."default");`)
   768  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TEXT SEARCH CONFIGURATION public.testconfiguration")
   769  				testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
   770  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
   771  				testhelper.AssertQueryRuns(connectionPool, `CREATE TEXT SEARCH CONFIGURATION testschema.testconfiguration (PARSER = pg_catalog."default");`)
   772  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TEXT SEARCH CONFIGURATION testschema.testconfiguration")
   773  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON TEXT SEARCH CONFIGURATION testschema.testconfiguration IS 'This is a text search configuration comment.'")
   774  
   775  				_ = backupCmdFlags.Set(options.INCLUDE_SCHEMA, "testschema")
   776  				resultMetadataMap = backup.GetMetadataForObjectType(connectionPool, backup.TYPE_TSCONFIGURATION)
   777  
   778  				Expect(resultMetadataMap).To(HaveLen(1))
   779  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "testschema", "testconfiguration", backup.TYPE_TSCONFIGURATION)
   780  				resultMetadata := resultMetadataMap[uniqueID]
   781  				structmatcher.ExpectStructsToMatch(&configurationMetadata, &resultMetadata)
   782  			})
   783  			It("returns a slice of default metadata for a collation in a specific schema", func() {
   784  				testutils.SkipIfBefore6(connectionPool)
   785  				testhelper.AssertQueryRuns(connectionPool, `CREATE COLLATION public.some_coll (lc_collate = 'POSIX', lc_ctype = 'POSIX');`)
   786  				defer testhelper.AssertQueryRuns(connectionPool, "DROP COLLATION public.some_coll")
   787  				testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
   788  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
   789  				testhelper.AssertQueryRuns(connectionPool, `CREATE COLLATION testschema.some_coll (lc_collate = 'POSIX', lc_ctype = 'POSIX');`)
   790  				defer testhelper.AssertQueryRuns(connectionPool, "DROP COLLATION testschema.some_coll")
   791  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON COLLATION testschema.some_coll IS 'This is a collation comment.'")
   792  
   793  				_ = backupCmdFlags.Set(options.INCLUDE_SCHEMA, "testschema")
   794  				resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_COLLATION)
   795  
   796  				Expect(resultMetadataMap).To(HaveLen(1))
   797  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "testschema", "some_coll", backup.TYPE_COLLATION)
   798  				collationMetadata := testutils.DefaultMetadata("COLLATION", false, true, true, false)
   799  				resultMetadata := resultMetadataMap[uniqueID]
   800  				structmatcher.ExpectStructsToMatch(&collationMetadata, &resultMetadata)
   801  			})
   802  		})
   803  	})
   804  	Describe("GetDefaultPrivileges", func() {
   805  		BeforeEach(func() {
   806  			testutils.SkipIfBefore6(connectionPool)
   807  		})
   808  		It("returns default privileges with single privilege", func() {
   809  			testhelper.AssertQueryRuns(connectionPool, "ALTER DEFAULT PRIVILEGES REVOKE USAGE ON SEQUENCES FROM testrole;")
   810  			defer testhelper.AssertQueryRuns(connectionPool, "ALTER DEFAULT PRIVILEGES GRANT USAGE ON SEQUENCES TO testrole;")
   811  
   812  			resultDefaultPrivileges := backup.GetDefaultPrivileges(connectionPool)
   813  
   814  			privs := []backup.ACL{{Grantee: "testrole", Update: true, Select: true}}
   815  			expectedDefaultPrivileges := backup.DefaultPrivileges{Schema: "", Privileges: privs, ObjectType: "S", Owner: "testrole"}
   816  			Expect(resultDefaultPrivileges).To(HaveLen(1))
   817  			structmatcher.ExpectStructsToMatchExcluding(&expectedDefaultPrivileges, &resultDefaultPrivileges[0], "Oid")
   818  		})
   819  		It("returns default privileges with multiple privileges", func() {
   820  			testhelper.AssertQueryRuns(connectionPool, "ALTER DEFAULT PRIVILEGES GRANT SELECT ON TABLES TO PUBLIC;")
   821  			defer testhelper.AssertQueryRuns(connectionPool, "ALTER DEFAULT PRIVILEGES REVOKE SELECT ON TABLES FROM PUBLIC;")
   822  
   823  			resultDefaultPrivileges := backup.GetDefaultPrivileges(connectionPool)
   824  
   825  			privs := []backup.ACL{{Grantee: "", Select: true}, testutils.DefaultACLForType("testrole", "TABLE")}
   826  			expectedDefaultPrivileges := backup.DefaultPrivileges{Schema: "", Privileges: privs, ObjectType: "r", Owner: "testrole"}
   827  			Expect(resultDefaultPrivileges).To(HaveLen(1))
   828  			structmatcher.ExpectStructsToMatchExcluding(&expectedDefaultPrivileges, &resultDefaultPrivileges[0], "Oid")
   829  		})
   830  		It("returns default privileges for role", func() {
   831  			testhelper.AssertQueryRuns(connectionPool, "ALTER DEFAULT PRIVILEGES FOR ROLE anothertestrole GRANT USAGE ON SEQUENCES TO testrole;")
   832  			defer testhelper.AssertQueryRuns(connectionPool, "ALTER DEFAULT PRIVILEGES FOR ROLE anothertestrole REVOKE USAGE ON SEQUENCES FROM testrole;")
   833  
   834  			resultDefaultPrivileges := backup.GetDefaultPrivileges(connectionPool)
   835  
   836  			privs := []backup.ACL{{Grantee: "anothertestrole", Select: true, Update: true, Usage: true}, {Grantee: "testrole", Usage: true}}
   837  			expectedDefaultPrivileges := backup.DefaultPrivileges{Schema: "", Privileges: privs, ObjectType: "S", Owner: "anothertestrole"}
   838  			Expect(resultDefaultPrivileges).To(HaveLen(1))
   839  			structmatcher.ExpectStructsToMatchExcluding(&expectedDefaultPrivileges, &resultDefaultPrivileges[0], "Oid")
   840  		})
   841  		It("returns default privileges in schema", func() {
   842  			testhelper.AssertQueryRuns(connectionPool, "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE ON SEQUENCES TO testrole;")
   843  			defer testhelper.AssertQueryRuns(connectionPool, "ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE USAGE ON SEQUENCES FROM testrole;")
   844  
   845  			resultDefaultPrivileges := backup.GetDefaultPrivileges(connectionPool)
   846  
   847  			privs := []backup.ACL{{Grantee: "testrole", Usage: true}}
   848  			expectedDefaultPrivileges := backup.DefaultPrivileges{Schema: "public", Privileges: privs, ObjectType: "S", Owner: "testrole"}
   849  			Expect(resultDefaultPrivileges).To(HaveLen(1))
   850  			structmatcher.ExpectStructsToMatchExcluding(&expectedDefaultPrivileges, &resultDefaultPrivileges[0], "Oid")
   851  		})
   852  
   853  	})
   854  	Describe("GetCommentsForObjectType", func() {
   855  		Context("comments for all objects of one type", func() {
   856  			It("returns a slice of default metadata for an index", func() {
   857  				resultMetadataMap := backup.GetCommentsForObjectType(connectionPool, backup.TYPE_INDEX)
   858  				numIndexes := len(resultMetadataMap)
   859  
   860  				testhelper.AssertQueryRuns(connectionPool, `CREATE TABLE public.testtable(i int)`)
   861  				testhelper.AssertQueryRuns(connectionPool, `CREATE INDEX testindex ON public.testtable USING btree(i)`)
   862  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE public.testtable")
   863  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON INDEX public.testindex IS 'This is an index comment.'")
   864  
   865  				resultMetadataMap = backup.GetCommentsForObjectType(connectionPool, backup.TYPE_INDEX)
   866  
   867  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "testindex", backup.TYPE_INDEX)
   868  				expectedMetadata := testutils.DefaultMetadata("INDEX", false, false, true, false)
   869  
   870  				Expect(resultMetadataMap).To(HaveLen(numIndexes + 1))
   871  				resultMetadata := resultMetadataMap[uniqueID]
   872  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   873  			})
   874  			It("returns a slice of default metadata for a rule", func() {
   875  				resultMetadataMap := backup.GetCommentsForObjectType(connectionPool, backup.TYPE_RULE)
   876  				numRules := len(resultMetadataMap)
   877  
   878  				testhelper.AssertQueryRuns(connectionPool, `CREATE TABLE public.testtable(i int)`)
   879  				testhelper.AssertQueryRuns(connectionPool, `CREATE RULE update_notify AS ON UPDATE TO public.testtable DO NOTIFY testtable`)
   880  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE public.testtable")
   881  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON RULE update_notify ON public.testtable IS 'This is a rule comment.'")
   882  
   883  				resultMetadataMap = backup.GetCommentsForObjectType(connectionPool, backup.TYPE_RULE)
   884  
   885  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "update_notify", backup.TYPE_RULE)
   886  				expectedMetadata := testutils.DefaultMetadata("RULE", false, false, true, false)
   887  
   888  				Expect(resultMetadataMap).To(HaveLen(numRules + 1))
   889  				resultMetadata := resultMetadataMap[uniqueID]
   890  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   891  			})
   892  			It("returns a slice of default metadata for a trigger", func() {
   893  				resultMetadataMap := backup.GetCommentsForObjectType(connectionPool, backup.TYPE_TRIGGER)
   894  				numTriggers := len(resultMetadataMap)
   895  
   896  				testhelper.AssertQueryRuns(connectionPool, `CREATE TABLE public.testtable(i int)`)
   897  				if false {
   898  					testhelper.AssertQueryRuns(connectionPool, `CREATE TRIGGER sync_testtable AFTER INSERT OR DELETE OR UPDATE ON public.testtable FOR EACH STATEMENT EXECUTE PROCEDURE "RI_FKey_check_ins"()`)
   899  				} else {
   900  					testhelper.AssertQueryRuns(connectionPool, `CREATE TRIGGER sync_testtable AFTER INSERT OR DELETE OR UPDATE ON public.testtable FOR EACH ROW EXECUTE FUNCTION "RI_FKey_check_ins"()`)
   901  				}
   902  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE public.testtable")
   903  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON TRIGGER sync_testtable ON public.testtable IS 'This is a trigger comment.'")
   904  
   905  				resultMetadataMap = backup.GetCommentsForObjectType(connectionPool, backup.TYPE_TRIGGER)
   906  
   907  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "sync_testtable", backup.TYPE_TRIGGER)
   908  				expectedMetadata := testutils.DefaultMetadata("TRIGGER", false, false, true, false)
   909  
   910  				Expect(resultMetadataMap).To(HaveLen(numTriggers + 1))
   911  				resultMetadata := resultMetadataMap[uniqueID]
   912  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   913  			})
   914  			It("returns a slice of default metadata for a cast in 4.3", func() {
   915  				testutils.SkipIfNot4(connectionPool)
   916  				resultMetadataMap := backup.GetCommentsForObjectType(connectionPool, backup.TYPE_CAST)
   917  				numCasts := len(resultMetadataMap)
   918  
   919  				testhelper.AssertQueryRuns(connectionPool, "CREATE FUNCTION public.casttotext(bool) RETURNS text STRICT IMMUTABLE LANGUAGE PLPGSQL AS $$ BEGIN IF $1 IS TRUE THEN RETURN 'true'; ELSE RETURN 'false'; END IF; END; $$;")
   920  				defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.casttotext(bool) CASCADE")
   921  				testhelper.AssertQueryRuns(connectionPool, "CREATE CAST (bool AS text) WITH FUNCTION public.casttotext(bool) AS ASSIGNMENT")
   922  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON CAST (bool AS text) IS 'This is a cast comment.'")
   923  
   924  				resultMetadataMap = backup.GetCommentsForObjectType(connectionPool, backup.TYPE_CAST)
   925  
   926  				boolOid := testutils.OidFromObjectName(connectionPool, "", "bool", backup.TYPE_TYPE)
   927  				textOid := testutils.OidFromObjectName(connectionPool, "", "text", backup.TYPE_TYPE)
   928  				oid := testutils.OidFromCast(connectionPool, boolOid, textOid)
   929  				expectedMetadata := testutils.DefaultMetadata("CAST", false, false, true, false)
   930  
   931  				Expect(resultMetadataMap).To(HaveLen(numCasts + 1))
   932  				resultMetadata := resultMetadataMap[backup.UniqueID{ClassID: backup.PG_CAST_OID, Oid: oid}]
   933  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   934  			})
   935  			It("returns a slice of default metadata for a cast in 5", func() {
   936  				testutils.SkipIfBefore5(connectionPool)
   937  				resultMetadataMap := backup.GetCommentsForObjectType(connectionPool, backup.TYPE_CAST)
   938  				numCasts := len(resultMetadataMap)
   939  
   940  				testhelper.AssertQueryRuns(connectionPool, `CREATE FUNCTION public.casttoint(text) RETURNS integer STRICT IMMUTABLE LANGUAGE SQL AS 'SELECT cast($1 as integer);'`)
   941  				defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.casttoint(text) CASCADE")
   942  				testhelper.AssertQueryRuns(connectionPool, "CREATE CAST (text AS int) WITH FUNCTION public.casttoint(text) AS ASSIGNMENT;")
   943  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON CAST (text AS int) IS 'This is a cast comment.'")
   944  
   945  				resultMetadataMap = backup.GetCommentsForObjectType(connectionPool, backup.TYPE_CAST)
   946  
   947  				textOid := testutils.OidFromObjectName(connectionPool, "", "text", backup.TYPE_TYPE)
   948  				intOid := testutils.OidFromObjectName(connectionPool, "", "int4", backup.TYPE_TYPE)
   949  				oid := testutils.OidFromCast(connectionPool, textOid, intOid)
   950  				expectedMetadata := testutils.DefaultMetadata("CAST", false, false, true, false)
   951  
   952  				Expect(resultMetadataMap).To(HaveLen(numCasts + 1))
   953  				resultMetadata := resultMetadataMap[backup.UniqueID{ClassID: backup.PG_CAST_OID, Oid: oid}]
   954  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   955  			})
   956  			It("returns a slice of default metadata for a resource queue", func() {
   957  				resultMetadataMap := backup.GetCommentsForObjectType(connectionPool, backup.TYPE_RESOURCEQUEUE)
   958  				numResQueues := len(resultMetadataMap)
   959  
   960  				testhelper.AssertQueryRuns(connectionPool, `CREATE RESOURCE QUEUE res_queue WITH (MAX_COST=32.8);`)
   961  				defer testhelper.AssertQueryRuns(connectionPool, "DROP RESOURCE QUEUE res_queue")
   962  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON RESOURCE QUEUE res_queue IS 'This is a resource queue comment.'")
   963  
   964  				resultMetadataMap = backup.GetCommentsForObjectType(connectionPool, backup.TYPE_RESOURCEQUEUE)
   965  
   966  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "res_queue", backup.TYPE_RESOURCEQUEUE)
   967  				expectedMetadata := testutils.DefaultMetadata("RESOURCE QUEUE", false, false, true, false)
   968  
   969  				Expect(resultMetadataMap).To(HaveLen(numResQueues + 1))
   970  				resultMetadata := resultMetadataMap[uniqueID]
   971  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
   972  			})
   973  			It("returns a slice of default metadata for a text search parser", func() {
   974  				testutils.SkipIfBefore5(connectionPool)
   975  				parserMetadata := testutils.DefaultMetadata("TEXT SEARCH PARSER", false, false, true, false)
   976  
   977  				testhelper.AssertQueryRuns(connectionPool, "CREATE TEXT SEARCH PARSER public.testparser(START = prsd_start, GETTOKEN = prsd_nexttoken, END = prsd_end, LEXTYPES = prsd_lextype);")
   978  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TEXT SEARCH PARSER public.testparser")
   979  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON TEXT SEARCH PARSER public.testparser IS 'This is a text search parser comment.'")
   980  
   981  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "testparser", backup.TYPE_TSPARSER)
   982  				resultMetadataMap := backup.GetCommentsForObjectType(connectionPool, backup.TYPE_TSPARSER)
   983  
   984  				Expect(resultMetadataMap).To(HaveLen(1))
   985  				resultMetadata := resultMetadataMap[uniqueID]
   986  				structmatcher.ExpectStructsToMatch(&parserMetadata, &resultMetadata)
   987  			})
   988  			It("returns a slice of default metadata for a text search template", func() {
   989  				testutils.SkipIfBefore5(connectionPool)
   990  				templateMetadata := testutils.DefaultMetadata("TEXT SEARCH TEMPLATE", false, false, true, false)
   991  
   992  				testhelper.AssertQueryRuns(connectionPool, "CREATE TEXT SEARCH TEMPLATE public.testtemplate(LEXIZE = dsimple_lexize);")
   993  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TEXT SEARCH TEMPLATE public.testtemplate")
   994  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON TEXT SEARCH TEMPLATE public.testtemplate IS 'This is a text search template comment.'")
   995  
   996  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "public", "testtemplate", backup.TYPE_TSTEMPLATE)
   997  				resultMetadataMap := backup.GetCommentsForObjectType(connectionPool, backup.TYPE_TSTEMPLATE)
   998  
   999  				Expect(resultMetadataMap).To(HaveLen(1))
  1000  				resultMetadata := resultMetadataMap[uniqueID]
  1001  				structmatcher.ExpectStructsToMatch(&templateMetadata, &resultMetadata)
  1002  			})
  1003  			It("returns a slice of default metadata for an extension", func() {
  1004  				testutils.SkipIfBefore5(connectionPool)
  1005  				extensionMetadata := testutils.DefaultMetadata("EXTENSION", false, false, true, false)
  1006  
  1007  				testhelper.AssertQueryRuns(connectionPool, "CREATE EXTENSION plperl;")
  1008  				defer testhelper.AssertQueryRuns(connectionPool, "DROP EXTENSION plperl")
  1009  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON EXTENSION plperl IS 'This is an extension comment.'")
  1010  
  1011  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "plperl", backup.TYPE_EXTENSION)
  1012  				resultMetadataMap := backup.GetCommentsForObjectType(connectionPool, backup.TYPE_EXTENSION)
  1013  
  1014  				Expect(resultMetadataMap).To(HaveLen(1))
  1015  				resultMetadata := resultMetadataMap[uniqueID]
  1016  				structmatcher.ExpectStructsToMatch(&extensionMetadata, &resultMetadata)
  1017  			})
  1018  		})
  1019  		Context("comments for objects in a specific schema", func() {
  1020  			It("returns a slice of default metadata for an index in a specific schema", func() {
  1021  
  1022  				testhelper.AssertQueryRuns(connectionPool, `CREATE TABLE public.testtable(i int)`)
  1023  				testhelper.AssertQueryRuns(connectionPool, `CREATE INDEX testindex ON public.testtable USING btree(i)`)
  1024  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE public.testtable")
  1025  				testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
  1026  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
  1027  				testhelper.AssertQueryRuns(connectionPool, `CREATE TABLE testschema.testtable(i int)`)
  1028  				testhelper.AssertQueryRuns(connectionPool, `CREATE INDEX testindex1 ON testschema.testtable USING btree(i)`)
  1029  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE testschema.testtable")
  1030  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON INDEX testschema.testindex1 IS 'This is an index comment.'")
  1031  
  1032  				_ = backupCmdFlags.Set(options.INCLUDE_SCHEMA, "testschema")
  1033  				resultMetadataMap := backup.GetCommentsForObjectType(connectionPool, backup.TYPE_INDEX)
  1034  
  1035  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "", "testindex1", backup.TYPE_INDEX)
  1036  				expectedMetadata := testutils.DefaultMetadata("INDEX", false, false, true, false)
  1037  
  1038  				resultMetadata := resultMetadataMap[uniqueID]
  1039  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
  1040  			})
  1041  			It("returns a slice of default metadata for a constraint in a specific schema", func() {
  1042  				testhelper.AssertQueryRuns(connectionPool, `CREATE TABLE public.testtable(i int UNIQUE)`)
  1043  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE public.testtable")
  1044  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON CONSTRAINT testtable_i_key ON public.testtable IS 'This is a constraint comment.'")
  1045  
  1046  				testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
  1047  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
  1048  				testhelper.AssertQueryRuns(connectionPool, `CREATE TABLE testschema.testtable(i int UNIQUE)`)
  1049  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TABLE testschema.testtable")
  1050  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON CONSTRAINT testtable_i_key ON testschema.testtable IS 'This is a constraint comment.'")
  1051  				_ = backupCmdFlags.Set(options.INCLUDE_SCHEMA, "testschema")
  1052  
  1053  				resultMetadataMap := backup.GetCommentsForObjectType(connectionPool, backup.TYPE_CONSTRAINT)
  1054  
  1055  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "testschema", "testtable_i_key", backup.TYPE_CONSTRAINT)
  1056  				expectedMetadata := testutils.DefaultMetadata("CONSTRAINT", false, false, true, false)
  1057  
  1058  				Expect(resultMetadataMap).To(HaveLen(1))
  1059  				resultMetadata := resultMetadataMap[uniqueID]
  1060  				structmatcher.ExpectStructsToMatchExcluding(&expectedMetadata, &resultMetadata, "Oid")
  1061  			})
  1062  			It("returns a slice of default metadata for a text search parser in a specific schema", func() {
  1063  				testutils.SkipIfBefore5(connectionPool)
  1064  				parserMetadata := testutils.DefaultMetadata("TEXT SEARCH PARSER", false, false, true, false)
  1065  
  1066  				testhelper.AssertQueryRuns(connectionPool, "CREATE TEXT SEARCH PARSER public.testparser(START = prsd_start, GETTOKEN = prsd_nexttoken, END = prsd_end, LEXTYPES = prsd_lextype);")
  1067  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TEXT SEARCH PARSER public.testparser")
  1068  				testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
  1069  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
  1070  				testhelper.AssertQueryRuns(connectionPool, "CREATE TEXT SEARCH PARSER testschema.testparser(START = prsd_start, GETTOKEN = prsd_nexttoken, END = prsd_end, LEXTYPES = prsd_lextype);")
  1071  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TEXT SEARCH PARSER testschema.testparser")
  1072  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON TEXT SEARCH PARSER testschema.testparser IS 'This is a text search parser comment.'")
  1073  
  1074  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "testschema", "testparser", backup.TYPE_TSPARSER)
  1075  				_ = backupCmdFlags.Set(options.INCLUDE_SCHEMA, "testschema")
  1076  				resultMetadataMap := backup.GetCommentsForObjectType(connectionPool, backup.TYPE_TSPARSER)
  1077  
  1078  				Expect(resultMetadataMap).To(HaveLen(1))
  1079  				resultMetadata := resultMetadataMap[uniqueID]
  1080  				structmatcher.ExpectStructsToMatch(&parserMetadata, &resultMetadata)
  1081  			})
  1082  			It("returns a slice of default metadata for a text search template in a specific schema", func() {
  1083  				testutils.SkipIfBefore5(connectionPool)
  1084  				templateMetadata := testutils.DefaultMetadata("TEXT SEARCH TEMPLATE", false, false, true, false)
  1085  
  1086  				testhelper.AssertQueryRuns(connectionPool, "CREATE TEXT SEARCH TEMPLATE public.testtemplate(LEXIZE = dsimple_lexize);")
  1087  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TEXT SEARCH TEMPLATE public.testtemplate")
  1088  				testhelper.AssertQueryRuns(connectionPool, "CREATE SCHEMA testschema")
  1089  				defer testhelper.AssertQueryRuns(connectionPool, "DROP SCHEMA testschema")
  1090  				testhelper.AssertQueryRuns(connectionPool, "CREATE TEXT SEARCH TEMPLATE testschema.testtemplate(LEXIZE = dsimple_lexize);")
  1091  				defer testhelper.AssertQueryRuns(connectionPool, "DROP TEXT SEARCH TEMPLATE testschema.testtemplate")
  1092  				testhelper.AssertQueryRuns(connectionPool, "COMMENT ON TEXT SEARCH TEMPLATE testschema.testtemplate IS 'This is a text search template comment.'")
  1093  
  1094  				uniqueID := testutils.UniqueIDFromObjectName(connectionPool, "testschema", "testtemplate", backup.TYPE_TSTEMPLATE)
  1095  				_ = backupCmdFlags.Set(options.INCLUDE_SCHEMA, "testschema")
  1096  				resultMetadataMap := backup.GetCommentsForObjectType(connectionPool, backup.TYPE_TSTEMPLATE)
  1097  
  1098  				Expect(resultMetadataMap).To(HaveLen(1))
  1099  				resultMetadata := resultMetadataMap[uniqueID]
  1100  				structmatcher.ExpectStructsToMatch(&templateMetadata, &resultMetadata)
  1101  			})
  1102  		})
  1103  	})
  1104  })