8000 Handle extension members when first setting object dump flags in pg_d… · ccneo/postgres@be2b276 · GitHub
[go: up one dir, main page]

Skip to content

Commit be2b276

Browse files
committed
Handle extension members when first setting object dump flags in pg_dump.
pg_dump's original approach to handling extension member objects was to run around and clear (or set) their dump flags rather late in its data collection process. Unfortunately, quite a lot of code expects those flags to be valid before that; which was an entirely reasonable expectation before we added extensions. In particular, this explains Karsten Hilbert's recent report of pg_upgrade failing on a database in which an extension has been installed into the pg_catalog schema. Its objects are initially marked as not-to-be-dumped on the strength of their schema, and later we change them to must-dump because we're doing a binary upgrade of their extension; but we've already skipped essential tasks like making associated DO_SHELL_TYPE objects. To fix, collect extension membership data first, and incorporate it in the initial setting of the dump flags, so that those are once again correct from the get-go. This has the undesirable side effect of slightly lengthening the time taken before pg_dump acquires table locks, but testing suggests that the increase in that window is not very much. Along the way, get rid of ugly special-case logic for deciding whether to dump procedural languages, FDWs, and foreign servers; dump decisions for those are now correct up-front, too. In 9.3 and up, this also fixes erroneous logic about when to dump event triggers (basically, they were *always* dumped before). In 9.5 and up, transform objects had that problem too. Since this problem came in with extensions, back-patch to all supported version 10000 s.
1 parent 3843ba5 commit be2b276

File tree

3 files changed

+313
-167
lines changed

3 files changed

+313
-167
lines changed

src/bin/pg_dump/common.c

Lines changed: 128 additions & 30 deletions
EDBE
Original file line numberDiff line numberDiff line change
@@ -38,37 +38,38 @@ static int numCatalogIds = 0;
3838

3939
/*
4040
* These variables are static to avoid the notational cruft of having to pass
41-
* them into findTableByOid() and friends. For each of these arrays, we
42-
* build a sorted-by-OID index array immediately after it's built, and then
43-
* we use binary search in findTableByOid() and friends. (qsort'ing the base
44-
* arrays themselves would be simpler, but it doesn't work because pg_dump.c
45-
* may have already established pointers between items.)
46-
*/
47-
static TableInfo *tblinfo;
48-
static TypeInfo *typinfo;
49-
static FuncInfo *funinfo;
50-
static OprInfo *oprinfo;
51-
static NamespaceInfo *nspinfo;
52-
static int numTables;
53-
static int numTypes;
54-
static int numFuncs;
55-
static int numOperators;
56-
static int numCollations;
57-
static int numNamespaces;
41+
* them into findTableByOid() and friends. For each of these arrays, we build
42+
* a sorted-by-OID index array immediately after the objects are fetched,
43+
* and then we use binary search in findTableByOid() and friends. (qsort'ing
44+
* the object arrays themselves would be simpler, but it doesn't work because
45+
* pg_dump.c may have already established pointers between items.)
46+
*/
5847
static DumpableObject **tblinfoindex;
5948
static DumpableObject **typinfoindex;
6049
static DumpableObject **funinfoindex;
6150
static DumpableObject **oprinfoindex;
6251
static DumpableObject **collinfoindex;
6352
static DumpableObject **nspinfoindex;
53+
static DumpableObject **extinfoindex;
54+
static int numTables;
55+
static int numTypes;
56+
static int numFuncs;
57+
static int numOperators;
58+
static int numCollations;
59+
static int numNamespaces;
60+
static int numExtensions;
6461

62+
/* This is an array of object identities, not actual DumpableObjects */
63+
static ExtensionMemberId *extmembers;
64+
static int numextmembers;
6565

6666
static void flagInhTables(TableInfo *tbinfo, int numTables,
6767
InhInfo *inhinfo, int numInherits);
6868
static void flagInhAttrs(TableInfo *tblinfo, int numTables);
6969
static DumpableObject **buildIndexArray(void *objArray, int numObjs,
7070
Size objSize);
7171
static int DOCatalogIdCompare(const void *p1, const void *p2);
72+
static int ExtensionMemberIdCompare(const void *p1, const void *p2);
7273
static void findParentsByOid(TableInfo *self,
7374
InhInfo *inhinfo, int numInherits);
7475
static int strInArray(const char *pattern, char **arr, int arr_size);
@@ -81,10 +82,14 @@ static int strInArray(const char *pattern, char **arr, int arr_size);
8182
TableInfo *
8283
getSchemaData(Archive *fout, int *numTablesPtr)
8384
{
85+
TableInfo *tblinfo;
86+
TypeInfo *typinfo;
87+
FuncInfo *funinfo;
88+
OprInfo *oprinfo;
89+
CollInfo *collinfo;
90+
NamespaceInfo *nspinfo;
8491
ExtensionInfo *extinfo;
8592
InhInfo *inhinfo;
86-
CollInfo *collinfo;
87-
int numExtensions;
8893
int numAggregates;
8994
int numInherits;
9095
int numRules;
@@ -101,6 +106,20 @@ getSchemaData(Archive *fout, int *numTablesPtr)
101106
int numForeignServers;
102107
int numDefaultACLs;
103108

109+
/*
110+
* We must read extensions and extension membership info first, because
111+
* extension membership needs to be consultable during decisions about
112+
* whether other objects are to be dumped.
113+
*/
114+
if (g_verbose)
115+
write_msg(NULL, "reading extensions\n");
116+
extinfo = getExtensions(fout, &numExtensions);
117+
extinfoindex = buildIndexArray(extinfo, numExtensions, sizeof(ExtensionInfo));
118+
119+
if (g_verbose)
120+
write_msg(NULL, "identifying extension members\n");
121+
getExtensionMembership(fout, extinfo, numExtensions);
122+
104123
if (g_verbose)
105124
write_msg(NULL, "reading schemas\n");
106125
nspinfo = getNamespaces(fout, &numNamespaces);
@@ -120,10 +139,6 @@ getSchemaData(Archive *fout, int *numTablesPtr)
120139
/* Do this after we've built tblinfoindex */
121140
getOwnedSeqs(fout, tblinfo, numTables);
122141

123-
if (g_verbose)
124-
write_msg(NULL, "reading extensions\n");
125-
extinfo = getExtensions(fout, &numExtensions);
126-
127142
if (g_verbose)
128143
write_msg(NULL, "reading user-defined functions\n");
129144
funinfo = getFuncs(fout, &numFuncs);
@@ -202,14 +217,10 @@ getSchemaData(Archive *fout, int *numTablesPtr)
202217
write_msg(NULL, "reading table inheritance information\n");
203218
inhinfo = getInherits(fout, &numInherits);
204219

205-
/*
206-
* Identify extension member objects and mark them as not to be dumped.
207-
* This must happen after reading all objects that can be direct members
208-
* of extensions, but before we begin to process table subsidiary objects.
209-
*/
220+
/* Identify extension configuration tables that should be dumped */
210221
if (g_verbose)
211-
write_msg(NULL, "finding extension members\n");
212-
getExtensionMembership(fout, extinfo, numExtensions);
222+
write_msg(NULL, "finding extension tables\n");
223+
processExtensionTables(fout, extinfo, numExtensions);
213224

214225
/* Link tables to parents, mark parents of target tables interesting */
215226
if (g_verbose)
@@ -746,6 +757,93 @@ findNamespaceByOid(Oid oid)
746757
return (NamespaceInfo *) findObjectByOid(oid, nspinfoindex, numNamespaces);
747758
}
748759

760+
/*
761+
* findExtensionByOid
762+
* finds the entry (in extinfo) of the extension with the given oid
763+
* returns NULL if not found
764+
*/
765+
ExtensionInfo *
766+
findExtensionByOid(Oid oid)
767+
{
768+
return (ExtensionInfo *) findObjectByOid(oid, extinfoindex, numExtensions);
769+
}
770+
771+
772+
/*
773+
* setExtensionMembership
774+
* accept and save data about which objects belong to extensions
775+
*/
776+
void
777+
setExtensionMembership(ExtensionMemberId *extmems, int nextmems)
778+
{
779+
/* Sort array in preparation for binary searches */
780+
if (nextmems > 1)
781+
qsort((void *) extmems, nextmems, sizeof(ExtensionMemberId),
782+
ExtensionMemberIdCompare);
783+
/* And save */
784+
extmembers = extmems;
785+
numextmembers = nextmems;
786+
}
787+
788+
/*
789+
* findOwningExtension
790+
* return owning extension for specified catalog ID, or NULL if none
791+
*/
792+
ExtensionInfo *
793+
findOwningExtension(CatalogId catalogId)
794+
{
795+
ExtensionMemberId *low;
796+
ExtensionMemberId *high;
797+
798+
/*
799+
* We could use bsearch() here, but the notational cruft of calling
800+
* bsearch is nearly as bad as doing it ourselves; and the generalized
801+
* bsearch function is noticeably slower as well.
802+
*/
803+
if (numextmembers <= 0)
804+
return NULL;
805+
low = extmembers;
806+
high = extmembers + (numextmembers - 1);
807+
while (low <= high)
808+
{
809+
ExtensionMemberId *middle;
810+
int difference;
811+
812+
middle = low + (high - low) / 2;
813+
/* comparison must match ExtensionMemberIdCompare, below */
814+
difference = oidcmp(middle->catId.oid, catalogId.oid);
815+
if (difference == 0)
816+
difference = oidcmp(middle->catId.tableoid, catalogId.tableoid);
817+
if (difference == 0)
818+
return middle->ext;
819+
else if (difference < 0)
820+
low = middle + 1;
821+
else
822+
high = middle - 1;
823+
}
824+
return NULL;
825+
}
826+
827+
/*
828+
* qsort comparator for ExtensionMemberIds
829+
*/
830+
static int
831+
ExtensionMemberIdCompare(const void *p1, const void *p2)
832+
{
833+
const ExtensionMemberId *obj1 = (const ExtensionMemberId *) p1;
834+
const ExtensionMemberId *obj2 = (const ExtensionMemberId *) p2;
835+
int cmpval;
836+
837+
/*
838+
* Compare OID first since it's usually unique, whereas there will only be
839+
* a few distinct values of tableoid.
840+
*/
841+
cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
842+
if (cmpval == 0)
843+
cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
844+
return cmpval;
845+
}
846+
749847

750848
/*
751849
* findParentsByOid

0 commit comments

Comments
 (0)
0