mirror of
https://github.com/postgres/postgres.git
synced 2025-05-02 11:44:50 +03:00
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 versions.
This commit is contained in:
parent
6adba13e42
commit
c42df2d46c
@ -40,30 +40,30 @@ static int numCatalogIds = 0;
|
||||
|
||||
/*
|
||||
* These variables are static to avoid the notational cruft of having to pass
|
||||
* them into findTableByOid() and friends. For each of these arrays, we
|
||||
* build a sorted-by-OID index array immediately after it's built, and then
|
||||
* we use binary search in findTableByOid() and friends. (qsort'ing the base
|
||||
* arrays themselves would be simpler, but it doesn't work because pg_dump.c
|
||||
* may have already established pointers between items.)
|
||||
* them into findTableByOid() and friends. For each of these arrays, we build
|
||||
* a sorted-by-OID index array immediately after the objects are fetched,
|
||||
* and then we use binary search in findTableByOid() and friends. (qsort'ing
|
||||
* the object arrays themselves would be simpler, but it doesn't work because
|
||||
* pg_dump.c may have already established pointers between items.)
|
||||
*/
|
||||
static TableInfo *tblinfo;
|
||||
static TypeInfo *typinfo;
|
||||
static FuncInfo *funinfo;
|
||||
static OprInfo *oprinfo;
|
||||
static NamespaceInfo *nspinfo;
|
||||
static int numTables;
|
||||
static int numTypes;
|
||||
static int numFuncs;
|
||||
static int numOperators;
|
||||
static int numCollations;
|
||||
static int numNamespaces;
|
||||
static DumpableObject **tblinfoindex;
|
||||
static DumpableObject **typinfoindex;
|
||||
static DumpableObject **funinfoindex;
|
||||
static DumpableObject **oprinfoindex;
|
||||
static DumpableObject **collinfoindex;
|
||||
static DumpableObject **nspinfoindex;
|
||||
static DumpableObject **extinfoindex;
|
||||
static int numTables;
|
||||
static int numTypes;
|
||||
static int numFuncs;
|
||||
static int numOperators;
|
||||
static int numCollations;
|
||||
static int numNamespaces;
|
||||
static int numExtensions;
|
||||
|
||||
/* This is an array of object identities, not actual DumpableObjects */
|
||||
static ExtensionMemberId *extmembers;
|
||||
static int numextmembers;
|
||||
|
||||
static void flagInhTables(TableInfo *tbinfo, int numTables,
|
||||
InhInfo *inhinfo, int numInherits);
|
||||
@ -71,6 +71,7 @@ static void flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables);
|
||||
static DumpableObject **buildIndexArray(void *objArray, int numObjs,
|
||||
Size objSize);
|
||||
static int DOCatalogIdCompare(const void *p1, const void *p2);
|
||||
static int ExtensionMemberIdCompare(const void *p1, const void *p2);
|
||||
static void findParentsByOid(TableInfo *self,
|
||||
InhInfo *inhinfo, int numInherits);
|
||||
static int strInArray(const char *pattern, char **arr, int arr_size);
|
||||
@ -83,10 +84,14 @@ static int strInArray(const char *pattern, char **arr, int arr_size);
|
||||
TableInfo *
|
||||
getSchemaData(Archive *fout, int *numTablesPtr)
|
||||
{
|
||||
TableInfo *tblinfo;
|
||||
TypeInfo *typinfo;
|
||||
FuncInfo *funinfo;
|
||||
OprInfo *oprinfo;
|
||||
CollInfo *collinfo;
|
||||
NamespaceInfo *nspinfo;
|
||||
ExtensionInfo *extinfo;
|
||||
InhInfo *inhinfo;
|
||||
CollInfo *collinfo;
|
||||
int numExtensions;
|
||||
int numAggregates;
|
||||
int numInherits;
|
||||
int numRules;
|
||||
@ -105,6 +110,20 @@ getSchemaData(Archive *fout, int *numTablesPtr)
|
||||
int numDefaultACLs;
|
||||
int numEventTriggers;
|
||||
|
||||
/*
|
||||
* We must read extensions and extension membership info first, because
|
||||
* extension membership needs to be consultable during decisions about
|
||||
* whether other objects are to be dumped.
|
||||
*/
|
||||
if (g_verbose)
|
||||
write_msg(NULL, "reading extensions\n");
|
||||
extinfo = getExtensions(fout, &numExtensions);
|
||||
extinfoindex = buildIndexArray(extinfo, numExtensions, sizeof(ExtensionInfo));
|
||||
|
||||
if (g_verbose)
|
||||
write_msg(NULL, "identifying extension members\n");
|
||||
getExtensionMembership(fout, extinfo, numExtensions);
|
||||
|
||||
if (g_verbose)
|
||||
write_msg(NULL, "reading schemas\n");
|
||||
nspinfo = getNamespaces(fout, &numNamespaces);
|
||||
@ -124,10 +143,6 @@ getSchemaData(Archive *fout, int *numTablesPtr)
|
||||
/* Do this after we've built tblinfoindex */
|
||||
getOwnedSeqs(fout, tblinfo, numTables);
|
||||
|
||||
if (g_verbose)
|
||||
write_msg(NULL, "reading extensions\n");
|
||||
extinfo = getExtensions(fout, &numExtensions);
|
||||
|
||||
if (g_verbose)
|
||||
write_msg(NULL, "reading user-defined functions\n");
|
||||
funinfo = getFuncs(fout, &numFuncs);
|
||||
@ -214,14 +229,10 @@ getSchemaData(Archive *fout, int *numTablesPtr)
|
||||
write_msg(NULL, "reading event triggers\n");
|
||||
getEventTriggers(fout, &numEventTriggers);
|
||||
|
||||
/*
|
||||
* Identify extension member objects and mark them as not to be dumped.
|
||||
* This must happen after reading all objects that can be direct members
|
||||
* of extensions, but before we begin to process table subsidiary objects.
|
||||
*/
|
||||
/* Identify extension configuration tables that should be dumped */
|
||||
if (g_verbose)
|
||||
write_msg(NULL, "finding extension members\n");
|
||||
getExtensionMembership(fout, extinfo, numExtensions);
|
||||
write_msg(NULL, "finding extension tables\n");
|
||||
processExtensionTables(fout, extinfo, numExtensions);
|
||||
|
||||
/* Link tables to parents, mark parents of target tables interesting */
|
||||
if (g_verbose)
|
||||
@ -764,6 +775,93 @@ findNamespaceByOid(Oid oid)
|
||||
return (NamespaceInfo *) findObjectByOid(oid, nspinfoindex, numNamespaces);
|
||||
}
|
||||
|
||||
/*
|
||||
* findExtensionByOid
|
||||
* finds the entry (in extinfo) of the extension with the given oid
|
||||
* returns NULL if not found
|
||||
*/
|
||||
ExtensionInfo *
|
||||
findExtensionByOid(Oid oid)
|
||||
{
|
||||
return (ExtensionInfo *) findObjectByOid(oid, extinfoindex, numExtensions);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* setExtensionMembership
|
||||
* accept and save data about which objects belong to extensions
|
||||
*/
|
||||
void
|
||||
setExtensionMembership(ExtensionMemberId *extmems, int nextmems)
|
||||
{
|
||||
/* Sort array in preparation for binary searches */
|
||||
if (nextmems > 1)
|
||||
qsort((void *) extmems, nextmems, sizeof(ExtensionMemberId),
|
||||
ExtensionMemberIdCompare);
|
||||
/* And save */
|
||||
extmembers = extmems;
|
||||
numextmembers = nextmems;
|
||||
}
|
||||
|
||||
/*
|
||||
* findOwningExtension
|
||||
* return owning extension for specified catalog ID, or NULL if none
|
||||
*/
|
||||
ExtensionInfo *
|
||||
findOwningExtension(CatalogId catalogId)
|
||||
{
|
||||
ExtensionMemberId *low;
|
||||
ExtensionMemberId *high;
|
||||
|
||||
/*
|
||||
* We could use bsearch() here, but the notational cruft of calling
|
||||
* bsearch is nearly as bad as doing it ourselves; and the generalized
|
||||
* bsearch function is noticeably slower as well.
|
||||
*/
|
||||
if (numextmembers <= 0)
|
||||
return NULL;
|
||||
low = extmembers;
|
||||
high = extmembers + (numextmembers - 1);
|
||||
while (low <= high)
|
||||
{
|
||||
ExtensionMemberId *middle;
|
||||
int difference;
|
||||
|
||||
middle = low + (high - low) / 2;
|
||||
/* comparison must match ExtensionMemberIdCompare, below */
|
||||
difference = oidcmp(middle->catId.oid, catalogId.oid);
|
||||
if (difference == 0)
|
||||
difference = oidcmp(middle->catId.tableoid, catalogId.tableoid);
|
||||
if (difference == 0)
|
||||
return middle->ext;
|
||||
else if (difference < 0)
|
||||
low = middle + 1;
|
||||
else
|
||||
high = middle - 1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* qsort comparator for ExtensionMemberIds
|
||||
*/
|
||||
static int
|
||||
ExtensionMemberIdCompare(const void *p1, const void *p2)
|
||||
{
|
||||
const ExtensionMemberId *obj1 = (const ExtensionMemberId *) p1;
|
||||
const ExtensionMemberId *obj2 = (const ExtensionMemberId *) p2;
|
||||
int cmpval;
|
||||
|
||||
/*
|
||||
* Compare OID first since it's usually unique, whereas there will only be
|
||||
* a few distinct values of tableoid.
|
||||
*/
|
||||
cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
|
||||
if (cmpval == 0)
|
||||
cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
|
||||
return cmpval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* findParentsByOid
|
||||
|
@ -1237,13 +1237,54 @@ expand_table_name_patterns(Archive *fout,
|
||||
destroyPQExpBuffer(query);
|
||||
}
|
||||
|
||||
/*
|
||||
* checkExtensionMembership
|
||||
* Determine whether object is an extension member, and if so,
|
||||
* record an appropriate dependency and set the object's dump flag.
|
||||
*
|
||||
* It's important to call this for each object that could be an extension
|
||||
* member. Generally, we integrate this with determining the object's
|
||||
* to-be-dumped-ness, since extension membership overrides other rules for that.
|
||||
*
|
||||
* Returns true if object is an extension member, else false.
|
||||
*/
|
||||
static bool
|
||||
checkExtensionMembership(DumpableObject *dobj, DumpOptions *dopt)
|
||||
{
|
||||
ExtensionInfo *ext = findOwningExtension(dobj->catId);
|
||||
|
||||
if (ext == NULL)
|
||||
return false;
|
||||
|
||||
dobj->ext_member = true;
|
||||
|
||||
/* Record dependency so that getDependencies needn't deal with that */
|
||||
addObjectDependency(dobj, ext->dobj.dumpId);
|
||||
|
||||
/*
|
||||
* Normally, mark the member object as not to be dumped. But in binary
|
||||
* upgrades, we still dump the members individually, since the idea is to
|
||||
* exactly reproduce the database contents rather than replace the
|
||||
* extension contents with something different.
|
||||
*/
|
||||
if (!dopt->binary_upgrade)
|
||||
dobj->dump = false;
|
||||
else
|
||||
dobj->dump = ext->dobj.dump;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* selectDumpableNamespace: policy-setting subroutine
|
||||
* Mark a namespace as to be dumped or not
|
||||
*/
|
||||
static void
|
||||
selectDumpableNamespace(NamespaceInfo *nsinfo)
|
||||
selectDumpableNamespace(NamespaceInfo *nsinfo, DumpOptions *dopt)
|
||||
{
|
||||
if (checkExtensionMembership(&nsinfo->dobj, dopt))
|
||||
return; /* extension membership overrides all else */
|
||||
|
||||
/*
|
||||
* If specific tables are being dumped, do not dump any complete
|
||||
* namespaces. If specific namespaces are being dumped, dump just those
|
||||
@ -1274,8 +1315,11 @@ selectDumpableNamespace(NamespaceInfo *nsinfo)
|
||||
* Mark a table as to be dumped or not
|
||||
*/
|
||||
static void
|
||||
selectDumpableTable(TableInfo *tbinfo)
|
||||
selectDumpableTable(TableInfo *tbinfo, DumpOptions *dopt)
|
||||
{
|
||||
if (checkExtensionMembership(&tbinfo->dobj, dopt))
|
||||
return; /* extension membership overrides all else */
|
||||
|
||||
/*
|
||||
* If specific tables are being dumped, dump just those tables; else, dump
|
||||
* according to the parent namespace's dump flag.
|
||||
@ -1309,7 +1353,7 @@ selectDumpableTable(TableInfo *tbinfo)
|
||||
* object (the table or base type).
|
||||
*/
|
||||
static void
|
||||
selectDumpableType(TypeInfo *tyinfo)
|
||||
selectDumpableType(TypeInfo *tyinfo, DumpOptions *dopt)
|
||||
{
|
||||
/* skip complex types, except for standalone composite types */
|
||||
if (OidIsValid(tyinfo->typrelid) &&
|
||||
@ -1338,6 +1382,9 @@ selectDumpableType(TypeInfo *tyinfo)
|
||||
*/
|
||||
}
|
||||
|
||||
if (checkExtensionMembership(&tyinfo->dobj, dopt))
|
||||
return; /* extension membership overrides all else */
|
||||
|
||||
/* dump only types in dumpable namespaces */
|
||||
if (!tyinfo->dobj.namespace->dobj.dump)
|
||||
tyinfo->dobj.dump = false;
|
||||
@ -1354,8 +1401,10 @@ selectDumpableType(TypeInfo *tyinfo)
|
||||
* and aclsSkip are checked separately.
|
||||
*/
|
||||
static void
|
||||
selectDumpableDefaultACL(DumpOptions *dopt, DefaultACLInfo *dinfo)
|
||||
selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
|
||||
{
|
||||
/* Default ACLs can't be extension members */
|
||||
|
||||
if (dinfo->dobj.namespace)
|
||||
dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
|
||||
else
|
||||
@ -1372,14 +1421,37 @@ selectDumpableDefaultACL(DumpOptions *dopt, DefaultACLInfo *dinfo)
|
||||
* OID is in the range reserved for initdb.
|
||||
*/
|
||||
static void
|
||||
selectDumpableCast(DumpOptions *dopt, CastInfo *cast)
|
||||
selectDumpableCast(CastInfo *cast, DumpOptions *dopt)
|
||||
{
|
||||
if (checkExtensionMembership(&cast->dobj, dopt))
|
||||
return; /* extension membership overrides all else */
|
||||
|
||||
if (cast->dobj.catId.oid < (Oid) FirstNormalObjectId)
|
||||
cast->dobj.dump = false;
|
||||
else
|
||||
cast->dobj.dump = dopt->include_everything;
|
||||
}
|
||||
|
||||
/*
|
||||
* selectDumpableProcLang: policy-setting subroutine
|
||||
* Mark a procedural language as to be dumped or not
|
||||
*
|
||||
* Procedural languages do not belong to any particular namespace. To
|
||||
* identify built-in languages, we must resort to checking whether the
|
||||
* language's OID is in the range reserved for initdb.
|
||||
*/
|
||||
static void
|
||||
selectDumpableProcLang(ProcLangInfo *plang, DumpOptions *dopt)
|
||||
{
|
||||
if (checkExtensionMembership(&plang->dobj, dopt))
|
||||
return; /* extension membership overrides all else */
|
||||
|
||||
if (plang->dobj.catId.oid < (Oid) FirstNormalObjectId)
|
||||
plang->dobj.dump = false;
|
||||
else
|
||||
plang->dobj.dump = dopt->include_everything;
|
||||
}
|
||||
|
||||
/*
|
||||
* selectDumpableExtension: policy-setting subroutine
|
||||
* Mark an extension as to be dumped or not
|
||||
@ -1391,7 +1463,7 @@ selectDumpableCast(DumpOptions *dopt, CastInfo *cast)
|
||||
* such extensions by their having OIDs in the range reserved for initdb.
|
||||
*/
|
||||
static void
|
||||
selectDumpableExtension(DumpOptions *dopt, ExtensionInfo *extinfo)
|
||||
selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
|
||||
{
|
||||
if (dopt->binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
|
||||
extinfo->dobj.dump = false;
|
||||
@ -1406,16 +1478,19 @@ selectDumpableExtension(DumpOptions *dopt, ExtensionInfo *extinfo)
|
||||
* Use this only for object types without a special-case routine above.
|
||||
*/
|
||||
static void
|
||||
selectDumpableObject(DumpableObject *dobj)
|
||||
selectDumpableObject(DumpableObject *dobj, DumpOptions *dopt)
|
||||
{
|
||||
if (checkExtensionMembership(dobj, dopt))
|
||||
return; /* extension membership overrides all else */
|
||||
|
||||
/*
|
||||
* Default policy is to dump if parent namespace is dumpable, or always
|
||||
* for non-namespace-associated items.
|
||||
* Default policy is to dump if parent namespace is dumpable, or for
|
||||
* non-namespace-associated items, dump if we're dumping "everything".
|
||||
*/
|
||||
if (dobj->namespace)
|
||||
dobj->dump = dobj->namespace->dobj.dump;
|
||||
else
|
||||
dobj->dump = true;
|
||||
dobj->dump = dopt->include_everything;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3242,6 +3317,7 @@ binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
|
||||
NamespaceInfo *
|
||||
getNamespaces(Archive *fout, int *numNamespaces)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
PGresult *res;
|
||||
int ntups;
|
||||
int i;
|
||||
@ -3269,7 +3345,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
|
||||
nsinfo[0].rolname = pg_strdup("");
|
||||
nsinfo[0].nspacl = pg_strdup("");
|
||||
|
||||
selectDumpableNamespace(&nsinfo[0]);
|
||||
selectDumpableNamespace(&nsinfo[0], dopt);
|
||||
|
||||
nsinfo[1].dobj.objType = DO_NAMESPACE;
|
||||
nsinfo[1].dobj.catId.tableoid = 0;
|
||||
@ -3279,7 +3355,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
|
||||
nsinfo[1].rolname = pg_strdup("");
|
||||
nsinfo[1].nspacl = pg_strdup("");
|
||||
|
||||
selectDumpableNamespace(&nsinfo[1]);
|
||||
selectDumpableNamespace(&nsinfo[1], dopt);
|
||||
|
||||
*numNamespaces = 2;
|
||||
|
||||
@ -3323,7 +3399,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
|
||||
nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
|
||||
|
||||
/* Decide whether to dump this namespace */
|
||||
selectDumpableNamespace(&nsinfo[i]);
|
||||
selectDumpableNamespace(&nsinfo[i], dopt);
|
||||
|
||||
if (strlen(nsinfo[i].rolname) == 0)
|
||||
write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
|
||||
@ -3447,7 +3523,7 @@ getExtensions(Archive *fout, int *numExtensions)
|
||||
extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableExtension(dopt, &(extinfo[i]));
|
||||
selectDumpableExtension(&(extinfo[i]), dopt);
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
@ -3471,6 +3547,7 @@ getExtensions(Archive *fout, int *numExtensions)
|
||||
TypeInfo *
|
||||
getTypes(Archive *fout, int *numTypes)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
PGresult *res;
|
||||
int ntups;
|
||||
int i;
|
||||
@ -3637,7 +3714,7 @@ getTypes(Archive *fout, int *numTypes)
|
||||
tyinfo[i].isArray = false;
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableType(&tyinfo[i]);
|
||||
selectDumpableType(&tyinfo[i], dopt);
|
||||
|
||||
/*
|
||||
* If it's a domain, fetch info about its constraints, if any
|
||||
@ -3743,6 +3820,7 @@ getTypes(Archive *fout, int *numTypes)
|
||||
OprInfo *
|
||||
getOperators(Archive *fout, int *numOprs)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
PGresult *res;
|
||||
int ntups;
|
||||
int i;
|
||||
@ -3828,7 +3906,7 @@ getOperators(Archive *fout, int *numOprs)
|
||||
oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableObject(&(oprinfo[i].dobj));
|
||||
selectDumpableObject(&(oprinfo[i].dobj), dopt);
|
||||
|
||||
if (strlen(oprinfo[i].rolname) == 0)
|
||||
write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
|
||||
@ -3852,6 +3930,7 @@ getOperators(Archive *fout, int *numOprs)
|
||||
CollInfo *
|
||||
getCollations(Archive *fout, int *numCollations)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
PGresult *res;
|
||||
int ntups;
|
||||
int i;
|
||||
@ -3913,7 +3992,7 @@ getCollations(Archive *fout, int *numCollations)
|
||||
collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableObject(&(collinfo[i].dobj));
|
||||
selectDumpableObject(&(collinfo[i].dobj), dopt);
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
@ -3933,6 +4012,7 @@ getCollations(Archive *fout, int *numCollations)
|
||||
ConvInfo *
|
||||
getConversions(Archive *fout, int *numConversions)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
PGresult *res;
|
||||
int ntups;
|
||||
int i;
|
||||
@ -3994,7 +4074,7 @@ getConversions(Archive *fout, int *numConversions)
|
||||
convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableObject(&(convinfo[i].dobj));
|
||||
selectDumpableObject(&(convinfo[i].dobj), dopt);
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
@ -4014,6 +4094,7 @@ getConversions(Archive *fout, int *numConversions)
|
||||
OpclassInfo *
|
||||
getOpclasses(Archive *fout, int *numOpclasses)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
PGresult *res;
|
||||
int ntups;
|
||||
int i;
|
||||
@ -4085,7 +4166,7 @@ getOpclasses(Archive *fout, int *numOpclasses)
|
||||
opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableObject(&(opcinfo[i].dobj));
|
||||
selectDumpableObject(&(opcinfo[i].dobj), dopt);
|
||||
|
||||
if (fout->remoteVersion >= 70300)
|
||||
{
|
||||
@ -4112,6 +4193,7 @@ getOpclasses(Archive *fout, int *numOpclasses)
|
||||
OpfamilyInfo *
|
||||
getOpfamilies(Archive *fout, int *numOpfamilies)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
PGresult *res;
|
||||
int ntups;
|
||||
int i;
|
||||
@ -4173,7 +4255,7 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
|
||||
opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableObject(&(opfinfo[i].dobj));
|
||||
selectDumpableObject(&(opfinfo[i].dobj), dopt);
|
||||
|
||||
if (fout->remoteVersion >= 70300)
|
||||
{
|
||||
@ -4338,7 +4420,7 @@ getAggregates(Archive *fout, int *numAggs)
|
||||
}
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableObject(&(agginfo[i].aggfn.dobj));
|
||||
selectDumpableObject(&(agginfo[i].aggfn.dobj), dopt);
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
@ -4496,7 +4578,7 @@ getFuncs(Archive *fout, int *numFuncs)
|
||||
}
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableObject(&(finfo[i].dobj));
|
||||
selectDumpableObject(&(finfo[i].dobj), dopt);
|
||||
|
||||
if (strlen(finfo[i].rolname) == 0)
|
||||
write_msg(NULL,
|
||||
@ -5159,7 +5241,7 @@ getTables(Archive *fout, int *numTables)
|
||||
if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
|
||||
tblinfo[i].dobj.dump = false;
|
||||
else
|
||||
selectDumpableTable(&tblinfo[i]);
|
||||
selectDumpableTable(&tblinfo[i], dopt);
|
||||
tblinfo[i].interesting = tblinfo[i].dobj.dump;
|
||||
|
||||
tblinfo[i].postponed_def = false; /* might get set during sort */
|
||||
@ -6239,6 +6321,7 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
|
||||
EventTriggerInfo *
|
||||
getEventTriggers(Archive *fout, int *numEventTriggers)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
int i;
|
||||
PQExpBuffer query;
|
||||
PGresult *res;
|
||||
@ -6306,6 +6389,9 @@ getEventTriggers(Archive *fout, int *numEventTriggers)
|
||||
evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
|
||||
evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
|
||||
evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableObject(&(evtinfo[i].dobj), dopt);
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
@ -6327,6 +6413,7 @@ getEventTriggers(Archive *fout, int *numEventTriggers)
|
||||
ProcLangInfo *
|
||||
getProcLangs(Archive *fout, int *numProcLangs)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
PGresult *res;
|
||||
int ntups;
|
||||
int i;
|
||||
@ -6460,6 +6547,9 @@ getProcLangs(Archive *fout, int *numProcLangs)
|
||||
planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
|
||||
planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableProcLang(&(planginfo[i]), dopt);
|
||||
|
||||
if (fout->remoteVersion < 70300)
|
||||
{
|
||||
/*
|
||||
@ -6597,7 +6687,7 @@ getCasts(Archive *fout, int *numCasts)
|
||||
}
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableCast(dopt, &(castinfo[i]));
|
||||
selectDumpableCast(&(castinfo[i]), dopt);
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
@ -6633,6 +6723,7 @@ get_language_name(Archive *fout, Oid langid)
|
||||
TransformInfo *
|
||||
getTransforms(Archive *fout, int *numTransforms)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
PGresult *res;
|
||||
int ntups;
|
||||
int i;
|
||||
@ -6705,6 +6796,9 @@ getTransforms(Archive *fout, int *numTransforms)
|
||||
typeInfo->dobj.name, lanname);
|
||||
transforminfo[i].dobj.name = namebuf.data;
|
||||
free(lanname);
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableObject(&(transforminfo[i].dobj), dopt);
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
@ -7315,6 +7409,7 @@ shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
|
||||
TSParserInfo *
|
||||
getTSParsers(Archive *fout, int *numTSParsers)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
PGresult *res;
|
||||
int ntups;
|
||||
int i;
|
||||
@ -7387,7 +7482,7 @@ getTSParsers(Archive *fout, int *numTSParsers)
|
||||
prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableObject(&(prsinfo[i].dobj));
|
||||
selectDumpableObject(&(prsinfo[i].dobj), dopt);
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
@ -7407,6 +7502,7 @@ getTSParsers(Archive *fout, int *numTSParsers)
|
||||
TSDictInfo *
|
||||
getTSDictionaries(Archive *fout, int *numTSDicts)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
PGresult *res;
|
||||
int ntups;
|
||||
int i;
|
||||
@ -7472,7 +7568,7 @@ getTSDictionaries(Archive *fout, int *numTSDicts)
|
||||
dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableObject(&(dictinfo[i].dobj));
|
||||
selectDumpableObject(&(dictinfo[i].dobj), dopt);
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
@ -7492,6 +7588,7 @@ getTSDictionaries(Archive *fout, int *numTSDicts)
|
||||
TSTemplateInfo *
|
||||
getTSTemplates(Archive *fout, int *numTSTemplates)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
PGresult *res;
|
||||
int ntups;
|
||||
int i;
|
||||
@ -7549,7 +7646,7 @@ getTSTemplates(Archive *fout, int *numTSTemplates)
|
||||
tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableObject(&(tmplinfo[i].dobj));
|
||||
selectDumpableObject(&(tmplinfo[i].dobj), dopt);
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
@ -7569,6 +7666,7 @@ getTSTemplates(Archive *fout, int *numTSTemplates)
|
||||
TSConfigInfo *
|
||||
getTSConfigurations(Archive *fout, int *numTSConfigs)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
PGresult *res;
|
||||
int ntups;
|
||||
int i;
|
||||
@ -7627,7 +7725,7 @@ getTSConfigurations(Archive *fout, int *numTSConfigs)
|
||||
cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableObject(&(cfginfo[i].dobj));
|
||||
selectDumpableObject(&(cfginfo[i].dobj), dopt);
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
@ -7647,6 +7745,7 @@ getTSConfigurations(Archive *fout, int *numTSConfigs)
|
||||
FdwInfo *
|
||||
getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
PGresult *res;
|
||||
int ntups;
|
||||
int i;
|
||||
@ -7735,7 +7834,7 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
|
||||
fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableObject(&(fdwinfo[i].dobj));
|
||||
selectDumpableObject(&(fdwinfo[i].dobj), dopt);
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
@ -7755,6 +7854,7 @@ getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
|
||||
ForeignServerInfo *
|
||||
getForeignServers(Archive *fout, int *numForeignServers)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
PGresult *res;
|
||||
int ntups;
|
||||
int i;
|
||||
@ -7827,7 +7927,7 @@ getForeignServers(Archive *fout, int *numForeignServers)
|
||||
srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableObject(&(srvinfo[i].dobj));
|
||||
selectDumpableObject(&(srvinfo[i].dobj), dopt);
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
@ -7915,7 +8015,7 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)
|
||||
daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableDefaultACL(dopt, &(daclinfo[i]));
|
||||
selectDumpableDefaultACL(&(daclinfo[i]), dopt);
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
@ -9879,32 +9979,6 @@ dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
|
||||
destroyPQExpBuffer(q);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether we want to dump definitions for procedural languages.
|
||||
* Since the languages themselves don't have schemas, we can't rely on
|
||||
* the normal schema-based selection mechanism. We choose to dump them
|
||||
* whenever neither --schema nor --table was given. (Before 8.1, we used
|
||||
* the dump flag of the PL's call handler function, but in 8.1 this will
|
||||
* probably always be false since call handlers are created in pg_catalog.)
|
||||
*
|
||||
* For some backwards compatibility with the older behavior, we forcibly
|
||||
* dump a PL if its handler function (and validator if any) are in a
|
||||
* dumpable namespace. That case is not checked here.
|
||||
*
|
||||
* Also, if the PL belongs to an extension, we do not use this heuristic.
|
||||
* That case isn't checked here either.
|
||||
*/
|
||||
static bool
|
||||
shouldDumpProcLangs(DumpOptions *dopt)
|
||||
{
|
||||
if (!dopt->include_everything)
|
||||
return false;
|
||||
/* And they're schema not data */
|
||||
if (dopt->dataOnly)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* dumpProcLang
|
||||
* writes out to fout the queries to recreate a user-defined
|
||||
@ -9956,25 +10030,13 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
|
||||
|
||||
/*
|
||||
* If the functions are dumpable then emit a traditional CREATE LANGUAGE
|
||||
* with parameters. Otherwise, dump only if shouldDumpProcLangs() says to
|
||||
* dump it.
|
||||
*
|
||||
* However, for a language that belongs to an extension, we must not use
|
||||
* the shouldDumpProcLangs heuristic, but just dump the language iff we're
|
||||
* told to (via dobj.dump). Generally the support functions will belong
|
||||
* to the same extension and so have the same dump flags ... if they
|
||||
* don't, this might not work terribly nicely.
|
||||
* with parameters. Otherwise, we'll write a parameterless command, which
|
||||
* will rely on data from pg_pltemplate.
|
||||
*/
|
||||
useParams = (funcInfo != NULL &&
|
||||
(inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
|
||||
(validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
|
||||
|
||||
if (!plang->dobj.ext_member)
|
||||
{
|
||||
if (!useParams && !shouldDumpProcLangs(dopt))
|
||||
return;
|
||||
}
|
||||
|
||||
defqry = createPQExpBuffer();
|
||||
delqry = createPQExpBuffer();
|
||||
labelq = createPQExpBuffer();
|
||||
@ -13002,14 +13064,6 @@ dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
|
||||
if (!fdwinfo->dobj.dump || dopt->dataOnly)
|
||||
return;
|
||||
|
||||
/*
|
||||
* FDWs that belong to an extension are dumped based on their "dump"
|
||||
* field. Otherwise omit them if we are only dumping some specific object.
|
||||
*/
|
||||
if (!fdwinfo->dobj.ext_member)
|
||||
if (!dopt->include_everything)
|
||||
return;
|
||||
|
||||
q = createPQExpBuffer();
|
||||
delq = createPQExpBuffer();
|
||||
labelq = createPQExpBuffer();
|
||||
@ -13085,7 +13139,7 @@ dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
|
||||
char *fdwname;
|
||||
|
||||
/* Skip if not to be dumped */
|
||||
if (!srvinfo->dobj.dump || dopt->dataOnly || !dopt->include_everything)
|
||||
if (!srvinfo->dobj.dump || dopt->dataOnly)
|
||||
return;
|
||||
|
||||
q = createPQExpBuffer();
|
||||
@ -15635,50 +15689,27 @@ dumpRule(Archive *fout, RuleInfo *rinfo)
|
||||
/*
|
||||
* getExtensionMembership --- obtain extension membership data
|
||||
*
|
||||
* There are three main parts to this process:
|
||||
*
|
||||
* 1. Identify objects which are members of extensions
|
||||
*
|
||||
* Generally speaking, this is to mark them as *not* being dumped, as most
|
||||
* extension objects are created by the single CREATE EXTENSION command.
|
||||
* The one exception is binary upgrades with pg_upgrade will still dump the
|
||||
* non-table objects.
|
||||
*
|
||||
* 2. Identify and create dump records for extension configuration tables.
|
||||
*
|
||||
* Extensions can mark tables as "configuration", which means that the user
|
||||
* is able and expected to modify those tables after the extension has been
|
||||
* loaded. For these tables, we dump out only the data- the structure is
|
||||
* expected to be handled at CREATE EXTENSION time, including any indexes or
|
||||
* foreign keys, which brings us to-
|
||||
*
|
||||
* 3. Record FK dependencies between configuration tables.
|
||||
*
|
||||
* Due to the FKs being created at CREATE EXTENSION time and therefore before
|
||||
* the data is loaded, we have to work out what the best order for reloading
|
||||
* the data is, to avoid FK violations when the tables are restored. This is
|
||||
* not perfect- we can't handle circular dependencies and if any exist they
|
||||
* will cause an invalid dump to be produced (though at least all of the data
|
||||
* is included for a user to manually restore). This is currently documented
|
||||
* but perhaps we can provide a better solution in the future.
|
||||
* We need to identify objects that are extension members as soon as they're
|
||||
* loaded, so that we can correctly determine whether they need to be dumped.
|
||||
* Generally speaking, extension member objects will get marked as *not* to
|
||||
* be dumped, as they will be recreated by the single CREATE EXTENSION
|
||||
* command. However, in binary upgrade mode we still need to dump the members
|
||||
* individually.
|
||||
*/
|
||||
void
|
||||
getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
|
||||
int numExtensions)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
PQExpBuffer query;
|
||||
PGresult *res;
|
||||
int ntups,
|
||||
nextmembers,
|
||||
i;
|
||||
int i_classid,
|
||||
i_objid,
|
||||
i_refclassid,
|
||||
i_refobjid,
|
||||
i_conrelid,
|
||||
i_confrelid;
|
||||
DumpableObject *dobj,
|
||||
*refdobj;
|
||||
i_refobjid;
|
||||
ExtensionMemberId *extmembers;
|
||||
ExtensionInfo *ext;
|
||||
|
||||
/* Nothing to do if no extensions */
|
||||
if (numExtensions == 0)
|
||||
@ -15691,11 +15722,11 @@ getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
|
||||
|
||||
/* refclassid constraint is redundant but may speed the search */
|
||||
appendPQExpBufferStr(query, "SELECT "
|
||||
"classid, objid, refclassid, refobjid "
|
||||
"classid, objid, refobjid "
|
||||
"FROM pg_depend "
|
||||
"WHERE refclassid = 'pg_extension'::regclass "
|
||||
"AND deptype = 'e' "
|
||||
"ORDER BY 3,4");
|
||||
"ORDER BY 3");
|
||||
|
||||
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
|
||||
|
||||
@ -15703,76 +15734,94 @@ getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
|
||||
|
||||
i_classid = PQfnumber(res, "classid");
|
||||
i_objid = PQfnumber(res, "objid");
|
||||
i_refclassid = PQfnumber(res, "refclassid");
|
||||
i_refobjid = PQfnumber(res, "refobjid");
|
||||
|
||||
extmembers = (ExtensionMemberId *) pg_malloc(ntups * sizeof(ExtensionMemberId));
|
||||
nextmembers = 0;
|
||||
|
||||
/*
|
||||
* Accumulate data into extmembers[].
|
||||
*
|
||||
* Since we ordered the SELECT by referenced ID, we can expect that
|
||||
* multiple entries for the same extension will appear together; this
|
||||
* saves on searches.
|
||||
*/
|
||||
refdobj = NULL;
|
||||
ext = NULL;
|
||||
|
||||
for (i = 0; i < ntups; i++)
|
||||
{
|
||||
CatalogId objId;
|
||||
CatalogId refobjId;
|
||||
Oid extId;
|
||||
|
||||
objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
|
||||
objId.oid = atooid(PQgetvalue(res, i, i_objid));
|
||||
refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
|
||||
refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
|
||||
extId = atooid(PQgetvalue(res, i, i_refobjid));
|
||||
|
||||
if (refdobj == NULL ||
|
||||
refdobj->catId.tableoid != refobjId.tableoid ||
|
||||
refdobj->catId.oid != refobjId.oid)
|
||||
refdobj = findObjectByCatalogId(refobjId);
|
||||
if (ext == NULL ||
|
||||
ext->dobj.catId.oid != extId)
|
||||
ext = findExtensionByOid(extId);
|
||||
|
||||
/*
|
||||
* Failure to find objects mentioned in pg_depend is not unexpected,
|
||||
* since for example we don't collect info about TOAST tables.
|
||||
*/
|
||||
if (refdobj == NULL)
|
||||
if (ext == NULL)
|
||||
{
|
||||
#ifdef NOT_USED
|
||||
fprintf(stderr, "no referenced object %u %u\n",
|
||||
refobjId.tableoid, refobjId.oid);
|
||||
#endif
|
||||
/* shouldn't happen */
|
||||
fprintf(stderr, "could not find referenced extension %u\n", extId);
|
||||
continue;
|
||||
}
|
||||
|
||||
dobj = findObjectByCatalogId(objId);
|
||||
|
||||
if (dobj == NULL)
|
||||
{
|
||||
#ifdef NOT_USED
|
||||
fprintf(stderr, "no referencing object %u %u\n",
|
||||
objId.tableoid, objId.oid);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Record dependency so that getDependencies needn't repeat this */
|
||||
addObjectDependency(dobj, refdobj->dumpId);
|
||||
|
||||
dobj->ext_member = true;
|
||||
|
||||
/*
|
||||
* Normally, mark the member object as not to be dumped. But in
|
||||
* binary upgrades, we still dump the members individually, since the
|
||||
* idea is to exactly reproduce the database contents rather than
|
||||
* replace the extension contents with something different.
|
||||
*/
|
||||
if (!dopt->binary_upgrade)
|
||||
dobj->dump = false;
|
||||
else
|
||||
dobj->dump = refdobj->dump;
|
||||
extmembers[nextmembers].catId = objId;
|
||||
extmembers[nextmembers].ext = ext;
|
||||
nextmembers++;
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
|
||||
/* Remember the data for use later */
|
||||
setExtensionMembership(extmembers, nextmembers);
|
||||
|
||||
destroyPQExpBuffer(query);
|
||||
}
|
||||
|
||||
/*
|
||||
* processExtensionTables --- deal with extension configuration tables
|
||||
*
|
||||
* There are two parts to this process:
|
||||
*
|
||||
* 1. Identify and create dump records for extension configuration tables.
|
||||
*
|
||||
* Extensions can mark tables as "configuration", which means that the user
|
||||
* is able and expected to modify those tables after the extension has been
|
||||
* loaded. For these tables, we dump out only the data- the structure is
|
||||
* expected to be handled at CREATE EXTENSION time, including any indexes or
|
||||
* foreign keys, which brings us to-
|
||||
*
|
||||
* 2. Record FK dependencies between configuration tables.
|
||||
*
|
||||
* Due to the FKs being created at CREATE EXTENSION time and therefore before
|
||||
* the data is loaded, we have to work out what the best order for reloading
|
||||
* the data is, to avoid FK violations when the tables are restored. This is
|
||||
* not perfect- we can't handle circular dependencies and if any exist they
|
||||
* will cause an invalid dump to be produced (though at least all of the data
|
||||
* is included for a user to manually restore). This is currently documented
|
||||
* but perhaps we can provide a better solution in the future.
|
||||
*/
|
||||
void
|
||||
processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
|
||||
int numExtensions)
|
||||
{
|
||||
DumpOptions *dopt = fout->dopt;
|
||||
PQExpBuffer query;
|
||||
PGresult *res;
|
||||
int ntups,
|
||||
i;
|
||||
int i_conrelid,
|
||||
i_confrelid;
|
||||
|
||||
/* Nothing to do if no extensions */
|
||||
if (numExtensions == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Now identify extension configuration tables and create TableDataInfo
|
||||
* Identify extension configuration tables and create TableDataInfo
|
||||
* objects for them, ensuring their data will be dumped even though the
|
||||
* tables themselves won't be.
|
||||
*
|
||||
@ -15860,11 +15909,17 @@ getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
|
||||
/*
|
||||
* Now that all the TableInfoData objects have been created for all the
|
||||
* extensions, check their FK dependencies and register them to try and
|
||||
* dump the data out in an order which they can be restored in.
|
||||
* dump the data out in an order that they can be restored in.
|
||||
*
|
||||
* Note that this is not a problem for user tables as their FKs are
|
||||
* recreated after the data has been loaded.
|
||||
*/
|
||||
|
||||
/* Make sure we are in proper schema */
|
||||
selectSourceSchema(fout, "pg_catalog");
|
||||
|
||||
query = createPQExpBuffer();
|
||||
|
||||
printfPQExpBuffer(query,
|
||||
"SELECT conrelid, confrelid "
|
||||
"FROM pg_constraint "
|
||||
|
@ -479,6 +479,16 @@ typedef struct _policyInfo
|
||||
char *polwithcheck;
|
||||
} PolicyInfo;
|
||||
|
||||
/*
|
||||
* We build an array of these with an entry for each object that is an
|
||||
* extension member according to pg_depend.
|
||||
*/
|
||||
typedef struct _extensionMemberId
|
||||
{
|
||||
CatalogId catId; /* tableoid+oid of some member object */
|
||||
ExtensionInfo *ext; /* owning extension */
|
||||
} ExtensionMemberId;
|
||||
|
||||
/* global decls */
|
||||
extern bool force_quotes; /* double-quotes for identifiers flag */
|
||||
extern bool g_verbose; /* verbose flag */
|
||||
@ -511,6 +521,10 @@ extern FuncInfo *findFuncByOid(Oid oid);
|
||||
extern OprInfo *findOprByOid(Oid oid);
|
||||
extern CollInfo *findCollationByOid(Oid oid);
|
||||
extern NamespaceInfo *findNamespaceByOid(Oid oid);
|
||||
extern ExtensionInfo *findExtensionByOid(Oid oid);
|
||||
|
||||
extern void setExtensionMembership(ExtensionMemberId *extmems, int nextmems);
|
||||
extern ExtensionInfo *findOwningExtension(CatalogId catalogId);
|
||||
|
||||
extern void simple_oid_list_append(SimpleOidList *list, Oid val);
|
||||
extern bool simple_oid_list_member(SimpleOidList *list, Oid val);
|
||||
@ -559,6 +573,8 @@ extern ForeignServerInfo *getForeignServers(Archive *fout,
|
||||
extern DefaultACLInfo *getDefaultACLs(Archive *fout, int *numDefaultACLs);
|
||||
extern void getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
|
||||
int numExtensions);
|
||||
extern void processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
|
||||
int numExtensions);
|
||||
extern EventTriggerInfo *getEventTriggers(Archive *fout, int *numEventTriggers);
|
||||
extern void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user