Skip to content

Commit c0ae033

Browse files
committed
Sort dump objects independent of OIDs, for the 7 holdout object types.
pg_dump sorts objects by their logical names, e.g. (nspname, relname, tgname), before dependency-driven reordering. That removes one source of logically-identical databases differing in their schema-only dumps. In other words, it helps with schema diffing. The logical name sort ignored essential sort keys for constraints, operators, PUBLICATION ... FOR TABLE, PUBLICATION ... FOR TABLES IN SCHEMA, operator classes, and operator families. pg_dump's sort then depended on object OID, yielding spurious schema diffs. After this change, OIDs affect dump order only in the event of catalog corruption. While pg_dump also wrongly ignored pg_collation.collencoding, CREATE COLLATION restrictions have been keeping that imperceptible in practical use. Use techniques like we use for object types already having full sort key coverage. Where the pertinent queries weren't fetching the ignored sort keys, this adds columns to those queries and stores those keys in memory for the long term. The ignorance of sort keys became more problematic when commit 172259a added a schema diff test sensitive to it. Buildfarm member hippopotamus witnessed that. However, dump order stability isn't a new goal, and this might avoid other dump comparison failures. Hence, back-patch to v13 (all supported versions). Reviewed-by: Robert Haas <robertmhaas@gmail.com> Discussion: https://postgr.es/m/20250707192654.9e.nmisch@google.com Backpatch-through: 13
1 parent da103c7 commit c0ae033

File tree

6 files changed

+335
-30
lines changed

6 files changed

+335
-30
lines changed

src/bin/pg_dump/common.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include <ctype.h>
1919

20+
#include "catalog/pg_am_d.h"
2021
#include "catalog/pg_class_d.h"
2122
#include "catalog/pg_collation_d.h"
2223
#include "catalog/pg_extension_d.h"
@@ -944,6 +945,24 @@ findOprByOid(Oid oid)
944945
return (OprInfo *) dobj;
945946
}
946947

948+
/*
949+
* findAccessMethodByOid
950+
* finds the DumpableObject for the access method with the given oid
951+
* returns NULL if not found
952+
*/
953+
AccessMethodInfo *
954+
findAccessMethodByOid(Oid oid)
955+
{
956+
CatalogId catId;
957+
DumpableObject *dobj;
958+
959+
catId.tableoid = AccessMethodRelationId;
960+
catId.oid = oid;
961+
dobj = findObjectByCatalogId(catId);
962+
Assert(dobj == NULL || dobj->objType == DO_ACCESS_METHOD);
963+
return (AccessMethodInfo *) dobj;
964+
}
965+
947966
/*
948967
* findCollationByOid
949968
* finds the DumpableObject for the collation with the given oid

src/bin/pg_dump/pg_dump.c

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2169,6 +2169,13 @@ selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
21692169
static void
21702170
selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
21712171
{
2172+
/* see getAccessMethods() comment about v9.6. */
2173+
if (fout->remoteVersion < 90600)
2174+
{
2175+
method->dobj.dump = DUMP_COMPONENT_NONE;
2176+
return;
2177+
}
2178+
21722179
if (checkExtensionMembership(&method->dobj, fout))
21732180
return; /* extension membership overrides all else */
21742181

@@ -6183,6 +6190,8 @@ getOperators(Archive *fout)
61836190
int i_oprnamespace;
61846191
int i_oprowner;
61856192
int i_oprkind;
6193+
int i_oprleft;
6194+
int i_oprright;
61866195
int i_oprcode;
61876196

61886197
/*
@@ -6194,6 +6203,8 @@ getOperators(Archive *fout)
61946203
"oprnamespace, "
61956204
"oprowner, "
61966205
"oprkind, "
6206+
"oprleft, "
6207+
"oprright, "
61976208
"oprcode::oid AS oprcode "
61986209
"FROM pg_operator");
61996210

@@ -6209,6 +6220,8 @@ getOperators(Archive *fout)
62096220
i_oprnamespace = PQfnumber(res, "oprnamespace");
62106221
i_oprowner = PQfnumber(res, "oprowner");
62116222
i_oprkind = PQfnumber(res, "oprkind");
6223+
i_oprleft = PQfnumber(res, "oprleft");
6224+
i_oprright = PQfnumber(res, "oprright");
62126225
i_oprcode = PQfnumber(res, "oprcode");
62136226

62146227
for (i = 0; i < ntups; i++)
@@ -6222,6 +6235,8 @@ getOperators(Archive *fout)
62226235
findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
62236236
oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
62246237
oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
6238+
oprinfo[i].oprleft = atooid(PQgetvalue(res, i, i_oprleft));
6239+
oprinfo[i].oprright = atooid(PQgetvalue(res, i, i_oprright));
62256240
oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
62266241

62276242
/* Decide whether we want to dump it */
@@ -6250,6 +6265,7 @@ getCollations(Archive *fout)
62506265
int i_collname;
62516266
int i_collnamespace;
62526267
int i_collowner;
6268+
int i_collencoding;
62536269

62546270
query = createPQExpBuffer();
62556271

@@ -6260,7 +6276,8 @@ getCollations(Archive *fout)
62606276

62616277
appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
62626278
"collnamespace, "
6263-
"collowner "
6279+
"collowner, "
6280+
"collencoding "
62646281
"FROM pg_collation");
62656282

62666283
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
@@ -6274,6 +6291,7 @@ getCollations(Archive *fout)
62746291
i_collname = PQfnumber(res, "collname");
62756292
i_collnamespace = PQfnumber(res, "collnamespace");
62766293
i_collowner = PQfnumber(res, "collowner");
6294+
i_collencoding = PQfnumber(res, "collencoding");
62776295

62786296
for (i = 0; i < ntups; i++)
62796297
{
@@ -6285,6 +6303,7 @@ getCollations(Archive *fout)
62856303
collinfo[i].dobj.namespace =
62866304
findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
62876305
collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
6306+
collinfo[i].collencoding = atoi(PQgetvalue(res, i, i_collencoding));
62886307

62896308
/* Decide whether we want to dump it */
62906309
selectDumpableObject(&(collinfo[i].dobj), fout);
@@ -6375,16 +6394,28 @@ getAccessMethods(Archive *fout)
63756394
int i_amhandler;
63766395
int i_amtype;
63776396

6378-
/* Before 9.6, there are no user-defined access methods */
6379-
if (fout->remoteVersion < 90600)
6380-
return;
6381-
63826397
query = createPQExpBuffer();
63836398

6384-
/* Select all access methods from pg_am table */
6385-
appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, amtype, "
6386-
"amhandler::pg_catalog.regproc AS amhandler "
6387-
"FROM pg_am");
6399+
/*
6400+
* Select all access methods from pg_am table. v9.6 introduced CREATE
6401+
* ACCESS METHOD, so earlier versions usually have only built-in access
6402+
* methods. v9.6 also changed the access method API, replacing dozens of
6403+
* pg_am columns with amhandler. Even if a user created an access method
6404+
* by "INSERT INTO pg_am", we have no way to translate pre-v9.6 pg_am
6405+
* columns to a v9.6+ CREATE ACCESS METHOD. Hence, before v9.6, read
6406+
* pg_am just to facilitate findAccessMethodByOid() providing the
6407+
* OID-to-name mapping.
6408+
*/
6409+
appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, ");
6410+
if (fout->remoteVersion >= 90600)
6411+
appendPQExpBufferStr(query,
6412+
"amtype, "
6413+
"amhandler::pg_catalog.regproc AS amhandler ");
6414+
else
6415+
appendPQExpBufferStr(query,
6416+
"'i'::pg_catalog.\"char\" AS amtype, "
6417+
"'-'::pg_catalog.regproc AS amhandler ");
6418+
appendPQExpBufferStr(query, "FROM pg_am");
63886419

63896420
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
63906421

@@ -6433,6 +6464,7 @@ getOpclasses(Archive *fout)
64336464
OpclassInfo *opcinfo;
64346465
int i_tableoid;
64356466
int i_oid;
6467+
int i_opcmethod;
64366468
int i_opcname;
64376469
int i_opcnamespace;
64386470
int i_opcowner;
@@ -6442,7 +6474,7 @@ getOpclasses(Archive *fout)
64426474
* system-defined opclasses at dump-out time.
64436475
*/
64446476

6445-
appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, "
6477+
appendPQExpBufferStr(query, "SELECT tableoid, oid, opcmethod, opcname, "
64466478
"opcnamespace, "
64476479
"opcowner "
64486480
"FROM pg_opclass");
@@ -6455,6 +6487,7 @@ getOpclasses(Archive *fout)
64556487

64566488
i_tableoid = PQfnumber(res, "tableoid");
64576489
i_oid = PQfnumber(res, "oid");
6490+
i_opcmethod = PQfnumber(res, "opcmethod");
64586491
i_opcname = PQfnumber(res, "opcname");
64596492
i_opcnamespace = PQfnumber(res, "opcnamespace");
64606493
i_opcowner = PQfnumber(res, "opcowner");
@@ -6468,6 +6501,7 @@ getOpclasses(Archive *fout)
64686501
opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
64696502
opcinfo[i].dobj.namespace =
64706503
findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
6504+
opcinfo[i].opcmethod = atooid(PQgetvalue(res, i, i_opcmethod));
64716505
opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
64726506

64736507
/* Decide whether we want to dump it */
@@ -6493,6 +6527,7 @@ getOpfamilies(Archive *fout)
64936527
OpfamilyInfo *opfinfo;
64946528
int i_tableoid;
64956529
int i_oid;
6530+
int i_opfmethod;
64966531
int i_opfname;
64976532
int i_opfnamespace;
64986533
int i_opfowner;
@@ -6504,7 +6539,7 @@ getOpfamilies(Archive *fout)
65046539
* system-defined opfamilies at dump-out time.
65056540
*/
65066541

6507-
appendPQExpBufferStr(query, "SELECT tableoid, oid, opfname, "
6542+
appendPQExpBufferStr(query, "SELECT tableoid, oid, opfmethod, opfname, "
65086543
"opfnamespace, "
65096544
"opfowner "
65106545
"FROM pg_opfamily");
@@ -6518,6 +6553,7 @@ getOpfamilies(Archive *fout)
65186553
i_tableoid = PQfnumber(res, "tableoid");
65196554
i_oid = PQfnumber(res, "oid");
65206555
i_opfname = PQfnumber(res, "opfname");
6556+
i_opfmethod = PQfnumber(res, "opfmethod");
65216557
i_opfnamespace = PQfnumber(res, "opfnamespace");
65226558
i_opfowner = PQfnumber(res, "opfowner");
65236559

@@ -6530,6 +6566,7 @@ getOpfamilies(Archive *fout)
65306566
opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
65316567
opfinfo[i].dobj.namespace =
65326568
findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
6569+
opfinfo[i].opfmethod = atooid(PQgetvalue(res, i, i_opfmethod));
65336570
opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
65346571

65356572
/* Decide whether we want to dump it */

src/bin/pg_dump/pg_dump.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ typedef struct _oprInfo
260260
DumpableObject dobj;
261261
const char *rolname;
262262
char oprkind;
263+
Oid oprleft;
264+
Oid oprright;
263265
Oid oprcode;
264266
} OprInfo;
265267

@@ -273,19 +275,22 @@ typedef struct _accessMethodInfo
273275
typedef struct _opclassInfo
274276
{
275277
DumpableObject dobj;
278+
Oid opcmethod;
276279
const char *rolname;
277280
} OpclassInfo;
278281

279282
typedef struct _opfamilyInfo
280283
{
281284
DumpableObject dobj;
285+
Oid opfmethod;
282286
const char *rolname;
283287
} OpfamilyInfo;
284288

285289
typedef struct _collInfo
286290
{
287291
DumpableObject dobj;
288292
const char *rolname;
293+
int collencoding;
289294
} CollInfo;
290295

291296
typedef struct _convInfo
@@ -759,6 +764,7 @@ extern TableInfo *findTableByOid(Oid oid);
759764
extern TypeInfo *findTypeByOid(Oid oid);
760765
extern FuncInfo *findFuncByOid(Oid oid);
761766
extern OprInfo *findOprByOid(Oid oid);
767+
extern AccessMethodInfo *findAccessMethodByOid(Oid oid);
762768
extern CollInfo *findCollationByOid(Oid oid);
763769
extern NamespaceInfo *findNamespaceByOid(Oid oid);
764770
extern ExtensionInfo *findExtensionByOid(Oid oid);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy