github.com/tuhaihe/gpbackup@v1.0.3/integration/predata_functions_create_test.go (about) 1 package integration 2 3 import ( 4 "database/sql" 5 "fmt" 6 7 "github.com/tuhaihe/gp-common-go-libs/structmatcher" 8 "github.com/tuhaihe/gp-common-go-libs/testhelper" 9 "github.com/tuhaihe/gpbackup/backup" 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 create statement tests", func() { 17 BeforeEach(func() { 18 tocfile, backupfile = testutils.InitializeTestTOC(buffer, "predata") 19 }) 20 Describe("PrintCreateFunctionStatement", func() { 21 Context("Tests for GPDB 4.3", func() { 22 BeforeEach(func() { 23 testutils.SkipIfNot4(connectionPool) 24 }) 25 funcMetadata := backup.ObjectMetadata{} 26 It("creates a function with a simple return type", func() { 27 addFunction := backup.Function{ 28 Schema: "public", Name: "add", ReturnsSet: false, FunctionBody: "SELECT $1 + $2", 29 BinaryPath: "", Arguments: sql.NullString{String: "integer, integer", Valid: true}, 30 IdentArgs: sql.NullString{String: "integer, integer", Valid: true}, 31 ResultType: sql.NullString{String: "integer", Valid: true}, 32 Volatility: "v", IsStrict: false, IsSecurityDefiner: false, Config: "", NumRows: 0, Language: "sql", ExecLocation: "a", 33 } 34 35 metadata := testutils.DefaultMetadata("FUNCTION", true, true, true, false) 36 backup.PrintCreateFunctionStatement(backupfile, tocfile, addFunction, metadata) 37 38 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 39 defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.add(integer, integer)") 40 41 resultFunctions := backup.GetFunctionsAllVersions(connectionPool) 42 43 Expect(resultFunctions).To(HaveLen(1)) 44 structmatcher.ExpectStructsToMatchExcluding(&addFunction, &resultFunctions[0], "Oid") 45 }) 46 It("creates a function that returns a set", func() { 47 appendFunction := backup.Function{ 48 Schema: "public", Name: "append", ReturnsSet: true, FunctionBody: "SELECT ($1, $2)", 49 BinaryPath: "", Arguments: sql.NullString{String: "integer, integer", Valid: true}, 50 IdentArgs: sql.NullString{String: "integer, integer", Valid: true}, 51 ResultType: sql.NullString{String: "SETOF record", Valid: true}, 52 Volatility: "s", IsStrict: true, IsSecurityDefiner: true, Language: "sql", ExecLocation: "a", 53 } 54 55 backup.PrintCreateFunctionStatement(backupfile, tocfile, appendFunction, funcMetadata) 56 57 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 58 defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.append(integer, integer)") 59 60 resultFunctions := backup.GetFunctionsAllVersions(connectionPool) 61 62 Expect(resultFunctions).To(HaveLen(1)) 63 structmatcher.ExpectStructsToMatchExcluding(&appendFunction, &resultFunctions[0], "Oid") 64 }) 65 It("creates a function that returns a table", func() { 66 dupFunction := backup.Function{ 67 Schema: "public", Name: "dup", ReturnsSet: true, FunctionBody: "SELECT $1, CAST($1 AS text) || ' is text'", 68 BinaryPath: "", Arguments: sql.NullString{String: "integer", Valid: true}, 69 IdentArgs: sql.NullString{String: "integer", Valid: true}, 70 ResultType: sql.NullString{String: "TABLE(f1 integer, f2 text)", Valid: true}, 71 Volatility: "v", IsStrict: false, IsSecurityDefiner: false, Language: "sql", ExecLocation: "a", 72 } 73 74 backup.PrintCreateFunctionStatement(backupfile, tocfile, dupFunction, funcMetadata) 75 76 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 77 defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.dup(integer)") 78 79 resultFunctions := backup.GetFunctionsAllVersions(connectionPool) 80 81 Expect(resultFunctions).To(HaveLen(1)) 82 structmatcher.ExpectStructsToMatchExcluding(&dupFunction, &resultFunctions[0], "Oid") 83 }) 84 }) 85 Context("Tests for GPDB 5 and above", func() { 86 BeforeEach(func() { 87 testutils.SkipIfBefore5(connectionPool) 88 }) 89 funcMetadata := backup.ObjectMetadata{} 90 It("creates a function with a simple return type", func() { 91 addFunction := backup.Function{ 92 Schema: "public", Name: "add", ReturnsSet: false, FunctionBody: "SELECT $1 + $2", 93 BinaryPath: "", Arguments: sql.NullString{String: "integer, integer", Valid: true}, 94 IdentArgs: sql.NullString{String: "integer, integer", Valid: true}, 95 ResultType: sql.NullString{String: "integer", Valid: true}, 96 Volatility: "v", IsStrict: false, IsSecurityDefiner: false, Config: "", Cost: 100, NumRows: 0, DataAccess: "c", 97 Language: "sql", ExecLocation: "a", 98 } 99 if true { 100 addFunction.PlannerSupport = "-" 101 addFunction.Kind = "f" 102 addFunction.Parallel = "u" 103 } 104 105 metadata := testutils.DefaultMetadata("FUNCTION", true, true, true, includeSecurityLabels) 106 backup.PrintCreateFunctionStatement(backupfile, tocfile, addFunction, metadata) 107 108 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 109 defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.add(integer, integer)") 110 111 resultFunctions := backup.GetFunctionsAllVersions(connectionPool) 112 113 Expect(resultFunctions).To(HaveLen(1)) 114 115 structmatcher.ExpectStructsToMatchExcluding(&addFunction, &resultFunctions[0], "Oid") 116 }) 117 It("creates a function that returns a set", func() { 118 appendFunction := backup.Function{ 119 Schema: "public", Name: "append", ReturnsSet: true, FunctionBody: "SELECT ($1, $2)", 120 BinaryPath: "", Arguments: sql.NullString{String: "integer, integer", Valid: true}, 121 IdentArgs: sql.NullString{String: "integer, integer", Valid: true}, 122 ResultType: sql.NullString{String: "SETOF record", Valid: true}, 123 Volatility: "s", IsStrict: true, IsSecurityDefiner: true, Config: "SET search_path TO 'pg_temp'", Cost: 200, 124 NumRows: 200, DataAccess: "m", Language: "sql", ExecLocation: "a", 125 } 126 if true { 127 appendFunction.PlannerSupport = "-" 128 appendFunction.Kind = "f" 129 appendFunction.Parallel = "u" 130 } 131 132 backup.PrintCreateFunctionStatement(backupfile, tocfile, appendFunction, funcMetadata) 133 134 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 135 defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.append(integer, integer)") 136 137 resultFunctions := backup.GetFunctionsAllVersions(connectionPool) 138 139 Expect(resultFunctions).To(HaveLen(1)) 140 141 structmatcher.ExpectStructsToMatchExcluding(&appendFunction, &resultFunctions[0], "Oid") 142 }) 143 It("creates a function that returns a table", func() { 144 dupFunction := backup.Function{ 145 Schema: "public", Name: "dup", ReturnsSet: true, FunctionBody: "SELECT $1, CAST($1 AS text) || ' is text'", 146 BinaryPath: "", Arguments: sql.NullString{String: "integer", Valid: true}, 147 IdentArgs: sql.NullString{String: "integer", Valid: true}, 148 ResultType: sql.NullString{String: "TABLE(f1 integer, f2 text)", Valid: true}, 149 Volatility: "v", IsStrict: false, IsSecurityDefiner: false, Config: "", Cost: 100, NumRows: 1000, DataAccess: "c", 150 Language: "sql", ExecLocation: "a", 151 } 152 if true { 153 dupFunction.PlannerSupport = "-" 154 dupFunction.Kind = "f" 155 dupFunction.Parallel = "u" 156 } 157 158 backup.PrintCreateFunctionStatement(backupfile, tocfile, dupFunction, funcMetadata) 159 160 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 161 defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.dup(integer)") 162 163 resultFunctions := backup.GetFunctionsAllVersions(connectionPool) 164 165 Expect(resultFunctions).To(HaveLen(1)) 166 structmatcher.ExpectStructsToMatchExcluding(&dupFunction, &resultFunctions[0], "Oid") 167 }) 168 }) 169 Context("Tests for GPDB 6", func() { 170 BeforeEach(func() { 171 testutils.SkipIfBefore6(connectionPool) 172 }) 173 funcMetadata := backup.ObjectMetadata{} 174 It("creates a window function to execute on coordinator", func() { 175 windowFunction := backup.Function{ 176 Schema: "public", Name: "add", ReturnsSet: false, FunctionBody: "SELECT $1 + $2", 177 BinaryPath: "", Arguments: sql.NullString{String: "integer, integer", Valid: true}, 178 IdentArgs: sql.NullString{String: "integer, integer", Valid: true}, 179 ResultType: sql.NullString{String: "integer", Valid: true}, 180 Volatility: "v", IsStrict: false, IsSecurityDefiner: false, Config: "", Cost: 100, NumRows: 0, DataAccess: "c", 181 Language: "sql", ExecLocation: "m", IsWindow: true} 182 if true { 183 windowFunction.PlannerSupport = "-" 184 windowFunction.Kind = "w" 185 windowFunction.Parallel = "u" 186 windowFunction.ExecLocation = "c" 187 188 // GPDB7 only allows set-returning functions to execute on coordinator 189 windowFunction.ReturnsSet = true 190 windowFunction.NumRows = 1000 191 windowFunction.ResultType = sql.NullString{String: "SETOF integer", Valid: true} 192 } 193 194 backup.PrintCreateFunctionStatement(backupfile, tocfile, windowFunction, funcMetadata) 195 196 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 197 defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.add(integer, integer)") 198 199 resultFunctions := backup.GetFunctionsAllVersions(connectionPool) 200 201 Expect(resultFunctions).To(HaveLen(1)) 202 structmatcher.ExpectStructsToMatchExcluding(&windowFunction, &resultFunctions[0], "Oid") 203 }) 204 It("creates a function to execute on segments", func() { 205 segmentFunction := backup.Function{ 206 Schema: "public", Name: "add", ReturnsSet: false, FunctionBody: "SELECT $1 + $2", 207 BinaryPath: "", Arguments: sql.NullString{String: "integer, integer", Valid: true}, 208 IdentArgs: sql.NullString{String: "integer, integer", Valid: true}, 209 ResultType: sql.NullString{String: "integer", Valid: true}, 210 Volatility: "v", IsStrict: false, IsSecurityDefiner: false, Config: "", Cost: 100, NumRows: 0, DataAccess: "c", 211 Language: "sql", IsWindow: false, ExecLocation: "s", 212 } 213 if true { 214 segmentFunction.PlannerSupport = "-" 215 segmentFunction.Kind = "f" 216 segmentFunction.Parallel = "u" 217 218 // GPDB7 only allows set-returning functions to execute on coordinator 219 segmentFunction.ReturnsSet = true 220 segmentFunction.NumRows = 1000 221 segmentFunction.ResultType = sql.NullString{String: "SETOF integer", Valid: true} 222 } 223 224 backup.PrintCreateFunctionStatement(backupfile, tocfile, segmentFunction, funcMetadata) 225 226 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 227 defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.add(integer, integer)") 228 229 resultFunctions := backup.GetFunctionsAllVersions(connectionPool) 230 231 Expect(resultFunctions).To(HaveLen(1)) 232 structmatcher.ExpectStructsToMatchExcluding(&segmentFunction, &resultFunctions[0], "Oid") 233 }) 234 It("creates a function with LEAKPROOF", func() { 235 leakProofFunction := backup.Function{ 236 Schema: "public", Name: "add", ReturnsSet: false, FunctionBody: "SELECT $1 + $2", 237 BinaryPath: "", Arguments: sql.NullString{String: "integer, integer", Valid: true}, 238 IdentArgs: sql.NullString{String: "integer, integer", Valid: true}, 239 ResultType: sql.NullString{String: "integer", Valid: true}, 240 Volatility: "v", IsStrict: false, IsLeakProof: true, IsSecurityDefiner: false, Config: "", Cost: 100, NumRows: 0, DataAccess: "c", 241 Language: "sql", IsWindow: false, ExecLocation: "a", 242 } 243 if true { 244 leakProofFunction.PlannerSupport = "-" 245 leakProofFunction.Kind = "f" 246 leakProofFunction.Parallel = "u" 247 } 248 249 backup.PrintCreateFunctionStatement(backupfile, tocfile, leakProofFunction, funcMetadata) 250 251 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 252 defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.add(integer, integer)") 253 254 resultFunctions := backup.GetFunctionsAllVersions(connectionPool) 255 256 Expect(resultFunctions).To(HaveLen(1)) 257 structmatcher.ExpectStructsToMatchExcluding(&leakProofFunction, &resultFunctions[0], "Oid") 258 }) 259 }) 260 Context("Tests for GPDB 7", func() { 261 BeforeEach(func() { 262 testutils.SkipIfBefore7(connectionPool) 263 }) 264 funcMetadata := backup.ObjectMetadata{} 265 It("creates a function with PARALLEL RESTRICTED", func() { 266 ParallelFunction := backup.Function{ 267 Schema: "public", Name: "add", ReturnsSet: false, FunctionBody: "SELECT $1 + $2", 268 BinaryPath: "", Arguments: sql.NullString{String: "integer, integer", Valid: true}, 269 IdentArgs: sql.NullString{String: "integer, integer", Valid: true}, 270 ResultType: sql.NullString{String: "integer", Valid: true}, 271 Volatility: "v", IsStrict: false, IsLeakProof: false, IsSecurityDefiner: false, Config: "", Cost: 100, NumRows: 0, DataAccess: "c", 272 Language: "sql", IsWindow: false, ExecLocation: "a", PlannerSupport: "-", Kind: "f", Parallel: "r", 273 } 274 275 backup.PrintCreateFunctionStatement(backupfile, tocfile, ParallelFunction, funcMetadata) 276 277 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 278 defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.add(integer, integer)") 279 280 resultFunctions := backup.GetFunctionsAllVersions(connectionPool) 281 282 Expect(resultFunctions).To(HaveLen(1)) 283 structmatcher.ExpectStructsToMatchExcluding(&ParallelFunction, &resultFunctions[0], "Oid") 284 }) 285 // This test is pended because getting the DLL for hstore_plperl compiled and working in our CI is proving very difficult. 286 // TODO: get this working in CI, and un-pend it then. 287 PIt("creates a function with TRANSFORM FOR TYPE", func() { 288 TransformFunction := backup.Function{ 289 Schema: "public", Name: "add", ReturnsSet: false, FunctionBody: "SELECT $1 + 1", 290 BinaryPath: "", Arguments: sql.NullString{String: "hstore", Valid: true}, 291 IdentArgs: sql.NullString{String: "hstore", Valid: true}, 292 ResultType: sql.NullString{String: "integer", Valid: true}, 293 Volatility: "v", IsStrict: false, IsLeakProof: false, IsSecurityDefiner: false, Config: "", Cost: 100, NumRows: 0, DataAccess: "c", 294 Language: "plperl", IsWindow: false, ExecLocation: "a", PlannerSupport: "-", Kind: "f", Parallel: "u", 295 TransformTypes: "FOR TYPE pg_catalog.hstore", 296 } 297 backup.PrintCreateFunctionStatement(backupfile, tocfile, TransformFunction, funcMetadata) 298 299 // set up types and transforms needed 300 testhelper.AssertQueryRuns(connectionPool, "CREATE EXTENSION hstore;") 301 defer testhelper.AssertQueryRuns(connectionPool, "DROP EXTENSION hstore CASCADE;") 302 303 testhelper.AssertQueryRuns(connectionPool, "CREATE EXTENSION plperl;") 304 defer testhelper.AssertQueryRuns(connectionPool, "DROP EXTENSION plperl CASCADE;") 305 306 testhelper.AssertQueryRuns(connectionPool, `CREATE FUNCTION hstore_to_plperl(val internal) RETURNS internal 307 AS '$libdir/hstore_plperl.so' LANGUAGE C STRICT IMMUTABLE;`) 308 defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION hstore_to_plperl CASCADE;") 309 310 testhelper.AssertQueryRuns(connectionPool, "CREATE TRANSFORM FOR hstore LANGUAGE plperl (FROM SQL WITH FUNCTION hstore_to_plperl(internal))") 311 312 // create and assess function 313 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 314 defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.add(hstore)") 315 316 resultFunctions := backup.GetFunctionsAllVersions(connectionPool) 317 318 Expect(resultFunctions).To(HaveLen(1)) 319 structmatcher.ExpectStructsToMatchExcluding(&TransformFunction, &resultFunctions[0], "Oid") 320 }) 321 }) 322 }) 323 Describe("PrintCreateAggregateStatement", func() { 324 emptyMetadata := backup.ObjectMetadata{} 325 basicAggregateDef := backup.Aggregate{} 326 funcInfoMap := map[uint32]backup.FunctionInfo{ 327 1: {QualifiedName: "public.mysfunc_accum", Arguments: sql.NullString{String: "numeric, numeric, numeric", Valid: true}}, 328 2: {QualifiedName: "public.mypre_accum", Arguments: sql.NullString{String: "numeric, numeric", Valid: true}}, 329 3: {QualifiedName: "pg_catalog.ordered_set_transition_multi", Arguments: sql.NullString{String: `internal, VARIADIC "any"`, Valid: true}}, 330 4: {QualifiedName: "pg_catalog.rank_final", Arguments: sql.NullString{String: `internal, VARIADIC "any"`, Valid: true}}, 331 5: {QualifiedName: "pg_catalog.numeric_avg", Arguments: sql.NullString{String: "internal", Valid: true}}, 332 6: {QualifiedName: "pg_catalog.numeric_avg_serialize", Arguments: sql.NullString{String: "internal", Valid: true}}, 333 7: {QualifiedName: "pg_catalog.numeric_avg_deserialize", Arguments: sql.NullString{String: "bytea, internal", Valid: true}}, 334 8: {QualifiedName: "pg_catalog.numeric_avg_accum", Arguments: sql.NullString{String: "numeric, numeric", Valid: true}}, 335 9: {QualifiedName: "pg_catalog.power", Arguments: sql.NullString{String: "numeric, numeric", Valid: true}}, 336 } 337 BeforeEach(func() { 338 //Run queries to set up the database state so we can successfully create an aggregate 339 testhelper.AssertQueryRuns(connectionPool, ` 340 CREATE FUNCTION public.mysfunc_accum(numeric, numeric, numeric) 341 RETURNS numeric 342 AS 'select $1 + $2 + $3' 343 LANGUAGE SQL 344 IMMUTABLE; 345 `) 346 testhelper.AssertQueryRuns(connectionPool, ` 347 CREATE FUNCTION public.mypre_accum(numeric, numeric) 348 RETURNS numeric 349 AS 'select $1 + $2' 350 LANGUAGE SQL 351 IMMUTABLE 352 RETURNS NULL ON NULL INPUT; 353 `) 354 355 basicAggregateDef = backup.Aggregate{ 356 Oid: 1, Schema: "public", Name: "agg_prefunc", Arguments: sql.NullString{String: "numeric, numeric", Valid: true}, 357 IdentArgs: sql.NullString{String: "numeric, numeric", Valid: true}, TransitionFunction: 1, PreliminaryFunction: 2, 358 TransitionDataType: "numeric", InitialValue: "0", MInitValIsNull: true, 359 } 360 if true { 361 basicAggregateDef.Kind = "n" 362 basicAggregateDef.Finalmodify = "r" 363 basicAggregateDef.Mfinalmodify = "r" 364 basicAggregateDef.Parallel = "u" 365 } 366 }) 367 AfterEach(func() { 368 testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.mysfunc_accum(numeric, numeric, numeric)") 369 testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.mypre_accum(numeric, numeric)") 370 }) 371 It("creates a basic aggregate", func() { 372 backup.PrintCreateAggregateStatement(backupfile, tocfile, basicAggregateDef, funcInfoMap, emptyMetadata) 373 374 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 375 defer testhelper.AssertQueryRuns(connectionPool, "DROP AGGREGATE public.agg_prefunc(numeric, numeric)") 376 377 resultAggregates := backup.GetAggregates(connectionPool) 378 Expect(resultAggregates).To(HaveLen(1)) 379 structmatcher.ExpectStructsToMatchExcluding(&basicAggregateDef, &resultAggregates[0], "Oid", "TransitionFunction", "PreliminaryFunction", "CombineFunction") 380 }) 381 It("creates an aggregate with an owner, security label, and a comment", func() { 382 aggMetadata := testutils.DefaultMetadata("AGGREGATE", false, true, true, includeSecurityLabels) 383 backup.PrintCreateAggregateStatement(backupfile, tocfile, basicAggregateDef, funcInfoMap, aggMetadata) 384 385 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 386 defer testhelper.AssertQueryRuns(connectionPool, "DROP AGGREGATE public.agg_prefunc(numeric, numeric)") 387 388 resultAggregates := backup.GetAggregates(connectionPool) 389 Expect(resultAggregates).To(HaveLen(1)) 390 resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_AGGREGATE) 391 resultMetadata := resultMetadataMap[resultAggregates[0].GetUniqueID()] 392 structmatcher.ExpectStructsToMatchExcluding(&basicAggregateDef, &resultAggregates[0], "Oid", "TransitionFunction", "PreliminaryFunction", "CombineFunction") 393 structmatcher.ExpectStructsToMatch(&aggMetadata, &resultMetadata) 394 }) 395 It("creates a hypothetical ordered-set aggregate", func() { 396 testutils.SkipIfBefore6(connectionPool) 397 complexAggregateDef := backup.Aggregate{ 398 Schema: "public", Name: "agg_hypo_ord", Arguments: sql.NullString{String: `VARIADIC "any" ORDER BY VARIADIC "any"`, Valid: true}, 399 IdentArgs: sql.NullString{String: `VARIADIC "any" ORDER BY VARIADIC "any"`, Valid: true}, TransitionFunction: 3, FinalFunction: 4, 400 TransitionDataType: "internal", InitValIsNull: true, FinalFuncExtra: true, Hypothetical: true, MInitValIsNull: true, 401 } 402 if true { 403 complexAggregateDef.Hypothetical = false 404 complexAggregateDef.Kind = "h" 405 complexAggregateDef.Finalmodify = "w" 406 complexAggregateDef.Mfinalmodify = "w" 407 complexAggregateDef.Parallel = "u" 408 } 409 410 backup.PrintCreateAggregateStatement(backupfile, tocfile, complexAggregateDef, funcInfoMap, emptyMetadata) 411 412 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 413 defer testhelper.AssertQueryRuns(connectionPool, `DROP AGGREGATE public.agg_hypo_ord(VARIADIC "any" ORDER BY VARIADIC "any")`) 414 resultAggregates := backup.GetAggregates(connectionPool) 415 416 Expect(resultAggregates).To(HaveLen(1)) 417 structmatcher.ExpectStructsToMatchExcluding(&complexAggregateDef, &resultAggregates[0], "Oid", "TransitionFunction", "FinalFunction") 418 }) 419 It("creates an aggregate with a sort operator", func() { 420 aggregateDef := backup.Aggregate{ 421 Schema: "public", Name: "agg_sort", Arguments: sql.NullString{String: "numeric", Valid: true}, 422 IdentArgs: sql.NullString{String: "numeric", Valid: true}, TransitionFunction: 9, FinalFunction: 0, 423 SortOperator: "+", SortOperatorSchema: "pg_catalog", TransitionDataType: "numeric", 424 InitialValue: "0", IsOrdered: false, MInitValIsNull: true, 425 } 426 if true { 427 aggregateDef.Kind = "n" 428 aggregateDef.Finalmodify = "r" 429 aggregateDef.Mfinalmodify = "r" 430 aggregateDef.Parallel = "u" 431 } 432 433 backup.PrintCreateAggregateStatement(backupfile, tocfile, aggregateDef, funcInfoMap, emptyMetadata) 434 435 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 436 defer testhelper.AssertQueryRuns(connectionPool, `DROP AGGREGATE public.agg_sort(numeric)`) 437 resultAggregates := backup.GetAggregates(connectionPool) 438 439 Expect(resultAggregates).To(HaveLen(1)) 440 structmatcher.ExpectStructsToMatchExcluding(&aggregateDef, &resultAggregates[0], "Oid", "TransitionFunction", "FinalFunction", "CombineFunction") 441 }) 442 It("creates an aggregate with combine function and transition data size", func() { 443 testutils.SkipIfBefore6(connectionPool) 444 aggregateDef := backup.Aggregate{ 445 Schema: "public", Name: "agg_6_features", Arguments: sql.NullString{String: "numeric, numeric", Valid: true}, 446 IdentArgs: sql.NullString{String: "numeric, numeric", Valid: true}, TransitionFunction: 1, CombineFunction: 2, 447 FinalFunction: 0, SortOperator: "", TransitionDataType: "numeric", TransitionDataSize: 1000, 448 InitialValue: "0", IsOrdered: false, MInitValIsNull: true, 449 } 450 if true { 451 aggregateDef.Kind = "n" 452 aggregateDef.Finalmodify = "r" 453 aggregateDef.Mfinalmodify = "r" 454 aggregateDef.Parallel = "u" 455 } 456 457 backup.PrintCreateAggregateStatement(backupfile, tocfile, aggregateDef, funcInfoMap, emptyMetadata) 458 459 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 460 defer testhelper.AssertQueryRuns(connectionPool, `DROP AGGREGATE public.agg_6_features(numeric, numeric)`) 461 resultAggregates := backup.GetAggregates(connectionPool) 462 463 Expect(resultAggregates).To(HaveLen(1)) 464 structmatcher.ExpectStructsToMatchExcluding(&aggregateDef, &resultAggregates[0], "Oid", "TransitionFunction", "FinalFunction", "CombineFunction") 465 }) 466 It("creates an aggregate with serial/deserial functions", func() { 467 testutils.SkipIfBefore6(connectionPool) 468 aggregateDef := backup.Aggregate{ 469 Schema: "public", Name: "myavg", Arguments: sql.NullString{String: "numeric", Valid: true}, 470 IdentArgs: sql.NullString{String: "numeric", Valid: true}, TransitionFunction: 8, 471 FinalFunction: 5, SerialFunction: 6, DeserialFunction: 7, TransitionDataType: "internal", 472 IsOrdered: false, InitValIsNull: true, MInitValIsNull: true, 473 } 474 if true { 475 aggregateDef.Kind = "n" 476 aggregateDef.Finalmodify = "r" 477 aggregateDef.Mfinalmodify = "r" 478 aggregateDef.Parallel = "u" 479 } 480 481 backup.PrintCreateAggregateStatement(backupfile, tocfile, aggregateDef, funcInfoMap, emptyMetadata) 482 483 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 484 defer testhelper.AssertQueryRuns(connectionPool, `DROP AGGREGATE public.myavg(numeric)`) 485 resultAggregates := backup.GetAggregates(connectionPool) 486 487 Expect(resultAggregates).To(HaveLen(1)) 488 structmatcher.ExpectStructsToMatchExcluding(&aggregateDef, &resultAggregates[0], "Oid", "TransitionFunction", "FinalFunction", "SerialFunction", "DeserialFunction") 489 }) 490 It("creates an aggregate with moving attributes", func() { 491 testutils.SkipIfBefore6(connectionPool) 492 aggregateDef := backup.Aggregate{ 493 Schema: "public", Name: "moving_agg", Arguments: sql.NullString{String: "numeric, numeric", Valid: true}, 494 IdentArgs: sql.NullString{String: "numeric, numeric", Valid: true}, TransitionFunction: 1, TransitionDataType: "numeric", 495 InitValIsNull: true, MTransitionFunction: 1, MInverseTransitionFunction: 1, 496 MTransitionDataType: "numeric", MTransitionDataSize: 100, MFinalFunction: 1, 497 MFinalFuncExtra: true, MInitialValue: "0", MInitValIsNull: false, 498 } 499 if true { 500 aggregateDef.Kind = "n" 501 aggregateDef.Finalmodify = "r" 502 aggregateDef.Mfinalmodify = "r" 503 aggregateDef.Parallel = "u" 504 } 505 506 backup.PrintCreateAggregateStatement(backupfile, tocfile, aggregateDef, funcInfoMap, emptyMetadata) 507 508 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 509 defer testhelper.AssertQueryRuns(connectionPool, `DROP AGGREGATE public.moving_agg(numeric, numeric)`) 510 resultAggregates := backup.GetAggregates(connectionPool) 511 512 Expect(resultAggregates).To(HaveLen(1)) 513 structmatcher.ExpectStructsToMatchExcluding(&aggregateDef, &resultAggregates[0], "Oid", "TransitionFunction", "MTransitionFunction", "MInverseTransitionFunction", "MFinalFunction") 514 }) 515 // TODO: test for aggregate with aggfinalmodify/aggmfinalmodify (no table, just couple examples to check on query is correct) 516 }) 517 Describe("PrintCreateCastStatement", func() { 518 var ( 519 castMetadata backup.ObjectMetadata 520 ) 521 BeforeEach(func() { 522 castMetadata = backup.ObjectMetadata{} 523 }) 524 It("prints a basic cast with a function", func() { 525 castDef := backup.Cast{Oid: 0, SourceTypeFQN: "pg_catalog.money", TargetTypeFQN: "pg_catalog.text", FunctionSchema: "public", FunctionName: "money_to_text", FunctionArgs: "money", CastContext: "a", CastMethod: "f"} 526 527 testhelper.AssertQueryRuns(connectionPool, "CREATE FUNCTION public.money_to_text(money) RETURNS TEXT AS $$ SELECT textin(cash_out($1)) $$ LANGUAGE SQL;") 528 defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.money_to_text(money)") 529 530 backup.PrintCreateCastStatement(backupfile, tocfile, castDef, castMetadata) 531 defer testhelper.AssertQueryRuns(connectionPool, "DROP CAST (money AS text)") 532 533 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 534 535 resultCasts := backup.GetCasts(connectionPool) 536 Expect(resultCasts).To(HaveLen(1)) 537 structmatcher.ExpectStructsToMatchExcluding(&castDef, &resultCasts[0], "Oid", "FunctionOid") 538 }) 539 It("prints a basic cast without a function", func() { 540 castDef := backup.Cast{Oid: 0, SourceTypeFQN: "pg_catalog.text", TargetTypeFQN: "public.casttesttype", FunctionSchema: "", FunctionName: "", FunctionArgs: "", CastContext: "i", CastMethod: "b"} 541 542 testhelper.AssertQueryRuns(connectionPool, "CREATE FUNCTION public.cast_in(cstring) RETURNS public.casttesttype AS $$textin$$ LANGUAGE internal STRICT NO SQL") 543 testhelper.AssertQueryRuns(connectionPool, "CREATE FUNCTION public.cast_out(public.casttesttype) RETURNS cstring AS $$textout$$ LANGUAGE internal STRICT NO SQL") 544 testhelper.AssertQueryRuns(connectionPool, "CREATE TYPE public.casttesttype (INTERNALLENGTH = variable, INPUT = public.cast_in, OUTPUT = public.cast_out)") 545 defer testhelper.AssertQueryRuns(connectionPool, "DROP TYPE public.casttesttype CASCADE") 546 547 backup.PrintCreateCastStatement(backupfile, tocfile, castDef, castMetadata) 548 defer testhelper.AssertQueryRuns(connectionPool, "DROP CAST (text AS public.casttesttype)") 549 550 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 551 552 resultCasts := backup.GetCasts(connectionPool) 553 Expect(resultCasts).To(HaveLen(1)) 554 structmatcher.ExpectStructsToMatchExcluding(&castDef, &resultCasts[0], "Oid") 555 }) 556 It("prints a cast with a comment", func() { 557 castDef := backup.Cast{Oid: 1, SourceTypeFQN: "pg_catalog.money", TargetTypeFQN: "pg_catalog.text", FunctionSchema: "public", FunctionName: "money_to_text", FunctionArgs: "money", CastContext: "a", CastMethod: "f"} 558 castMetadata = testutils.DefaultMetadata("CAST", false, false, true, false) 559 560 testhelper.AssertQueryRuns(connectionPool, "CREATE FUNCTION public.money_to_text(money) RETURNS TEXT AS $$ SELECT textin(cash_out($1)) $$ LANGUAGE SQL;") 561 defer testhelper.AssertQueryRuns(connectionPool, "DROP FUNCTION public.money_to_text(money)") 562 563 backup.PrintCreateCastStatement(backupfile, tocfile, castDef, castMetadata) 564 defer testhelper.AssertQueryRuns(connectionPool, "DROP CAST (money AS text)") 565 566 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 567 568 resultCasts := backup.GetCasts(connectionPool) 569 Expect(resultCasts).To(HaveLen(1)) 570 resultMetadataMap := backup.GetCommentsForObjectType(connectionPool, backup.TYPE_CAST) 571 resultMetadata := resultMetadataMap[resultCasts[0].GetUniqueID()] 572 structmatcher.ExpectStructsToMatchExcluding(&castDef, &resultCasts[0], "Oid", "FunctionOid") 573 structmatcher.ExpectStructsToMatchExcluding(&resultMetadata, &castMetadata, "Oid") 574 }) 575 It("prints an inout cast ", func() { 576 testutils.SkipIfBefore6(connectionPool) 577 castDef := backup.Cast{Oid: 0, SourceTypeFQN: `pg_catalog."varchar"`, TargetTypeFQN: "public.custom_numeric", FunctionSchema: "", FunctionName: "", FunctionArgs: "", CastContext: "a", CastMethod: "i"} 578 testhelper.AssertQueryRuns(connectionPool, "CREATE TYPE public.custom_numeric AS (i numeric)") 579 defer testhelper.AssertQueryRuns(connectionPool, "DROP TYPE public.custom_numeric") 580 581 backup.PrintCreateCastStatement(backupfile, tocfile, castDef, castMetadata) 582 defer testhelper.AssertQueryRuns(connectionPool, "DROP CAST (varchar AS public.custom_numeric)") 583 584 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 585 586 resultCasts := backup.GetCasts(connectionPool) 587 Expect(resultCasts).To(HaveLen(1)) 588 structmatcher.ExpectStructsToMatchExcluding(&castDef, &resultCasts[0], "Oid") 589 }) 590 }) 591 Describe("PrintCreateLanguageStatements", func() { 592 It("creates procedural languages", func() { 593 plpythonString := "plpython" 594 if true { 595 plpythonString = "plpython3" 596 } 597 598 funcInfoMap := map[uint32]backup.FunctionInfo{ 599 1: {QualifiedName: fmt.Sprintf("pg_catalog.%s_call_handler", plpythonString), Arguments: sql.NullString{String: "", Valid: true}, IsInternal: true}, 600 2: {QualifiedName: fmt.Sprintf("pg_catalog.%s_inline_handler", plpythonString), Arguments: sql.NullString{String: "internal", Valid: true}, IsInternal: true}, 601 } 602 langOwner := "" 603 var langMetadata backup.ObjectMetadata 604 if false { 605 langOwner = testutils.GetUserByID(connectionPool, 10) 606 langMetadata = backup.ObjectMetadata{ObjectType: "LANGUAGE", Privileges: []backup.ACL{}, Owner: langOwner, Comment: "This is a language comment"} 607 } else { 608 langOwner = "testrole" 609 langMetadata = testutils.DefaultMetadata("LANGUAGE", false, true, true, includeSecurityLabels) 610 } 611 plpythonInfo := backup.ProceduralLanguage{Oid: 1, Name: fmt.Sprintf("%su", plpythonString), Owner: langOwner, IsPl: true, PlTrusted: false, Handler: 1, Inline: 2} 612 613 langMetadataMap := map[backup.UniqueID]backup.ObjectMetadata{plpythonInfo.GetUniqueID(): langMetadata} 614 if false { 615 plpythonInfo.Inline = 0 616 } 617 procLangs := []backup.ProceduralLanguage{plpythonInfo} 618 619 backup.PrintCreateLanguageStatements(backupfile, tocfile, procLangs, funcInfoMap, langMetadataMap) 620 621 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 622 defer testhelper.AssertQueryRuns(connectionPool, fmt.Sprintf("DROP LANGUAGE %su", plpythonString)) 623 624 resultProcLangs := backup.GetProceduralLanguages(connectionPool) 625 resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_PROCLANGUAGE) 626 627 plpythonInfo.Oid = testutils.OidFromObjectName(connectionPool, "", fmt.Sprintf("%su", plpythonString), backup.TYPE_PROCLANGUAGE) 628 Expect(resultProcLangs).To(HaveLen(1)) 629 resultMetadata := resultMetadataMap[plpythonInfo.GetUniqueID()] 630 structmatcher.ExpectStructsToMatchIncluding(&plpythonInfo, &resultProcLangs[0], "Name", "IsPl", "PlTrusted") 631 structmatcher.ExpectStructsToMatch(&langMetadata, &resultMetadata) 632 }) 633 }) 634 Describe("PrintCreateExtensions", func() { 635 It("creates extensions", func() { 636 testutils.SkipIfBefore5(connectionPool) 637 plperlExtension := backup.Extension{Oid: 1, Name: "plperl", Schema: "pg_catalog"} 638 extensions := []backup.Extension{plperlExtension} 639 extensionMetadataMap := testutils.DefaultMetadataMap("EXTENSION", false, false, true, false) 640 extensionMetadata := extensionMetadataMap[plperlExtension.GetUniqueID()] 641 backup.PrintCreateExtensionStatements(backupfile, tocfile, extensions, extensionMetadataMap) 642 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 643 defer testhelper.AssertQueryRuns(connectionPool, "DROP EXTENSION plperl; SET search_path=pg_catalog") 644 resultExtensions := backup.GetExtensions(connectionPool) 645 resultMetadataMap := backup.GetCommentsForObjectType(connectionPool, backup.TYPE_EXTENSION) 646 plperlExtension.Oid = testutils.OidFromObjectName(connectionPool, "", "plperl", backup.TYPE_EXTENSION) 647 Expect(resultExtensions).To(HaveLen(1)) 648 plperlMetadata := resultMetadataMap[plperlExtension.GetUniqueID()] 649 structmatcher.ExpectStructsToMatch(&plperlExtension, &resultExtensions[0]) 650 structmatcher.ExpectStructsToMatch(&extensionMetadata, &plperlMetadata) 651 }) 652 }) 653 Describe("PrintCreateTransformStatements", func() { 654 var fromSQLFuncOid uint32 655 var toSQLFuncOid uint32 656 var funcInfoMap map[uint32]backup.FunctionInfo 657 658 BeforeEach(func() { 659 testutils.SkipIfBefore7(connectionPool) 660 fromSQLFuncOid = testutils.OidFromObjectName(connectionPool, "pg_catalog", "numeric_support", backup.TYPE_FUNCTION) 661 toSQLFuncOid = testutils.OidFromObjectName(connectionPool, "pg_catalog", "int2recv", backup.TYPE_FUNCTION) 662 663 funcInfoMap = map[uint32]backup.FunctionInfo{ 664 fromSQLFuncOid: {QualifiedName: "numeric_support", IdentArgs: sql.NullString{String: "internal", Valid: true}}, 665 toSQLFuncOid: {QualifiedName: "int2recv", IdentArgs: sql.NullString{String: "internal", Valid: true}}, 666 } 667 }) 668 669 DescribeTable("creates transforms", func(fromSql func() uint32, toSql func() uint32) { 670 transform := backup.Transform{Oid: 1, TypeNamespace: "pg_catalog", TypeName: "int2", LanguageName: "c", FromSQLFunc: fromSql(), ToSQLFunc: toSql()} 671 transMetadata := testutils.DefaultMetadata("TRANSFORM", false, false, false, false) 672 backup.PrintCreateTransformStatement(backupfile, tocfile, transform, funcInfoMap, transMetadata) 673 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 674 defer testhelper.AssertQueryRuns(connectionPool, "DROP TRANSFORM FOR int2 LANGUAGE c") 675 676 resultTransforms := backup.GetTransforms(connectionPool) 677 Expect(resultTransforms).To(HaveLen(1)) 678 structmatcher.ExpectStructsToMatchExcluding(&transform, &resultTransforms[0], "Oid") 679 }, 680 Entry("both functions are specified", func() uint32 { return fromSQLFuncOid }, func() uint32 { return toSQLFuncOid }), 681 Entry("only fromSQL function is specified", func() uint32 { return fromSQLFuncOid }, func() uint32 { return uint32(0) }), 682 Entry("only toSql function is specified", func() uint32 { return uint32(0) }, func() uint32 { return toSQLFuncOid }), 683 ) 684 }) 685 Describe("PrintCreateConversionStatements", func() { 686 It("creates conversions", func() { 687 convOne := backup.Conversion{Oid: 1, Schema: "public", Name: "conv_one", ForEncoding: "LATIN1", ToEncoding: "MULE_INTERNAL", ConversionFunction: "pg_catalog.latin1_to_mic", IsDefault: false} 688 convTwo := backup.Conversion{Oid: 0, Schema: "public", Name: "conv_two", ForEncoding: "LATIN1", ToEncoding: "MULE_INTERNAL", ConversionFunction: "pg_catalog.latin1_to_mic", IsDefault: true} 689 conversions := []backup.Conversion{convOne, convTwo} 690 convMetadataMap := testutils.DefaultMetadataMap("CONVERSION", false, true, true, false) 691 convMetadata := convMetadataMap[convOne.GetUniqueID()] 692 693 backup.PrintCreateConversionStatements(backupfile, tocfile, conversions, convMetadataMap) 694 695 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 696 defer testhelper.AssertQueryRuns(connectionPool, "DROP CONVERSION public.conv_one") 697 defer testhelper.AssertQueryRuns(connectionPool, "DROP CONVERSION public.conv_two") 698 699 resultConversions := backup.GetConversions(connectionPool) 700 resultMetadataMap := backup.GetMetadataForObjectType(connectionPool, backup.TYPE_CONVERSION) 701 702 convOne.Oid = testutils.OidFromObjectName(connectionPool, "public", "conv_one", backup.TYPE_CONVERSION) 703 convTwo.Oid = testutils.OidFromObjectName(connectionPool, "public", "conv_two", backup.TYPE_CONVERSION) 704 Expect(resultConversions).To(HaveLen(2)) 705 resultMetadata := resultMetadataMap[convOne.GetUniqueID()] 706 structmatcher.ExpectStructsToMatch(&convOne, &resultConversions[0]) 707 structmatcher.ExpectStructsToMatch(&convTwo, &resultConversions[1]) 708 structmatcher.ExpectStructsToMatch(&convMetadata, &resultMetadata) 709 }) 710 }) 711 Describe("PrintCreateForeignDataWrapperStatement", func() { 712 emptyMetadata := backup.ObjectMetadata{} 713 funcInfoMap := map[uint32]backup.FunctionInfo{ 714 1: {QualifiedName: "pg_catalog.postgresql_fdw_validator", Arguments: sql.NullString{String: "", Valid: true}, IsInternal: true}, 715 } 716 It("creates foreign data wrappers with a validator and options", func() { 717 testutils.SkipIfBefore6(connectionPool) 718 foreignDataWrapperValidator := backup.ForeignDataWrapper{Name: "foreigndata1", Validator: 1} 719 foreignDataWrapperOptions := backup.ForeignDataWrapper{Name: "foreigndata2", Options: "dbname 'testdb'"} 720 721 backup.PrintCreateForeignDataWrapperStatement(backupfile, tocfile, foreignDataWrapperValidator, funcInfoMap, emptyMetadata) 722 backup.PrintCreateForeignDataWrapperStatement(backupfile, tocfile, foreignDataWrapperOptions, funcInfoMap, emptyMetadata) 723 724 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 725 defer testhelper.AssertQueryRuns(connectionPool, "DROP FOREIGN DATA WRAPPER foreigndata1") 726 defer testhelper.AssertQueryRuns(connectionPool, "DROP FOREIGN DATA WRAPPER foreigndata2") 727 728 resultWrappers := backup.GetForeignDataWrappers(connectionPool) 729 730 Expect(resultWrappers).To(HaveLen(2)) 731 structmatcher.ExpectStructsToMatchExcluding(&foreignDataWrapperValidator, &resultWrappers[0], "Oid", "Validator") 732 structmatcher.ExpectStructsToMatchExcluding(&foreignDataWrapperOptions, &resultWrappers[1], "Oid", "Validator") 733 }) 734 }) 735 Describe("PrintCreateServerStatement", func() { 736 emptyMetadata := backup.ObjectMetadata{} 737 It("creates a foreign server with all options", func() { 738 testutils.SkipIfBefore6(connectionPool) 739 foreignServer := backup.ForeignServer{Name: "foreignserver", Type: "mytype", Version: "myversion", ForeignDataWrapper: "foreigndatawrapper", Options: "dbname 'testdb', host 'localhost'"} 740 741 backup.PrintCreateServerStatement(backupfile, tocfile, foreignServer, emptyMetadata) 742 743 testhelper.AssertQueryRuns(connectionPool, "CREATE FOREIGN DATA WRAPPER foreigndatawrapper") 744 defer testhelper.AssertQueryRuns(connectionPool, "DROP FOREIGN DATA WRAPPER foreigndatawrapper CASCADE") 745 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 746 747 resultServers := backup.GetForeignServers(connectionPool) 748 749 Expect(resultServers).To(HaveLen(1)) 750 structmatcher.ExpectStructsToMatchExcluding(&foreignServer, &resultServers[0], "Oid") 751 }) 752 }) 753 Describe("PrintCreateUserMappingStatement", func() { 754 It("creates a user mapping for a specific user with all options", func() { 755 testutils.SkipIfBefore6(connectionPool) 756 testhelper.AssertQueryRuns(connectionPool, "CREATE FOREIGN DATA WRAPPER foreigndatawrapper") 757 defer testhelper.AssertQueryRuns(connectionPool, "DROP FOREIGN DATA WRAPPER foreigndatawrapper CASCADE") 758 testhelper.AssertQueryRuns(connectionPool, "CREATE SERVER server FOREIGN DATA WRAPPER foreigndatawrapper") 759 userMapping := backup.UserMapping{User: "testrole", Server: "server", Options: "dbname 'testdb', host 'localhost'"} 760 761 backup.PrintCreateUserMappingStatement(backupfile, tocfile, userMapping) 762 763 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 764 765 resultMappings := backup.GetUserMappings(connectionPool) 766 767 Expect(resultMappings).To(HaveLen(1)) 768 structmatcher.ExpectStructsToMatchExcluding(&userMapping, &resultMappings[0], "Oid") 769 }) 770 It("creates a user mapping for public", func() { 771 testutils.SkipIfBefore6(connectionPool) 772 testhelper.AssertQueryRuns(connectionPool, "CREATE FOREIGN DATA WRAPPER foreigndatawrapper") 773 defer testhelper.AssertQueryRuns(connectionPool, "DROP FOREIGN DATA WRAPPER foreigndatawrapper CASCADE") 774 testhelper.AssertQueryRuns(connectionPool, "CREATE SERVER server FOREIGN DATA WRAPPER foreigndatawrapper") 775 userMapping := backup.UserMapping{User: "public", Server: "server"} 776 777 backup.PrintCreateUserMappingStatement(backupfile, tocfile, userMapping) 778 779 testhelper.AssertQueryRuns(connectionPool, buffer.String()) 780 781 resultMappings := backup.GetUserMappings(connectionPool) 782 783 Expect(resultMappings).To(HaveLen(1)) 784 structmatcher.ExpectStructsToMatchExcluding(&userMapping, &resultMappings[0], "Oid") 785 }) 786 }) 787 })