From b0f1a6ca6bf0981b905c1c647357f7cffbb1c7c2 Mon Sep 17 00:00:00 2001 From: "Paul A. Jungwirth" Date: Sat, 21 Sep 2019 21:28:37 -0700 Subject: [PATCH v6 3/4] multirange pg_dump --- src/backend/commands/typecmds.c | 85 +++++++++++++++++-- src/backend/utils/adt/pg_upgrade_support.c | 22 +++++ src/bin/pg_dump/pg_dump.c | 130 ++++++++++++++++++++--------- src/bin/pg_dump/pg_dump.h | 1 + src/include/catalog/binary_upgrade.h | 2 + src/include/catalog/pg_proc.dat | 8 ++ src/include/commands/typecmds.h | 2 + 7 files changed, 205 insertions(+), 45 deletions(-) diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 7a440cafd1..38948a049b 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -85,6 +85,8 @@ typedef struct /* Potentially set by pg_upgrade_support functions */ Oid binary_upgrade_next_array_pg_type_oid = InvalidOid; +Oid binary_upgrade_next_multirange_pg_type_oid = InvalidOid; +Oid binary_upgrade_next_multirange_array_pg_type_oid = InvalidOid; static void makeRangeConstructors(const char *name, Oid namespace, Oid rangeOid, Oid subtype); @@ -1356,11 +1358,11 @@ DefineRange(CreateRangeStmt *stmt) char *typeName; Oid typeNamespace; Oid typoid; - Oid mltrngtypoid; char *rangeArrayName; char *multirangeTypeName; char *multirangeArrayName; Oid rangeArrayOid; + Oid multirangeOid; Oid multirangeArrayOid; Oid rangeSubtype = InvalidOid; List *rangeSubOpclassName = NIL; @@ -1530,8 +1532,11 @@ DefineRange(CreateRangeStmt *stmt) /* Allocate OID for array type */ rangeArrayOid = AssignTypeArrayOid(); + /* Allocate OID for multirange type */ + multirangeOid = AssignTypeMultirangeOid(); + /* Allocate OID for multirange array type */ - multirangeArrayOid = AssignTypeArrayOid(); + multirangeArrayOid = AssignTypeMultirangeArrayOid(); /* Create the pg_type entry */ address = @@ -1573,7 +1578,7 @@ DefineRange(CreateRangeStmt *stmt) multirangeTypeName = makeMultirangeTypeName(typeName, typeNamespace); mltrngaddress = - TypeCreate(InvalidOid, /* no predetermined type OID */ + TypeCreate(multirangeOid, /* force assignment of this type OID */ multirangeTypeName, /* type name */ typeNamespace, /* namespace */ InvalidOid, /* relation oid (n/a here) */ @@ -1604,11 +1609,11 @@ DefineRange(CreateRangeStmt *stmt) 0, /* Array dimensions of typbasetype */ false, /* Type NOT NULL */ InvalidOid); /* type's collation (ranges never have one) */ - mltrngtypoid = mltrngaddress.objectId; + Assert(multirangeOid == mltrngaddress.objectId); /* Create the entry in pg_range */ RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass, - rangeCanonical, rangeSubtypeDiff, mltrngtypoid); + rangeCanonical, rangeSubtypeDiff, multirangeOid); /* * Create the array type that goes with it. @@ -1671,7 +1676,7 @@ DefineRange(CreateRangeStmt *stmt) InvalidOid, /* typmodin procedure - none */ InvalidOid, /* typmodout procedure - none */ F_ARRAY_TYPANALYZE, /* analyze procedure */ - mltrngtypoid, /* element type ID */ + multirangeOid, /* element type ID */ true, /* yes this is an array type */ InvalidOid, /* no further array type */ InvalidOid, /* base type ID */ @@ -1688,7 +1693,7 @@ DefineRange(CreateRangeStmt *stmt) /* And create the constructor functions for this range type */ makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype); makeMultirangeConstructors(multirangeTypeName, typeNamespace, - mltrngtypoid, rangeArrayOid); + multirangeOid, rangeArrayOid); pfree(multirangeTypeName); pfree(multirangeArrayName); @@ -2269,6 +2274,72 @@ AssignTypeArrayOid(void) return type_array_oid; } +/* + * AssignTypeMultirangeOid + * + * Pre-assign the range type's multirange OID for use in pg_type.oid + */ +Oid +AssignTypeMultirangeOid(void) +{ + Oid type_multirange_oid; + + /* Use binary-upgrade override for pg_type.oid? */ + if (IsBinaryUpgrade) + { + if (!OidIsValid(binary_upgrade_next_multirange_pg_type_oid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("pg_type multirange OID value not set when in binary upgrade mode"))); + + type_multirange_oid = binary_upgrade_next_multirange_pg_type_oid; + binary_upgrade_next_multirange_pg_type_oid = InvalidOid; + } + else + { + Relation pg_type = table_open(TypeRelationId, AccessShareLock); + + type_multirange_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId, + Anum_pg_type_oid); + table_close(pg_type, AccessShareLock); + } + + return type_multirange_oid; +} + +/* + * AssignTypeMultirangeArrayOid + * + * Pre-assign the range type's multirange array OID for use in pg_type.typarray + */ +Oid +AssignTypeMultirangeArrayOid(void) +{ + Oid type_multirange_array_oid; + + /* Use binary-upgrade override for pg_type.oid? */ + if (IsBinaryUpgrade) + { + if (!OidIsValid(binary_upgrade_next_multirange_array_pg_type_oid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("pg_type multirange array OID value not set when in binary upgrade mode"))); + + type_multirange_array_oid = binary_upgrade_next_multirange_array_pg_type_oid; + binary_upgrade_next_multirange_array_pg_type_oid = InvalidOid; + } + else + { + Relation pg_type = table_open(TypeRelationId, AccessShareLock); + + type_multirange_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId, + Anum_pg_type_oid); + table_close(pg_type, AccessShareLock); + } + + return type_multirange_array_oid; +} + /*------------------------------------------------------------------- * DefineCompositeType diff --git a/src/backend/utils/adt/pg_upgrade_support.c b/src/backend/utils/adt/pg_upgrade_support.c index 99db5ba389..d980b96f48 100644 --- a/src/backend/utils/adt/pg_upgrade_support.c +++ b/src/backend/utils/adt/pg_upgrade_support.c @@ -52,6 +52,28 @@ binary_upgrade_set_next_array_pg_type_oid(PG_FUNCTION_ARGS) } Datum +binary_upgrade_set_next_multirange_pg_type_oid(PG_FUNCTION_ARGS) +{ + Oid typoid = PG_GETARG_OID(0); + + CHECK_IS_BINARY_UPGRADE; + binary_upgrade_next_multirange_pg_type_oid = typoid; + + PG_RETURN_VOID(); +} + +Datum +binary_upgrade_set_next_multirange_array_pg_type_oid(PG_FUNCTION_ARGS) +{ + Oid typoid = PG_GETARG_OID(0); + + CHECK_IS_BINARY_UPGRADE; + binary_upgrade_next_multirange_array_pg_type_oid = typoid; + + PG_RETURN_VOID(); +} + +Datum binary_upgrade_set_next_toast_pg_type_oid(PG_FUNCTION_ARGS) { Oid typoid = PG_GETARG_OID(0); diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index bf69adc2f4..4c65b047d2 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -274,7 +274,8 @@ static void dumpSearchPath(Archive *AH); static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout, PQExpBuffer upgrade_buffer, Oid pg_type_oid, - bool force_array_type); + bool force_array_type, + bool include_multirange_type); static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout, PQExpBuffer upgrade_buffer, Oid pg_rel_oid); static void binary_upgrade_set_pg_class_oids(Archive *fout, @@ -1583,7 +1584,7 @@ selectDumpableType(TypeInfo *tyinfo, Archive *fout) } /* skip auto-generated array types */ - if (tyinfo->isArray) + if (tyinfo->isArray || tyinfo->isMultirange) { tyinfo->dobj.objType = DO_DUMMY_TYPE; @@ -4275,15 +4276,48 @@ dumpSubscription(Archive *fout, SubscriptionInfo *subinfo) free(qsubname); } +static Oid get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query) +{ + /* + * If the old version didn't assign an array type, but the new version + * does, we must select an unused type OID to assign. This currently + * only happens for domains, when upgrading pre-v11 to v11 and up. + * + * Note: local state here is kind of ugly, but we must have some, + * since we mustn't choose the same unused OID more than once. + */ + static Oid next_possible_free_oid = FirstNormalObjectId; + PGresult *res; + bool is_dup; + + do + { + ++next_possible_free_oid; + printfPQExpBuffer(upgrade_query, + "SELECT EXISTS(SELECT 1 " + "FROM pg_catalog.pg_type " + "WHERE oid = '%u'::pg_catalog.oid);", + next_possible_free_oid); + res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data); + is_dup = (PQgetvalue(res, 0, 0)[0] == 't'); + PQclear(res); + } while (is_dup); + + return next_possible_free_oid; +} + static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout, PQExpBuffer upgrade_buffer, Oid pg_type_oid, - bool force_array_type) + bool force_array_type, + bool include_multirange_type) { PQExpBuffer upgrade_query = createPQExpBuffer(); PGresult *res; Oid pg_type_array_oid; + Oid pg_type_multirange_oid; + Oid pg_type_multirange_array_oid; appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n"); appendPQExpBuffer(upgrade_buffer, @@ -4304,33 +4338,7 @@ binary_upgrade_set_type_oids_by_type_oid(Archive *fout, PQclear(res); if (!OidIsValid(pg_type_array_oid) && force_array_type) - { - /* - * If the old version didn't assign an array type, but the new version - * does, we must select an unused type OID to assign. This currently - * only happens for domains, when upgrading pre-v11 to v11 and up. - * - * Note: local state here is kind of ugly, but we must have some, - * since we mustn't choose the same unused OID more than once. - */ - static Oid next_possible_free_oid = FirstNormalObjectId; - bool is_dup; - - do - { - ++next_possible_free_oid; - printfPQExpBuffer(upgrade_query, - "SELECT EXISTS(SELECT 1 " - "FROM pg_catalog.pg_type " - "WHERE oid = '%u'::pg_catalog.oid);", - next_possible_free_oid); - res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data); - is_dup = (PQgetvalue(res, 0, 0)[0] == 't'); - PQclear(res); - } while (is_dup); - - pg_type_array_oid = next_possible_free_oid; - } + pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query); if (OidIsValid(pg_type_array_oid)) { @@ -4341,6 +4349,46 @@ binary_upgrade_set_type_oids_by_type_oid(Archive *fout, pg_type_array_oid); } + /* + * Pre-set the multirange type oid and its own array type oid. + */ + if (include_multirange_type) + { + if (fout->remoteVersion >= 130000) + { + appendPQExpBuffer(upgrade_query, + "SELECT t.oid, t.typarray " + "FROM pg_catalog.pg_type t " + "JOIN pg_catalog.pg_range r " + "ON t.oid = r.mltrngtypid " + "WHERE r.rngtypid = '%u'::pg_catalog.oid;", + pg_type_oid); + + res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data); + + pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid"))); + pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray"))); + + PQclear(res); + } + else + { + pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query); + pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query); + } + + appendPQExpBufferStr(upgrade_buffer, + "\n-- For binary upgrade, must preserve multirange pg_type oid\n"); + appendPQExpBuffer(upgrade_buffer, + "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n", + pg_type_multirange_oid); + appendPQExpBufferStr(upgrade_buffer, + "\n-- For binary upgrade, must preserve multirange pg_type array oid\n"); + appendPQExpBuffer(upgrade_buffer, + "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n", + pg_type_multirange_array_oid); + } + destroyPQExpBuffer(upgrade_query); } @@ -4374,7 +4422,7 @@ binary_upgrade_set_type_oids_by_rel_oid(Archive *fout, pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel"))); binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer, - pg_type_oid, false); + pg_type_oid, false, false); if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel"))) { @@ -4923,6 +4971,11 @@ getTypes(Archive *fout, int *numTypes) else tyinfo[i].isArray = false; + if (tyinfo[i].typtype == 'm') + tyinfo[i].isMultirange = true; + else + tyinfo[i].isMultirange = false; + /* Decide whether we want to dump it */ selectDumpableType(&tyinfo[i], fout); @@ -10245,7 +10298,7 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo) if (dopt->binary_upgrade) binary_upgrade_set_type_oids_by_type_oid(fout, q, tyinfo->dobj.catId.oid, - false); + false, false); appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (", qualtypname); @@ -10371,7 +10424,7 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo) if (dopt->binary_upgrade) binary_upgrade_set_type_oids_by_type_oid(fout, q, tyinfo->dobj.catId.oid, - false); + false, true); appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (", qualtypname); @@ -10477,7 +10530,7 @@ dumpUndefinedType(Archive *fout, TypeInfo *tyinfo) if (dopt->binary_upgrade) binary_upgrade_set_type_oids_by_type_oid(fout, q, tyinfo->dobj.catId.oid, - false); + false, false); appendPQExpBuffer(q, "CREATE TYPE %s;\n", qualtypname); @@ -10682,7 +10735,7 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo) if (dopt->binary_upgrade) binary_upgrade_set_type_oids_by_type_oid(fout, q, tyinfo->dobj.catId.oid, - false); + false, false); appendPQExpBuffer(q, "CREATE TYPE %s (\n" @@ -10869,7 +10922,8 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo) if (dopt->binary_upgrade) binary_upgrade_set_type_oids_by_type_oid(fout, q, tyinfo->dobj.catId.oid, - true); /* force array type */ + true, /* force array type */ + false); /* force multirange type */ qtypname = pg_strdup(fmtId(tyinfo->dobj.name)); qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo)); @@ -11057,7 +11111,7 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo) { binary_upgrade_set_type_oids_by_type_oid(fout, q, tyinfo->dobj.catId.oid, - false); + false, false); binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false); } @@ -11331,7 +11385,7 @@ dumpShellType(Archive *fout, ShellTypeInfo *stinfo) if (dopt->binary_upgrade) binary_upgrade_set_type_oids_by_type_oid(fout, q, stinfo->baseType->dobj.catId.oid, - false); + false, false); appendPQExpBuffer(q, "CREATE TYPE %s;\n", fmtQualifiedDumpable(stinfo)); diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 7b2c1524a5..e27a752b6d 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -175,6 +175,7 @@ typedef struct _typeInfo char typrelkind; /* 'r', 'v', 'c', etc */ char typtype; /* 'b', 'c', etc */ bool isArray; /* true if auto-generated array type */ + bool isMultirange; /* true if auto-generated multirange type */ bool isDefined; /* true if typisdefined */ /* If needed, we'll create a "shell type" entry for it; link that here: */ struct _shellTypeInfo *shellType; /* shell-type entry, or NULL */ diff --git a/src/include/catalog/binary_upgrade.h b/src/include/catalog/binary_upgrade.h index 2927b7a4d3..2b6e87bb84 100644 --- a/src/include/catalog/binary_upgrade.h +++ b/src/include/catalog/binary_upgrade.h @@ -16,6 +16,8 @@ extern PGDLLIMPORT Oid binary_upgrade_next_pg_type_oid; extern PGDLLIMPORT Oid binary_upgrade_next_array_pg_type_oid; +extern PGDLLIMPORT Oid binary_upgrade_next_multirange_pg_type_oid; +extern PGDLLIMPORT Oid binary_upgrade_next_multirange_array_pg_type_oid; extern PGDLLIMPORT Oid binary_upgrade_next_toast_pg_type_oid; extern PGDLLIMPORT Oid binary_upgrade_next_heap_pg_class_oid; diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 13ea94c024..d3cb8c8cb4 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -10368,6 +10368,14 @@ proname => 'binary_upgrade_set_next_array_pg_type_oid', provolatile => 'v', proparallel => 'r', prorettype => 'void', proargtypes => 'oid', prosrc => 'binary_upgrade_set_next_array_pg_type_oid' }, +{ oid => '8144', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_next_multirange_pg_type_oid', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => 'oid', + prosrc => 'binary_upgrade_set_next_multirange_pg_type_oid' }, +{ oid => '8145', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_next_multirange_array_pg_type_oid', provolatile => 'v', + proparallel => 'r', prorettype => 'void', proargtypes => 'oid', + prosrc => 'binary_upgrade_set_next_multirange_array_pg_type_oid' }, { oid => '3585', descr => 'for use by pg_upgrade', proname => 'binary_upgrade_set_next_toast_pg_type_oid', provolatile => 'v', proparallel => 'r', prorettype => 'void', proargtypes => 'oid', diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h index 8af0665f29..2b9115b6a0 100644 --- a/src/include/commands/typecmds.h +++ b/src/include/commands/typecmds.h @@ -29,6 +29,8 @@ extern ObjectAddress DefineRange(CreateRangeStmt *stmt); extern ObjectAddress AlterEnum(AlterEnumStmt *stmt); extern ObjectAddress DefineCompositeType(RangeVar *typevar, List *coldeflist); extern Oid AssignTypeArrayOid(void); +extern Oid AssignTypeMultirangeOid(void); +extern Oid AssignTypeMultirangeArrayOid(void); extern ObjectAddress AlterDomainDefault(List *names, Node *defaultRaw); extern ObjectAddress AlterDomainNotNull(List *names, bool notNull); -- 2.11.0