github.com/greenplum-db/gpbackup@v0.0.0-20240517212602-89daab1885b3/backup/predata_types_test.go (about) 1 package backup_test 2 3 import ( 4 "database/sql" 5 "fmt" 6 7 "github.com/greenplum-db/gpbackup/backup" 8 "github.com/greenplum-db/gpbackup/testutils" 9 "github.com/greenplum-db/gpbackup/toc" 10 11 . "github.com/onsi/ginkgo/v2" 12 ) 13 14 var _ = Describe("backup/predata_types tests", func() { 15 emptyMetadata := backup.ObjectMetadata{} 16 emptyMetadataMap := backup.MetadataMap{} 17 typeMetadata := testutils.DefaultMetadata(toc.OBJ_TYPE, false, true, true, true) 18 typeMetadataMap := testutils.DefaultMetadataMap(toc.OBJ_TYPE, false, true, true, true) 19 20 BeforeEach(func() { 21 tocfile, backupfile = testutils.InitializeTestTOC(buffer, "predata") 22 }) 23 Describe("PrintCreateEnumTypeStatements", func() { 24 enumOne := backup.EnumType{Oid: 1, Schema: "public", Name: "enum_type", EnumLabels: "'bar',\n\t'baz',\n\t'foo'"} 25 enumTwo := backup.EnumType{Oid: 1, Schema: "public", Name: "enum_type", EnumLabels: "'bar',\n\t'baz',\n\t'foo'"} 26 27 It("prints an enum type with multiple attributes", func() { 28 backup.PrintCreateEnumTypeStatements(backupfile, tocfile, []backup.EnumType{enumOne}, emptyMetadataMap) 29 testutils.ExpectEntry(tocfile.PredataEntries, 0, "public", "", "enum_type", toc.OBJ_TYPE) 30 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, `CREATE TYPE public.enum_type AS ENUM ( 31 'bar', 32 'baz', 33 'foo' 34 );`) 35 }) 36 It("prints an enum type with comment, security label, and owner", func() { 37 backup.PrintCreateEnumTypeStatements(backupfile, tocfile, []backup.EnumType{enumTwo}, typeMetadataMap) 38 expectedStatements := []string{`CREATE TYPE public.enum_type AS ENUM ( 39 'bar', 40 'baz', 41 'foo' 42 );`, 43 "COMMENT ON TYPE public.enum_type IS 'This is a type comment.';", 44 "ALTER TYPE public.enum_type OWNER TO testrole;", 45 "SECURITY LABEL FOR dummy ON TYPE public.enum_type IS 'unclassified';"} 46 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, expectedStatements...) 47 }) 48 }) 49 Describe("PrintCreateCompositeTypeStatement", func() { 50 var compType backup.CompositeType 51 var oneAtt, oneAttWithCollation, twoAtts, attWithComment []backup.Attribute 52 BeforeEach(func() { 53 compType = backup.CompositeType{Oid: 1, Schema: "public", Name: "composite_type"} 54 oneAtt = []backup.Attribute{{Name: "foo", Type: "integer"}} 55 oneAttWithCollation = []backup.Attribute{{Name: "foo", Type: "integer", Collation: "public.some_coll"}} 56 twoAtts = []backup.Attribute{{Name: "foo", Type: "integer"}, {Name: "bar", Type: "text"}} 57 attWithComment = []backup.Attribute{{Name: "foo", Type: "integer", Comment: "'attribute comment'"}} 58 }) 59 60 It("prints a composite type with one attribute", func() { 61 compType.Attributes = oneAtt 62 backup.PrintCreateCompositeTypeStatement(backupfile, tocfile, compType, emptyMetadata) 63 testutils.ExpectEntry(tocfile.PredataEntries, 0, "public", "", "composite_type", toc.OBJ_TYPE) 64 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, `CREATE TYPE public.composite_type AS ( 65 foo integer 66 );`) 67 }) 68 It("prints a composite type with one attribute with a collation", func() { 69 compType.Attributes = oneAttWithCollation 70 backup.PrintCreateCompositeTypeStatement(backupfile, tocfile, compType, emptyMetadata) 71 testutils.ExpectEntry(tocfile.PredataEntries, 0, "public", "", "composite_type", toc.OBJ_TYPE) 72 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, `CREATE TYPE public.composite_type AS ( 73 foo integer COLLATE public.some_coll 74 );`) 75 }) 76 It("prints a composite type with multiple attributes", func() { 77 compType.Attributes = twoAtts 78 backup.PrintCreateCompositeTypeStatement(backupfile, tocfile, compType, emptyMetadata) 79 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, `CREATE TYPE public.composite_type AS ( 80 foo integer, 81 bar text 82 );`) 83 }) 84 It("prints a composite type with comment, security label, and owner", func() { 85 compType.Attributes = twoAtts 86 backup.PrintCreateCompositeTypeStatement(backupfile, tocfile, compType, typeMetadata) 87 expectedEntries := []string{`CREATE TYPE public.composite_type AS ( 88 foo integer, 89 bar text 90 );`, 91 "COMMENT ON TYPE public.composite_type IS 'This is a type comment.';", 92 "ALTER TYPE public.composite_type OWNER TO testrole;", 93 "SECURITY LABEL FOR dummy ON TYPE public.composite_type IS 'unclassified';"} 94 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, expectedEntries...) 95 }) 96 It("prints a composite type with attribute comment", func() { 97 compType.Attributes = attWithComment 98 backup.PrintCreateCompositeTypeStatement(backupfile, tocfile, compType, emptyMetadata) 99 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, `CREATE TYPE public.composite_type AS ( 100 foo integer 101 );`, "COMMENT ON COLUMN public.composite_type.foo IS 'attribute comment';") 102 }) 103 }) 104 Describe("PrintCreateBaseTypeStatement", func() { 105 baseSimple := backup.BaseType{Oid: 1, Schema: "public", Name: "base_type", Input: "input_fn", Output: "output_fn", Receive: "", Send: "", ModIn: "", ModOut: "", InternalLength: -1, IsPassedByValue: false, Alignment: "c", Storage: "p", DefaultVal: "", Element: "", Category: "U", Preferred: false, Delimiter: ""} 106 basePartial := backup.BaseType{Oid: 1, Schema: "public", Name: "base_type", Input: "input_fn", Output: "output_fn", Receive: "receive_fn", Send: "send_fn", ModIn: "modin_fn", ModOut: "modout_fn", InternalLength: -1, IsPassedByValue: false, Alignment: "c", Storage: "p", DefaultVal: "42", Element: "int4", Category: "U", Delimiter: ","} 107 baseFull := backup.BaseType{Oid: 1, Schema: "public", Name: "base_type", Input: "input_fn", Output: "output_fn", Receive: "receive_fn", Send: "send_fn", ModIn: "modin_fn", ModOut: "modout_fn", InternalLength: 16, IsPassedByValue: true, Alignment: "s", Storage: "e", DefaultVal: "42", Element: "int4", Category: "N", Preferred: true, Delimiter: ",", StorageOptions: "compresstype=zlib, compresslevel=1, blocksize=32768", Collatable: true} 108 basePermOne := backup.BaseType{Oid: 1, Schema: "public", Name: "base_type", Input: "input_fn", Output: "output_fn", Receive: "", Send: "", ModIn: "", ModOut: "", InternalLength: -1, IsPassedByValue: false, Alignment: "d", Storage: "m", DefaultVal: "", Element: "", Category: "U", Delimiter: ""} 109 basePermTwo := backup.BaseType{Oid: 1, Schema: "public", Name: "base_type", Input: "input_fn", Output: "output_fn", Receive: "", Send: "", ModIn: "", ModOut: "", InternalLength: -1, IsPassedByValue: false, Alignment: "i", Storage: "x", DefaultVal: "", Element: "", Category: "U", Delimiter: ""} 110 111 It("prints a base type with no optional arguments", func() { 112 backup.PrintCreateBaseTypeStatement(backupfile, tocfile, baseSimple, emptyMetadata) 113 testutils.ExpectEntry(tocfile.PredataEntries, 0, "public", "", "base_type", toc.OBJ_TYPE) 114 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, `CREATE TYPE public.base_type ( 115 INPUT = input_fn, 116 OUTPUT = output_fn 117 );`) 118 }) 119 It("prints a base type where all optional arguments have default values where possible", func() { 120 backup.PrintCreateBaseTypeStatement(backupfile, tocfile, basePartial, emptyMetadata) 121 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, fmt.Sprintf(`CREATE TYPE public.base_type ( 122 INPUT = input_fn, 123 OUTPUT = output_fn, 124 RECEIVE = receive_fn, 125 SEND = send_fn, 126 TYPMOD_IN = modin_fn, 127 TYPMOD_OUT = modout_fn, 128 DEFAULT = '42', 129 ELEMENT = int4, 130 DELIMITER = ',' 131 );`)) 132 }) 133 It("prints a base type with all optional arguments provided", func() { 134 backup.PrintCreateBaseTypeStatement(backupfile, tocfile, baseFull, emptyMetadata) 135 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, fmt.Sprintf(`CREATE TYPE public.base_type ( 136 INPUT = input_fn, 137 OUTPUT = output_fn, 138 RECEIVE = receive_fn, 139 SEND = send_fn, 140 TYPMOD_IN = modin_fn, 141 TYPMOD_OUT = modout_fn, 142 INTERNALLENGTH = 16, 143 PASSEDBYVALUE, 144 ALIGNMENT = int2, 145 STORAGE = external, 146 DEFAULT = '42', 147 ELEMENT = int4, 148 DELIMITER = ',', 149 CATEGORY = 'N', 150 PREFERRED = true, 151 COLLATABLE = true 152 ); 153 154 ALTER TYPE public.base_type 155 SET DEFAULT ENCODING (compresstype=zlib, compresslevel=1, blocksize=32768);`)) 156 }) 157 It("prints a base type with double alignment and main storage", func() { 158 backup.PrintCreateBaseTypeStatement(backupfile, tocfile, basePermOne, emptyMetadata) 159 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, `CREATE TYPE public.base_type ( 160 INPUT = input_fn, 161 OUTPUT = output_fn, 162 ALIGNMENT = double, 163 STORAGE = main 164 );`) 165 }) 166 It("prints a base type with int4 alignment and external storage", func() { 167 backup.PrintCreateBaseTypeStatement(backupfile, tocfile, basePermTwo, emptyMetadata) 168 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, `CREATE TYPE public.base_type ( 169 INPUT = input_fn, 170 OUTPUT = output_fn, 171 ALIGNMENT = int4, 172 STORAGE = extended 173 );`) 174 }) 175 It("prints a base type with comment, security label, and owner", func() { 176 backup.PrintCreateBaseTypeStatement(backupfile, tocfile, baseSimple, typeMetadata) 177 expectedEntries := []string{`CREATE TYPE public.base_type ( 178 INPUT = input_fn, 179 OUTPUT = output_fn 180 );`, 181 "COMMENT ON TYPE public.base_type IS 'This is a type comment.';", 182 "ALTER TYPE public.base_type OWNER TO testrole;", 183 "SECURITY LABEL FOR dummy ON TYPE public.base_type IS 'unclassified';"} 184 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, expectedEntries...) 185 }) 186 }) 187 Describe("PrintCreateShellTypeStatements", func() { 188 shellOne := backup.ShellType{Oid: 1, Schema: "public", Name: "shell_type1"} 189 baseOne := backup.BaseType{Oid: 1, Schema: "public", Name: "base_type1", Input: "input_fn", Output: "output_fn", Receive: "", Send: "", ModIn: "", ModOut: "", InternalLength: -1, IsPassedByValue: false, Alignment: "c", Storage: "p", DefaultVal: "", Element: "", Category: "U", Delimiter: ""} 190 baseTwo := backup.BaseType{Oid: 1, Schema: "public", Name: "base_type2", Input: "input_fn", Output: "output_fn", Receive: "", Send: "", ModIn: "", ModOut: "", InternalLength: -1, IsPassedByValue: false, Alignment: "c", Storage: "p", DefaultVal: "", Element: "", Category: "U", Delimiter: ""} 191 rangeOne := backup.RangeType{Oid: 1, Schema: "public", Name: "range_type1"} 192 It("prints shell type for a shell type", func() { 193 backup.PrintCreateShellTypeStatements(backupfile, tocfile, []backup.ShellType{shellOne}, []backup.BaseType{}, []backup.RangeType{}) 194 testutils.ExpectEntry(tocfile.PredataEntries, 0, "public", "", "shell_type1", toc.OBJ_TYPE) 195 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, "CREATE TYPE public.shell_type1;") 196 }) 197 It("prints shell type for a base type", func() { 198 backup.PrintCreateShellTypeStatements(backupfile, tocfile, []backup.ShellType{}, []backup.BaseType{baseOne, baseTwo}, []backup.RangeType{}) 199 testutils.ExpectEntry(tocfile.PredataEntries, 0, "public", "", "base_type1", toc.OBJ_TYPE) 200 testutils.ExpectEntry(tocfile.PredataEntries, 1, "public", "", "base_type2", toc.OBJ_TYPE) 201 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, "CREATE TYPE public.base_type1;", "CREATE TYPE public.base_type2;") 202 }) 203 It("prints shell type for a range type", func() { 204 backup.PrintCreateShellTypeStatements(backupfile, tocfile, []backup.ShellType{}, []backup.BaseType{}, []backup.RangeType{rangeOne}) 205 testutils.ExpectEntry(tocfile.PredataEntries, 0, "public", "", "range_type1", toc.OBJ_TYPE) 206 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, "CREATE TYPE public.range_type1;") 207 }) 208 }) 209 Describe("PrintCreateDomainStatement", func() { 210 emptyConstraint := make([]backup.Constraint, 0) 211 checkConstraint := []backup.Constraint{{Name: "domain1_check", Def: sql.NullString{String: "CHECK (VALUE > 2)", Valid: true}, OwningObject: "public.domain1"}} 212 domainOne := backup.Domain{Oid: 1, Schema: "public", Name: "domain1", DefaultVal: "4", BaseType: "numeric", NotNull: true, Collation: "public.mycollation"} 213 domainTwo := backup.Domain{Oid: 1, Schema: "public", Name: "domain2", DefaultVal: "", BaseType: "varchar", NotNull: false, Collation: ""} 214 It("prints a domain with a constraint", func() { 215 backup.PrintCreateDomainStatement(backupfile, tocfile, domainOne, emptyMetadata, checkConstraint) 216 testutils.ExpectEntry(tocfile.PredataEntries, 0, "public", "", "domain1", toc.OBJ_DOMAIN) 217 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, `CREATE DOMAIN public.domain1 AS numeric DEFAULT 4 COLLATE public.mycollation NOT NULL 218 CONSTRAINT domain1_check CHECK (VALUE > 2);`) 219 }) 220 It("prints a domain without constraint", func() { 221 backup.PrintCreateDomainStatement(backupfile, tocfile, domainOne, emptyMetadata, emptyConstraint) 222 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, `CREATE DOMAIN public.domain1 AS numeric DEFAULT 4 COLLATE public.mycollation NOT NULL;`) 223 }) 224 It("prints a domain without constraint with comment, security label, and owner", func() { 225 domainMetadata := testutils.DefaultMetadata(toc.OBJ_DOMAIN, false, true, true, true) 226 backup.PrintCreateDomainStatement(backupfile, tocfile, domainTwo, domainMetadata, emptyConstraint) 227 expectedEntries := []string{"CREATE DOMAIN public.domain2 AS varchar;", 228 "COMMENT ON DOMAIN public.domain2 IS 'This is a domain comment.';", 229 "ALTER DOMAIN public.domain2 OWNER TO testrole;", 230 "SECURITY LABEL FOR dummy ON DOMAIN public.domain2 IS 'unclassified';"} 231 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, expectedEntries...) 232 }) 233 }) 234 Describe("PrintCreateRangeTypeStatement", func() { 235 basicRangeType := backup.RangeType{ 236 Name: "rangetype", 237 Schema: "public", 238 SubType: "test_subtype_schema.test_subtype", 239 } 240 complexRangeType := backup.RangeType{ 241 Name: "rangetype", Schema: "public", 242 SubType: "test_subtype_schema.test_subtype", 243 SubTypeOpClass: "opclass_schema.test_opclass", 244 Collation: "collation_schema.test_collation", 245 Canonical: "canonical_schema.test_canonical", 246 SubTypeDiff: "diff_schema.test_diff", 247 } 248 It("prints a basic range type", func() { 249 backup.PrintCreateRangeTypeStatement(backupfile, tocfile, basicRangeType, emptyMetadata) 250 testutils.ExpectEntry(tocfile.PredataEntries, 0, "public", "", "rangetype", toc.OBJ_TYPE) 251 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, `CREATE TYPE public.rangetype AS RANGE ( 252 SUBTYPE = test_subtype_schema.test_subtype 253 );`) 254 }) 255 It("prints a complex range type", func() { 256 backup.PrintCreateRangeTypeStatement(backupfile, tocfile, complexRangeType, emptyMetadata) 257 testutils.ExpectEntry(tocfile.PredataEntries, 0, "public", "", "rangetype", toc.OBJ_TYPE) 258 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, `CREATE TYPE public.rangetype AS RANGE ( 259 SUBTYPE = test_subtype_schema.test_subtype, 260 SUBTYPE_OPCLASS = opclass_schema.test_opclass, 261 COLLATION = collation_schema.test_collation, 262 CANONICAL = canonical_schema.test_canonical, 263 SUBTYPE_DIFF = diff_schema.test_diff 264 );`) 265 }) 266 It("prints a range type with an owner, security label, and a comment", func() { 267 backup.PrintCreateRangeTypeStatement(backupfile, tocfile, basicRangeType, typeMetadata) 268 expectedStatements := []string{`CREATE TYPE public.rangetype AS RANGE ( 269 SUBTYPE = test_subtype_schema.test_subtype 270 );`, 271 "COMMENT ON TYPE public.rangetype IS 'This is a type comment.';", 272 "ALTER TYPE public.rangetype OWNER TO testrole;", 273 "SECURITY LABEL FOR dummy ON TYPE public.rangetype IS 'unclassified';"} 274 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, expectedStatements...) 275 }) 276 }) 277 Describe("PrintCreateCollationStatement", func() { 278 It("prints a create collation statement", func() { 279 collation := backup.Collation{Oid: 1, Name: "collation1", Collate: "collate1", Ctype: "ctype1", Schema: "schema1"} 280 backup.PrintCreateCollationStatements(backupfile, tocfile, []backup.Collation{collation}, emptyMetadataMap) 281 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, `CREATE COLLATION schema1.collation1 (LC_COLLATE = 'collate1', LC_CTYPE = 'ctype1');`) 282 }) 283 It("prints a create collation statement with owner and comment", func() { 284 collation := backup.Collation{Oid: 1, Name: "collation1", Collate: "collate1", Ctype: "ctype1", Schema: "schema1"} 285 collationMetadataMap := testutils.DefaultMetadataMap(toc.OBJ_COLLATION, false, true, true, false) 286 backup.PrintCreateCollationStatements(backupfile, tocfile, []backup.Collation{collation}, collationMetadataMap) 287 expectedStatements := []string{ 288 "CREATE COLLATION schema1.collation1 (LC_COLLATE = 'collate1', LC_CTYPE = 'ctype1');", 289 "COMMENT ON COLLATION schema1.collation1 IS 'This is a collation comment.';", 290 "ALTER COLLATION schema1.collation1 OWNER TO testrole;"} 291 testutils.AssertBufferContents(tocfile.PredataEntries, buffer, expectedStatements...) 292 }) 293 }) 294 })