Skip to content

Commit 22f126d

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 e99010c commit 22f126d

File tree

6 files changed

+335
-33
lines changed

6 files changed

+335
-33
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"
@@ -851,6 +852,24 @@ findOprByOid(Oid oid)
851852
return (OprInfo *) dobj;
852853
}
853854

855+
/*
856+
* findAccessMethodByOid
857+
* finds the DumpableObject for the access method with the given oid
858+
* returns NULL if not found
859+
*/
860+
AccessMethodInfo *
861+
findAccessMethodByOid(Oid oid)
862+
{
863+
CatalogId catId;
864+
DumpableObject *dobj;
865+
866+
catId.tableoid = AccessMethodRelationId;
867+
catId.oid = oid;
868+
dobj = findObjectByCatalogId(catId);
869+
Assert(dobj == NULL || dobj->objType == DO_ACCESS_METHOD);
870+
return (AccessMethodInfo *) dobj;
871+
}
872+
854873
/*
855874
* findCollationByOid
856875
* finds the DumpableObject for the collation with the given oid

src/bin/pg_dump/pg_dump.c

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1874,6 +1874,13 @@ selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
18741874
static void
18751875
selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
18761876
{
1877+
/* see getAccessMethods() comment about v9.6. */
1878+
if (fout->remoteVersion < 90600)
1879+
{
1880+
method->dobj.dump = DUMP_COMPONENT_NONE;
1881+
return;
1882+
}
1883+
18771884
if (checkExtensionMembership(&method->dobj, fout))
18781885
return; /* extension membership overrides all else */
18791886

@@ -5496,6 +5503,8 @@ getOperators(Archive *fout, int *numOprs)
54965503
int i_oprnamespace;
54975504
int i_oprowner;
54985505
int i_oprkind;
5506+
int i_oprleft;
5507+
int i_oprright;
54995508
int i_oprcode;
55005509

55015510
/*
@@ -5507,6 +5516,8 @@ getOperators(Archive *fout, int *numOprs)
55075516
"oprnamespace, "
55085517
"oprowner, "
55095518
"oprkind, "
5519+
"oprleft, "
5520+
"oprright, "
55105521
"oprcode::oid AS oprcode "
55115522
"FROM pg_operator");
55125523

@@ -5523,6 +5534,8 @@ getOperators(Archive *fout, int *numOprs)
55235534
i_oprnamespace = PQfnumber(res, "oprnamespace");
55245535
i_oprowner = PQfnumber(res, "oprowner");
55255536
i_oprkind = PQfnumber(res, "oprkind");
5537+
i_oprleft = PQfnumber(res, "oprleft");
5538+
i_oprright = PQfnumber(res, "oprright");
55265539
i_oprcode = PQfnumber(res, "oprcode");
55275540

55285541
for (i = 0; i < ntups; i++)
@@ -5536,6 +5549,8 @@ getOperators(Archive *fout, int *numOprs)
55365549
findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
55375550
oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
55385551
oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
5552+
oprinfo[i].oprleft = atooid(PQgetvalue(res, i, i_oprleft));
5553+
oprinfo[i].oprright = atooid(PQgetvalue(res, i, i_oprright));
55395554
oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
55405555

55415556
/* Decide whether we want to dump it */
@@ -5569,6 +5584,7 @@ getCollations(Archive *fout, int *numCollations)
55695584
int i_collname;
55705585
int i_collnamespace;
55715586
int i_collowner;
5587+
int i_collencoding;
55725588

55735589
query = createPQExpBuffer();
55745590

@@ -5579,7 +5595,8 @@ getCollations(Archive *fout, int *numCollations)
55795595

55805596
appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
55815597
"collnamespace, "
5582-
"collowner "
5598+
"collowner, "
5599+
"collencoding "
55835600
"FROM pg_collation");
55845601

55855602
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
@@ -5594,6 +5611,7 @@ getCollations(Archive *fout, int *numCollations)
55945611
i_collname = PQfnumber(res, "collname");
55955612
i_collnamespace = PQfnumber(res, "collnamespace");
55965613
i_collowner = PQfnumber(res, "collowner");
5614+
i_collencoding = PQfnumber(res, "collencoding");
55975615

55985616
for (i = 0; i < ntups; i++)
55995617
{
@@ -5605,6 +5623,7 @@ getCollations(Archive *fout, int *numCollations)
56055623
collinfo[i].dobj.namespace =
56065624
findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
56075625
collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
5626+
collinfo[i].collencoding = atoi(PQgetvalue(res, i, i_collencoding));
56085627

56095628
/* Decide whether we want to dump it */
56105629
selectDumpableObject(&(collinfo[i].dobj), fout);
@@ -5706,19 +5725,28 @@ getAccessMethods(Archive *fout, int *numAccessMethods)
57065725
int i_amhandler;
57075726
int i_amtype;
57085727

5709-
/* Before 9.6, there are no user-defined access methods */
5710-
if (fout->remoteVersion < 90600)
5711-
{
5712-
*numAccessMethods = 0;
5713-
return NULL;
5714-
}
5715-
57165728
query = createPQExpBuffer();
57175729

5718-
/* Select all access methods from pg_am table */
5719-
appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, amtype, "
5720-
"amhandler::pg_catalog.regproc AS amhandler "
5721-
"FROM pg_am");
5730+
/*
5731+
* Select all access methods from pg_am table. v9.6 introduced CREATE
5732+
* ACCESS METHOD, so earlier versions usually have only built-in access
5733+
* methods. v9.6 also changed the access method API, replacing dozens of
5734+
* pg_am columns with amhandler. Even if a user created an access method
5735+
* by "INSERT INTO pg_am", we have no way to translate pre-v9.6 pg_am
5736+
* columns to a v9.6+ CREATE ACCESS METHOD. Hence, before v9.6, read
5737+
* pg_am just to facilitate findAccessMethodByOid() providing the
5738+
* OID-to-name mapping.
5739+
*/
5740+
appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, ");
5741+
if (fout->remoteVersion >= 90600)
5742+
appendPQExpBufferStr(query,
5743+
"amtype, "
5744+
"amhandler::pg_catalog.regproc AS amhandler ");
5745+
else
5746+
appendPQExpBufferStr(query,
5747+
"'i'::pg_catalog.\"char\" AS amtype, "
5748+
"'-'::pg_catalog.regproc AS amhandler ");
5749+
appendPQExpBufferStr(query, "FROM pg_am");
57225750

57235751
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
57245752

@@ -5773,6 +5801,7 @@ getOpclasses(Archive *fout, int *numOpclasses)
57735801
OpclassInfo *opcinfo;
57745802
int i_tableoid;
57755803
int i_oid;
5804+
int i_opcmethod;
57765805
int i_opcname;
57775806
int i_opcnamespace;
57785807
int i_opcowner;
@@ -5782,7 +5811,7 @@ getOpclasses(Archive *fout, int *numOpclasses)
57825811
* system-defined opclasses at dump-out time.
57835812
*/
57845813

5785-
appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
5814+
appendPQExpBuffer(query, "SELECT tableoid, oid, opcmethod, opcname, "
57865815
"opcnamespace, "
57875816
"opcowner "
57885817
"FROM pg_opclass");
@@ -5796,6 +5825,7 @@ getOpclasses(Archive *fout, int *numOpclasses)
57965825

57975826
i_tableoid = PQfnumber(res, "tableoid");
57985827
i_oid = PQfnumber(res, "oid");
5828+
i_opcmethod = PQfnumber(res, "opcmethod");
57995829
i_opcname = PQfnumber(res, "opcname");
58005830
i_opcnamespace = PQfnumber(res, "opcnamespace");
58015831
i_opcowner = PQfnumber(res, "opcowner");
@@ -5809,6 +5839,7 @@ getOpclasses(Archive *fout, int *numOpclasses)
58095839
opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
58105840
opcinfo[i].dobj.namespace =
58115841
findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
5842+
opcinfo[i].opcmethod = atooid(PQgetvalue(res, i, i_opcmethod));
58125843
opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
58135844

58145845
/* Decide whether we want to dump it */
@@ -5839,6 +5870,7 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
58395870
OpfamilyInfo *opfinfo;
58405871
int i_tableoid;
58415872
int i_oid;
5873+
int i_opfmethod;
58425874
int i_opfname;
58435875
int i_opfnamespace;
58445876
int i_opfowner;
@@ -5850,7 +5882,7 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
58505882
* system-defined opfamilies at dump-out time.
58515883
*/
58525884

5853-
appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
5885+
appendPQExpBuffer(query, "SELECT tableoid, oid, opfmethod, opfname, "
58545886
"opfnamespace, "
58555887
"opfowner "
58565888
"FROM pg_opfamily");
@@ -5865,6 +5897,7 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
58655897
i_tableoid = PQfnumber(res, "tableoid");
58665898
i_oid = PQfnumber(res, "oid");
58675899
i_opfname = PQfnumber(res, "opfname");
5900+
i_opfmethod = PQfnumber(res, "opfmethod");
58685901
i_opfnamespace = PQfnumber(res, "opfnamespace");
58695902
i_opfowner = PQfnumber(res, "opfowner");
58705903

@@ -5877,6 +5910,7 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
58775910
opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
58785911
opfinfo[i].dobj.namespace =
58795912
findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
5913+
opfinfo[i].opfmethod = atooid(PQgetvalue(res, i, i_opfmethod));
58805914
opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
58815915

58825916
/* 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
@@ -250,6 +250,8 @@ typedef struct _oprInfo
250250
DumpableObject dobj;
251251
const char *rolname;
252252
char oprkind;
253+
Oid oprleft;
254+
Oid oprright;
253255
Oid oprcode;
254256
} OprInfo;
255257

@@ -263,19 +265,22 @@ typedef struct _accessMethodInfo
263265
typedef struct _opclassInfo
264266
{
265267
DumpableObject dobj;
268+
Oid opcmethod;
266269
const char *rolname;
267270
} OpclassInfo;
268271

269272
typedef struct _opfamilyInfo
270273
{
271274
DumpableObject dobj;
275+
Oid opfmethod;
272276
const char *rolname;
273277
} OpfamilyInfo;
274278

275279
typedef struct _collInfo
276280
{
277281
DumpableObject dobj;
278282
const char *rolname;
283+
int collencoding;
279284
} CollInfo;
280285

281286
typedef struct _convInfo
@@ -694,6 +699,7 @@ extern TableInfo *findTableByOid(Oid oid);
694699
extern TypeInfo *findTypeByOid(Oid oid);
695700
extern FuncInfo *findFuncByOid(Oid oid);
696701
extern OprInfo *findOprByOid(Oid oid);
702+
extern AccessMethodInfo *findAccessMethodByOid(Oid oid);
697703
extern CollInfo *findCollationByOid(Oid oid);
698704
extern NamespaceInfo *findNamespaceByOid(Oid oid);
699705
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