diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 75f08cd792..e34c83acd2 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -253,7 +253,9 @@ static void dumpDatabase(Archive *AH); static void dumpEncoding(Archive *AH); static void dumpStdStrings(Archive *AH); static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout, - PQExpBuffer upgrade_buffer, Oid pg_type_oid); + PQExpBuffer upgrade_buffer, + Oid pg_type_oid, + bool force_array_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, @@ -3949,10 +3951,11 @@ dumpSubscription(Archive *fout, SubscriptionInfo *subinfo) static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout, PQExpBuffer upgrade_buffer, - Oid pg_type_oid) + Oid pg_type_oid, + bool force_array_type) { PQExpBuffer upgrade_query = createPQExpBuffer(); - PGresult *upgrade_res; + PGresult *res; Oid pg_type_array_oid; appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n"); @@ -3964,12 +3967,43 @@ binary_upgrade_set_type_oids_by_type_oid(Archive *fout, appendPQExpBuffer(upgrade_query, "SELECT typarray " "FROM pg_catalog.pg_type " - "WHERE pg_type.oid = '%u'::pg_catalog.oid;", + "WHERE oid = '%u'::pg_catalog.oid;", pg_type_oid); - upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data); + res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data); - pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray"))); + pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray"))); + + 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; + } if (OidIsValid(pg_type_array_oid)) { @@ -3980,7 +4014,6 @@ binary_upgrade_set_type_oids_by_type_oid(Archive *fout, pg_type_array_oid); } - PQclear(upgrade_res); destroyPQExpBuffer(upgrade_query); } @@ -4008,7 +4041,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); + pg_type_oid, false); if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel"))) { @@ -9840,7 +9873,8 @@ dumpEnumType(Archive *fout, TypeInfo *tyinfo) if (dopt->binary_upgrade) binary_upgrade_set_type_oids_by_type_oid(fout, q, - tyinfo->dobj.catId.oid); + tyinfo->dobj.catId.oid, + false); appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (", qtypname); @@ -9976,8 +10010,9 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo) qtypname); if (dopt->binary_upgrade) - binary_upgrade_set_type_oids_by_type_oid(fout, - q, tyinfo->dobj.catId.oid); + binary_upgrade_set_type_oids_by_type_oid(fout, q, + tyinfo->dobj.catId.oid, + false); appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (", qtypname); @@ -10091,8 +10126,9 @@ dumpUndefinedType(Archive *fout, TypeInfo *tyinfo) qtypname); if (dopt->binary_upgrade) - binary_upgrade_set_type_oids_by_type_oid(fout, - q, tyinfo->dobj.catId.oid); + binary_upgrade_set_type_oids_by_type_oid(fout, q, + tyinfo->dobj.catId.oid, + false); appendPQExpBuffer(q, "CREATE TYPE %s;\n", qtypname); @@ -10296,10 +10332,14 @@ dumpBaseType(Archive *fout, TypeInfo *tyinfo) appendPQExpBuffer(delq, "%s CASCADE;\n", qtypname); - /* We might already have a shell type, but setting pg_type_oid is harmless */ + /* + * We might already have a shell type, but setting pg_type_oid is + * harmless, and in any case we'd better set the array type OID. + */ if (dopt->binary_upgrade) binary_upgrade_set_type_oids_by_type_oid(fout, q, - tyinfo->dobj.catId.oid); + tyinfo->dobj.catId.oid, + false); appendPQExpBuffer(q, "CREATE TYPE %s (\n" @@ -10490,7 +10530,8 @@ dumpDomain(Archive *fout, TypeInfo *tyinfo) if (dopt->binary_upgrade) binary_upgrade_set_type_oids_by_type_oid(fout, q, - tyinfo->dobj.catId.oid); + tyinfo->dobj.catId.oid, + true); /* force array type */ qtypname = pg_strdup(fmtId(tyinfo->dobj.name)); @@ -10692,7 +10733,8 @@ dumpCompositeType(Archive *fout, TypeInfo *tyinfo) if (dopt->binary_upgrade) { binary_upgrade_set_type_oids_by_type_oid(fout, q, - tyinfo->dobj.catId.oid); + tyinfo->dobj.catId.oid, + false); binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false); } @@ -10967,7 +11009,8 @@ dumpShellType(Archive *fout, ShellTypeInfo *stinfo) if (dopt->binary_upgrade) binary_upgrade_set_type_oids_by_type_oid(fout, q, - stinfo->baseType->dobj.catId.oid); + stinfo->baseType->dobj.catId.oid, + false); appendPQExpBuffer(q, "CREATE TYPE %s;\n", fmtId(stinfo->dobj.name));